diff --git a/README.md b/README.md index 56eba3d..318fd8f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Monitor and control your Mikrotik device from Home Assistant. ![Interface Sensor](https://raw.githubusercontent.com/tomaae/homeassistant-mikrotik_router/master/docs/assets/images/ui/interface_sensor.png) ![Script Switch](https://raw.githubusercontent.com/tomaae/homeassistant-mikrotik_router/master/docs/assets/images/ui/script_switch.png) ![NAT switch](https://raw.githubusercontent.com/tomaae/homeassistant-mikrotik_router/master/docs/assets/images/ui/nat.png) - +![Queue switch](https://raw.githubusercontent.com/tomaae/homeassistant-mikrotik_router/master/docs/assets/images/ui/queue_switch.png) Features: * Interface device tracker @@ -25,7 +25,8 @@ Features: * System sensors (CPU, Memory, HDD) * Firmware update binary sensor * Switches to run scripts - + * Enable/disable Simple Queue switches + # Setup integration Setup this integration for your Mikrotik device in Home Assistant via `Configuration -> Integrations -> Add -> Mikrotik Router`. You can add this integration several times for different devices. diff --git a/custom_components/mikrotik_router/mikrotik_controller.py b/custom_components/mikrotik_router/mikrotik_controller.py index 1757427..bbe632c 100644 --- a/custom_components/mikrotik_router/mikrotik_controller.py +++ b/custom_components/mikrotik_router/mikrotik_controller.py @@ -56,6 +56,7 @@ class MikrotikControllerData: "nat": {}, "fw-update": {}, "script": {}, + "queue": {}, } self.listeners = [] @@ -70,6 +71,23 @@ class MikrotikControllerData: self.hass, self.force_fwupdate_check, timedelta(hours=1) ) + def _get_traffic_type_and_div(self): + traffic_type = self.option_traffic_type + if traffic_type == "Kbps": + traffic_div = 0.001 + elif traffic_type == "Mbps": + traffic_div = 0.000001 + elif traffic_type == "B/s": + traffic_div = 0.125 + elif traffic_type == "KB/s": + traffic_div = 0.000125 + elif traffic_type == "MB/s": + traffic_div = 0.000000125 + else: + traffic_type = "bps" + traffic_div = 1 + return traffic_type, traffic_div + # --------------------------- # force_update # --------------------------- @@ -171,6 +189,7 @@ class MikrotikControllerData: await self.hass.async_add_executor_job(self.get_nat) await self.hass.async_add_executor_job(self.get_system_resource) await self.hass.async_add_executor_job(self.get_script) + await self.hass.async_add_executor_job(self.get_queue) async_dispatcher_send(self.hass, self.signal_update) self.lock.release() @@ -260,20 +279,7 @@ class MikrotikControllerData: ], ) - traffic_type = self.option_traffic_type - if traffic_type == "Kbps": - traffic_div = 0.001 - elif traffic_type == "Mbps": - traffic_div = 0.000001 - elif traffic_type == "B/s": - traffic_div = 0.125 - elif traffic_type == "KB/s": - traffic_div = 0.000125 - elif traffic_type == "MB/s": - traffic_div = 0.000000125 - else: - traffic_type = "bps" - traffic_div = 1 + traffic_type, traffic_div = self._get_traffic_type_and_div() for uid in self.data["interface"]: self.data["interface"][uid][ @@ -565,3 +571,61 @@ class MikrotikControllerData: {"name": "run-count", "default": "unknown"}, ], ) + + # --------------------------- + # get_queue + # --------------------------- + + def get_queue(self): + """Get Queue data from Mikrotik""" + self.data["queue"] = parse_api( + data=self.data["queue"], + source=self.api.path("/queue/simple"), + key="name", + vals=[ + {"name": ".id"}, + {"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, + }, + ] + ) + + traffic_type, traffic_div = self._get_traffic_type_and_div() + + for uid in self.data["queue"]: + upload_max_limit_bps, download_max_limit_bps = [int(x) for x in + self.data["queue"][uid]["max-limit"].split('/')] + self.data["queue"][uid]["upload-max-limit"] = f"{round(upload_max_limit_bps * traffic_div)} {traffic_type}" + self.data["queue"][uid]["download-max-limit"] = f"{round(download_max_limit_bps * traffic_div)} {traffic_type}" + + upload_limit_at_bps, download_limit_at_bps = [int(x) for x in + self.data["queue"][uid]["limit-at"].split('/')] + self.data["queue"][uid]["upload-limit-at"] = f"{round(upload_limit_at_bps * traffic_div)} {traffic_type}" + self.data["queue"][uid]["download-limit-at"] = f"{round(download_limit_at_bps * traffic_div)} {traffic_type}" + + upload_burst_limit_bps, download_burst_limit_bps = [int(x) for x in + self.data["queue"][uid]["burst-limit"].split('/')] + self.data["queue"][uid]["upload-burst-limit"] = f"{round(upload_burst_limit_bps * traffic_div)} {traffic_type}" + self.data["queue"][uid]["download-burst-limit"] = f"{round(download_burst_limit_bps * traffic_div)} {traffic_type}" + + upload_burst_threshold_bps, download_burst_threshold_bps = [int(x) for x in + self.data["queue"][uid]["burst-threshold"].split('/')] + self.data["queue"][uid]["upload-burst-threshold"] = f"{round(upload_burst_threshold_bps * traffic_div)} {traffic_type}" + self.data["queue"][uid]["download-burst-threshold"] = f"{round(download_burst_threshold_bps * traffic_div)} {traffic_type}" + + upload_burst_time, download_burst_time = self.data["queue"][uid]["burst-time"].split('/') + self.data["queue"][uid]["upload-burst-time"] = upload_burst_time + self.data["queue"][uid]["download-burst-time"] = download_burst_time diff --git a/custom_components/mikrotik_router/switch.py b/custom_components/mikrotik_router/switch.py index 1a7bf5e..81cb12f 100644 --- a/custom_components/mikrotik_router/switch.py +++ b/custom_components/mikrotik_router/switch.py @@ -42,6 +42,23 @@ DEVICE_ATTRIBUTES_SCRIPT = [ "run-count", ] +DEVICE_ATTRIBUTES_QUEUE = [ + "target", + "download-max-limit", + "upload-max-limit", + "upload-limit-at", + "download-limit-at", + "upload-burst-limit", + "download-burst-limit", + "upload-burst-threshold", + "download-burst-threshold", + "upload-burst-time", + "download-burst-time", + "packet-marks", + "parent", + "comment", +] + # --------------------------- # format_attribute @@ -88,11 +105,12 @@ def update_items(inst, mikrotik_controller, async_add_entities, switches): # Add switches for sid, sid_func in zip( - ["interface", "nat", "script"], + ["interface", "nat", "script", "queue"], [ MikrotikControllerPortSwitch, MikrotikControllerNATSwitch, MikrotikControllerScriptSwitch, + MikrotikControllerQueueSwitch, ], ): for uid in mikrotik_controller.data[sid]: @@ -416,3 +434,112 @@ class MikrotikControllerScriptSwitch(MikrotikControllerSwitch): def is_on(self): """Return true if device is on.""" return False + + +# --------------------------- +# MikrotikControllerNATSwitch +# --------------------------- +class MikrotikControllerQueueSwitch(MikrotikControllerSwitch): + """Representation of a queue switch.""" + + def __init__(self, inst, uid, mikrotik_controller): + """Set up queue switch.""" + super().__init__(inst, uid, mikrotik_controller) + + self._data = mikrotik_controller.data["queue"][self._uid] + self._attrs = { + ATTR_ATTRIBUTION: ATTRIBUTION, + } + + async def async_added_to_hass(self): + """Queue switch entity created.""" + _LOGGER.debug("New queue switch %s (%s)", self._inst, self._data["name"]) + + @property + def name(self) -> str: + """Return the name of the queue switch.""" + return f"{self._inst} Queue {self._data['name']}" + + @property + def unique_id(self) -> str: + """Return a unique identifier for this queue switch.""" + return f"{self._inst.lower()}-queue_switch-{self._data['name']}" + + @property + def icon(self): + """Return the icon.""" + if not self._data["enabled"]: + icon = "mdi:leaf-off" + else: + icon = "mdi:leaf" + + return icon + + @property + def device_info(self): + """Return a queue switch description for device registry.""" + info = { + "identifiers": { + ( + DOMAIN, + "serial-number", + self._ctrl.data["routerboard"]["serial-number"], + "switch", + "Queue", + ) + }, + "manufacturer": self._ctrl.data["resource"]["platform"], + "model": self._ctrl.data["resource"]["board-name"], + "name": "Queue", + } + return info + + @property + def device_state_attributes(self): + """Return the queue switch state attributes.""" + attributes = self._attrs + + for variable in DEVICE_ATTRIBUTES_QUEUE: + if variable in self._data: + attributes[format_attribute(variable)] = self._data[variable] + + return attributes + + async def async_turn_on(self): + """Turn on the queue switch.""" + path = "/queue/simple" + param = ".id" + value = None + for uid in self._ctrl.data["queue"]: + if ( + self._ctrl.data["queue"][uid]["name"] + == f"{self._data['name']}" + ): + value = self._ctrl.data["queue"][uid][".id"] + + mod_param = "disabled" + mod_value = False + self._ctrl.set_value(path, param, value, mod_param, mod_value) + await self._ctrl.force_update() + + async def async_turn_off(self): + """Turn on the queue switch.""" + path = "/queue/simple" + param = ".id" + value = None + for uid in self._ctrl.data["queue"]: + if ( + self._ctrl.data["queue"][uid]["name"] + == f"{self._data['name']}" + ): + value = self._ctrl.data["queue"][uid][".id"] + + mod_param = "disabled" + mod_value = True + self._ctrl.set_value(path, param, value, mod_param, mod_value) + await self._ctrl.async_update() + + @property + def is_on(self): + """Return true if the queue is on.""" + return self._data["enabled"] diff --git a/docs/assets/images/ui/queue_switch.png b/docs/assets/images/ui/queue_switch.png new file mode 100644 index 0000000..b680ccd Binary files /dev/null and b/docs/assets/images/ui/queue_switch.png differ