reformatted using black

This commit is contained in:
tomaae 2020-04-11 05:45:36 +02:00
parent 8f89051be6
commit 70cdb93eb3
8 changed files with 319 additions and 222 deletions

View file

@ -44,13 +44,11 @@ async def async_setup_entry(hass, config_entry):
) )
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, hass.config_entries.async_forward_entry_setup(config_entry, "binary_sensor")
"binary_sensor")
) )
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, hass.config_entries.async_forward_entry_setup(config_entry, "device_tracker")
"device_tracker")
) )
hass.async_create_task( hass.async_create_task(
@ -76,10 +74,8 @@ async def async_unload_entry(hass, config_entry):
"""Unload a config entry.""" """Unload a config entry."""
controller = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] controller = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
await hass.config_entries.async_forward_entry_unload(config_entry, "sensor") await hass.config_entries.async_forward_entry_unload(config_entry, "sensor")
await hass.config_entries.async_forward_entry_unload(config_entry, await hass.config_entries.async_forward_entry_unload(config_entry, "binary_sensor")
"binary_sensor") await hass.config_entries.async_forward_entry_unload(config_entry, "device_tracker")
await hass.config_entries.async_forward_entry_unload(config_entry,
"device_tracker")
await hass.config_entries.async_forward_entry_unload(config_entry, "switch") await hass.config_entries.async_forward_entry_unload(config_entry, "switch")
await controller.async_reset() await controller.async_reset()
hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id) hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id)

View file

@ -50,8 +50,7 @@ _LOGGER = logging.getLogger(__name__)
def configured_instances(hass): def configured_instances(hass):
"""Return a set of configured instances.""" """Return a set of configured instances."""
return set( return set(
entry.data[CONF_NAME] for entry in entry.data[CONF_NAME] for entry in hass.config_entries.async_entries(DOMAIN)
hass.config_entries.async_entries(DOMAIN)
) )
@ -91,7 +90,7 @@ class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN):
username=user_input[CONF_USERNAME], username=user_input[CONF_USERNAME],
password=user_input[CONF_PASSWORD], password=user_input[CONF_PASSWORD],
port=user_input[CONF_PORT], port=user_input[CONF_PORT],
use_ssl=user_input[CONF_SSL] use_ssl=user_input[CONF_SSL],
) )
if not api.connect(): if not api.connect():
errors[CONF_HOST] = api.error errors[CONF_HOST] = api.error
@ -99,14 +98,10 @@ class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN):
# Save instance # Save instance
if not errors: if not errors:
return self.async_create_entry( return self.async_create_entry(
title=user_input[CONF_NAME], title=user_input[CONF_NAME], data=user_input
data=user_input
) )
return self._show_config_form( return self._show_config_form(user_input=user_input, errors=errors)
user_input=user_input,
errors=errors,
)
return self._show_config_form( return self._show_config_form(
user_input={ user_input={
@ -117,7 +112,7 @@ class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN):
CONF_PORT: DEFAULT_PORT, CONF_PORT: DEFAULT_PORT,
CONF_SSL: DEFAULT_SSL, CONF_SSL: DEFAULT_SSL,
}, },
errors=errors errors=errors,
) )
# --------------------------- # ---------------------------
@ -195,7 +190,7 @@ class MikrotikControllerOptionsFlowHandler(OptionsFlow):
default=self.config_entry.options.get( default=self.config_entry.options.get(
CONF_TRACK_HOSTS_TIMEOUT, DEFAULT_TRACK_HOST_TIMEOUT CONF_TRACK_HOSTS_TIMEOUT, DEFAULT_TRACK_HOST_TIMEOUT
), ),
): int ): int,
} }
), ),
) )

View file

@ -88,7 +88,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
@callback @callback
def update_controller(): def update_controller():
"""Update the values of the controller.""" """Update the values of the controller."""
update_items(inst, config_entry, mikrotik_controller, async_add_entities, tracked) update_items(
inst, config_entry, mikrotik_controller, async_add_entities, tracked
)
mikrotik_controller.listeners.append( mikrotik_controller.listeners.append(
async_dispatcher_connect( async_dispatcher_connect(
@ -111,10 +113,7 @@ def update_items(inst, config_entry, mikrotik_controller, async_add_entities, tr
for sid, sid_uid, sid_func in zip( for sid, sid_uid, sid_func in zip(
["interface", "host"], ["interface", "host"],
["default-name", "mac-address"], ["default-name", "mac-address"],
[ [MikrotikControllerPortDeviceTracker, MikrotikControllerHostDeviceTracker],
MikrotikControllerPortDeviceTracker,
MikrotikControllerHostDeviceTracker,
],
): ):
for uid in mikrotik_controller.data[sid]: for uid in mikrotik_controller.data[sid]:
item_id = f"{inst}-{sid}-{mikrotik_controller.data[sid][uid][sid_uid]}" item_id = f"{inst}-{sid}-{mikrotik_controller.data[sid][uid][sid_uid]}"
@ -206,8 +205,7 @@ class MikrotikControllerPortDeviceTracker(ScannerEntity):
def device_info(self): def device_info(self):
"""Return a port description for device registry.""" """Return a port description for device registry."""
info = { info = {
"connections": { "connections": {(CONNECTION_NETWORK_MAC, self._data["port-mac-address"])},
(CONNECTION_NETWORK_MAC, self._data["port-mac-address"])},
"manufacturer": self._ctrl.data["resource"]["platform"], "manufacturer": self._ctrl.data["resource"]["platform"],
"model": self._ctrl.data["resource"]["board-name"], "model": self._ctrl.data["resource"]["board-name"],
"name": f"{self._inst} {self._data['default-name']}", "name": f"{self._inst} {self._data['default-name']}",
@ -333,11 +331,10 @@ class MikrotikControllerHostDeviceTracker(ScannerEntity):
def device_info(self): def device_info(self):
"""Return a host description for device registry.""" """Return a host description for device registry."""
info = { info = {
"connections": { "connections": {(CONNECTION_NETWORK_MAC, self._data["mac-address"])},
(CONNECTION_NETWORK_MAC, self._data["mac-address"])},
"manufacturer": self._ctrl.data["resource"]["platform"], "manufacturer": self._ctrl.data["resource"]["platform"],
"model": self._ctrl.data["resource"]["board-name"], "model": self._ctrl.data["resource"]["board-name"],
"name": self._data['host-name'], "name": self._data["host-name"],
} }
return info return info
@ -349,12 +346,22 @@ class MikrotikControllerHostDeviceTracker(ScannerEntity):
if variable in self._data: if variable in self._data:
if variable == "last-seen": if variable == "last-seen":
if self._data[variable]: if self._data[variable]:
attributes[format_attribute(variable)] = get_age(self._data[variable]) attributes[format_attribute(variable)] = get_age(
self._data[variable]
)
else: else:
attributes[format_attribute(variable)] = "unknown" attributes[format_attribute(variable)] = "unknown"
else: else:
if self._data[variable] in ["dhcp", "dns", "capsman", "wireless", "restored"]: if self._data[variable] in [
attributes[format_attribute(variable)] = format_value(self._data[variable]) "dhcp",
"dns",
"capsman",
"wireless",
"restored",
]:
attributes[format_attribute(variable)] = format_value(
self._data[variable]
)
else: else:
attributes[format_attribute(variable)] = self._data[variable] attributes[format_attribute(variable)] = self._data[variable]

View file

@ -266,8 +266,7 @@ def fill_vals_proc(data, uid, vals_proc) -> dict:
if _action == "combine": if _action == "combine":
if "key" in val: if "key" in val:
tmp = _data[val["key"]]\ tmp = _data[val["key"]] if val["key"] in _data else "unknown"
if val["key"] in _data else "unknown"
if not _value: if not _value:
_value = tmp _value = tmp
else: else:

View file

@ -32,7 +32,7 @@ from .const import (
DEFAULT_UNIT_OF_MEASUREMENT, DEFAULT_UNIT_OF_MEASUREMENT,
) )
from .exceptions import ApiEntryNotFound from .exceptions import ApiEntryNotFound
from .helper import from_entry, parse_api from .helper import parse_api
from .mikrotikapi import MikrotikAPI from .mikrotikapi import MikrotikAPI
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -70,7 +70,7 @@ class MikrotikControllerData:
"wireless_hosts": {}, "wireless_hosts": {},
"host": {}, "host": {},
"host_hass": {}, "host_hass": {},
"accounting": {} "accounting": {},
} }
self.listeners = [] self.listeners = []
@ -82,7 +82,7 @@ class MikrotikControllerData:
config_entry.data[CONF_USERNAME], config_entry.data[CONF_USERNAME],
config_entry.data[CONF_PASSWORD], config_entry.data[CONF_PASSWORD],
config_entry.data[CONF_PORT], config_entry.data[CONF_PORT],
config_entry.data[CONF_SSL] config_entry.data[CONF_SSL],
) )
self.api_ping = MikrotikAPI( self.api_ping = MikrotikAPI(
@ -90,7 +90,7 @@ class MikrotikControllerData:
config_entry.data[CONF_USERNAME], config_entry.data[CONF_USERNAME],
config_entry.data[CONF_PASSWORD], config_entry.data[CONF_PASSWORD],
config_entry.data[CONF_PORT], config_entry.data[CONF_PORT],
config_entry.data[CONF_SSL] config_entry.data[CONF_SSL],
) )
self.nat_removed = {} self.nat_removed = {}
@ -121,7 +121,9 @@ class MikrotikControllerData:
@property @property
def option_track_iface_clients(self): def option_track_iface_clients(self):
"""Config entry option to not track ARP.""" """Config entry option to not track ARP."""
return self.config_entry.options.get(CONF_TRACK_IFACE_CLIENTS, DEFAULT_TRACK_IFACE_CLIENTS) return self.config_entry.options.get(
CONF_TRACK_IFACE_CLIENTS, DEFAULT_TRACK_IFACE_CLIENTS
)
# --------------------------- # ---------------------------
# option_track_network_hosts # option_track_network_hosts
@ -229,9 +231,11 @@ class MikrotikControllerData:
"""Get host data from HA entity registry""" """Get host data from HA entity registry"""
registry = await self.hass.helpers.entity_registry.async_get_registry() registry = await self.hass.helpers.entity_registry.async_get_registry()
for entity in registry.entities.values(): for entity in registry.entities.values():
if entity.config_entry_id == self.config_entry.entry_id \ if (
and entity.domain == DEVICE_TRACKER_DOMAIN \ entity.config_entry_id == self.config_entry.entry_id
and "-host-" in entity.unique_id: and entity.domain == DEVICE_TRACKER_DOMAIN
and "-host-" in entity.unique_id
):
_, mac = entity.unique_id.split("-host-", 2) _, mac = entity.unique_id.split("-host-", 2)
self.data["host_hass"][mac] = entity.original_name self.data["host_hass"][mac] = entity.original_name
@ -283,17 +287,30 @@ class MikrotikControllerData:
for uid, vals in self.data["host"].items(): for uid, vals in self.data["host"].items():
# Add missing default values # Add missing default values
for key, default in zip( for key, default in zip(
["address", "mac-address", "interface", "host-name", "last-seen", "available"], [
["unknown", "unknown", "unknown", "unknown", False, False], "address",
"mac-address",
"interface",
"host-name",
"last-seen",
"available",
],
["unknown", "unknown", "unknown", "unknown", False, False],
): ):
if key not in self.data["host"][uid]: if key not in self.data["host"][uid]:
self.data["host"][uid][key] = default self.data["host"][uid][key] = default
# Check host availability # Check host availability
if vals["source"] not in ["capsman", "wireless"] \ if (
and vals["address"] != "unknown" and vals["interface"] != "unknown": vals["source"] not in ["capsman", "wireless"]
self.data["host"][uid]["available"] = \ and vals["address"] != "unknown"
await self.hass.async_add_executor_job(self.api_ping.arp_ping, vals["address"], vals["interface"]) and vals["interface"] != "unknown"
):
self.data["host"][uid][
"available"
] = await self.hass.async_add_executor_job(
self.api_ping.arp_ping, vals["address"], vals["interface"]
)
# Update last seen # Update last seen
if self.data["host"][uid]["available"]: if self.data["host"][uid]["available"]:
@ -409,10 +426,8 @@ class MikrotikControllerData:
uom_type, uom_div = self._get_unit_of_measurement() uom_type, uom_div = self._get_unit_of_measurement()
for uid in self.data["interface"]: for uid in self.data["interface"]:
self.data["interface"][uid][ self.data["interface"][uid]["rx-bits-per-second-attr"] = uom_type
"rx-bits-per-second-attr"] = uom_type self.data["interface"][uid]["tx-bits-per-second-attr"] = uom_type
self.data["interface"][uid][
"tx-bits-per-second-attr"] = uom_type
self.data["interface"][uid]["rx-bits-per-second"] = round( self.data["interface"][uid]["rx-bits-per-second"] = round(
self.data["interface"][uid]["rx-bits-per-second"] * uom_div self.data["interface"][uid]["rx-bits-per-second"] * uom_div
) )
@ -440,7 +455,9 @@ class MikrotikControllerData:
"reverse": True, "reverse": True,
}, },
], ],
only=[{"key": "local", "value": False}], only=[
{"key": "local", "value": False}
],
) )
for uid, vals in self.data["bridge_host"].items(): for uid, vals in self.data["bridge_host"].items():
@ -465,12 +482,16 @@ class MikrotikControllerData:
continue continue
if self.data["interface"][uid]["client-ip-address"] == "": if self.data["interface"][uid]["client-ip-address"] == "":
self.data["interface"][uid]["client-ip-address"] = arp_vals["address"] self.data["interface"][uid]["client-ip-address"] = arp_vals[
"address"
]
else: else:
self.data["interface"][uid]["client-ip-address"] = "multiple" self.data["interface"][uid]["client-ip-address"] = "multiple"
if self.data["interface"][uid]["client-mac-address"] == "": if self.data["interface"][uid]["client-mac-address"] == "":
self.data["interface"][uid]["client-mac-address"] = arp_vals["mac-address"] self.data["interface"][uid]["client-mac-address"] = arp_vals[
"mac-address"
]
else: else:
self.data["interface"][uid]["client-mac-address"] = "multiple" self.data["interface"][uid]["client-mac-address"] = "multiple"
@ -513,7 +534,9 @@ class MikrotikControllerData:
{"key": "dst-port"}, {"key": "dst-port"},
] ]
], ],
only=[{"key": "action", "value": "dst-nat"}], only=[
{"key": "action", "value": "dst-nat"}
],
) )
# Remove duplicate NAT entries to prevent crash # Remove duplicate NAT entries to prevent crash
@ -530,8 +553,11 @@ class MikrotikControllerData:
for uid in nat_del: for uid in nat_del:
if self.data["nat"][uid]["name"] not in self.nat_removed: if self.data["nat"][uid]["name"] not in self.nat_removed:
self.nat_removed[self.data["nat"][uid]["name"]] = 1 self.nat_removed[self.data["nat"][uid]["name"]] = 1
_LOGGER.error("Mikrotik %s duplicate NAT rule %s, entity will be unavailable.", _LOGGER.error(
self.host, self.data["nat"][uid]["name"]) "Mikrotik %s duplicate NAT rule %s, entity will be unavailable.",
self.host,
self.data["nat"][uid]["name"],
)
del self.data["nat"][uid] del self.data["nat"][uid]
@ -619,8 +645,8 @@ class MikrotikControllerData:
if "status" in self.data["fw-update"]: if "status" in self.data["fw-update"]:
self.data["fw-update"]["available"] = ( self.data["fw-update"]["available"] = (
True if self.data["fw-update"][ True
"status"] == "New version is available" if self.data["fw-update"]["status"] == "New version is available"
else False else False
) )
else: else:
@ -671,40 +697,52 @@ class MikrotikControllerData:
"type": "bool", "type": "bool",
"reverse": True, "reverse": True,
}, },
] ],
) )
uom_type, uom_div = self._get_unit_of_measurement() uom_type, uom_div = self._get_unit_of_measurement()
for uid, vals in self.data["queue"].items(): for uid, vals in self.data["queue"].items():
upload_max_limit_bps, download_max_limit_bps = \ upload_max_limit_bps, download_max_limit_bps = [
[int(x) for x in vals["max-limit"].split('/')] int(x) for x in vals["max-limit"].split("/")
self.data["queue"][uid]["upload-max-limit"] = \ ]
f"{round(upload_max_limit_bps * uom_div)} {uom_type}" self.data["queue"][uid][
self.data["queue"][uid]["download-max-limit"] = \ "upload-max-limit"
f"{round(download_max_limit_bps * uom_div)} {uom_type}" ] = f"{round(upload_max_limit_bps * uom_div)} {uom_type}"
self.data["queue"][uid][
"download-max-limit"
] = f"{round(download_max_limit_bps * uom_div)} {uom_type}"
upload_limit_at_bps, download_limit_at_bps = \ upload_limit_at_bps, download_limit_at_bps = [
[int(x) for x in vals["limit-at"].split('/')] int(x) for x in vals["limit-at"].split("/")
self.data["queue"][uid]["upload-limit-at"] = \ ]
f"{round(upload_limit_at_bps * uom_div)} {uom_type}" self.data["queue"][uid][
self.data["queue"][uid]["download-limit-at"] = \ "upload-limit-at"
f"{round(download_limit_at_bps * uom_div)} {uom_type}" ] = f"{round(upload_limit_at_bps * uom_div)} {uom_type}"
self.data["queue"][uid][
"download-limit-at"
] = f"{round(download_limit_at_bps * uom_div)} {uom_type}"
upload_burst_limit_bps, download_burst_limit_bps = \ upload_burst_limit_bps, download_burst_limit_bps = [
[int(x) for x in vals["burst-limit"].split('/')] int(x) for x in vals["burst-limit"].split("/")
self.data["queue"][uid]["upload-burst-limit"] = \ ]
f"{round(upload_burst_limit_bps * uom_div)} {uom_type}" self.data["queue"][uid][
self.data["queue"][uid]["download-burst-limit"] = \ "upload-burst-limit"
f"{round(download_burst_limit_bps * uom_div)} {uom_type}" ] = f"{round(upload_burst_limit_bps * uom_div)} {uom_type}"
self.data["queue"][uid][
"download-burst-limit"
] = f"{round(download_burst_limit_bps * uom_div)} {uom_type}"
upload_burst_threshold_bps, download_burst_threshold_bps = \ upload_burst_threshold_bps, download_burst_threshold_bps = [
[int(x) for x in vals["burst-threshold"].split('/')] int(x) for x in vals["burst-threshold"].split("/")
self.data["queue"][uid]["upload-burst-threshold"] = \ ]
f"{round(upload_burst_threshold_bps * uom_div)} {uom_type}" self.data["queue"][uid][
self.data["queue"][uid]["download-burst-threshold"] = \ "upload-burst-threshold"
f"{round(download_burst_threshold_bps * uom_div)} {uom_type}" ] = f"{round(upload_burst_threshold_bps * uom_div)} {uom_type}"
self.data["queue"][uid][
"download-burst-threshold"
] = f"{round(download_burst_threshold_bps * uom_div)} {uom_type}"
upload_burst_time, download_burst_time = vals["burst-time"].split('/') upload_burst_time, download_burst_time = vals["burst-time"].split("/")
self.data["queue"][uid]["upload-burst-time"] = upload_burst_time self.data["queue"][uid]["upload-burst-time"] = upload_burst_time
self.data["queue"][uid]["download-burst-time"] = download_burst_time self.data["queue"][uid]["download-burst-time"] = download_burst_time
@ -724,13 +762,18 @@ class MikrotikControllerData:
], ],
ensure_vals=[ ensure_vals=[
{"name": "bridge", "default": ""}, {"name": "bridge", "default": ""},
] ],
) )
for uid, vals in self.data["arp"].items(): for uid, vals in self.data["arp"].items():
if vals["interface"] in self.data["bridge"] and uid in self.data["bridge_host"]: if (
vals["interface"] in self.data["bridge"]
and uid in self.data["bridge_host"]
):
self.data["arp"][uid]["bridge"] = vals["interface"] self.data["arp"][uid]["bridge"] = vals["interface"]
self.data["arp"][uid]["interface"] = self.data["bridge_host"][uid]["interface"] self.data["arp"][uid]["interface"] = self.data["bridge_host"][uid][
"interface"
]
# --------------------------- # ---------------------------
# get_dns # get_dns
@ -768,12 +811,14 @@ class MikrotikControllerData:
ensure_vals=[ ensure_vals=[
{"name": "address"}, {"name": "address"},
{"name": "IPv4Network", "default": ""}, {"name": "IPv4Network", "default": ""},
] ],
) )
for uid, vals in self.data["dhcp-network"].items(): for uid, vals in self.data["dhcp-network"].items():
if vals["IPv4Network"] == "": if vals["IPv4Network"] == "":
self.data["dhcp-network"][uid]["IPv4Network"] = IPv4Network(vals["address"]) self.data["dhcp-network"][uid]["IPv4Network"] = IPv4Network(
vals["address"]
)
# TODO: run only on demand # TODO: run only on demand
self.data["dhcp-server"] = parse_api( self.data["dhcp-server"] = parse_api(
@ -783,7 +828,7 @@ class MikrotikControllerData:
vals=[ vals=[
{"name": "name"}, {"name": "name"},
{"name": "interface", "default": ""}, {"name": "interface", "default": ""},
] ],
) )
self.data["dhcp"] = parse_api( self.data["dhcp"] = parse_api(
@ -801,12 +846,13 @@ class MikrotikControllerData:
], ],
ensure_vals=[ ensure_vals=[
{"name": "interface"}, {"name": "interface"},
] ],
) )
for uid in self.data["dhcp"]: for uid in self.data["dhcp"]:
self.data["dhcp"][uid]["interface"] = \ self.data["dhcp"][uid]["interface"] = self.data["dhcp-server"][
self.data["dhcp-server"][self.data["dhcp"][uid]["server"]]["interface"] self.data["dhcp"][uid]["server"]
]["interface"]
# --------------------------- # ---------------------------
# get_capsman_hosts # get_capsman_hosts
@ -821,7 +867,7 @@ class MikrotikControllerData:
{"name": "mac-address"}, {"name": "mac-address"},
{"name": "interface", "default": "unknown"}, {"name": "interface", "default": "unknown"},
{"name": "ssid", "default": "unknown"}, {"name": "ssid", "default": "unknown"},
] ],
) )
# --------------------------- # ---------------------------
@ -838,7 +884,7 @@ class MikrotikControllerData:
{"name": "interface", "default": "unknown"}, {"name": "interface", "default": "unknown"},
{"name": "ap", "type": "bool"}, {"name": "ap", "type": "bool"},
{"name": "uptime"}, {"name": "uptime"},
] ],
) )
# --------------------------- # ---------------------------
@ -847,8 +893,8 @@ class MikrotikControllerData:
async def async_process_host(self): async def async_process_host(self):
"""Get host tracking data""" """Get host tracking data"""
# Add hosts from CAPS-MAN # Add hosts from CAPS-MAN
capsman_detected = {}
if self.support_capsman: if self.support_capsman:
capsman_detected = {}
for uid, vals in self.data["capsman_hosts"].items(): for uid, vals in self.data["capsman_hosts"].items():
if uid not in self.data["host"]: if uid not in self.data["host"]:
self.data["host"][uid] = {} self.data["host"][uid] = {}
@ -858,12 +904,15 @@ class MikrotikControllerData:
self.data["host"][uid]["available"] = True self.data["host"][uid]["available"] = True
self.data["host"][uid]["last-seen"] = utcnow() self.data["host"][uid]["last-seen"] = utcnow()
for key in ["mac-address", "interface"]: for key in ["mac-address", "interface"]:
if key not in self.data["host"][uid] or self.data["host"][uid][key] == "unknown": if (
key not in self.data["host"][uid]
or self.data["host"][uid][key] == "unknown"
):
self.data["host"][uid][key] = vals[key] self.data["host"][uid][key] = vals[key]
# Add hosts from wireless # Add hosts from wireless
wireless_detected = {}
if self.support_wireless: if self.support_wireless:
wireless_detected = {}
for uid, vals in self.data["wireless_hosts"].items(): for uid, vals in self.data["wireless_hosts"].items():
if vals["ap"]: if vals["ap"]:
continue continue
@ -876,7 +925,10 @@ class MikrotikControllerData:
self.data["host"][uid]["available"] = True self.data["host"][uid]["available"] = True
self.data["host"][uid]["last-seen"] = utcnow() self.data["host"][uid]["last-seen"] = utcnow()
for key in ["mac-address", "interface"]: for key in ["mac-address", "interface"]:
if key not in self.data["host"][uid] or self.data["host"][uid][key] == "unknown": if (
key not in self.data["host"][uid]
or self.data["host"][uid][key] == "unknown"
):
self.data["host"][uid][key] = vals[key] self.data["host"][uid][key] = vals[key]
# Add hosts from DHCP # Add hosts from DHCP
@ -885,7 +937,10 @@ class MikrotikControllerData:
self.data["host"][uid] = {} self.data["host"][uid] = {}
self.data["host"][uid]["source"] = "dhcp" self.data["host"][uid]["source"] = "dhcp"
for key in ["address", "mac-address", "interface"]: for key in ["address", "mac-address", "interface"]:
if key not in self.data["host"][uid] or self.data["host"][uid][key] == "unknown": if (
key not in self.data["host"][uid]
or self.data["host"][uid][key] == "unknown"
):
self.data["host"][uid][key] = vals[key] self.data["host"][uid][key] = vals[key]
# Add hosts from ARP # Add hosts from ARP
@ -894,7 +949,10 @@ class MikrotikControllerData:
self.data["host"][uid] = {} self.data["host"][uid] = {}
self.data["host"][uid]["source"] = "arp" self.data["host"][uid]["source"] = "arp"
for key in ["address", "mac-address", "interface"]: for key in ["address", "mac-address", "interface"]:
if key not in self.data["host"][uid] or self.data["host"][uid][key] == "unknown": if (
key not in self.data["host"][uid]
or self.data["host"][uid][key] == "unknown"
):
self.data["host"][uid][key] = vals[key] self.data["host"][uid][key] = vals[key]
# Add restored hosts from hass registry # Add restored hosts from hass registry
@ -922,34 +980,59 @@ class MikrotikControllerData:
# Update IP and interface (DHCP/returned host) # Update IP and interface (DHCP/returned host)
if uid in self.data["dhcp"] and "." in self.data["dhcp"][uid]["address"]: if uid in self.data["dhcp"] and "." in self.data["dhcp"][uid]["address"]:
if self.data["dhcp"][uid]["address"] != self.data["host"][uid]["address"]: if (
self.data["host"][uid]["address"] = self.data["dhcp"][uid]["address"] self.data["dhcp"][uid]["address"]
!= self.data["host"][uid]["address"]
):
self.data["host"][uid]["address"] = self.data["dhcp"][uid][
"address"
]
if vals["source"] not in ["capsman", "wireless"]: if vals["source"] not in ["capsman", "wireless"]:
self.data["host"][uid]["source"] = "dhcp" self.data["host"][uid]["source"] = "dhcp"
self.data["host"][uid]["interface"] = self.data["dhcp"][uid]["interface"] self.data["host"][uid]["interface"] = self.data["dhcp"][uid][
"interface"
]
elif uid in self.data["arp"] and "." in self.data["arp"][uid]["address"] \ elif (
and self.data["arp"][uid]["address"] != self.data["host"][uid]["address"]: uid in self.data["arp"]
and "." in self.data["arp"][uid]["address"]
and self.data["arp"][uid]["address"]
!= self.data["host"][uid]["address"]
):
self.data["host"][uid]["address"] = self.data["arp"][uid]["address"] self.data["host"][uid]["address"] = self.data["arp"][uid]["address"]
if vals["source"] not in ["capsman", "wireless"]: if vals["source"] not in ["capsman", "wireless"]:
self.data["host"][uid]["source"] = "arp" self.data["host"][uid]["source"] = "arp"
self.data["host"][uid]["interface"] = self.data["arp"][uid]["interface"] self.data["host"][uid]["interface"] = self.data["arp"][uid][
"interface"
]
if vals["host-name"] == "unknown": if vals["host-name"] == "unknown":
# Resolve hostname from static DNS # Resolve hostname from static DNS
if vals["address"] != "unknown": if vals["address"] != "unknown":
for dns_uid, dns_vals in self.data["dns"].items(): for dns_uid, dns_vals in self.data["dns"].items():
if dns_vals["address"] == vals["address"]: if dns_vals["address"] == vals["address"]:
self.data["host"][uid]["host-name"] = dns_vals["name"].split('.')[0] self.data["host"][uid]["host-name"] = dns_vals[
"name"
].split(".")[0]
break break
# Resolve hostname from DHCP comment # Resolve hostname from DHCP comment
if self.data["host"][uid]["host-name"] == "unknown" \ if (
and uid in self.data["dhcp"] and self.data["dhcp"][uid]["comment"] != "": self.data["host"][uid]["host-name"] == "unknown"
self.data["host"][uid]["host-name"] = self.data["dhcp"][uid]["comment"] and uid in self.data["dhcp"]
and self.data["dhcp"][uid]["comment"] != ""
):
self.data["host"][uid]["host-name"] = self.data["dhcp"][uid][
"comment"
]
# Resolve hostname from DHCP hostname # Resolve hostname from DHCP hostname
elif self.data["host"][uid]["host-name"] == "unknown" \ elif (
and uid in self.data["dhcp"] and self.data["dhcp"][uid]["host-name"] != "unknown": self.data["host"][uid]["host-name"] == "unknown"
self.data["host"][uid]["host-name"] = self.data["dhcp"][uid]["host-name"] and uid in self.data["dhcp"]
and self.data["dhcp"][uid]["host-name"] != "unknown"
):
self.data["host"][uid]["host-name"] = self.data["dhcp"][uid][
"host-name"
]
# Fallback to mac address for hostname # Fallback to mac address for hostname
elif self.data["host"][uid]["host-name"] == "unknown": elif self.data["host"][uid]["host-name"] == "unknown":
self.data["host"][uid]["host-name"] = uid self.data["host"][uid]["host-name"] = uid
@ -960,31 +1043,34 @@ class MikrotikControllerData:
def process_accounting(self): def process_accounting(self):
"""Get Accounting data from Mikrotik""" """Get Accounting data from Mikrotik"""
# Check if accounting and account-local-traffic is enabled # Check if accounting and account-local-traffic is enabled
accounting_enabled, local_traffic_enabled = self.api.is_accounting_and_local_traffic_enabled() (
accounting_enabled,
local_traffic_enabled,
) = self.api.is_accounting_and_local_traffic_enabled()
uom_type, uom_div = self._get_unit_of_measurement() uom_type, uom_div = self._get_unit_of_measurement()
# Build missing hosts from main hosts dict # Build missing hosts from main hosts dict
for uid, vals in self.data["host"].items(): for uid, vals in self.data["host"].items():
if uid not in self.data["accounting"]: if uid not in self.data["accounting"]:
self.data["accounting"][uid] = { self.data["accounting"][uid] = {
'address': vals['address'], "address": vals["address"],
'mac-address': vals['mac-address'], "mac-address": vals["mac-address"],
'host-name': vals['host-name'], "host-name": vals["host-name"],
'tx-rx-attr': uom_type, "tx-rx-attr": uom_type,
'available': False, "available": False,
'local_accounting': False "local_accounting": False,
} }
_LOGGER.debug(f"Working with {len(self.data['accounting'])} accounting devices") _LOGGER.debug(f"Working with {len(self.data['accounting'])} accounting devices")
# Build temp accounting values dict with ip address as key # Build temp accounting values dict with ip address as key
tmp_accounting_values = {} tmp_accounting_values = {}
for uid, vals in self.data['accounting'].items(): for uid, vals in self.data["accounting"].items():
tmp_accounting_values[vals['address']] = { tmp_accounting_values[vals["address"]] = {
"wan-tx": 0, "wan-tx": 0,
"wan-rx": 0, "wan-rx": 0,
"lan-tx": 0, "lan-tx": 0,
"lan-rx": 0 "lan-rx": 0,
} }
time_diff = self.api.take_accounting_snapshot() time_diff = self.api.take_accounting_snapshot()
@ -1002,57 +1088,75 @@ class MikrotikControllerData:
) )
for item in accounting_data.values(): for item in accounting_data.values():
source_ip = str(item.get('src-address')).strip() source_ip = str(item.get("src-address")).strip()
destination_ip = str(item.get('dst-address')).strip() destination_ip = str(item.get("dst-address")).strip()
bits_count = int(str(item.get('bytes')).strip()) * 8 bits_count = int(str(item.get("bytes")).strip()) * 8
if self._address_part_of_local_network(source_ip) and \ if self._address_part_of_local_network(
self._address_part_of_local_network(destination_ip): source_ip
) and self._address_part_of_local_network(destination_ip):
# LAN TX/RX # LAN TX/RX
if source_ip in tmp_accounting_values: if source_ip in tmp_accounting_values:
tmp_accounting_values[source_ip]['lan-tx'] += bits_count tmp_accounting_values[source_ip]["lan-tx"] += bits_count
if destination_ip in tmp_accounting_values: if destination_ip in tmp_accounting_values:
tmp_accounting_values[destination_ip]['lan-rx'] += bits_count tmp_accounting_values[destination_ip]["lan-rx"] += bits_count
elif self._address_part_of_local_network(source_ip) and \ elif self._address_part_of_local_network(
not self._address_part_of_local_network(destination_ip): source_ip
) and not self._address_part_of_local_network(destination_ip):
# WAN TX # WAN TX
if source_ip in tmp_accounting_values: if source_ip in tmp_accounting_values:
tmp_accounting_values[source_ip]['wan-tx'] += bits_count tmp_accounting_values[source_ip]["wan-tx"] += bits_count
elif not self._address_part_of_local_network(source_ip) and \ elif (
self._address_part_of_local_network(destination_ip) and \ not self._address_part_of_local_network(source_ip)
destination_ip in tmp_accounting_values: and self._address_part_of_local_network(destination_ip)
and destination_ip in tmp_accounting_values
):
# WAN RX # WAN RX
tmp_accounting_values[destination_ip]['wan-rx'] += bits_count tmp_accounting_values[destination_ip]["wan-rx"] += bits_count
# Calculate real throughput and transform it to appropriate unit # Calculate real throughput and transform it to appropriate unit
# Also handle availability of accounting and local_accounting from Mikrotik # Also handle availability of accounting and local_accounting from Mikrotik
for addr, vals in tmp_accounting_values.items(): for addr, vals in tmp_accounting_values.items():
uid = self._get_accounting_uid_by_ip(addr) uid = self._get_accounting_uid_by_ip(addr)
if not uid: if not uid:
_LOGGER.warning(f"Address {addr} not found in accounting data, skipping update") _LOGGER.warning(
f"Address {addr} not found in accounting data, skipping update"
)
continue continue
self.data['accounting'][uid]['tx-rx-attr'] = uom_type self.data["accounting"][uid]["tx-rx-attr"] = uom_type
self.data['accounting'][uid]['available'] = accounting_enabled self.data["accounting"][uid]["available"] = accounting_enabled
self.data['accounting'][uid]['local_accounting'] = local_traffic_enabled self.data["accounting"][uid]["local_accounting"] = local_traffic_enabled
if not accounting_enabled: if not accounting_enabled:
# Skip calculation for WAN and LAN if accounting is disabled # Skip calculation for WAN and LAN if accounting is disabled
continue continue
self.data['accounting'][uid]['wan-tx'] = \ self.data["accounting"][uid]["wan-tx"] = (
round(vals['wan-tx'] / time_diff * uom_div, 2) if vals['wan-tx'] else 0.0 round(vals["wan-tx"] / time_diff * uom_div, 2)
self.data['accounting'][uid]['wan-rx'] = \ if vals["wan-tx"]
round(vals['wan-rx'] / time_diff * uom_div, 2) if vals['wan-rx'] else 0.0 else 0.0
)
self.data["accounting"][uid]["wan-rx"] = (
round(vals["wan-rx"] / time_diff * uom_div, 2)
if vals["wan-rx"]
else 0.0
)
if not local_traffic_enabled: if not local_traffic_enabled:
# Skip calculation for LAN if LAN accounting is disabled # Skip calculation for LAN if LAN accounting is disabled
continue continue
self.data['accounting'][uid]['lan-tx'] = \ self.data["accounting"][uid]["lan-tx"] = (
round(vals['lan-tx'] / time_diff * uom_div, 2) if vals['lan-tx'] else 0.0 round(vals["lan-tx"] / time_diff * uom_div, 2)
self.data['accounting'][uid]['lan-rx'] = \ if vals["lan-tx"]
round(vals['lan-rx'] / time_diff * uom_div, 2) if vals['lan-rx'] else 0.0 else 0.0
)
self.data["accounting"][uid]["lan-rx"] = (
round(vals["lan-rx"] / time_diff * uom_div, 2)
if vals["lan-rx"]
else 0.0
)
# --------------------------- # ---------------------------
# _get_unit_of_measurement # _get_unit_of_measurement
@ -1088,8 +1192,8 @@ class MikrotikControllerData:
# _get_accounting_uid_by_ip # _get_accounting_uid_by_ip
# --------------------------- # ---------------------------
def _get_accounting_uid_by_ip(self, requested_ip): def _get_accounting_uid_by_ip(self, requested_ip):
for mac, vals in self.data['accounting'].items(): for mac, vals in self.data["accounting"].items():
if vals.get('address') is requested_ip: if vals.get("address") is requested_ip:
return mac return mac
return None return None

View file

@ -1,11 +1,9 @@
"""Mikrotik API for Mikrotik Router.""" """Mikrotik API for Mikrotik Router."""
import importlib
import logging import logging
import os
import ssl import ssl
import sys
import time import time
from time import time
from threading import Lock from threading import Lock
from voluptuous import Optional from voluptuous import Optional
@ -65,7 +63,7 @@ class MikrotikAPI:
def connection_check(self) -> bool: def connection_check(self) -> bool:
"""Check if mikrotik is connected""" """Check if mikrotik is connected"""
if not self._connected or not self._connection: if not self._connected or not self._connection:
if self._connection_epoch > time.time() - self._connection_retry_sec: if self._connection_epoch > time() - self._connection_retry_sec:
return False return False
if not self.connect(): if not self.connect():
@ -76,13 +74,18 @@ class MikrotikAPI:
# --------------------------- # ---------------------------
# disconnect # disconnect
# --------------------------- # ---------------------------
def disconnect(self, location="unknown", error="unknown"): def disconnect(self, location="unknown", error=None):
"""Disconnect from Mikrotik device.""" """Disconnect from Mikrotik device."""
if not error:
error = "unknown"
if not self.connection_error_reported: if not self.connection_error_reported:
if location == "unknown": if location == "unknown":
_LOGGER.error("Mikrotik %s connection closed", self._host) _LOGGER.error("Mikrotik %s connection closed", self._host)
else: else:
_LOGGER.error("Mikrotik %s error while %s : %s", self._host, location, error) _LOGGER.error(
"Mikrotik %s error while %s : %s", self._host, location, error
)
self.connection_error_reported = True self.connection_error_reported = True
@ -97,7 +100,7 @@ class MikrotikAPI:
"""Connect to Mikrotik device.""" """Connect to Mikrotik device."""
self.error = "" self.error = ""
self._connected = None self._connected = None
self._connection_epoch = time.time() self._connection_epoch = time()
kwargs = { kwargs = {
"encoding": self._encoding, "encoding": self._encoding,
@ -129,8 +132,7 @@ class MikrotikAPI:
) as api_error: ) as api_error:
if not self.connection_error_reported: if not self.connection_error_reported:
_LOGGER.error( _LOGGER.error(
"Mikrotik %s error while connecting: %s", self._host, "Mikrotik %s error while connecting: %s", self._host, api_error
api_error
) )
self.connection_error_reported = True self.connection_error_reported = True
@ -141,8 +143,7 @@ class MikrotikAPI:
except: except:
if not self.connection_error_reported: if not self.connection_error_reported:
_LOGGER.error( _LOGGER.error(
"Mikrotik %s error while connecting: %s", self._host, "Mikrotik %s error while connecting: %s", self._host, "Unknown"
"Unknown"
) )
self.connection_error_reported = True self.connection_error_reported = True
@ -199,14 +200,14 @@ class MikrotikAPI:
self.lock.release() self.lock.release()
return None return None
except ( except (
librouteros.exceptions.TrapError, librouteros.exceptions.TrapError,
librouteros.exceptions.MultiTrapError, librouteros.exceptions.MultiTrapError,
librouteros.exceptions.ProtocolError, librouteros.exceptions.ProtocolError,
librouteros.exceptions.FatalError, librouteros.exceptions.FatalError,
ssl.SSLError, ssl.SSLError,
BrokenPipeError, BrokenPipeError,
OSError, OSError,
ValueError, ValueError,
) as api_error: ) as api_error:
self.disconnect("path", api_error) self.disconnect("path", api_error)
self.lock.release() self.lock.release()
@ -282,7 +283,12 @@ class MikrotikAPI:
self.lock.release() self.lock.release()
if not entry_found: if not entry_found:
_LOGGER.error("Mikrotik %s Update parameter %s with value %s not found", self._host, param, value) _LOGGER.error(
"Mikrotik %s Update parameter %s with value %s not found",
self._host,
param,
value,
)
return True return True
@ -459,7 +465,6 @@ class MikrotikAPI:
@staticmethod @staticmethod
def _current_milliseconds(): def _current_milliseconds():
from time import time
return int(round(time() * 1000)) return int(round(time() * 1000))
def is_accounting_and_local_traffic_enabled(self) -> (bool, bool): def is_accounting_and_local_traffic_enabled(self) -> (bool, bool):
@ -475,15 +480,15 @@ class MikrotikAPI:
return False, False return False, False
for item in response: for item in response:
if 'enabled' not in item: if "enabled" not in item:
continue continue
if not item['enabled']: if not item["enabled"]:
return False, False return False, False
for item in response: for item in response:
if 'account-local-traffic' not in item: if "account-local-traffic" not in item:
continue continue
if not item['account-local-traffic']: if not item["account-local-traffic"]:
return True, False return True, False
return True, True return True, True
@ -502,20 +507,20 @@ class MikrotikAPI:
self.lock.acquire() self.lock.acquire()
try: try:
# Prepare command # Prepare command
take = accounting('snapshot/take') take = accounting("snapshot/take")
except librouteros.exceptions.ConnectionClosed: except librouteros.exceptions.ConnectionClosed:
self.disconnect() self.disconnect()
self.lock.release() self.lock.release()
return 0 return 0
except ( except (
librouteros.exceptions.TrapError, librouteros.exceptions.TrapError,
librouteros.exceptions.MultiTrapError, librouteros.exceptions.MultiTrapError,
librouteros.exceptions.ProtocolError, librouteros.exceptions.ProtocolError,
librouteros.exceptions.FatalError, librouteros.exceptions.FatalError,
ssl.SSLError, ssl.SSLError,
BrokenPipeError, BrokenPipeError,
OSError, OSError,
ValueError, ValueError,
) as api_error: ) as api_error:
self.disconnect("accounting_snapshot", api_error) self.disconnect("accounting_snapshot", api_error)
self.lock.release() self.lock.release()

View file

@ -2,13 +2,13 @@
import logging import logging
from homeassistant.const import (CONF_NAME, ATTR_ATTRIBUTION, ATTR_DEVICE_CLASS) from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION, ATTR_DEVICE_CLASS
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from .const import (DOMAIN, DATA_CLIENT, ATTRIBUTION) from .const import DOMAIN, DATA_CLIENT, ATTRIBUTION
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -117,11 +117,7 @@ SENSOR_TYPES = {
}, },
} }
DEVICE_ATTRIBUTES_ACCOUNTING = [ DEVICE_ATTRIBUTES_ACCOUNTING = ["address", "mac-address", "host-name"]
"address",
"mac-address",
"host-name"
]
# --------------------------- # ---------------------------
@ -165,8 +161,7 @@ def update_items(inst, mikrotik_controller, async_add_entities, sensors):
continue continue
sensors[item_id] = MikrotikControllerSensor( sensors[item_id] = MikrotikControllerSensor(
mikrotik_controller=mikrotik_controller, inst=inst, mikrotik_controller=mikrotik_controller, inst=inst, sensor=sensor
sensor=sensor
) )
new_sensors.append(sensors[item_id]) new_sensors.append(sensors[item_id])
@ -197,7 +192,10 @@ def update_items(inst, mikrotik_controller, async_add_entities, sensors):
sensors[item_id].async_schedule_update_ha_state() sensors[item_id].async_schedule_update_ha_state()
continue continue
if SENSOR_TYPES[sensor][ATTR_ATTR] in mikrotik_controller.data['accounting'][uid].keys(): if (
SENSOR_TYPES[sensor][ATTR_ATTR]
in mikrotik_controller.data["accounting"][uid].keys()
):
sensors[item_id] = MikrotikAccountingSensor( sensors[item_id] = MikrotikAccountingSensor(
mikrotik_controller=mikrotik_controller, mikrotik_controller=mikrotik_controller,
inst=inst, inst=inst,
@ -319,8 +317,7 @@ class MikrotikControllerTrafficSensor(MikrotikControllerSensor):
"""Initialize.""" """Initialize."""
super().__init__(mikrotik_controller, inst, sensor) super().__init__(mikrotik_controller, inst, sensor)
self._uid = uid self._uid = uid
self._data = mikrotik_controller.data[SENSOR_TYPES[sensor][ATTR_PATH]][ self._data = mikrotik_controller.data[SENSOR_TYPES[sensor][ATTR_PATH]][uid]
uid]
@property @property
def name(self): def name(self):
@ -336,8 +333,7 @@ class MikrotikControllerTrafficSensor(MikrotikControllerSensor):
def device_info(self): def device_info(self):
"""Return a port description for device registry.""" """Return a port description for device registry."""
info = { info = {
"connections": { "connections": {(CONNECTION_NETWORK_MAC, self._data["port-mac-address"])},
(CONNECTION_NETWORK_MAC, self._data["port-mac-address"])},
"manufacturer": self._ctrl.data["resource"]["platform"], "manufacturer": self._ctrl.data["resource"]["platform"],
"model": self._ctrl.data["resource"]["board-name"], "model": self._ctrl.data["resource"]["board-name"],
"name": f"{self._inst} {self._data['default-name']}", "name": f"{self._inst} {self._data['default-name']}",
@ -382,20 +378,23 @@ class MikrotikAccountingSensor(MikrotikControllerSensor):
"""Return if controller and accounting feature in Mikrotik is available. """Return if controller and accounting feature in Mikrotik is available.
Additional check for lan-tx/rx sensors Additional check for lan-tx/rx sensors
""" """
if self._attr in ['lan-tx', 'lan-rx']: if self._attr in ["lan-tx", "lan-rx"]:
return self._ctrl.connected() and self._data['available'] and self._data['local_accounting'] return (
self._ctrl.connected()
and self._data["available"]
and self._data["local_accounting"]
)
else: else:
return self._ctrl.connected() and self._data['available'] return self._ctrl.connected() and self._data["available"]
@property @property
def device_info(self): def device_info(self):
"""Return a accounting description for device registry.""" """Return a accounting description for device registry."""
info = { info = {
"connections": { "connections": {(CONNECTION_NETWORK_MAC, self._data["mac-address"])},
(CONNECTION_NETWORK_MAC, self._data["mac-address"])},
"manufacturer": self._ctrl.data["resource"]["platform"], "manufacturer": self._ctrl.data["resource"]["platform"],
"model": self._ctrl.data["resource"]["board-name"], "model": self._ctrl.data["resource"]["board-name"],
"name": self._data['host-name'], "name": self._data["host-name"],
} }
return info return info

View file

@ -2,13 +2,13 @@
import logging import logging
from homeassistant.components.switch import SwitchDevice from homeassistant.components.switch import SwitchDevice
from homeassistant.const import (CONF_NAME, ATTR_ATTRIBUTION) from homeassistant.const import CONF_NAME, ATTR_ATTRIBUTION
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from .const import (DOMAIN, DATA_CLIENT, ATTRIBUTION) from .const import DOMAIN, DATA_CLIENT, ATTRIBUTION
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -204,8 +204,7 @@ class MikrotikControllerPortSwitch(MikrotikControllerSwitch):
def device_info(self): def device_info(self):
"""Return a port description for device registry.""" """Return a port description for device registry."""
info = { info = {
"connections": { "connections": {(CONNECTION_NETWORK_MAC, self._data["port-mac-address"])},
(CONNECTION_NETWORK_MAC, self._data["port-mac-address"])},
"manufacturer": self._ctrl.data["resource"]["platform"], "manufacturer": self._ctrl.data["resource"]["platform"],
"model": self._ctrl.data["resource"]["board-name"], "model": self._ctrl.data["resource"]["board-name"],
"name": f"{self._inst} {self._data['default-name']}", "name": f"{self._inst} {self._data['default-name']}",
@ -375,8 +374,7 @@ class MikrotikControllerScriptSwitch(MikrotikControllerSwitch):
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Script switch entity created.""" """Script switch entity created."""
_LOGGER.debug("New script switch %s (%s)", self._inst, _LOGGER.debug("New script switch %s (%s)", self._inst, self._data["name"])
self._data["name"])
@property @property
def name(self) -> str: def name(self) -> str:
@ -512,10 +510,7 @@ class MikrotikControllerQueueSwitch(MikrotikControllerSwitch):
param = ".id" param = ".id"
value = None value = None
for uid in self._ctrl.data["queue"]: for uid in self._ctrl.data["queue"]:
if ( if self._ctrl.data["queue"][uid]["name"] == f"{self._data['name']}":
self._ctrl.data["queue"][uid]["name"]
== f"{self._data['name']}"
):
value = self._ctrl.data["queue"][uid][".id"] value = self._ctrl.data["queue"][uid][".id"]
mod_param = "disabled" mod_param = "disabled"
@ -529,10 +524,7 @@ class MikrotikControllerQueueSwitch(MikrotikControllerSwitch):
param = ".id" param = ".id"
value = None value = None
for uid in self._ctrl.data["queue"]: for uid in self._ctrl.data["queue"]:
if ( if self._ctrl.data["queue"][uid]["name"] == f"{self._data['name']}":
self._ctrl.data["queue"][uid]["name"]
== f"{self._data['name']}"
):
value = self._ctrl.data["queue"][uid][".id"] value = self._ctrl.data["queue"][uid][".id"]
mod_param = "disabled" mod_param = "disabled"