diff --git a/custom_components/mikrotik_router/.translations/en.json b/custom_components/mikrotik_router/.translations/en.json index ca60582..8e4a33d 100644 --- a/custom_components/mikrotik_router/.translations/en.json +++ b/custom_components/mikrotik_router/.translations/en.json @@ -13,7 +13,6 @@ "password": "Password", "ssl": "Use SSL", "unit_of_measurement": "Unit of measurement", - "track_accounting": "Track accounting" } } }, @@ -23,7 +22,6 @@ "ssl_handshake_failure": "SSL handshake failure.", "connection_timeout": "Mikrotik connection timeout.", "wrong_login": "Invalid username or password.", - "accounting_disabled": "Accounting disabled in Mikrotik, cannot track." } }, "options": { diff --git a/custom_components/mikrotik_router/.translations/ru.json b/custom_components/mikrotik_router/.translations/ru.json index b8216d0..3a2f5fe 100644 --- a/custom_components/mikrotik_router/.translations/ru.json +++ b/custom_components/mikrotik_router/.translations/ru.json @@ -13,7 +13,6 @@ "password": "Пароль", "ssl": "Использовать SSL", "unit_of_measurement": "Единицы измерения", - "track_accounting": "Отслеживание учета" } } }, @@ -23,7 +22,6 @@ "ssl_handshake_failure": "Ошибка SSL-соединения", "connection_timeout": "Таймаут подключения к Mikrotik.", "wrong_login": "Неверные имя пользователя или пароль.", - "accounting_disabled": "Учетная запись отключена в Mikrotik, не может отслеживать." } }, "options": { diff --git a/custom_components/mikrotik_router/__init__.py b/custom_components/mikrotik_router/__init__.py index c052bff..b84d19d 100644 --- a/custom_components/mikrotik_router/__init__.py +++ b/custom_components/mikrotik_router/__init__.py @@ -17,7 +17,6 @@ from .const import ( DOMAIN, DATA_CLIENT, DEFAULT_TRAFFIC_TYPE, - CONF_TRACK_ACCOUNTING, ) from .mikrotik_controller import MikrotikControllerData @@ -49,11 +48,10 @@ async def async_setup_entry(hass, config_entry): traffic_type = config_entry.data[CONF_UNIT_OF_MEASUREMENT] else: traffic_type = DEFAULT_TRAFFIC_TYPE - track_accounting = config_entry.data[CONF_TRACK_ACCOUNTING] mikrotik_controller = MikrotikControllerData( hass, config_entry, name, host, port, username, password, use_ssl, - traffic_type, track_accounting + traffic_type ) await mikrotik_controller.hwinfo_update() diff --git a/custom_components/mikrotik_router/config_flow.py b/custom_components/mikrotik_router/config_flow.py index fdc6285..ec574aa 100644 --- a/custom_components/mikrotik_router/config_flow.py +++ b/custom_components/mikrotik_router/config_flow.py @@ -27,7 +27,6 @@ from .const import ( DEFAULT_SCAN_INTERVAL, DEFAULT_TRAFFIC_TYPE, TRAFFIC_TYPES, - CONF_TRACK_ACCOUNTING, ) from .mikrotikapi import MikrotikAPI @@ -52,7 +51,7 @@ def configured_instances(hass): class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN): """MikrotikControllerConfigFlow class""" - VERSION = 2 + VERSION = 1 CONNECTION_CLASS = CONN_CLASS_LOCAL_POLL def __init__(self): @@ -86,9 +85,6 @@ class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN): ) if not api.connect(): errors[CONF_HOST] = api.error - else: - if user_input[CONF_TRACK_ACCOUNTING] and not api.is_accounting_enabled(): - errors[CONF_HOST] = "accounting_disabled" # Save instance if not errors: @@ -103,7 +99,6 @@ class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN): port=user_input["port"], name=user_input["name"], use_ssl=user_input["ssl"], - track_accounting=user_input["track_accounting"], errors=errors, ) @@ -120,7 +115,6 @@ class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN): port=0, name="Mikrotik", use_ssl=False, - track_accounting=False, errors=None, ): """Show the configuration form to edit data.""" @@ -137,7 +131,6 @@ class MikrotikControllerConfigFlow(ConfigFlow, domain=DOMAIN): vol.Optional(CONF_PORT, default=port): int, vol.Optional(CONF_NAME, default=name): str, vol.Optional(CONF_SSL, default=use_ssl): bool, - vol.Optional(CONF_TRACK_ACCOUNTING, default=track_accounting): bool, } ), errors=errors, diff --git a/custom_components/mikrotik_router/const.py b/custom_components/mikrotik_router/const.py index c9d4a11..0472cca 100644 --- a/custom_components/mikrotik_router/const.py +++ b/custom_components/mikrotik_router/const.py @@ -16,5 +16,3 @@ DEFAULT_LOGIN_METHOD = "plain" DEFAULT_TRAFFIC_TYPE = "Kbps" TRAFFIC_TYPES = ["bps", "Kbps", "Mbps", "B/s", "KB/s", "MB/s"] - -CONF_TRACK_ACCOUNTING = "track_accounting" diff --git a/custom_components/mikrotik_router/mikrotik_controller.py b/custom_components/mikrotik_router/mikrotik_controller.py index 5b9a5b4..9776030 100644 --- a/custom_components/mikrotik_router/mikrotik_controller.py +++ b/custom_components/mikrotik_router/mikrotik_controller.py @@ -42,7 +42,6 @@ class MikrotikControllerData: password, use_ssl, traffic_type, - track_accounting, ): """Initialize MikrotikController.""" self.name = name @@ -50,7 +49,6 @@ class MikrotikControllerData: self.host = host self.config_entry = config_entry self.traffic_type = traffic_type - self.track_accounting = track_accounting self.data = { "routerboard": {}, @@ -73,6 +71,7 @@ class MikrotikControllerData: self.api = MikrotikAPI(host, username, password, port, use_ssl) + self.raw_arp_entries = [] self.nat_removed = {} async_track_time_interval( @@ -81,10 +80,6 @@ class MikrotikControllerData: async_track_time_interval( self.hass, self.force_fwupdate_check, timedelta(hours=1) ) - # if self.track_accounting: - # async_track_time_interval( - # self.hass, self.force_accounting_hosts_update, timedelta(minutes=15) - # ) def _get_traffic_type_and_div(self): traffic_type = self.option_traffic_type @@ -111,14 +106,6 @@ class MikrotikControllerData: """Trigger update by timer""" await self.async_update() - # --------------------------- - # force_accounting_hosts_update - # --------------------------- - # @callback - # async def force_accounting_hosts_update(self, _now=None): - # """Trigger update by timer""" - # await self.async_accounting_hosts_update() - # --------------------------- # force_fwupdate_check # --------------------------- @@ -185,19 +172,6 @@ class MikrotikControllerData: await self.hass.async_add_executor_job(self.get_system_resource) self.lock.release() - # --------------------------- - # async_accounting_hosts_update - # --------------------------- - # async def async_accounting_hosts_update(self): - # """Update Mikrotik accounting hosts""" - # try: - # await asyncio.wait_for(self.lock.acquire(), timeout=10) - # except: - # return - # - # await self.hass.async_add_executor_job(self.build_accounting_hosts) - # self.lock.release() - # --------------------------- # async_fwupdate_check # --------------------------- @@ -227,8 +201,7 @@ class MikrotikControllerData: await self.hass.async_add_executor_job(self.get_script) await self.hass.async_add_executor_job(self.get_queue) await self.hass.async_add_executor_job(self.get_dhcp) - if self.track_accounting: - await self.hass.async_add_executor_job(self.get_accounting) + await self.hass.async_add_executor_job(self.get_accounting) async_dispatcher_send(self.hass, self.signal_update) self.lock.release() @@ -371,6 +344,7 @@ class MikrotikControllerData: def update_arp(self, mac2ip, bridge_used): """Get list of hosts in ARP for interface client data from Mikrotik""" data = self.api.path("/ip/arp") + self.raw_arp_entries = data if not data: return mac2ip, bridge_used @@ -763,10 +737,38 @@ class MikrotikControllerData: def get_accounting(self): """Get Accounting data from Mikrotik""" + # Check if accounting and account-local-traffic is enabled + accounting_enabled, local_traffic_enabled = self.api.is_accounting_and_local_traffic_enabled() + + if not accounting_enabled: + # If any hosts were created return counters to 0 so sensors wont get stuck on last value + for mac, vals in self.data["accounting"].items(): + if 'wan-tx' in vals: + self.data["accounting"]['wan-tx'] = 0.0 + if 'wan-rx' in vals: + self.data["accounting"]['wan-rx'] = 0.0 + if 'lan-tx' in vals: + self.data["accounting"]['lan-tx'] = 0.0 + if 'lan-rx' in vals: + self.data["accounting"]['lan-rx'] = 0.0 + return + # Build missing hosts from already retrieved DHCP Server leases for mac, vals in self.data["dhcp"].items(): if mac not in self.data["accounting"]: - self.data["accounting"][mac] = vals + self.data["accounting"][mac] = { + 'address': vals['address'], + 'mac-address': vals['mac-address'], + 'host-name': vals['host-name'], + } + + # Build missing hosts from already retrieved ARP list + for entry in self.raw_arp_entries: + if entry['mac-address'] not in self.data["accounting"]: + self.data["accounting"][entry['mac-address']] = { + 'address': entry['address'], + 'mac-address': entry['mac-address'], + } # Build name for host dns_data = parse_api( @@ -855,7 +857,7 @@ class MikrotikControllerData: self.data['accounting'][mac]['wan-rx'] = round( tmp_accounting_values[addr]['wan-rx'] / time_diff * traffic_div, 2) - if self.api.is_accounting_local_traffic_enabled(): + if local_traffic_enabled: self.data['accounting'][mac]['lan-tx'] = round( tmp_accounting_values[addr]['lan-tx'] / time_diff * traffic_div, 2) self.data['accounting'][mac]['lan-rx'] = round( @@ -877,6 +879,6 @@ class MikrotikControllerData: self.data['accounting'][mac]['wan-tx'] = 0.0 self.data['accounting'][mac]['wan-rx'] = 0.0 - if self.api.is_accounting_local_traffic_enabled(): + if local_traffic_enabled: self.data['accounting'][mac]['lan-tx'] = 0.0 self.data['accounting'][mac]['lan-rx'] = 0.0 diff --git a/custom_components/mikrotik_router/mikrotikapi.py b/custom_components/mikrotik_router/mikrotikapi.py index 9a71ee8..66f1bbc 100644 --- a/custom_components/mikrotik_router/mikrotikapi.py +++ b/custom_components/mikrotik_router/mikrotikapi.py @@ -471,36 +471,31 @@ class MikrotikAPI: from time import time return int(round(time() * 1000)) - def is_accounting_enabled(self) -> bool: + def is_accounting_and_local_traffic_enabled(self) -> (bool, bool): + # Returns: + # 1st bool: Is accounting enabled + # 2nd bool: Is account-local-traffic enabled + if not self.connection_check(): - return False + return False, False response = self.path("/ip/accounting") if response is None: - return False + return False, False for item in response: if 'enabled' not in item: continue - if item['enabled']: - return True + if not item['enabled']: + return False, False - return False - - def is_accounting_local_traffic_enabled(self) -> bool: - if not self.connection_check(): - return False - - accounting = self.path("/ip/accounting") - if accounting is None: - return False - - for item in accounting: + for item in response: if 'account-local-traffic' not in item: continue - if item['account-local-traffic']: - return True - return False + if not item['account-local-traffic']: + return True, False + + return True, True # --------------------------- # take_accounting_snapshot diff --git a/custom_components/mikrotik_router/strings.json b/custom_components/mikrotik_router/strings.json index 913af8a..8ff7b12 100644 --- a/custom_components/mikrotik_router/strings.json +++ b/custom_components/mikrotik_router/strings.json @@ -13,7 +13,6 @@ "password": "Password", "ssl": "Use SSL", "unit_of_measurement": "Unit of measurement", - "track_accounting": "Track accounting" } } }, @@ -23,7 +22,6 @@ "ssl_handshake_failure": "SSL handshake failure", "connection_timeout": "Mikrotik connection timeout.", "wrong_login": "Invalid user name or password.", - "accounting_disabled": "Accounting disabled in Mikrotik, cannot track." } }, "options": {