Accounting feature renamed to Client traffic. In case of older firmware fallback to accounting fetature for client traffic monitoring, instead use kid-control-devices

This commit is contained in:
Ivan Pavlina 2022-01-01 17:26:40 +00:00
parent 0120409382
commit e93b02e71d
3 changed files with 225 additions and 100 deletions

View file

@ -129,8 +129,8 @@ class MikrotikControllerData:
"wireless_hosts": {},
"host": {},
"host_hass": {},
"accounting": {},
"environment": {},
"client_traffic": {},
"environment": {}
}
self.listeners = []
@ -612,12 +612,13 @@ class MikrotikControllerData:
if self.api.connected():
await self.hass.async_add_executor_job(self.get_system_resource)
if (
self.api.connected()
and self.option_sensor_client_traffic
and 0 < self.major_fw_version < 7
):
await self.hass.async_add_executor_job(self.process_accounting)
if self.api.connected() and self.option_sensor_client_traffic:
if 0 < self.major_fw_version < 7:
_LOGGER.info("Using accounting feature for client traffic processing")
await self.hass.async_add_executor_job(self.process_accounting)
elif 0 < self.major_fw_version >= 7:
_LOGGER.info("Using accounting kid control devices for client traffic processing")
await self.hass.async_add_executor_job(self.process_kid_control_devices)
if self.api.connected() and self.option_sensor_simple_queues:
await self.hass.async_add_executor_job(self.get_queue)
@ -1875,8 +1876,8 @@ class MikrotikControllerData:
# Build missing hosts from main hosts dict
for uid, vals in self.data["host"].items():
if uid not in self.data["accounting"]:
self.data["accounting"][uid] = {
if uid not in self.data["client_traffic"]:
self.data["client_traffic"][uid] = {
"address": vals["address"],
"mac-address": vals["mac-address"],
"host-name": vals["host-name"],
@ -1885,11 +1886,11 @@ class MikrotikControllerData:
"local_accounting": False,
}
_LOGGER.debug(f"Working with {len(self.data['accounting'])} accounting devices")
_LOGGER.debug(f"Working with {len(self.data['client_traffic'])} accounting devices")
# Build temp accounting values dict with ip address as key
tmp_accounting_values = {}
for uid, vals in self.data["accounting"].items():
for uid, vals in self.data["client_traffic"].items():
tmp_accounting_values[vals["address"]] = {
"wan-tx": 0,
"wan-rx": 0,
@ -1897,7 +1898,7 @@ class MikrotikControllerData:
"lan-rx": 0,
}
time_diff = self.api.take_accounting_snapshot()
time_diff = self.api.take_client_traffic_snapshot(True)
if time_diff:
accounting_data = parse_api(
data={},
@ -1965,20 +1966,20 @@ class MikrotikControllerData:
)
continue
self.data["accounting"][uid]["tx-rx-attr"] = uom_type
self.data["accounting"][uid]["available"] = accounting_enabled
self.data["accounting"][uid]["local_accounting"] = local_traffic_enabled
self.data["client_traffic"][uid]["tx-rx-attr"] = uom_type
self.data["client_traffic"][uid]["available"] = accounting_enabled
self.data["client_traffic"][uid]["local_accounting"] = local_traffic_enabled
if not accounting_enabled:
# Skip calculation for WAN and LAN if accounting is disabled
continue
self.data["accounting"][uid]["wan-tx"] = (
self.data["client_traffic"][uid]["wan-tx"] = (
round(vals["wan-tx"] / time_diff * uom_div, 2)
if vals["wan-tx"]
else 0.0
)
self.data["accounting"][uid]["wan-rx"] = (
self.data["client_traffic"][uid]["wan-rx"] = (
round(vals["wan-rx"] / time_diff * uom_div, 2)
if vals["wan-rx"]
else 0.0
@ -1988,12 +1989,12 @@ class MikrotikControllerData:
# Skip calculation for LAN if LAN accounting is disabled
continue
self.data["accounting"][uid]["lan-tx"] = (
self.data["client_traffic"][uid]["lan-tx"] = (
round(vals["lan-tx"] / time_diff * uom_div, 2)
if vals["lan-tx"]
else 0.0
)
self.data["accounting"][uid]["lan-rx"] = (
self.data["client_traffic"][uid]["lan-rx"] = (
round(vals["lan-rx"] / time_diff * uom_div, 2)
if vals["lan-rx"]
else 0.0
@ -2033,7 +2034,7 @@ class MikrotikControllerData:
# _get_accounting_uid_by_ip
# ---------------------------
def _get_accounting_uid_by_ip(self, requested_ip):
for mac, vals in self.data["accounting"].items():
for mac, vals in self.data["client_traffic"].items():
if vals.get("address") is requested_ip:
return mac
return None
@ -2050,3 +2051,125 @@ class MikrotikControllerData:
break
return uid
# ---------------------------
# process_kid_control
# ---------------------------
def process_kid_control_devices(self):
"""Get Kid Control Device data from Mikrotik"""
uom_type, uom_div = self._get_unit_of_measurement()
# Build missing hosts from main hosts dict
for uid, vals in self.data["host"].items():
if uid not in self.data["client_traffic"]:
self.data["client_traffic"][uid] = {
"address": vals["address"],
"mac-address": vals["mac-address"],
"host-name": vals["host-name"],
"previous-bytes-up": 0.0,
"previous-bytes-down": 0.0,
"wan-tx": 0.0,
"wan-rx": 0.0,
"tx-rx-attr": uom_type,
"available": False,
"local_accounting": False,
}
_LOGGER.debug(f"Working with {len(self.data['client_traffic'])} kid control devices")
time_diff = self.api.take_client_traffic_snapshot(False)
if not time_diff:
return
kid_control_devices_data = parse_api(
data={},
source=self.api.path("/ip/kid-control/device"),
key="mac-address",
vals=[
{"name": "mac-address"},
{"name": "bytes-down"},
{"name": "bytes-up"},
{
"name": "enabled",
"source": "disabled",
"type": "bool",
"reverse": True,
}
]
)
if not kid_control_devices_data:
_LOGGER.debug("No kid control devices found, make sure kid-control feature is configured")
for uid, vals in kid_control_devices_data.items():
if uid not in self.data["client_traffic"]:
_LOGGER.debug(f"Skipping unknown device {uid}")
continue
self.data["client_traffic"][uid]["available"] = vals['enabled']
current_tx = vals['bytes-up']
previous_tx = self.data["client_traffic"][uid]['previous-bytes-up']
delta_tx = max(0, current_tx - previous_tx)
self.data["client_traffic"][uid]['wan-tx'] = round(delta_tx / time_diff * uom_div, 2)
self.data["client_traffic"][uid]['previous-bytes-up'] = current_tx
current_rx = vals['bytes-down']
previous_rx = self.data["client_traffic"][uid]['previous-bytes-down']
delta_rx = max(0, current_rx - previous_rx)
self.data["client_traffic"][uid]['wan-rx'] = round(delta_rx / time_diff * uom_div, 2)
self.data["client_traffic"][uid]['previous-bytes-down'] = current_rx
# ---------------------------
# _get_unit_of_measurement
# ---------------------------
def _get_unit_of_measurement(self):
uom_type = self.option_unit_of_measurement
if uom_type == "Kbps":
uom_div = 0.001
elif uom_type == "Mbps":
uom_div = 0.000001
elif uom_type == "B/s":
uom_div = 0.125
elif uom_type == "KB/s":
uom_div = 0.000125
elif uom_type == "MB/s":
uom_div = 0.000000125
else:
uom_type = "bps"
uom_div = 1
return uom_type, uom_div
# ---------------------------
# _address_part_of_local_network
# ---------------------------
def _address_part_of_local_network(self, address):
address = ip_address(address)
for vals in self.data["dhcp-network"].values():
if address in vals["IPv4Network"]:
return True
return False
# ---------------------------
# _get_accounting_uid_by_ip
# ---------------------------
def _get_accounting_uid_by_ip(self, requested_ip):
for mac, vals in self.data["client_traffic"].items():
if vals.get("address") is requested_ip:
return mac
return None
# ---------------------------
# _get_iface_from_entry
# ---------------------------
def _get_iface_from_entry(self, entry):
"""Get interface default-name using name from interface dict"""
uid = None
for ifacename in self.data["interface"]:
if self.data["interface"][ifacename]["name"] == entry["interface"]:
uid = ifacename
break
return uid