1 """The Mikrotik router class."""
3 from __future__
import annotations
5 from datetime
import timedelta
11 from librouteros.login
import plain
as login_plain, token
as login_token
28 DEFAULT_DETECTION_TIME,
43 from .device
import Device
44 from .errors
import CannotConnect, LoginError
46 _LOGGER = logging.getLogger(__name__)
50 """Handle all communication with the Mikrotik API."""
53 self, hass: HomeAssistant, config_entry: ConfigEntry, api: librouteros.Api
55 """Initialize the Mikrotik Client."""
59 self._host: str = self.
config_entryconfig_entry.data[CONF_HOST]
60 self.
all_devicesall_devices: dict[str, dict[str, Any]] = {}
61 self.devices: dict[str, Device] = {}
67 self.
modelmodel: str =
""
72 def load_mac(devices: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
73 """Load dictionary using MAC address as key."""
75 for device
in devices:
76 if "mac-address" in device:
77 mac = device[
"mac-address"]
78 mac_devices[mac] = device
83 """Return arp_ping option setting."""
84 return self.
config_entryconfig_entry.options.get(CONF_ARP_PING,
False)
88 """Return force_dhcp option setting."""
89 return self.
config_entryconfig_entry.options.get(CONF_FORCE_DHCP,
False)
92 """Return device model name."""
93 cmd = IDENTITY
if param == NAME
else INFO
94 if data := self.
commandcommand(MIKROTIK_SERVICES[cmd], suppress_errors=(cmd == INFO)):
95 return str(data[0].
get(param))
105 self.
commandcommand(MIKROTIK_SERVICES[IS_CAPSMAN], suppress_errors=
True)
108 self.
commandcommand(MIKROTIK_SERVICES[IS_WIRELESS], suppress_errors=
True)
111 self.
commandcommand(MIKROTIK_SERVICES[IS_WIFIWAVE2], suppress_errors=
True)
114 self.
commandcommand(MIKROTIK_SERVICES[IS_WIFI], suppress_errors=
True)
118 """Get devices from interface."""
119 if result := self.
commandcommand(MIKROTIK_SERVICES[interface]):
120 return self.
load_macload_mac(result)
124 """Restore a missing device after restart."""
128 """Get list of devices with latest status."""
131 wireless_devices = {}
135 _LOGGER.debug(
"Hub is a CAPSman manager")
138 _LOGGER.debug(
"Hub supports wireless Interface")
141 _LOGGER.debug(
"Hub supports wifiwave2 Interface")
144 _LOGGER.debug(
"Hub supports wifi Interface")
147 if not device_list
or self.
force_dhcpforce_dhcp:
149 _LOGGER.debug(
"Falling back to DHCP for scanning devices")
152 _LOGGER.debug(
"Using arp-ping to check devices")
158 except CannotConnect
as err:
159 raise UpdateFailed
from err
160 except LoginError
as err:
161 raise ConfigEntryAuthFailed
from err
166 for mac, params
in device_list.items():
167 if mac
not in self.devices:
172 if mac
in wireless_devices:
175 wireless_params=wireless_devices[mac], active=
True
179 if not params.get(
"active-address"):
180 self.devices[mac].
update(active=
False)
184 if self.
arp_enabledarp_enabled
and mac
in arp_devices:
186 str(params.get(
"active-address")),
187 str(arp_devices[mac].
get(
"interface")),
189 self.devices[mac].
update(active=active)
192 """Attempt to arp ping MAC address via interface."""
193 _LOGGER.debug(
"pinging - %s", ip_address)
198 "interface": interface,
199 "address": ip_address,
202 data = self.
commandcommand(cmd, params)
206 if "status" in result:
208 if status == len(data):
210 "Mikrotik %s - %s arp_ping timed out", ip_address, interface
218 params: dict[str, Any] |
None =
None,
219 suppress_errors: bool =
False,
220 ) -> list[dict[str, Any]]:
221 """Retrieve data from Mikrotik API."""
222 _LOGGER.debug(
"Running command %s", cmd)
225 return list(self.
apiapi(cmd=cmd, **params))
226 return list(self.
apiapi(cmd=cmd))
228 librouteros.exceptions.ConnectionClosed,
232 _LOGGER.error(
"Mikrotik %s connection error %s", self._host, api_error)
236 raise CannotConnect
from api_error
237 except librouteros.exceptions.ProtocolError
as api_error:
238 emsg =
"Mikrotik %s failed to retrieve data. cmd=[%s] Error: %s"
239 if suppress_errors
and "no such command prefix" in str(api_error):
240 _LOGGER.debug(emsg, self._host, cmd, api_error)
242 _LOGGER.warning(emsg, self._host, cmd, api_error)
247 """Mikrotik Hub Object."""
250 self, hass: HomeAssistant, config_entry: ConfigEntry, api: librouteros.Api
252 """Initialize the Mikrotik Client."""
254 self.
config_entryconfig_entry: ConfigEntry = config_entry
259 name=f
"{DOMAIN} - {self.host}",
265 """Return the host of this hub."""
270 """Return the hostname of the hub."""
271 return self.
_mk_data_mk_data.hostname
275 """Return the model of the hub."""
280 """Return the firmware of the hub."""
281 return self.
_mk_data_mk_data.firmware
285 """Return the serial number of the hub."""
286 return self.
_mk_data_mk_data.serial_number
290 """Config entry option defining number of seconds from last seen to away."""
293 CONF_DETECTION_TIME, DEFAULT_DETECTION_TIME
298 def api(self) -> MikrotikData:
299 """Represent Mikrotik data object."""
303 """Update Mikrotik devices information."""
304 await self.
hasshasshass.async_add_executor_job(self.
_mk_data_mk_data.update_devices)
307 def get_api(entry: dict[str, Any]) -> librouteros.Api:
308 """Connect to Mikrotik hub."""
309 _LOGGER.debug(
"Connecting to Mikrotik hub [%s]", entry[CONF_HOST])
311 _login_method = (login_plain, login_token)
312 kwargs = {
"login_methods": _login_method,
"port": entry[
"port"],
"encoding":
"utf8"}
314 if entry[CONF_VERIFY_SSL]:
315 ssl_context = ssl.create_default_context()
316 ssl_context.check_hostname =
False
317 ssl_context.verify_mode = ssl.CERT_NONE
318 _ssl_wrapper = ssl_context.wrap_socket
319 kwargs[
"ssl_wrapper"] = _ssl_wrapper
322 api = librouteros.connect(
324 entry[CONF_USERNAME],
325 entry[CONF_PASSWORD],
329 librouteros.exceptions.LibRouterosError,
333 _LOGGER.error(
"Mikrotik %s error: %s", entry[CONF_HOST], api_error)
334 if "invalid user name or password" in str(api_error):
335 raise LoginError
from api_error
336 raise CannotConnect
from api_error
338 _LOGGER.debug(
"Connected to %s successfully", entry[CONF_HOST])
timedelta option_detection_time(self)
None __init__(self, HomeAssistant hass, ConfigEntry config_entry, librouteros.Api api)
None _async_update_data(self)
dict[str, dict[str, Any]] get_list_from_interface(self, str interface)
None get_hub_details(self)
bool do_arp_ping(self, str ip_address, str interface)
None update_devices(self)
list[dict[str, Any]] command(self, str cmd, dict[str, Any]|None params=None, bool suppress_errors=False)
None __init__(self, HomeAssistant hass, ConfigEntry config_entry, librouteros.Api api)
str get_info(self, str param)
dict[str, dict[str, Any]] load_mac(list[dict[str, Any]] devices)
None restore_device(self, str mac)
web.Response get(self, web.Request request, str config_key)
IssData update(pyiss.ISS iss)
librouteros.Api get_api(dict[str, Any] entry)