2019-12-02 04:19:40 +01:00
|
|
|
"""Mikrotik Controller for Mikrotik Router."""
|
|
|
|
|
2019-12-12 23:01:57 +01:00
|
|
|
import asyncio
|
2019-12-02 04:19:40 +01:00
|
|
|
import logging
|
2020-03-21 19:02:28 +03:00
|
|
|
from datetime import timedelta
|
2020-04-08 10:19:29 +02:00
|
|
|
from ipaddress import ip_address, IPv4Network
|
2020-03-21 18:46:54 +03:00
|
|
|
|
|
|
|
from homeassistant.core import callback
|
2019-12-02 04:19:40 +01:00
|
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
|
|
|
from homeassistant.helpers.event import async_track_time_interval
|
2020-04-08 09:17:25 +02:00
|
|
|
from homeassistant.util.dt import utcnow
|
2020-04-09 02:53:43 +02:00
|
|
|
from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER_DOMAIN
|
2019-12-02 04:19:40 +01:00
|
|
|
|
2020-04-08 20:31:47 +02:00
|
|
|
from homeassistant.const import (
|
|
|
|
CONF_NAME,
|
|
|
|
CONF_HOST,
|
|
|
|
CONF_PORT,
|
|
|
|
CONF_UNIT_OF_MEASUREMENT,
|
|
|
|
CONF_USERNAME,
|
|
|
|
CONF_PASSWORD,
|
|
|
|
CONF_SSL,
|
|
|
|
)
|
|
|
|
|
2019-12-02 04:19:40 +01:00
|
|
|
from .const import (
|
2019-12-02 18:13:55 +01:00
|
|
|
DOMAIN,
|
2020-04-08 20:31:47 +02:00
|
|
|
CONF_TRACK_IFACE_CLIENTS,
|
|
|
|
DEFAULT_TRACK_IFACE_CLIENTS,
|
2020-04-09 23:17:39 +02:00
|
|
|
CONF_TRACK_HOSTS,
|
|
|
|
DEFAULT_TRACK_HOSTS,
|
2019-12-02 18:13:55 +01:00
|
|
|
CONF_SCAN_INTERVAL,
|
|
|
|
DEFAULT_SCAN_INTERVAL,
|
2020-04-08 20:31:47 +02:00
|
|
|
DEFAULT_UNIT_OF_MEASUREMENT,
|
2019-12-02 04:19:40 +01:00
|
|
|
)
|
2019-12-12 23:01:57 +01:00
|
|
|
from .exceptions import ApiEntryNotFound
|
2020-04-11 05:45:36 +02:00
|
|
|
from .helper import parse_api
|
2020-03-21 19:02:28 +03:00
|
|
|
from .mikrotikapi import MikrotikAPI
|
2019-12-02 04:19:40 +01:00
|
|
|
|
2019-12-02 17:59:49 +01:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2019-12-02 04:19:40 +01:00
|
|
|
|
2019-12-02 16:22:01 +01:00
|
|
|
|
2019-12-02 17:59:49 +01:00
|
|
|
# ---------------------------
|
2019-12-02 04:19:40 +01:00
|
|
|
# MikrotikControllerData
|
2019-12-02 17:59:49 +01:00
|
|
|
# ---------------------------
|
2020-03-16 04:51:41 +01:00
|
|
|
class MikrotikControllerData:
|
2019-12-05 20:42:14 +01:00
|
|
|
"""MikrotikController Class"""
|
2020-03-16 04:51:41 +01:00
|
|
|
|
2020-04-08 20:31:47 +02:00
|
|
|
def __init__(self, hass, config_entry):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Initialize MikrotikController."""
|
2019-12-02 18:13:55 +01:00
|
|
|
self.hass = hass
|
|
|
|
self.config_entry = config_entry
|
2020-04-08 20:31:47 +02:00
|
|
|
self.name = config_entry.data[CONF_NAME]
|
|
|
|
self.host = config_entry.data[CONF_HOST]
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data = {
|
|
|
|
"routerboard": {},
|
|
|
|
"resource": {},
|
|
|
|
"interface": {},
|
2020-04-11 02:32:33 +02:00
|
|
|
"bridge": {},
|
2020-04-11 01:26:44 +02:00
|
|
|
"bridge_host": {},
|
2020-03-16 04:51:41 +01:00
|
|
|
"arp": {},
|
|
|
|
"nat": {},
|
|
|
|
"fw-update": {},
|
|
|
|
"script": {},
|
2020-03-25 13:18:49 +01:00
|
|
|
"queue": {},
|
2020-04-08 09:15:26 +02:00
|
|
|
"dns": {},
|
2020-04-07 03:55:38 +02:00
|
|
|
"dhcp-server": {},
|
2020-04-08 10:09:31 +02:00
|
|
|
"dhcp-network": {},
|
2020-04-07 03:55:38 +02:00
|
|
|
"dhcp": {},
|
2020-04-09 22:24:48 +02:00
|
|
|
"capsman_hosts": {},
|
|
|
|
"wireless_hosts": {},
|
2020-04-08 07:15:14 +02:00
|
|
|
"host": {},
|
2020-04-09 02:53:43 +02:00
|
|
|
"host_hass": {},
|
2020-04-11 05:45:36 +02:00
|
|
|
"accounting": {},
|
2020-03-16 04:51:41 +01:00
|
|
|
}
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
self.listeners = []
|
2019-12-12 23:01:57 +01:00
|
|
|
self.lock = asyncio.Lock()
|
2020-04-11 05:14:39 +02:00
|
|
|
self.lock_ping = asyncio.Lock()
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-08 20:31:47 +02:00
|
|
|
self.api = MikrotikAPI(
|
|
|
|
config_entry.data[CONF_HOST],
|
|
|
|
config_entry.data[CONF_USERNAME],
|
|
|
|
config_entry.data[CONF_PASSWORD],
|
|
|
|
config_entry.data[CONF_PORT],
|
2020-04-11 05:45:36 +02:00
|
|
|
config_entry.data[CONF_SSL],
|
2020-04-08 20:31:47 +02:00
|
|
|
)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-11 05:14:39 +02:00
|
|
|
self.api_ping = MikrotikAPI(
|
|
|
|
config_entry.data[CONF_HOST],
|
|
|
|
config_entry.data[CONF_USERNAME],
|
|
|
|
config_entry.data[CONF_PASSWORD],
|
|
|
|
config_entry.data[CONF_PORT],
|
2020-04-11 05:45:36 +02:00
|
|
|
config_entry.data[CONF_SSL],
|
2020-04-11 05:14:39 +02:00
|
|
|
)
|
|
|
|
|
2020-04-06 22:50:01 +02:00
|
|
|
self.nat_removed = {}
|
2020-04-09 02:53:43 +02:00
|
|
|
self.host_hass_recovered = False
|
2020-04-11 05:14:39 +02:00
|
|
|
self.host_tracking_initialized = False
|
2020-04-06 22:50:01 +02:00
|
|
|
|
2020-04-09 22:08:26 +02:00
|
|
|
self.support_capsman = False
|
|
|
|
self.support_wireless = False
|
|
|
|
|
2020-04-11 05:14:39 +02:00
|
|
|
self._force_update_callback = None
|
|
|
|
self._force_fwupdate_check_callback = None
|
|
|
|
self._async_ping_tracked_hosts_callback = None
|
|
|
|
|
|
|
|
async def async_init(self):
|
|
|
|
self._force_update_callback = async_track_time_interval(
|
2020-03-16 04:51:41 +01:00
|
|
|
self.hass, self.force_update, self.option_scan_interval
|
|
|
|
)
|
2020-04-11 05:14:39 +02:00
|
|
|
self._force_fwupdate_check_callback = async_track_time_interval(
|
2020-03-16 04:51:41 +01:00
|
|
|
self.hass, self.force_fwupdate_check, timedelta(hours=1)
|
|
|
|
)
|
2020-04-11 05:14:39 +02:00
|
|
|
self._async_ping_tracked_hosts_callback = async_track_time_interval(
|
|
|
|
self.hass, self.async_ping_tracked_hosts, timedelta(seconds=15)
|
|
|
|
)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
2020-04-08 20:31:47 +02:00
|
|
|
# option_track_iface_clients
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
|
|
|
@property
|
2020-04-08 20:31:47 +02:00
|
|
|
def option_track_iface_clients(self):
|
2019-12-02 18:13:55 +01:00
|
|
|
"""Config entry option to not track ARP."""
|
2020-04-11 05:45:36 +02:00
|
|
|
return self.config_entry.options.get(
|
|
|
|
CONF_TRACK_IFACE_CLIENTS, DEFAULT_TRACK_IFACE_CLIENTS
|
|
|
|
)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-09 23:17:39 +02:00
|
|
|
# ---------------------------
|
|
|
|
# option_track_network_hosts
|
|
|
|
# ---------------------------
|
|
|
|
@property
|
|
|
|
def option_track_network_hosts(self):
|
|
|
|
"""Config entry option to not track ARP."""
|
|
|
|
return self.config_entry.options.get(CONF_TRACK_HOSTS, DEFAULT_TRACK_HOSTS)
|
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
|
|
|
# option_scan_interval
|
|
|
|
# ---------------------------
|
|
|
|
@property
|
|
|
|
def option_scan_interval(self):
|
|
|
|
"""Config entry option scan interval."""
|
2020-03-16 04:51:41 +01:00
|
|
|
scan_interval = self.config_entry.options.get(
|
|
|
|
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
|
|
|
|
)
|
2019-12-02 18:13:55 +01:00
|
|
|
return timedelta(seconds=scan_interval)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-03-16 01:32:13 +01:00
|
|
|
# ---------------------------
|
2020-04-08 20:31:47 +02:00
|
|
|
# option_unit_of_measurement
|
2020-03-16 01:32:13 +01:00
|
|
|
# ---------------------------
|
|
|
|
@property
|
2020-04-08 20:31:47 +02:00
|
|
|
def option_unit_of_measurement(self):
|
2020-03-16 01:32:13 +01:00
|
|
|
"""Config entry option to not track ARP."""
|
2020-03-16 04:51:41 +01:00
|
|
|
return self.config_entry.options.get(
|
2020-04-08 20:31:47 +02:00
|
|
|
CONF_UNIT_OF_MEASUREMENT, DEFAULT_UNIT_OF_MEASUREMENT
|
2020-03-16 04:51:41 +01:00
|
|
|
)
|
2020-03-16 01:32:13 +01:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
|
|
|
# signal_update
|
|
|
|
# ---------------------------
|
|
|
|
@property
|
|
|
|
def signal_update(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Event to signal new data."""
|
2020-03-16 19:02:54 +01:00
|
|
|
return f"{DOMAIN}-update-{self.name}"
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-11 01:10:56 +02:00
|
|
|
# ---------------------------
|
|
|
|
# async_reset
|
|
|
|
# ---------------------------
|
|
|
|
async def async_reset(self):
|
|
|
|
"""Reset dispatchers"""
|
|
|
|
for unsub_dispatcher in self.listeners:
|
|
|
|
unsub_dispatcher()
|
|
|
|
|
|
|
|
self.listeners = []
|
|
|
|
return True
|
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
|
|
|
# connected
|
|
|
|
# ---------------------------
|
|
|
|
def connected(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Return connected state"""
|
2019-12-02 18:13:55 +01:00
|
|
|
return self.api.connected()
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
# set_value
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
def set_value(self, path, param, value, mod_param, mod_value):
|
|
|
|
"""Change value using Mikrotik API"""
|
|
|
|
return self.api.update(path, param, value, mod_param, mod_value)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-04 16:09:30 +01:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
# run_script
|
2019-12-04 16:09:30 +01:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
def run_script(self, name):
|
|
|
|
"""Run script using Mikrotik API"""
|
|
|
|
try:
|
|
|
|
self.api.run_script(name)
|
|
|
|
except ApiEntryNotFound as error:
|
|
|
|
_LOGGER.error("Failed to run script: %s", error)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-09 22:08:26 +02:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
# get_capabilities
|
2020-04-09 22:08:26 +02:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
def get_capabilities(self):
|
2020-04-09 22:08:26 +02:00
|
|
|
"""Update Mikrotik data"""
|
|
|
|
packages = parse_api(
|
|
|
|
data={},
|
|
|
|
source=self.api.path("/system/package"),
|
|
|
|
key="name",
|
|
|
|
vals=[
|
|
|
|
{"name": "name"},
|
|
|
|
{
|
|
|
|
"name": "enabled",
|
|
|
|
"source": "disabled",
|
|
|
|
"type": "bool",
|
|
|
|
"reverse": True,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
if "wireless" in packages:
|
|
|
|
self.support_capsman = packages["wireless"]["enabled"]
|
|
|
|
self.support_wireless = packages["wireless"]["enabled"]
|
|
|
|
else:
|
|
|
|
self.support_capsman = False
|
2020-04-09 22:24:48 +02:00
|
|
|
self.support_wireless = False
|
2020-04-09 22:08:26 +02:00
|
|
|
|
2020-04-11 01:10:56 +02:00
|
|
|
# ---------------------------
|
|
|
|
# async_get_host_hass
|
|
|
|
# ---------------------------
|
|
|
|
async def async_get_host_hass(self):
|
|
|
|
"""Get host data from HA entity registry"""
|
|
|
|
registry = await self.hass.helpers.entity_registry.async_get_registry()
|
|
|
|
for entity in registry.entities.values():
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
entity.config_entry_id == self.config_entry.entry_id
|
|
|
|
and entity.domain == DEVICE_TRACKER_DOMAIN
|
|
|
|
and "-host-" in entity.unique_id
|
|
|
|
):
|
2020-04-11 01:10:56 +02:00
|
|
|
_, mac = entity.unique_id.split("-host-", 2)
|
|
|
|
self.data["host_hass"][mac] = entity.original_name
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
# async_hwinfo_update
|
|
|
|
# ---------------------------
|
|
|
|
async def async_hwinfo_update(self):
|
|
|
|
"""Update Mikrotik hardware info"""
|
|
|
|
try:
|
2020-04-13 07:36:00 +02:00
|
|
|
await asyncio.wait_for(self.lock.acquire(), timeout=30)
|
2020-04-11 01:10:56 +02:00
|
|
|
except:
|
|
|
|
return
|
|
|
|
|
2020-04-13 07:36:00 +02:00
|
|
|
_LOGGER.warning("Running async_hwinfo_update")
|
|
|
|
|
2020-04-11 01:10:56 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_capabilities)
|
|
|
|
await self.hass.async_add_executor_job(self.get_system_routerboard)
|
|
|
|
await self.hass.async_add_executor_job(self.get_system_resource)
|
2020-04-13 06:47:26 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_script)
|
2020-04-13 07:00:35 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_dhcp_network)
|
2020-04-13 07:02:10 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_dns)
|
2020-04-13 07:03:44 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_queue)
|
2020-04-11 01:10:56 +02:00
|
|
|
self.lock.release()
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
# force_fwupdate_check
|
|
|
|
# ---------------------------
|
|
|
|
@callback
|
|
|
|
async def force_fwupdate_check(self, _now=None):
|
|
|
|
"""Trigger hourly update by timer"""
|
|
|
|
await self.async_fwupdate_check()
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
# async_fwupdate_check
|
|
|
|
# ---------------------------
|
|
|
|
async def async_fwupdate_check(self):
|
|
|
|
"""Update Mikrotik data"""
|
|
|
|
await self.hass.async_add_executor_job(self.get_firmware_update)
|
|
|
|
async_dispatcher_send(self.hass, self.signal_update)
|
|
|
|
|
2020-04-11 05:14:39 +02:00
|
|
|
# ---------------------------
|
|
|
|
# async_ping_tracked_hosts
|
|
|
|
# ---------------------------
|
|
|
|
@callback
|
|
|
|
async def async_ping_tracked_hosts(self, _now=None):
|
|
|
|
"""Trigger update by timer"""
|
|
|
|
if not self.option_track_network_hosts:
|
|
|
|
return
|
|
|
|
|
|
|
|
try:
|
|
|
|
await asyncio.wait_for(self.lock_ping.acquire(), timeout=3)
|
|
|
|
except:
|
|
|
|
return
|
|
|
|
|
2020-04-11 17:44:45 +02:00
|
|
|
for uid in list(self.data["host"]):
|
2020-04-11 06:08:50 +02:00
|
|
|
if not self.host_tracking_initialized:
|
|
|
|
# Add missing default values
|
|
|
|
for key, default in zip(
|
|
|
|
[
|
|
|
|
"address",
|
|
|
|
"mac-address",
|
|
|
|
"interface",
|
|
|
|
"host-name",
|
|
|
|
"last-seen",
|
|
|
|
"available",
|
|
|
|
],
|
|
|
|
["unknown", "unknown", "unknown", "unknown", False, False],
|
|
|
|
):
|
|
|
|
if key not in self.data["host"][uid]:
|
|
|
|
self.data["host"][uid][key] = default
|
2020-04-11 05:14:39 +02:00
|
|
|
|
|
|
|
# Check host availability
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
2020-04-11 17:44:45 +02:00
|
|
|
self.data["host"][uid]["source"] not in ["capsman", "wireless"]
|
|
|
|
and self.data["host"][uid]["address"] != "unknown"
|
|
|
|
and self.data["host"][uid]["interface"] != "unknown"
|
2020-04-11 05:45:36 +02:00
|
|
|
):
|
2020-04-12 22:12:35 +02:00
|
|
|
tmp_interface = self.data["host"][uid]["interface"]
|
|
|
|
if uid in self.data["arp"] and self.data["arp"][uid]["bridge"] != "":
|
|
|
|
tmp_interface = self.data["arp"][uid]["bridge"]
|
|
|
|
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["host"][uid][
|
|
|
|
"available"
|
|
|
|
] = await self.hass.async_add_executor_job(
|
2020-04-11 17:44:45 +02:00
|
|
|
self.api_ping.arp_ping,
|
|
|
|
self.data["host"][uid]["address"],
|
2020-04-12 22:12:35 +02:00
|
|
|
tmp_interface,
|
2020-04-11 05:45:36 +02:00
|
|
|
)
|
2020-04-11 05:14:39 +02:00
|
|
|
|
|
|
|
# Update last seen
|
|
|
|
if self.data["host"][uid]["available"]:
|
|
|
|
self.data["host"][uid]["last-seen"] = utcnow()
|
|
|
|
|
|
|
|
self.host_tracking_initialized = True
|
|
|
|
self.lock_ping.release()
|
|
|
|
|
2020-04-11 01:10:56 +02:00
|
|
|
# ---------------------------
|
|
|
|
# force_update
|
|
|
|
# ---------------------------
|
|
|
|
@callback
|
|
|
|
async def force_update(self, _now=None):
|
|
|
|
"""Trigger update by timer"""
|
|
|
|
await self.async_update()
|
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
|
|
|
# async_update
|
|
|
|
# ---------------------------
|
|
|
|
async def async_update(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Update Mikrotik data"""
|
2020-04-13 07:36:00 +02:00
|
|
|
if self.api.has_reconnected():
|
|
|
|
await self.async_hwinfo_update()
|
|
|
|
|
2019-12-12 23:01:57 +01:00
|
|
|
try:
|
|
|
|
await asyncio.wait_for(self.lock.acquire(), timeout=10)
|
|
|
|
except:
|
|
|
|
return
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-03-16 04:51:41 +01:00
|
|
|
if "available" not in self.data["fw-update"]:
|
2019-12-04 16:09:30 +01:00
|
|
|
await self.async_fwupdate_check()
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-09 02:53:43 +02:00
|
|
|
if not self.data["host_hass"]:
|
2020-04-11 00:02:50 +02:00
|
|
|
await self.async_get_host_hass()
|
2020-04-09 02:53:43 +02:00
|
|
|
|
2020-04-09 22:09:38 +02:00
|
|
|
if self.support_capsman:
|
2020-04-09 22:24:48 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_capsman_hosts)
|
|
|
|
|
|
|
|
if self.support_wireless:
|
|
|
|
await self.hass.async_add_executor_job(self.get_wireless_hosts)
|
2020-04-09 22:09:38 +02:00
|
|
|
|
2019-12-12 23:01:57 +01:00
|
|
|
await self.hass.async_add_executor_job(self.get_interface)
|
2020-04-11 02:32:33 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_bridge)
|
2020-04-08 10:01:31 +02:00
|
|
|
await self.hass.async_add_executor_job(self.get_arp)
|
|
|
|
await self.hass.async_add_executor_job(self.get_dhcp)
|
2020-04-11 05:14:39 +02:00
|
|
|
await self.async_process_host()
|
2019-12-12 23:01:57 +01:00
|
|
|
await self.hass.async_add_executor_job(self.get_interface_traffic)
|
2020-04-11 02:33:06 +02:00
|
|
|
await self.hass.async_add_executor_job(self.process_interface_client)
|
2019-12-12 23:01:57 +01:00
|
|
|
await self.hass.async_add_executor_job(self.get_nat)
|
|
|
|
await self.hass.async_add_executor_job(self.get_system_resource)
|
2020-04-11 01:10:56 +02:00
|
|
|
await self.hass.async_add_executor_job(self.process_accounting)
|
2020-04-08 07:15:14 +02:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
async_dispatcher_send(self.hass, self.signal_update)
|
2019-12-12 23:01:57 +01:00
|
|
|
self.lock.release()
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
2019-12-05 20:42:14 +01:00
|
|
|
# get_interface
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
2019-12-12 23:01:57 +01:00
|
|
|
def get_interface(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Get all interfaces data from Mikrotik"""
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["interface"] = parse_api(
|
|
|
|
data=self.data["interface"],
|
2020-04-04 21:43:19 +02:00
|
|
|
source=self.api.path("/interface"),
|
2020-03-16 04:51:41 +01:00
|
|
|
key="default-name",
|
2019-12-10 22:32:59 +01:00
|
|
|
vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "default-name"},
|
|
|
|
{"name": "name", "default_val": "default-name"},
|
|
|
|
{"name": "type", "default": "unknown"},
|
|
|
|
{"name": "running", "type": "bool"},
|
|
|
|
{
|
|
|
|
"name": "enabled",
|
|
|
|
"source": "disabled",
|
|
|
|
"type": "bool",
|
|
|
|
"reverse": True,
|
|
|
|
},
|
|
|
|
{"name": "port-mac-address", "source": "mac-address"},
|
|
|
|
{"name": "comment"},
|
|
|
|
{"name": "last-link-down-time"},
|
|
|
|
{"name": "last-link-up-time"},
|
|
|
|
{"name": "link-downs"},
|
|
|
|
{"name": "tx-queue-drop"},
|
|
|
|
{"name": "actual-mtu"},
|
2019-12-10 22:32:59 +01:00
|
|
|
],
|
|
|
|
ensure_vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "client-ip-address"},
|
|
|
|
{"name": "client-mac-address"},
|
|
|
|
{"name": "rx-bits-per-second", "default": 0},
|
|
|
|
{"name": "tx-bits-per-second", "default": 0},
|
|
|
|
],
|
2019-12-10 22:32:59 +01:00
|
|
|
)
|
2019-12-08 22:49:36 +01:00
|
|
|
|
2019-12-08 11:20:02 +01:00
|
|
|
# ---------------------------
|
|
|
|
# get_interface_traffic
|
|
|
|
# ---------------------------
|
2019-12-12 23:01:57 +01:00
|
|
|
def get_interface_traffic(self):
|
2019-12-11 09:13:35 +01:00
|
|
|
"""Get traffic for all interfaces from Mikrotik"""
|
|
|
|
interface_list = ""
|
2020-03-16 04:51:41 +01:00
|
|
|
for uid in self.data["interface"]:
|
|
|
|
interface_list += self.data["interface"][uid]["name"] + ","
|
2019-12-10 22:32:59 +01:00
|
|
|
|
2019-12-11 15:34:35 +01:00
|
|
|
interface_list = interface_list[:-1]
|
2019-12-08 11:20:02 +01:00
|
|
|
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["interface"] = parse_api(
|
|
|
|
data=self.data["interface"],
|
2019-12-12 23:01:57 +01:00
|
|
|
source=self.api.get_traffic(interface_list),
|
2020-03-16 04:51:41 +01:00
|
|
|
key_search="name",
|
2019-12-11 09:13:35 +01:00
|
|
|
vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "rx-bits-per-second", "default": 0},
|
|
|
|
{"name": "tx-bits-per-second", "default": 0},
|
|
|
|
],
|
2019-12-11 09:13:35 +01:00
|
|
|
)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-08 20:31:47 +02:00
|
|
|
uom_type, uom_div = self._get_unit_of_measurement()
|
2020-03-16 18:20:21 +01:00
|
|
|
|
2020-03-16 04:51:41 +01:00
|
|
|
for uid in self.data["interface"]:
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["interface"][uid]["rx-bits-per-second-attr"] = uom_type
|
|
|
|
self.data["interface"][uid]["tx-bits-per-second-attr"] = uom_type
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["interface"][uid]["rx-bits-per-second"] = round(
|
2020-04-08 20:31:47 +02:00
|
|
|
self.data["interface"][uid]["rx-bits-per-second"] * uom_div
|
2020-03-16 04:51:41 +01:00
|
|
|
)
|
|
|
|
self.data["interface"][uid]["tx-bits-per-second"] = round(
|
2020-04-08 20:31:47 +02:00
|
|
|
self.data["interface"][uid]["tx-bits-per-second"] * uom_div
|
2020-03-16 04:51:41 +01:00
|
|
|
)
|
2020-03-11 23:25:51 +01:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
2020-04-11 02:32:33 +02:00
|
|
|
# get_bridge
|
2020-04-11 01:26:44 +02:00
|
|
|
# ---------------------------
|
2020-04-11 02:32:33 +02:00
|
|
|
def get_bridge(self):
|
2020-04-11 01:26:44 +02:00
|
|
|
"""Get system resources data from Mikrotik"""
|
|
|
|
self.data["bridge_host"] = parse_api(
|
|
|
|
data=self.data["bridge_host"],
|
|
|
|
source=self.api.path("/interface/bridge/host"),
|
|
|
|
key="mac-address",
|
|
|
|
vals=[
|
|
|
|
{"name": "mac-address"},
|
|
|
|
{"name": "interface", "default": "unknown"},
|
|
|
|
{"name": "bridge", "default": "unknown"},
|
|
|
|
{
|
|
|
|
"name": "enabled",
|
|
|
|
"source": "disabled",
|
|
|
|
"type": "bool",
|
|
|
|
"reverse": True,
|
|
|
|
},
|
|
|
|
],
|
2020-04-12 08:49:34 +02:00
|
|
|
only=[{"key": "local", "value": False}],
|
2020-04-11 01:26:44 +02:00
|
|
|
)
|
|
|
|
|
2020-04-11 02:32:33 +02:00
|
|
|
for uid, vals in self.data["bridge_host"].items():
|
|
|
|
self.data["bridge"][vals["bridge"]] = True
|
|
|
|
|
2020-04-11 01:26:44 +02:00
|
|
|
# ---------------------------
|
2020-04-11 02:33:06 +02:00
|
|
|
# process_interface_client
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
2020-04-11 02:33:06 +02:00
|
|
|
def process_interface_client(self):
|
2019-12-05 22:29:25 +01:00
|
|
|
# Remove data if disabled
|
2020-04-08 20:31:47 +02:00
|
|
|
if not self.option_track_iface_clients:
|
2020-03-16 04:51:41 +01:00
|
|
|
for uid in self.data["interface"]:
|
|
|
|
self.data["interface"][uid]["client-ip-address"] = "disabled"
|
|
|
|
self.data["interface"][uid]["client-mac-address"] = "disabled"
|
2019-12-12 09:06:15 +01:00
|
|
|
return
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-11 02:33:06 +02:00
|
|
|
for uid, vals in self.data["interface"].items():
|
|
|
|
self.data["interface"][uid]["client-ip-address"] = ""
|
|
|
|
self.data["interface"][uid]["client-mac-address"] = ""
|
|
|
|
for arp_uid, arp_vals in self.data["arp"].items():
|
|
|
|
if arp_vals["interface"] != vals["name"]:
|
|
|
|
continue
|
2020-03-11 23:39:43 +01:00
|
|
|
|
2020-04-11 02:33:06 +02:00
|
|
|
if self.data["interface"][uid]["client-ip-address"] == "":
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["interface"][uid]["client-ip-address"] = arp_vals[
|
|
|
|
"address"
|
|
|
|
]
|
2020-04-11 02:33:06 +02:00
|
|
|
else:
|
|
|
|
self.data["interface"][uid]["client-ip-address"] = "multiple"
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-11 02:33:06 +02:00
|
|
|
if self.data["interface"][uid]["client-mac-address"] == "":
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["interface"][uid]["client-mac-address"] = arp_vals[
|
|
|
|
"mac-address"
|
|
|
|
]
|
2020-04-11 02:33:06 +02:00
|
|
|
else:
|
|
|
|
self.data["interface"][uid]["client-mac-address"] = "multiple"
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-11 02:33:06 +02:00
|
|
|
if self.data["interface"][uid]["client-ip-address"] == "":
|
|
|
|
self.data["interface"][uid]["client-ip-address"] = "none"
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-11 02:33:06 +02:00
|
|
|
if self.data["interface"][uid]["client-mac-address"] == "":
|
|
|
|
self.data["interface"][uid]["client-mac-address"] = "none"
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-03 18:29:05 +01:00
|
|
|
# ---------------------------
|
|
|
|
# get_nat
|
|
|
|
# ---------------------------
|
2019-12-12 23:01:57 +01:00
|
|
|
def get_nat(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Get NAT data from Mikrotik"""
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["nat"] = parse_api(
|
|
|
|
data=self.data["nat"],
|
2020-04-04 21:43:19 +02:00
|
|
|
source=self.api.path("/ip/firewall/nat"),
|
2020-03-16 04:51:41 +01:00
|
|
|
key=".id",
|
2019-12-12 09:06:15 +01:00
|
|
|
vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": ".id"},
|
|
|
|
{"name": "protocol", "default": "any"},
|
|
|
|
{"name": "dst-port", "default": "any"},
|
|
|
|
{"name": "in-interface", "default": "any"},
|
|
|
|
{"name": "to-addresses"},
|
|
|
|
{"name": "to-ports"},
|
|
|
|
{"name": "comment"},
|
|
|
|
{
|
|
|
|
"name": "enabled",
|
|
|
|
"source": "disabled",
|
|
|
|
"type": "bool",
|
|
|
|
"reverse": True,
|
|
|
|
},
|
2019-12-12 09:06:15 +01:00
|
|
|
],
|
|
|
|
val_proc=[
|
|
|
|
[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "name"},
|
|
|
|
{"action": "combine"},
|
|
|
|
{"key": "protocol"},
|
|
|
|
{"text": ":"},
|
|
|
|
{"key": "dst-port"},
|
2019-12-12 09:06:15 +01:00
|
|
|
]
|
2019-12-12 13:02:11 +01:00
|
|
|
],
|
2020-04-12 08:49:34 +02:00
|
|
|
only=[{"key": "action", "value": "dst-nat"}],
|
2019-12-12 09:06:15 +01:00
|
|
|
)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2020-04-11 00:02:50 +02:00
|
|
|
# Remove duplicate NAT entries to prevent crash
|
2020-04-06 22:50:01 +02:00
|
|
|
nat_uniq = {}
|
|
|
|
nat_del = {}
|
|
|
|
for uid in self.data["nat"]:
|
|
|
|
tmp_name = self.data["nat"][uid]["name"]
|
|
|
|
if tmp_name not in nat_uniq:
|
|
|
|
nat_uniq[tmp_name] = uid
|
|
|
|
else:
|
|
|
|
nat_del[uid] = 1
|
|
|
|
nat_del[nat_uniq[tmp_name]] = 1
|
|
|
|
|
|
|
|
for uid in nat_del:
|
|
|
|
if self.data["nat"][uid]["name"] not in self.nat_removed:
|
|
|
|
self.nat_removed[self.data["nat"][uid]["name"]] = 1
|
2020-04-11 05:45:36 +02:00
|
|
|
_LOGGER.error(
|
|
|
|
"Mikrotik %s duplicate NAT rule %s, entity will be unavailable.",
|
|
|
|
self.host,
|
|
|
|
self.data["nat"][uid]["name"],
|
|
|
|
)
|
2020-04-06 22:50:01 +02:00
|
|
|
|
|
|
|
del self.data["nat"][uid]
|
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
|
|
|
# get_system_routerboard
|
|
|
|
# ---------------------------
|
2019-12-12 23:01:57 +01:00
|
|
|
def get_system_routerboard(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Get routerboard data from Mikrotik"""
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["routerboard"] = parse_api(
|
|
|
|
data=self.data["routerboard"],
|
2020-04-04 21:43:19 +02:00
|
|
|
source=self.api.path("/system/routerboard"),
|
2019-12-11 15:34:35 +01:00
|
|
|
vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "routerboard", "type": "bool"},
|
|
|
|
{"name": "model", "default": "unknown"},
|
|
|
|
{"name": "serial-number", "default": "unknown"},
|
|
|
|
{"name": "firmware", "default": "unknown"},
|
|
|
|
],
|
2019-12-11 15:34:35 +01:00
|
|
|
)
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-02 18:13:55 +01:00
|
|
|
# ---------------------------
|
|
|
|
# get_system_resource
|
|
|
|
# ---------------------------
|
2019-12-12 23:01:57 +01:00
|
|
|
def get_system_resource(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Get system resources data from Mikrotik"""
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["resource"] = parse_api(
|
|
|
|
data=self.data["resource"],
|
2020-04-04 21:43:19 +02:00
|
|
|
source=self.api.path("/system/resource"),
|
2019-12-11 15:34:35 +01:00
|
|
|
vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "platform", "default": "unknown"},
|
|
|
|
{"name": "board-name", "default": "unknown"},
|
|
|
|
{"name": "version", "default": "unknown"},
|
|
|
|
{"name": "uptime", "default": "unknown"},
|
|
|
|
{"name": "cpu-load", "default": "unknown"},
|
|
|
|
{"name": "free-memory", "default": 0},
|
|
|
|
{"name": "total-memory", "default": 0},
|
|
|
|
{"name": "free-hdd-space", "default": 0},
|
|
|
|
{"name": "total-hdd-space", "default": 0},
|
|
|
|
],
|
2019-12-11 15:34:35 +01:00
|
|
|
)
|
2019-12-08 22:49:36 +01:00
|
|
|
|
2020-03-16 04:51:41 +01:00
|
|
|
if self.data["resource"]["total-memory"] > 0:
|
|
|
|
self.data["resource"]["memory-usage"] = round(
|
|
|
|
(
|
|
|
|
(
|
|
|
|
self.data["resource"]["total-memory"]
|
|
|
|
- self.data["resource"]["free-memory"]
|
|
|
|
)
|
|
|
|
/ self.data["resource"]["total-memory"]
|
|
|
|
)
|
|
|
|
* 100
|
|
|
|
)
|
2019-12-12 08:37:28 +01:00
|
|
|
else:
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["resource"]["memory-usage"] = "unknown"
|
|
|
|
|
|
|
|
if self.data["resource"]["total-hdd-space"] > 0:
|
|
|
|
self.data["resource"]["hdd-usage"] = round(
|
|
|
|
(
|
|
|
|
(
|
|
|
|
self.data["resource"]["total-hdd-space"]
|
|
|
|
- self.data["resource"]["free-hdd-space"]
|
|
|
|
)
|
|
|
|
/ self.data["resource"]["total-hdd-space"]
|
|
|
|
)
|
|
|
|
* 100
|
|
|
|
)
|
2019-12-12 08:37:28 +01:00
|
|
|
else:
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["resource"]["hdd-usage"] = "unknown"
|
2019-12-05 20:45:04 +01:00
|
|
|
|
2019-12-04 16:09:30 +01:00
|
|
|
# ---------------------------
|
2020-04-07 13:33:48 +02:00
|
|
|
# get_firmware_update
|
2019-12-04 16:09:30 +01:00
|
|
|
# ---------------------------
|
2019-12-12 23:01:57 +01:00
|
|
|
def get_firmware_update(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Check for firmware update on Mikrotik"""
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["fw-update"] = parse_api(
|
|
|
|
data=self.data["fw-update"],
|
2020-04-04 21:43:19 +02:00
|
|
|
source=self.api.path("/system/package/update"),
|
2019-12-12 13:02:11 +01:00
|
|
|
vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "status"},
|
|
|
|
{"name": "channel", "default": "unknown"},
|
|
|
|
{"name": "installed-version", "default": "unknown"},
|
|
|
|
{"name": "latest-version", "default": "unknown"},
|
|
|
|
],
|
2019-12-12 13:02:11 +01:00
|
|
|
)
|
|
|
|
|
2020-03-16 04:51:41 +01:00
|
|
|
if "status" in self.data["fw-update"]:
|
|
|
|
self.data["fw-update"]["available"] = (
|
2020-04-11 05:45:36 +02:00
|
|
|
True
|
|
|
|
if self.data["fw-update"]["status"] == "New version is available"
|
2020-03-16 04:51:41 +01:00
|
|
|
else False
|
|
|
|
)
|
2019-12-12 13:02:11 +01:00
|
|
|
else:
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["fw-update"]["available"] = False
|
2019-12-12 13:02:11 +01:00
|
|
|
|
2019-12-04 20:13:11 +01:00
|
|
|
# ---------------------------
|
|
|
|
# get_script
|
|
|
|
# ---------------------------
|
2019-12-12 23:01:57 +01:00
|
|
|
def get_script(self):
|
2019-12-05 20:42:14 +01:00
|
|
|
"""Get list of all scripts from Mikrotik"""
|
2020-03-16 04:51:41 +01:00
|
|
|
self.data["script"] = parse_api(
|
|
|
|
data=self.data["script"],
|
2020-04-04 21:43:19 +02:00
|
|
|
source=self.api.path("/system/script"),
|
2020-03-16 04:51:41 +01:00
|
|
|
key="name",
|
2019-12-11 15:34:35 +01:00
|
|
|
vals=[
|
2020-03-16 04:51:41 +01:00
|
|
|
{"name": "name"},
|
|
|
|
{"name": "last-started", "default": "unknown"},
|
|
|
|
{"name": "run-count", "default": "unknown"},
|
|
|
|
],
|
2019-12-11 15:34:35 +01:00
|
|
|
)
|
2020-03-25 13:18:49 +01:00
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
# get_queue
|
|
|
|
# ---------------------------
|
|
|
|
def get_queue(self):
|
|
|
|
"""Get Queue data from Mikrotik"""
|
|
|
|
self.data["queue"] = parse_api(
|
|
|
|
data=self.data["queue"],
|
2020-04-04 21:43:19 +02:00
|
|
|
source=self.api.path("/queue/simple"),
|
2020-03-25 13:18:49 +01:00
|
|
|
key="name",
|
|
|
|
vals=[
|
2020-03-25 13:28:52 +01:00
|
|
|
{"name": ".id"},
|
2020-03-25 13:18:49 +01:00
|
|
|
{"name": "name", "default": "unknown"},
|
|
|
|
{"name": "target", "default": "unknown"},
|
|
|
|
{"name": "max-limit", "default": "0/0"},
|
|
|
|
{"name": "limit-at", "default": "0/0"},
|
|
|
|
{"name": "burst-limit", "default": "0/0"},
|
|
|
|
{"name": "burst-threshold", "default": "0/0"},
|
|
|
|
{"name": "burst-time", "default": "0s/0s"},
|
|
|
|
{"name": "packet-marks", "default": "none"},
|
|
|
|
{"name": "parent", "default": "none"},
|
|
|
|
{"name": "comment"},
|
|
|
|
{
|
|
|
|
"name": "enabled",
|
|
|
|
"source": "disabled",
|
|
|
|
"type": "bool",
|
|
|
|
"reverse": True,
|
|
|
|
},
|
2020-04-11 05:45:36 +02:00
|
|
|
],
|
2020-03-25 13:18:49 +01:00
|
|
|
)
|
|
|
|
|
2020-04-08 20:31:47 +02:00
|
|
|
uom_type, uom_div = self._get_unit_of_measurement()
|
2020-04-11 00:02:50 +02:00
|
|
|
for uid, vals in self.data["queue"].items():
|
2020-04-11 05:45:36 +02:00
|
|
|
upload_max_limit_bps, download_max_limit_bps = [
|
|
|
|
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][
|
|
|
|
"download-max-limit"
|
|
|
|
] = f"{round(download_max_limit_bps * uom_div)} {uom_type}"
|
|
|
|
|
|
|
|
upload_limit_at_bps, download_limit_at_bps = [
|
|
|
|
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][
|
|
|
|
"download-limit-at"
|
|
|
|
] = f"{round(download_limit_at_bps * uom_div)} {uom_type}"
|
|
|
|
|
|
|
|
upload_burst_limit_bps, download_burst_limit_bps = [
|
|
|
|
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][
|
|
|
|
"download-burst-limit"
|
|
|
|
] = f"{round(download_burst_limit_bps * uom_div)} {uom_type}"
|
|
|
|
|
|
|
|
upload_burst_threshold_bps, download_burst_threshold_bps = [
|
|
|
|
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][
|
|
|
|
"download-burst-threshold"
|
|
|
|
] = f"{round(download_burst_threshold_bps * uom_div)} {uom_type}"
|
|
|
|
|
|
|
|
upload_burst_time, download_burst_time = vals["burst-time"].split("/")
|
2020-03-25 13:18:49 +01:00
|
|
|
self.data["queue"][uid]["upload-burst-time"] = upload_burst_time
|
|
|
|
self.data["queue"][uid]["download-burst-time"] = download_burst_time
|
2020-04-07 03:55:38 +02:00
|
|
|
|
2020-04-08 10:01:09 +02:00
|
|
|
# ---------------------------
|
|
|
|
# get_arp
|
|
|
|
# ---------------------------
|
|
|
|
def get_arp(self):
|
|
|
|
"""Get ARP data from Mikrotik"""
|
|
|
|
self.data["arp"] = parse_api(
|
|
|
|
data=self.data["arp"],
|
|
|
|
source=self.api.path("/ip/arp"),
|
|
|
|
key="mac-address",
|
2020-04-12 08:49:34 +02:00
|
|
|
vals=[{"name": "mac-address"}, {"name": "address"}, {"name": "interface"},],
|
|
|
|
ensure_vals=[{"name": "bridge", "default": ""},],
|
2020-04-08 10:01:09 +02:00
|
|
|
)
|
|
|
|
|
2020-04-11 02:32:33 +02:00
|
|
|
for uid, vals in self.data["arp"].items():
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
vals["interface"] in self.data["bridge"]
|
|
|
|
and uid in self.data["bridge_host"]
|
|
|
|
):
|
2020-04-11 02:32:33 +02:00
|
|
|
self.data["arp"][uid]["bridge"] = vals["interface"]
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["arp"][uid]["interface"] = self.data["bridge_host"][uid][
|
|
|
|
"interface"
|
|
|
|
]
|
2020-04-11 02:32:33 +02:00
|
|
|
|
2020-04-08 09:15:26 +02:00
|
|
|
# ---------------------------
|
|
|
|
# get_dns
|
|
|
|
# ---------------------------
|
|
|
|
def get_dns(self):
|
|
|
|
"""Get static DNS data from Mikrotik"""
|
|
|
|
self.data["dns"] = parse_api(
|
|
|
|
data=self.data["dns"],
|
|
|
|
source=self.api.path("/ip/dns/static"),
|
|
|
|
key="name",
|
2020-04-12 08:49:34 +02:00
|
|
|
vals=[{"name": "name"}, {"name": "address"},],
|
2020-04-08 09:15:26 +02:00
|
|
|
)
|
|
|
|
|
2020-04-07 03:55:38 +02:00
|
|
|
# ---------------------------
|
|
|
|
# get_dhcp
|
|
|
|
# ---------------------------
|
|
|
|
def get_dhcp(self):
|
|
|
|
"""Get DHCP data from Mikrotik"""
|
|
|
|
self.data["dhcp"] = parse_api(
|
|
|
|
data=self.data["dhcp"],
|
|
|
|
source=self.api.path("/ip/dhcp-server/lease"),
|
|
|
|
key="mac-address",
|
|
|
|
vals=[
|
|
|
|
{"name": "mac-address"},
|
|
|
|
{"name": "address", "default": "unknown"},
|
|
|
|
{"name": "host-name", "default": "unknown"},
|
|
|
|
{"name": "status", "default": "unknown"},
|
|
|
|
{"name": "last-seen", "default": "unknown"},
|
|
|
|
{"name": "server", "default": "unknown"},
|
2020-04-08 16:31:26 +02:00
|
|
|
{"name": "comment", "default": ""},
|
2020-04-07 04:01:33 +02:00
|
|
|
],
|
2020-04-13 06:09:50 +02:00
|
|
|
ensure_vals=[{"name": "interface", "default": "unknown"},],
|
2020-04-07 03:55:38 +02:00
|
|
|
)
|
|
|
|
|
2020-04-13 06:43:02 +02:00
|
|
|
dhcpserver_query = False
|
2020-04-07 03:55:38 +02:00
|
|
|
for uid in self.data["dhcp"]:
|
2020-04-13 06:43:02 +02:00
|
|
|
if not dhcpserver_query and self.data["dhcp"][uid]["server"] not in self.data["dhcp-server"]:
|
2020-04-13 07:00:11 +02:00
|
|
|
self.get_dhcp_server()
|
2020-04-13 06:43:02 +02:00
|
|
|
dhcpserver_query = True
|
|
|
|
|
2020-04-13 06:09:50 +02:00
|
|
|
if self.data["dhcp"][uid]["server"] in self.data["dhcp-server"]:
|
|
|
|
self.data["dhcp"][uid]["interface"] = self.data["dhcp-server"][
|
|
|
|
self.data["dhcp"][uid]["server"]
|
|
|
|
]["interface"]
|
|
|
|
elif uid in self.data["arp"]:
|
|
|
|
if self.data["arp"][uid]["bridge"] != "unknown":
|
|
|
|
self.data["dhcp"][uid]["interface"] = self.data["arp"][uid][
|
|
|
|
"bridge"
|
|
|
|
]
|
|
|
|
else:
|
|
|
|
self.data["dhcp"][uid]["interface"] = self.data["arp"][uid][
|
|
|
|
"interface"
|
|
|
|
]
|
2020-04-07 03:55:38 +02:00
|
|
|
|
2020-04-13 07:00:11 +02:00
|
|
|
# ---------------------------
|
|
|
|
# get_dhcp_server
|
|
|
|
# ---------------------------
|
|
|
|
def get_dhcp_server(self):
|
|
|
|
"""Get DHCP server data from Mikrotik"""
|
|
|
|
self.data["dhcp-server"] = parse_api(
|
|
|
|
data=self.data["dhcp-server"],
|
|
|
|
source=self.api.path("/ip/dhcp-server"),
|
|
|
|
key="name",
|
|
|
|
vals=[{"name": "name"}, {"name": "interface", "default": "unknown"}, ],
|
|
|
|
)
|
|
|
|
|
2020-04-13 06:55:08 +02:00
|
|
|
# ---------------------------
|
|
|
|
# get_dhcp_network
|
|
|
|
# ---------------------------
|
|
|
|
def get_dhcp_network(self):
|
2020-04-13 07:00:35 +02:00
|
|
|
"""Get DHCP network data from Mikrotik"""
|
2020-04-13 06:55:08 +02:00
|
|
|
self.data["dhcp-network"] = parse_api(
|
|
|
|
data=self.data["dhcp-network"],
|
|
|
|
source=self.api.path("/ip/dhcp-server/network"),
|
|
|
|
key="address",
|
|
|
|
vals=[
|
|
|
|
{"name": "address"},
|
|
|
|
{"name": "gateway", "default": ""},
|
|
|
|
{"name": "netmask", "default": ""},
|
|
|
|
{"name": "dns-server", "default": ""},
|
|
|
|
{"name": "domain", "default": ""},
|
|
|
|
],
|
|
|
|
ensure_vals=[{"name": "address"}, {"name": "IPv4Network", "default": ""},],
|
|
|
|
)
|
|
|
|
|
|
|
|
for uid, vals in self.data["dhcp-network"].items():
|
|
|
|
if vals["IPv4Network"] == "":
|
|
|
|
self.data["dhcp-network"][uid]["IPv4Network"] = IPv4Network(
|
|
|
|
vals["address"]
|
|
|
|
)
|
|
|
|
|
2020-04-09 22:09:38 +02:00
|
|
|
# ---------------------------
|
2020-04-09 22:24:48 +02:00
|
|
|
# get_capsman_hosts
|
2020-04-09 22:09:38 +02:00
|
|
|
# ---------------------------
|
2020-04-09 22:24:48 +02:00
|
|
|
def get_capsman_hosts(self):
|
|
|
|
"""Get CAPS-MAN hosts data from Mikrotik"""
|
|
|
|
self.data["capsman_hosts"] = parse_api(
|
2020-04-10 01:38:15 +02:00
|
|
|
data={},
|
2020-04-09 22:09:38 +02:00
|
|
|
source=self.api.path("/caps-man/registration-table"),
|
|
|
|
key="mac-address",
|
|
|
|
vals=[
|
|
|
|
{"name": "mac-address"},
|
|
|
|
{"name": "interface", "default": "unknown"},
|
|
|
|
{"name": "ssid", "default": "unknown"},
|
2020-04-11 05:45:36 +02:00
|
|
|
],
|
2020-04-09 22:09:38 +02:00
|
|
|
)
|
|
|
|
|
2020-04-09 22:24:48 +02:00
|
|
|
# ---------------------------
|
|
|
|
# get_wireless_hosts
|
|
|
|
# ---------------------------
|
|
|
|
def get_wireless_hosts(self):
|
|
|
|
"""Get wireless hosts data from Mikrotik"""
|
|
|
|
self.data["wireless_hosts"] = parse_api(
|
2020-04-10 01:38:15 +02:00
|
|
|
data={},
|
2020-04-09 22:24:48 +02:00
|
|
|
source=self.api.path("/interface/wireless/registration-table"),
|
|
|
|
key="mac-address",
|
|
|
|
vals=[
|
|
|
|
{"name": "mac-address"},
|
|
|
|
{"name": "interface", "default": "unknown"},
|
2020-04-10 01:21:20 +02:00
|
|
|
{"name": "ap", "type": "bool"},
|
2020-04-10 01:38:15 +02:00
|
|
|
{"name": "uptime"},
|
2020-04-11 05:45:36 +02:00
|
|
|
],
|
2020-04-09 22:24:48 +02:00
|
|
|
)
|
|
|
|
|
2020-04-08 07:15:14 +02:00
|
|
|
# ---------------------------
|
2020-04-11 05:14:39 +02:00
|
|
|
# async_process_host
|
2020-04-08 07:15:14 +02:00
|
|
|
# ---------------------------
|
2020-04-11 05:14:39 +02:00
|
|
|
async def async_process_host(self):
|
2020-04-08 07:15:14 +02:00
|
|
|
"""Get host tracking data"""
|
2020-04-09 22:09:38 +02:00
|
|
|
# Add hosts from CAPS-MAN
|
2020-04-11 05:45:36 +02:00
|
|
|
capsman_detected = {}
|
2020-04-09 22:09:38 +02:00
|
|
|
if self.support_capsman:
|
2020-04-09 22:24:48 +02:00
|
|
|
for uid, vals in self.data["capsman_hosts"].items():
|
2020-04-09 22:09:38 +02:00
|
|
|
if uid not in self.data["host"]:
|
|
|
|
self.data["host"][uid] = {}
|
|
|
|
|
|
|
|
self.data["host"][uid]["source"] = "capsman"
|
|
|
|
capsman_detected[uid] = True
|
|
|
|
self.data["host"][uid]["available"] = True
|
|
|
|
self.data["host"][uid]["last-seen"] = utcnow()
|
2020-04-11 00:02:50 +02:00
|
|
|
for key in ["mac-address", "interface"]:
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
key not in self.data["host"][uid]
|
|
|
|
or self.data["host"][uid][key] == "unknown"
|
|
|
|
):
|
2020-04-11 00:02:50 +02:00
|
|
|
self.data["host"][uid][key] = vals[key]
|
2020-04-09 22:09:38 +02:00
|
|
|
|
2020-04-09 22:24:48 +02:00
|
|
|
# Add hosts from wireless
|
2020-04-11 05:45:36 +02:00
|
|
|
wireless_detected = {}
|
2020-04-09 22:24:48 +02:00
|
|
|
if self.support_wireless:
|
|
|
|
for uid, vals in self.data["wireless_hosts"].items():
|
2020-04-10 01:21:20 +02:00
|
|
|
if vals["ap"]:
|
2020-04-09 22:36:34 +02:00
|
|
|
continue
|
|
|
|
|
2020-04-09 22:24:48 +02:00
|
|
|
if uid not in self.data["host"]:
|
|
|
|
self.data["host"][uid] = {}
|
|
|
|
|
|
|
|
self.data["host"][uid]["source"] = "wireless"
|
|
|
|
wireless_detected[uid] = True
|
|
|
|
self.data["host"][uid]["available"] = True
|
|
|
|
self.data["host"][uid]["last-seen"] = utcnow()
|
2020-04-11 00:02:50 +02:00
|
|
|
for key in ["mac-address", "interface"]:
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
key not in self.data["host"][uid]
|
|
|
|
or self.data["host"][uid][key] == "unknown"
|
|
|
|
):
|
2020-04-11 00:02:50 +02:00
|
|
|
self.data["host"][uid][key] = vals[key]
|
2020-04-09 22:24:48 +02:00
|
|
|
|
2020-04-08 09:17:25 +02:00
|
|
|
# Add hosts from DHCP
|
|
|
|
for uid, vals in self.data["dhcp"].items():
|
|
|
|
if uid not in self.data["host"]:
|
|
|
|
self.data["host"][uid] = {}
|
|
|
|
self.data["host"][uid]["source"] = "dhcp"
|
2020-04-11 00:02:50 +02:00
|
|
|
for key in ["address", "mac-address", "interface"]:
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
key not in self.data["host"][uid]
|
|
|
|
or self.data["host"][uid][key] == "unknown"
|
|
|
|
):
|
2020-04-11 00:02:50 +02:00
|
|
|
self.data["host"][uid][key] = vals[key]
|
2020-04-08 10:32:02 +02:00
|
|
|
|
|
|
|
# Add hosts from ARP
|
|
|
|
for uid, vals in self.data["arp"].items():
|
|
|
|
if uid not in self.data["host"]:
|
|
|
|
self.data["host"][uid] = {}
|
|
|
|
self.data["host"][uid]["source"] = "arp"
|
2020-04-11 00:02:50 +02:00
|
|
|
for key in ["address", "mac-address", "interface"]:
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
key not in self.data["host"][uid]
|
|
|
|
or self.data["host"][uid][key] == "unknown"
|
|
|
|
):
|
2020-04-11 00:02:50 +02:00
|
|
|
self.data["host"][uid][key] = vals[key]
|
2020-04-08 09:17:25 +02:00
|
|
|
|
2020-04-11 00:02:50 +02:00
|
|
|
# Add restored hosts from hass registry
|
2020-04-09 02:53:43 +02:00
|
|
|
if not self.host_hass_recovered:
|
2020-04-11 00:02:50 +02:00
|
|
|
self.host_hass_recovered = True
|
2020-04-09 02:53:43 +02:00
|
|
|
for uid in self.data["host_hass"]:
|
|
|
|
if uid not in self.data["host"]:
|
|
|
|
self.data["host"][uid] = {}
|
|
|
|
self.data["host"][uid]["source"] = "restored"
|
|
|
|
self.data["host"][uid]["mac-address"] = uid
|
|
|
|
self.data["host"][uid]["host-name"] = self.data["host_hass"][uid]
|
|
|
|
|
2020-04-11 06:08:50 +02:00
|
|
|
for uid, vals in self.data["host"].items():
|
|
|
|
# Add missing default values
|
|
|
|
for key, default in zip(
|
|
|
|
[
|
|
|
|
"address",
|
|
|
|
"mac-address",
|
|
|
|
"interface",
|
|
|
|
"host-name",
|
|
|
|
"last-seen",
|
|
|
|
"available",
|
|
|
|
],
|
|
|
|
["unknown", "unknown", "unknown", "unknown", False, False],
|
|
|
|
):
|
|
|
|
if key not in self.data["host"][uid]:
|
|
|
|
self.data["host"][uid][key] = default
|
|
|
|
|
2020-04-11 05:14:39 +02:00
|
|
|
if not self.host_tracking_initialized:
|
|
|
|
await self.async_ping_tracked_hosts(utcnow())
|
|
|
|
|
2020-04-08 09:17:25 +02:00
|
|
|
# Process hosts
|
|
|
|
for uid, vals in self.data["host"].items():
|
2020-04-11 00:02:50 +02:00
|
|
|
# CAPS-MAN availability
|
2020-04-09 22:09:38 +02:00
|
|
|
if vals["source"] == "capsman" and uid not in capsman_detected:
|
|
|
|
self.data["host"][uid]["available"] = False
|
|
|
|
|
2020-04-11 00:02:50 +02:00
|
|
|
# Wireless availability
|
2020-04-09 22:24:48 +02:00
|
|
|
if vals["source"] == "wireless" and uid not in wireless_detected:
|
|
|
|
self.data["host"][uid]["available"] = False
|
|
|
|
|
2020-04-09 02:59:22 +02:00
|
|
|
# Update IP and interface (DHCP/returned host)
|
|
|
|
if uid in self.data["dhcp"] and "." in self.data["dhcp"][uid]["address"]:
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
self.data["dhcp"][uid]["address"]
|
|
|
|
!= self.data["host"][uid]["address"]
|
|
|
|
):
|
|
|
|
self.data["host"][uid]["address"] = self.data["dhcp"][uid][
|
|
|
|
"address"
|
|
|
|
]
|
2020-04-09 22:24:48 +02:00
|
|
|
if vals["source"] not in ["capsman", "wireless"]:
|
2020-04-09 22:09:38 +02:00
|
|
|
self.data["host"][uid]["source"] = "dhcp"
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["host"][uid]["interface"] = self.data["dhcp"][uid][
|
|
|
|
"interface"
|
|
|
|
]
|
|
|
|
|
|
|
|
elif (
|
|
|
|
uid in self.data["arp"]
|
|
|
|
and "." in self.data["arp"][uid]["address"]
|
|
|
|
and self.data["arp"][uid]["address"]
|
|
|
|
!= self.data["host"][uid]["address"]
|
|
|
|
):
|
2020-04-11 00:02:50 +02:00
|
|
|
self.data["host"][uid]["address"] = self.data["arp"][uid]["address"]
|
2020-04-09 22:24:48 +02:00
|
|
|
if vals["source"] not in ["capsman", "wireless"]:
|
2020-04-11 00:02:50 +02:00
|
|
|
self.data["host"][uid]["source"] = "arp"
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["host"][uid]["interface"] = self.data["arp"][uid][
|
|
|
|
"interface"
|
|
|
|
]
|
2020-04-09 22:09:38 +02:00
|
|
|
|
2020-04-08 16:53:20 +02:00
|
|
|
if vals["host-name"] == "unknown":
|
2020-04-11 00:02:50 +02:00
|
|
|
# Resolve hostname from static DNS
|
2020-04-08 09:17:25 +02:00
|
|
|
if vals["address"] != "unknown":
|
|
|
|
for dns_uid, dns_vals in self.data["dns"].items():
|
|
|
|
if dns_vals["address"] == vals["address"]:
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["host"][uid]["host-name"] = dns_vals[
|
|
|
|
"name"
|
|
|
|
].split(".")[0]
|
2020-04-08 09:17:25 +02:00
|
|
|
break
|
2020-04-11 00:02:50 +02:00
|
|
|
# Resolve hostname from DHCP comment
|
2020-04-11 05:45:36 +02:00
|
|
|
if (
|
|
|
|
self.data["host"][uid]["host-name"] == "unknown"
|
|
|
|
and uid in self.data["dhcp"]
|
|
|
|
and self.data["dhcp"][uid]["comment"] != ""
|
|
|
|
):
|
|
|
|
self.data["host"][uid]["host-name"] = self.data["dhcp"][uid][
|
|
|
|
"comment"
|
|
|
|
]
|
2020-04-11 00:02:50 +02:00
|
|
|
# Resolve hostname from DHCP hostname
|
2020-04-11 05:45:36 +02:00
|
|
|
elif (
|
|
|
|
self.data["host"][uid]["host-name"] == "unknown"
|
|
|
|
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"
|
|
|
|
]
|
2020-04-11 00:02:50 +02:00
|
|
|
# Fallback to mac address for hostname
|
2020-04-08 16:53:20 +02:00
|
|
|
elif self.data["host"][uid]["host-name"] == "unknown":
|
|
|
|
self.data["host"][uid]["host-name"] = uid
|
2020-04-08 09:17:25 +02:00
|
|
|
|
2020-04-08 17:52:58 +02:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
# process_accounting
|
2020-04-08 17:52:58 +02:00
|
|
|
# ---------------------------
|
2020-04-11 01:10:56 +02:00
|
|
|
def process_accounting(self):
|
2020-04-04 19:42:05 +02:00
|
|
|
"""Get Accounting data from Mikrotik"""
|
2020-04-07 14:50:26 +02:00
|
|
|
# Check if accounting and account-local-traffic is enabled
|
2020-04-11 05:45:36 +02:00
|
|
|
(
|
|
|
|
accounting_enabled,
|
|
|
|
local_traffic_enabled,
|
|
|
|
) = self.api.is_accounting_and_local_traffic_enabled()
|
2020-04-08 20:31:47 +02:00
|
|
|
uom_type, uom_div = self._get_unit_of_measurement()
|
2020-04-07 14:50:26 +02:00
|
|
|
|
2020-04-08 13:41:03 +02:00
|
|
|
# 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] = {
|
2020-04-11 05:45:36 +02:00
|
|
|
"address": vals["address"],
|
|
|
|
"mac-address": vals["mac-address"],
|
|
|
|
"host-name": vals["host-name"],
|
|
|
|
"tx-rx-attr": uom_type,
|
|
|
|
"available": False,
|
|
|
|
"local_accounting": False,
|
2020-04-07 14:50:26 +02:00
|
|
|
}
|
|
|
|
|
2020-04-07 20:31:16 +02:00
|
|
|
_LOGGER.debug(f"Working with {len(self.data['accounting'])} accounting devices")
|
2020-04-04 19:42:05 +02:00
|
|
|
|
2020-04-07 11:32:38 +02:00
|
|
|
# Build temp accounting values dict with ip address as key
|
2020-04-05 18:32:48 +02:00
|
|
|
tmp_accounting_values = {}
|
2020-04-11 05:45:36 +02:00
|
|
|
for uid, vals in self.data["accounting"].items():
|
|
|
|
tmp_accounting_values[vals["address"]] = {
|
2020-04-05 16:04:17 +02:00
|
|
|
"wan-tx": 0,
|
|
|
|
"wan-rx": 0,
|
|
|
|
"lan-tx": 0,
|
2020-04-11 05:45:36 +02:00
|
|
|
"lan-rx": 0,
|
2020-04-05 16:04:17 +02:00
|
|
|
}
|
2020-04-04 19:42:05 +02:00
|
|
|
|
|
|
|
time_diff = self.api.take_accounting_snapshot()
|
|
|
|
if time_diff:
|
|
|
|
accounting_data = parse_api(
|
|
|
|
data={},
|
2020-04-07 13:33:48 +02:00
|
|
|
source=self.api.path("/ip/accounting/snapshot"),
|
2020-04-04 19:42:05 +02:00
|
|
|
key=".id",
|
|
|
|
vals=[
|
|
|
|
{"name": ".id"},
|
|
|
|
{"name": "src-address"},
|
|
|
|
{"name": "dst-address"},
|
|
|
|
{"name": "bytes", "default": 0},
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
for item in accounting_data.values():
|
2020-04-11 05:45:36 +02:00
|
|
|
source_ip = str(item.get("src-address")).strip()
|
|
|
|
destination_ip = str(item.get("dst-address")).strip()
|
|
|
|
bits_count = int(str(item.get("bytes")).strip()) * 8
|
2020-04-04 19:42:05 +02:00
|
|
|
|
2020-04-11 05:45:36 +02:00
|
|
|
if self._address_part_of_local_network(
|
|
|
|
source_ip
|
|
|
|
) and self._address_part_of_local_network(destination_ip):
|
2020-04-04 19:42:05 +02:00
|
|
|
# LAN TX/RX
|
2020-04-05 18:32:48 +02:00
|
|
|
if source_ip in tmp_accounting_values:
|
2020-04-11 05:45:36 +02:00
|
|
|
tmp_accounting_values[source_ip]["lan-tx"] += bits_count
|
2020-04-05 18:32:48 +02:00
|
|
|
if destination_ip in tmp_accounting_values:
|
2020-04-11 05:45:36 +02:00
|
|
|
tmp_accounting_values[destination_ip]["lan-rx"] += bits_count
|
|
|
|
elif self._address_part_of_local_network(
|
|
|
|
source_ip
|
|
|
|
) and not self._address_part_of_local_network(destination_ip):
|
2020-04-04 19:42:05 +02:00
|
|
|
# WAN TX
|
2020-04-05 18:32:48 +02:00
|
|
|
if source_ip in tmp_accounting_values:
|
2020-04-11 05:45:36 +02:00
|
|
|
tmp_accounting_values[source_ip]["wan-tx"] += bits_count
|
|
|
|
elif (
|
|
|
|
not self._address_part_of_local_network(source_ip)
|
|
|
|
and self._address_part_of_local_network(destination_ip)
|
|
|
|
and destination_ip in tmp_accounting_values
|
|
|
|
):
|
2020-04-04 19:42:05 +02:00
|
|
|
# WAN RX
|
2020-04-11 05:45:36 +02:00
|
|
|
tmp_accounting_values[destination_ip]["wan-rx"] += bits_count
|
2020-04-08 13:41:03 +02:00
|
|
|
|
|
|
|
# Calculate real throughput and transform it to appropriate unit
|
|
|
|
# Also handle availability of accounting and local_accounting from Mikrotik
|
2020-04-11 00:02:50 +02:00
|
|
|
for addr, vals in tmp_accounting_values.items():
|
2020-04-08 15:44:28 +02:00
|
|
|
uid = self._get_accounting_uid_by_ip(addr)
|
2020-04-08 13:41:03 +02:00
|
|
|
if not uid:
|
2020-04-11 05:45:36 +02:00
|
|
|
_LOGGER.warning(
|
|
|
|
f"Address {addr} not found in accounting data, skipping update"
|
|
|
|
)
|
2020-04-08 13:41:03 +02:00
|
|
|
continue
|
2020-04-04 19:42:05 +02:00
|
|
|
|
2020-04-11 05:45:36 +02:00
|
|
|
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
|
2020-04-07 11:32:38 +02:00
|
|
|
|
2020-04-08 13:41:03 +02:00
|
|
|
if not accounting_enabled:
|
2020-04-11 00:02:50 +02:00
|
|
|
# Skip calculation for WAN and LAN if accounting is disabled
|
2020-04-08 13:41:03 +02:00
|
|
|
continue
|
|
|
|
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["accounting"][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"] = (
|
|
|
|
round(vals["wan-rx"] / time_diff * uom_div, 2)
|
|
|
|
if vals["wan-rx"]
|
|
|
|
else 0.0
|
|
|
|
)
|
2020-04-08 15:44:28 +02:00
|
|
|
|
|
|
|
if not local_traffic_enabled:
|
2020-04-11 00:02:50 +02:00
|
|
|
# Skip calculation for LAN if LAN accounting is disabled
|
2020-04-08 15:44:28 +02:00
|
|
|
continue
|
|
|
|
|
2020-04-11 05:45:36 +02:00
|
|
|
self.data["accounting"][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"] = (
|
|
|
|
round(vals["lan-rx"] / time_diff * uom_div, 2)
|
|
|
|
if vals["lan-rx"]
|
|
|
|
else 0.0
|
|
|
|
)
|
2020-04-11 01:10:56 +02:00
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
# _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):
|
2020-04-11 05:45:36 +02:00
|
|
|
for mac, vals in self.data["accounting"].items():
|
|
|
|
if vals.get("address") is requested_ip:
|
2020-04-11 01:10:56 +02:00
|
|
|
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
|