From e4926b9a6749132a43ee48448e627ec693b6d4f2 Mon Sep 17 00:00:00 2001 From: tomaae <23486452+tomaae@users.noreply.github.com> Date: Fri, 25 Dec 2020 17:50:21 +0100 Subject: [PATCH] Moved PPP from device tracker to binary sensors #76 --- .../mikrotik_router/binary_sensor.py | 176 +++++++++++++++++- .../mikrotik_router/device_tracker.py | 99 +--------- 2 files changed, 174 insertions(+), 101 deletions(-) diff --git a/custom_components/mikrotik_router/binary_sensor.py b/custom_components/mikrotik_router/binary_sensor.py index 849aa0b..2dc01a8 100644 --- a/custom_components/mikrotik_router/binary_sensor.py +++ b/custom_components/mikrotik_router/binary_sensor.py @@ -2,7 +2,10 @@ import logging -from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import ( + BinarySensorEntity, + DEVICE_CLASS_CONNECTIVITY, +) from homeassistant.const import ( CONF_NAME, ATTR_ATTRIBUTION, @@ -14,6 +17,8 @@ from .const import ( DOMAIN, DATA_CLIENT, ATTRIBUTION, + CONF_SENSOR_PPP, + DEFAULT_SENSOR_PPP, ) _LOGGER = logging.getLogger(__name__) @@ -32,6 +37,39 @@ SENSOR_TYPES = { }, } +DEVICE_ATTRIBUTES_PPP_SECRET = [ + "connected", + "service", + "profile", + "comment", + "caller-id", + "encoding", +] + + +# --------------------------- +# format_attribute +# --------------------------- +def format_attribute(attr): + res = attr.replace("-", " ") + res = res.capitalize() + res = res.replace(" ip ", " IP ") + res = res.replace(" mac ", " MAC ") + res = res.replace(" mtu", " MTU") + return res + + +# --------------------------- +# format_value +# --------------------------- +def format_value(res): + res = res.replace("dhcp", "DHCP") + res = res.replace("dns", "DNS") + res = res.replace("capsman", "CAPsMAN") + res = res.replace("wireless", "Wireless") + res = res.replace("restored", "Restored") + return res + # --------------------------- # async_setup_entry @@ -45,7 +83,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): @callback def update_controller(): """Update the values of the controller.""" - update_items(inst, mikrotik_controller, async_add_entities, sensors) + update_items( + inst, config_entry, mikrotik_controller, async_add_entities, sensors + ) mikrotik_controller.listeners.append( async_dispatcher_connect( @@ -59,10 +99,46 @@ async def async_setup_entry(hass, config_entry, async_add_entities): # update_items # --------------------------- @callback -def update_items(inst, mikrotik_controller, async_add_entities, sensors): +def update_items(inst, config_entry, mikrotik_controller, async_add_entities, sensors): """Update sensor state from the controller.""" new_sensors = [] + # Add switches + for sid, sid_uid, sid_name, sid_ref, sid_func in zip( + # Data point name + ["ppp_secret"], + # Data point unique id + ["name"], + # Entry Name + ["name"], + # Entry Unique id + ["name"], + # Tracker function + [ + MikrotikControllerPPPSecretBinarySensor, + ], + ): + for uid in mikrotik_controller.data[sid]: + # Update entity + item_id = f"{inst}-{sid}-{mikrotik_controller.data[sid][uid][sid_uid]}" + _LOGGER.debug("Updating binary_sensor %s", item_id) + if item_id in sensors: + if sensors[item_id].enabled: + sensors[item_id].async_schedule_update_ha_state() + continue + + # Create new entity + sid_data = { + "sid": sid, + "sid_uid": sid_uid, + "sid_name": sid_name, + "sid_ref": sid_ref, + } + sensors[item_id] = sid_func( + inst, uid, mikrotik_controller, config_entry, sid_data + ) + new_sensors.append(sensors[item_id]) + for sensor in SENSOR_TYPES: item_id = f"{inst}-{sensor}" _LOGGER.debug("Updating binary_sensor %s", item_id) @@ -88,9 +164,10 @@ class MikrotikControllerBinarySensor(BinarySensorEntity): self._inst = inst self._sensor = sensor self._ctrl = mikrotik_controller - self._data = mikrotik_controller.data[SENSOR_TYPES[sensor][ATTR_PATH]] - self._type = SENSOR_TYPES[sensor] - self._attr = SENSOR_TYPES[sensor][ATTR_ATTR] + if sensor in SENSOR_TYPES: + self._data = mikrotik_controller.data[SENSOR_TYPES[sensor][ATTR_PATH]] + self._type = SENSOR_TYPES[sensor] + self._attr = SENSOR_TYPES[sensor][ATTR_ATTR] self._device_class = None self._state = None @@ -154,3 +231,90 @@ class MikrotikControllerBinarySensor(BinarySensorEntity): val = self._data[self._attr] return val + + +# --------------------------- +# MikrotikControllerPPPSecretBinarySensor +# --------------------------- +class MikrotikControllerPPPSecretBinarySensor(MikrotikControllerBinarySensor): + """Representation of a network device.""" + + def __init__(self, inst, uid, mikrotik_controller, config_entry, sid_data): + """Set up tracked port.""" + super().__init__(mikrotik_controller, inst, uid) + self._sid_data = sid_data + self._data = mikrotik_controller.data[self._sid_data["sid"]][uid] + self._config_entry = config_entry + + @property + def option_sensor_ppp(self): + """Config entry option to not track ARP.""" + return self._config_entry.options.get(CONF_SENSOR_PPP, DEFAULT_SENSOR_PPP) + + @property + def name(self): + """Return the name of the port.""" + return f"{self._inst} PPP {self._data['name']}" + + @property + def is_on(self): + """Return true if the host is connected to the network.""" + if not self.option_sensor_ppp: + return False + + return self._data["connected"] + + @property + def device_class(self) -> str: + """Return the device class.""" + return DEVICE_CLASS_CONNECTIVITY + + @property + def available(self) -> bool: + """Return if controller is available.""" + if not self.option_sensor_ppp: + return False + + return self._ctrl.connected() + + @property + def unique_id(self): + """Return a unique identifier for this port.""" + return f"{self._inst.lower()}-{self._sid_data['sid']}_tracker-{self._data[self._sid_data['sid_ref']]}" + + @property + def icon(self): + """Return the icon.""" + if self._data["connected"]: + return "mdi:account-network-outline" + else: + return "mdi:account-off-outline" + + @property + def device_state_attributes(self): + """Return the port state attributes.""" + attributes = self._attrs + for variable in DEVICE_ATTRIBUTES_PPP_SECRET: + if variable in self._data: + attributes[format_attribute(variable)] = self._data[variable] + + return attributes + + @property + def device_info(self): + """Return a PPP Secret switch description for device registry.""" + info = { + "identifiers": { + ( + DOMAIN, + "serial-number", + self._ctrl.data["routerboard"]["serial-number"], + "switch", + "PPP", + ) + }, + "manufacturer": self._ctrl.data["resource"]["platform"], + "model": self._ctrl.data["resource"]["board-name"], + "name": f"{self._inst} PPP", + } + return info diff --git a/custom_components/mikrotik_router/device_tracker.py b/custom_components/mikrotik_router/device_tracker.py index 1c3522d..eacf655 100644 --- a/custom_components/mikrotik_router/device_tracker.py +++ b/custom_components/mikrotik_router/device_tracker.py @@ -24,8 +24,6 @@ from .const import ( DEFAULT_TRACK_HOST_TIMEOUT, CONF_SENSOR_PORT_TRACKER, DEFAULT_SENSOR_PORT_TRACKER, - CONF_SENSOR_PPP, - DEFAULT_SENSOR_PPP, ) _LOGGER = logging.getLogger(__name__) @@ -56,15 +54,6 @@ DEVICE_ATTRIBUTES_HOST = [ "last-seen", ] -DEVICE_ATTRIBUTES_PPP_SECRET = [ - "connected", - "service", - "profile", - "comment", - "caller-id", - "encoding", -] - # --------------------------- # format_attribute @@ -126,18 +115,17 @@ def update_items(inst, config_entry, mikrotik_controller, async_add_entities, tr # Add switches for sid, sid_uid, sid_name, sid_ref, sid_func in zip( # Data point name - ["interface", "host", "ppp_secret"], + ["interface", "host"], # Data point unique id - ["default-name", "mac-address", "name"], + ["default-name", "mac-address"], # Entry Name - ["name", "host-name", "name"], + ["name", "host-name"], # Entry Unique id - ["port-mac-address", "mac-address", "name"], + ["port-mac-address", "mac-address"], # Tracker function [ MikrotikControllerPortDeviceTracker, MikrotikControllerHostDeviceTracker, - MikrotikControllerPPPSecretDeviceTracker, ], ): if ( @@ -425,82 +413,3 @@ class MikrotikControllerHostDeviceTracker(MikrotikControllerDeviceTracker): info["name"] = f"{self._inst} {self._data[self._sid_data['sid_name']]}" return info - - -# --------------------------- -# MikrotikControllerPPPSecretDeviceTracker -# --------------------------- -class MikrotikControllerPPPSecretDeviceTracker(MikrotikControllerDeviceTracker): - """Representation of a network device.""" - - def __init__(self, inst, uid, mikrotik_controller, config_entry, sid_data): - """Set up tracked port.""" - super().__init__(inst, uid, mikrotik_controller, config_entry, sid_data) - - @property - def option_sensor_ppp(self): - """Config entry option to not track ARP.""" - return self._config_entry.options.get(CONF_SENSOR_PPP, DEFAULT_SENSOR_PPP) - - @property - def name(self): - """Return the name of the port.""" - return f"{self._inst} PPP {self._data['name']}" - - @property - def is_connected(self): - """Return true if the host is connected to the network.""" - if not self.option_sensor_ppp: - return False - - return self._data["connected"] - - @property - def available(self) -> bool: - """Return if controller is available.""" - if not self.option_sensor_ppp: - return False - - return self._ctrl.connected() - - @property - def unique_id(self): - """Return a unique identifier for this port.""" - return f"{self._inst.lower()}-{self._sid_data['sid']}_tracker-{self._data[self._sid_data['sid_ref']]}" - - @property - def icon(self): - """Return the icon.""" - if self._data["connected"]: - return "mdi:account-network-outline" - else: - return "mdi:account-off-outline" - - @property - def device_state_attributes(self): - """Return the port state attributes.""" - attributes = self._attrs - for variable in DEVICE_ATTRIBUTES_IFACE: - if variable in self._data: - attributes[format_attribute(variable)] = self._data[variable] - - return attributes - - @property - def device_info(self): - """Return a PPP Secret switch description for device registry.""" - info = { - "identifiers": { - ( - DOMAIN, - "serial-number", - self._ctrl.data["routerboard"]["serial-number"], - "switch", - "PPP", - ) - }, - "manufacturer": self._ctrl.data["resource"]["platform"], - "model": self._ctrl.data["resource"]["board-name"], - "name": f"{self._inst} PPP", - } - return info