mirror of
https://github.com/tomaae/homeassistant-mikrotik_router.git
synced 2025-08-30 06:29:39 +02:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
eee634cfc8
2 changed files with 167 additions and 29 deletions
|
@ -11,6 +11,7 @@ from homeassistant.const import (
|
||||||
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.util.dt import get_age
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -37,11 +38,10 @@ DEVICE_ATTRIBUTES_IFACE = [
|
||||||
]
|
]
|
||||||
|
|
||||||
DEVICE_ATTRIBUTES_HOST = [
|
DEVICE_ATTRIBUTES_HOST = [
|
||||||
"host-name",
|
"hostname",
|
||||||
"address",
|
"address",
|
||||||
"mac-address",
|
"mac-address",
|
||||||
"interface",
|
"interface",
|
||||||
"status",
|
|
||||||
"last-seen",
|
"last-seen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ def update_items(inst, mikrotik_controller, async_add_entities, tracked):
|
||||||
|
|
||||||
# Add switches
|
# Add switches
|
||||||
for sid, sid_uid, sid_func in zip(
|
for sid, sid_uid, sid_func in zip(
|
||||||
["interface", "dhcp"],
|
["interface", "host"],
|
||||||
["default-name", "mac-address"],
|
["default-name", "mac-address"],
|
||||||
[
|
[
|
||||||
MikrotikControllerPortDeviceTracker,
|
MikrotikControllerPortDeviceTracker,
|
||||||
|
@ -218,7 +218,7 @@ class MikrotikControllerHostDeviceTracker(ScannerEntity):
|
||||||
"""Set up tracked port."""
|
"""Set up tracked port."""
|
||||||
self._inst = inst
|
self._inst = inst
|
||||||
self._ctrl = mikrotik_controller
|
self._ctrl = mikrotik_controller
|
||||||
self._data = mikrotik_controller.data["dhcp"][uid]
|
self._data = mikrotik_controller.data["host"][uid]
|
||||||
|
|
||||||
self._attrs = {
|
self._attrs = {
|
||||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||||
|
@ -234,7 +234,7 @@ class MikrotikControllerHostDeviceTracker(ScannerEntity):
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"New host tracker %s (%s - %s)",
|
"New host tracker %s (%s - %s)",
|
||||||
self._inst,
|
self._inst,
|
||||||
self._data["host-name"],
|
self._data["hostname"],
|
||||||
self._data["mac-address"],
|
self._data["mac-address"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ class MikrotikControllerHostDeviceTracker(ScannerEntity):
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the host."""
|
"""Return the name of the host."""
|
||||||
return f"{self._inst} {self._data['host-name']}"
|
return f"{self._data['hostname']}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
|
@ -302,6 +302,12 @@ class MikrotikControllerHostDeviceTracker(ScannerEntity):
|
||||||
|
|
||||||
for variable in DEVICE_ATTRIBUTES_HOST:
|
for variable in DEVICE_ATTRIBUTES_HOST:
|
||||||
if variable in self._data:
|
if variable in self._data:
|
||||||
attributes[format_attribute(variable)] = self._data[variable]
|
if variable == "last-seen":
|
||||||
|
if self._data[variable]:
|
||||||
|
attributes[format_attribute(variable)] = get_age(self._data[variable])
|
||||||
|
else:
|
||||||
|
attributes[format_attribute(variable)] = "unknown"
|
||||||
|
else:
|
||||||
|
attributes[format_attribute(variable)] = self._data[variable]
|
||||||
|
|
||||||
return attributes
|
return attributes
|
||||||
|
|
|
@ -8,6 +8,7 @@ from ipaddress import ip_address, IPv4Network
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -55,12 +56,16 @@ class MikrotikControllerData:
|
||||||
"resource": {},
|
"resource": {},
|
||||||
"interface": {},
|
"interface": {},
|
||||||
"arp": {},
|
"arp": {},
|
||||||
|
"arp_tmp": {},
|
||||||
"nat": {},
|
"nat": {},
|
||||||
"fw-update": {},
|
"fw-update": {},
|
||||||
"script": {},
|
"script": {},
|
||||||
"queue": {},
|
"queue": {},
|
||||||
|
"dns": {},
|
||||||
"dhcp-server": {},
|
"dhcp-server": {},
|
||||||
|
"dhcp-network": {},
|
||||||
"dhcp": {},
|
"dhcp": {},
|
||||||
|
"host": {},
|
||||||
"accounting": {}
|
"accounting": {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +199,10 @@ class MikrotikControllerData:
|
||||||
await self.async_fwupdate_check()
|
await self.async_fwupdate_check()
|
||||||
|
|
||||||
await self.hass.async_add_executor_job(self.get_interface)
|
await self.hass.async_add_executor_job(self.get_interface)
|
||||||
|
await self.hass.async_add_executor_job(self.get_arp)
|
||||||
|
await self.hass.async_add_executor_job(self.get_dns)
|
||||||
|
await self.hass.async_add_executor_job(self.get_dhcp)
|
||||||
|
await self.hass.async_add_executor_job(self.process_host)
|
||||||
await self.hass.async_add_executor_job(self.get_interface_traffic)
|
await self.hass.async_add_executor_job(self.get_interface_traffic)
|
||||||
await self.hass.async_add_executor_job(self.get_interface_client)
|
await self.hass.async_add_executor_job(self.get_interface_client)
|
||||||
await self.hass.async_add_executor_job(self.get_nat)
|
await self.hass.async_add_executor_job(self.get_nat)
|
||||||
|
@ -204,6 +213,7 @@ class MikrotikControllerData:
|
||||||
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)
|
async_dispatcher_send(self.hass, self.signal_update)
|
||||||
|
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
@ -310,7 +320,7 @@ class MikrotikControllerData:
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
def get_interface_client(self):
|
def get_interface_client(self):
|
||||||
"""Get ARP data from Mikrotik"""
|
"""Get ARP data from Mikrotik"""
|
||||||
self.data["arp"] = {}
|
self.data["arp_tmp"] = {}
|
||||||
|
|
||||||
# Remove data if disabled
|
# Remove data if disabled
|
||||||
if not self.option_track_arp:
|
if not self.option_track_arp:
|
||||||
|
@ -328,14 +338,14 @@ class MikrotikControllerData:
|
||||||
|
|
||||||
# Map ARP to ifaces
|
# Map ARP to ifaces
|
||||||
for uid in self.data["interface"]:
|
for uid in self.data["interface"]:
|
||||||
if uid not in self.data["arp"]:
|
if uid not in self.data["arp_tmp"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.data["interface"][uid]["client-ip-address"] = from_entry(
|
self.data["interface"][uid]["client-ip-address"] = from_entry(
|
||||||
self.data["arp"][uid], "address"
|
self.data["arp_tmp"][uid], "address"
|
||||||
)
|
)
|
||||||
self.data["interface"][uid]["client-mac-address"] = from_entry(
|
self.data["interface"][uid]["client-mac-address"] = from_entry(
|
||||||
self.data["arp"][uid], "mac-address"
|
self.data["arp_tmp"][uid], "mac-address"
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
@ -372,16 +382,16 @@ class MikrotikControllerData:
|
||||||
|
|
||||||
_LOGGER.debug("Processing entry %s, entry %s", "/ip/arp", entry)
|
_LOGGER.debug("Processing entry %s, entry %s", "/ip/arp", entry)
|
||||||
# Create uid arp dict
|
# Create uid arp dict
|
||||||
if uid not in self.data["arp"]:
|
if uid not in self.data["arp_tmp"]:
|
||||||
self.data["arp"][uid] = {}
|
self.data["arp_tmp"][uid] = {}
|
||||||
|
|
||||||
# Add data
|
# Add data
|
||||||
self.data["arp"][uid]["interface"] = uid
|
self.data["arp_tmp"][uid]["interface"] = uid
|
||||||
self.data["arp"][uid]["mac-address"] = (
|
self.data["arp_tmp"][uid]["mac-address"] = (
|
||||||
from_entry(entry, "mac-address") if "mac-address" not in self.data["arp"][uid] else "multiple"
|
from_entry(entry, "mac-address") if "mac-address" not in self.data["arp_tmp"][uid] else "multiple"
|
||||||
)
|
)
|
||||||
self.data["arp"][uid]["address"] = (
|
self.data["arp_tmp"][uid]["address"] = (
|
||||||
from_entry(entry, "address") if "address" not in self.data["arp"][uid] else "multiple"
|
from_entry(entry, "address") if "address" not in self.data["arp_tmp"][uid] else "multiple"
|
||||||
)
|
)
|
||||||
|
|
||||||
return mac2ip, bridge_used
|
return mac2ip, bridge_used
|
||||||
|
@ -409,20 +419,19 @@ class MikrotikControllerData:
|
||||||
"Processing entry %s, entry %s", "/interface/bridge/host", entry
|
"Processing entry %s, entry %s", "/interface/bridge/host", entry
|
||||||
)
|
)
|
||||||
# Create uid arp dict
|
# Create uid arp dict
|
||||||
if uid not in self.data["arp"]:
|
if uid not in self.data["arp_tmp"]:
|
||||||
self.data["arp"][uid] = {}
|
self.data["arp_tmp"][uid] = {}
|
||||||
|
|
||||||
# Add data
|
# Add data
|
||||||
self.data["arp"][uid]["interface"] = uid
|
self.data["arp_tmp"][uid]["interface"] = uid
|
||||||
if "mac-address" in self.data["arp"][uid]:
|
if "mac-address" in self.data["arp_tmp"][uid]:
|
||||||
self.data["arp"][uid]["mac-address"] = "multiple"
|
self.data["arp_tmp"][uid]["mac-address"] = "multiple"
|
||||||
self.data["arp"][uid]["address"] = "multiple"
|
self.data["arp_tmp"][uid]["address"] = "multiple"
|
||||||
else:
|
else:
|
||||||
self.data["arp"][uid]["mac-address"] = from_entry(entry,
|
self.data["arp_tmp"][uid]["mac-address"] = from_entry(entry, "mac-address")
|
||||||
"mac-address")
|
self.data["arp_tmp"][uid]["address"] = (
|
||||||
self.data["arp"][uid]["address"] = (
|
mac2ip[self.data["arp_tmp"][uid]["mac-address"]]
|
||||||
mac2ip[self.data["arp"][uid]["mac-address"]]
|
if self.data["arp_tmp"][uid]["mac-address"] in mac2ip
|
||||||
if self.data["arp"][uid]["mac-address"] in mac2ip
|
|
||||||
else ""
|
else ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -666,12 +675,64 @@ class MikrotikControllerData:
|
||||||
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
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 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",
|
||||||
|
vals=[
|
||||||
|
{"name": "mac-address"},
|
||||||
|
{"name": "address"},
|
||||||
|
{"name": "interface"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 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",
|
||||||
|
vals=[
|
||||||
|
{"name": "name"},
|
||||||
|
{"name": "address"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
# get_dhcp
|
# get_dhcp
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
def get_dhcp(self):
|
def get_dhcp(self):
|
||||||
"""Get DHCP data from Mikrotik"""
|
"""Get DHCP data from Mikrotik"""
|
||||||
|
|
||||||
|
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"])
|
||||||
|
|
||||||
self.data["dhcp-server"] = parse_api(
|
self.data["dhcp-server"] = parse_api(
|
||||||
data=self.data["dhcp-server"],
|
data=self.data["dhcp-server"],
|
||||||
source=self.api.path("/ip/dhcp-server"),
|
source=self.api.path("/ip/dhcp-server"),
|
||||||
|
@ -716,6 +777,77 @@ class MikrotikControllerData:
|
||||||
)
|
)
|
||||||
|
|
||||||
for uid in self.data["dhcp"]:
|
for uid in self.data["dhcp"]:
|
||||||
|
self.data["dhcp"][uid]["interface"] = \
|
||||||
|
self.data["dhcp-server"][self.data["dhcp"][uid]["server"]]["interface"]
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# process_host
|
||||||
|
# ---------------------------
|
||||||
|
def process_host(self):
|
||||||
|
"""Get host tracking data"""
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
for key, key_data in zip(
|
||||||
|
["address", "mac-address", "interface"],
|
||||||
|
["address", "mac-address", "interface"],
|
||||||
|
):
|
||||||
|
if key not in self.data["host"][uid] or self.data["host"][uid][key] == "unknown":
|
||||||
|
self.data["host"][uid][key] = vals[key_data]
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
for key, key_data in zip(
|
||||||
|
["address", "mac-address", "interface"],
|
||||||
|
["address", "mac-address", "interface"],
|
||||||
|
):
|
||||||
|
if key not in self.data["host"][uid] or self.data["host"][uid][key] == "unknown":
|
||||||
|
self.data["host"][uid][key] = vals[key_data]
|
||||||
|
|
||||||
|
# Process hosts
|
||||||
|
for uid, vals in self.data["host"].items():
|
||||||
|
# Add missing default values
|
||||||
|
for key, default in zip(
|
||||||
|
["address", "mac-address", "interface", "hostname", "last-seen", "available"],
|
||||||
|
["unknown", "unknown", "unknown", "unknown", False],
|
||||||
|
):
|
||||||
|
if key not in self.data["host"][uid]:
|
||||||
|
self.data["host"][uid][key] = default
|
||||||
|
|
||||||
|
# Resolve hostname
|
||||||
|
if vals["hostname"] == "unknown":
|
||||||
|
if vals["address"] != "unknown":
|
||||||
|
for dns_uid, dns_vals in self.data["dns"].items():
|
||||||
|
if dns_vals["address"] == vals["address"]:
|
||||||
|
self.data["host"][uid]["hostname"] = dns_vals["name"].split('.')[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.data["host"][uid]["hostname"] == "unknown" \
|
||||||
|
and uid in self.data["dhcp"] and self.data["dhcp"][uid]["comment"] != "":
|
||||||
|
self.data["host"][uid]["hostname"] = self.data["dhcp"][uid]["comment"]
|
||||||
|
|
||||||
|
elif self.data["host"][uid]["hostname"] == "unknown" \
|
||||||
|
and uid in self.data["dhcp"] and self.data["dhcp"][uid]["host-name"] != "unknown":
|
||||||
|
self.data["host"][uid]["hostname"] = self.data["dhcp"][uid]["host-name"]
|
||||||
|
|
||||||
|
elif self.data["host"][uid]["hostname"] == "unknown":
|
||||||
|
self.data["host"][uid]["hostname"] = uid
|
||||||
|
|
||||||
|
# Check host availability
|
||||||
|
if vals["address"] != "unknown" and vals["interface"] != "unknown":
|
||||||
|
self.data["host"][uid]["available"] = \
|
||||||
|
self.api.arp_ping(vals["address"], vals["interface"])
|
||||||
|
|
||||||
|
# Update last seen
|
||||||
|
if self.data["host"][uid]["available"]:
|
||||||
|
self.data["host"][uid]["last-seen"] = utcnow()
|
||||||
self.data["dhcp"][uid]['interface'] = \
|
self.data["dhcp"][uid]['interface'] = \
|
||||||
self.data["dhcp-server"][self.data["dhcp"][uid]['server']]["interface"]
|
self.data["dhcp-server"][self.data["dhcp"][uid]['server']]["interface"]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue