From bcf86dc7a3c33c43e6977dcf2e4b136503f31679 Mon Sep 17 00:00:00 2001 From: Ivan Pavlina Date: Wed, 25 Mar 2020 13:18:49 +0100 Subject: [PATCH 1/3] Add support for simple queues. Transfer traffic_type and traffic_div calculation to separate method --- .../mikrotik_router/mikrotik_controller.py | 91 ++++++++++-- custom_components/mikrotik_router/switch.py | 129 +++++++++++++++++- 2 files changed, 205 insertions(+), 15 deletions(-) diff --git a/custom_components/mikrotik_router/mikrotik_controller.py b/custom_components/mikrotik_router/mikrotik_controller.py index 0949ced..9c835f9 100644 --- a/custom_components/mikrotik_router/mikrotik_controller.py +++ b/custom_components/mikrotik_router/mikrotik_controller.py @@ -55,6 +55,7 @@ class MikrotikControllerData: "nat": {}, "fw-update": {}, "script": {}, + "queue": {}, } self.listeners = [] @@ -69,6 +70,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 # --------------------------- @@ -168,6 +186,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() @@ -257,20 +276,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]["rx-bits-per-second-attr"] = traffic_type @@ -559,3 +565,60 @@ 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": "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 5992fcb..94d93d5 100644 --- a/custom_components/mikrotik_router/switch.py +++ b/custom_components/mikrotik_router/switch.py @@ -49,6 +49,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 @@ -95,11 +112,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]: @@ -421,3 +439,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"] From 63210ec62bede9a94579ad86a793a357bc4138e4 Mon Sep 17 00:00:00 2001 From: Ivan Pavlina Date: Wed, 25 Mar 2020 13:28:52 +0100 Subject: [PATCH 2/3] Fix - .id was missing from retrieved params --- custom_components/mikrotik_router/mikrotik_controller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/mikrotik_router/mikrotik_controller.py b/custom_components/mikrotik_router/mikrotik_controller.py index 9c835f9..0b9a04a 100644 --- a/custom_components/mikrotik_router/mikrotik_controller.py +++ b/custom_components/mikrotik_router/mikrotik_controller.py @@ -577,6 +577,7 @@ class MikrotikControllerData: 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"}, From 6d6f6e43d36cb65091df54fcd5cb4dbf8f89d7be Mon Sep 17 00:00:00 2001 From: Ivan Pavlina Date: Wed, 25 Mar 2020 16:45:17 +0100 Subject: [PATCH 3/3] Updated docs for simple queue switch --- README.md | 5 +++-- docs/assets/images/ui/queue_switch.png | Bin 0 -> 29464 bytes 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 docs/assets/images/ui/queue_switch.png 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/docs/assets/images/ui/queue_switch.png b/docs/assets/images/ui/queue_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..b680ccdad7ca8e9cba1b9fbd8864655539217580 GIT binary patch literal 29464 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

mn7E# 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 Qnk9v?fjPDu;}G(H02^C9p#T5? literal 0 HcmV?d00001