diff --git a/.gitignore b/.gitignore index b6e4761..7f6b817 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,5 @@ dmypy.json # Pyre type checker .pyre/ + +.DS_Store diff --git a/README.md b/README.md index b58026f..dc71c1f 100644 --- a/README.md +++ b/README.md @@ -31,14 +31,18 @@ A. The integration creates sensors to track the number of connected devices thro A. This is a legacy device tracking option. But the integration allows importing names, dev_id, icon from the file `known_devices.yaml` and associating with new devices by mac-address. To do this, simply create or rename the file to `legacy_known_devices.yaml` -**Q. Does the integration support routers connected in `repeater mode`?** +**Q. Does the integration support routers connected in `repeater mode` or `access point mode`?** -A. Yes, the integration supports devices connected in `repeater mode`. But to get the number of devices and their tracking, you will also need to connect and configure the parent router. +A. Yes, the integration supports devices connected in `repeater mode` or `access point mode`. But to get the number of devices and their tracking, you will also need to connect and configure the parent router. **Q. Can I use the router in repeater mode without a parent MiWiFi device?** A. It is possible with the `force_load_repeater_devices` option enabled. But there is a limitation. You will not see IP, uptime, and connection type, but the name will be the mac-address. +**Q. Is a reboot required after changing the [PRO] settings?** + +A. Reboot is required + ## Install Installed through the custom repository [HACS](https://hacs.xyz/) - `dmamontov/hass-miwifi` @@ -56,7 +60,7 @@ For authorization, use the ip of your router and its password miwifi: ip_address: router_ip password: router_pass - force_load_repeater_devices: False # PRO + force_load_repeater_devices: False # [PRO] ``` ## Advanced config @@ -71,7 +75,7 @@ The component supports automatic deletion of monitored devices after a specified ```yaml miwifi: ... - last_activity_days: 30 # PRO + last_activity_days: 30 # [PRO] ``` ## Services diff --git a/custom_components/miwifi/binary_sensor.py b/custom_components/miwifi/binary_sensor.py index 3c600a7..35f6c0b 100644 --- a/custom_components/miwifi/binary_sensor.py +++ b/custom_components/miwifi/binary_sensor.py @@ -21,7 +21,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn sensors = [] for sensor, data in BINARY_SENSORS.items(): - sensors.append(MiWiFiBinarySensor(hass, luci, sensor, data)) + if sensor in luci.api.data["binary_sensor"]: + sensors.append(MiWiFiBinarySensor(hass, luci, sensor, data)) async_add_entities(sensors, True) diff --git a/custom_components/miwifi/core/const.py b/custom_components/miwifi/core/const.py index e858d7e..2795515 100644 --- a/custom_components/miwifi/core/const.py +++ b/custom_components/miwifi/core/const.py @@ -26,7 +26,6 @@ BINARY_SENSORS = { "state": {"name": "State", "icon": "mdi:router-wireless", "skip_available": True}, - "repeater_mode": {"name": "Repeater mode", "icon": "mdi:repeat"}, "wifi_state": {"name": "Wifi state", "icon": "mdi:wifi"}, "wan_state": {"name": "Wan state", "icon": "mdi:wan", "device_class": "connectivity"}, } @@ -36,7 +35,9 @@ "devices_lan": {"name": "Devices (lan)", "icon": "mdi:counter", "unit": "pcs"}, "devices_5ghz": {"name": "Devices (5 Ghz)", "icon": "mdi:counter", "unit": "pcs"}, "devices_2_4ghz": {"name": "Devices (2.4 Ghz)", "icon": "mdi:counter", "unit": "pcs"}, + "devices_guest": {"name": "Devices (guest)", "icon": "mdi:counter", "unit": "pcs"}, "uptime": {"name": "Uptime", "icon": "mdi:timer-sand", "unit": None}, + "mode": {"name": "Mode", "icon": "mdi:transit-connection-variant", "unit": None} } LIGHTS = { @@ -53,10 +54,18 @@ 0: "devices_lan", 1: "devices_2_4ghz", 2: "devices_5ghz", + 3: "devices_guest", } CONNECTION_RANGES = { 0: "Lan", 1: "2.4 Ghz", - 2: "5 Ghz" + 2: "5 Ghz", + 3: "Guest", +} + +MODE_MAP = { + 0: "default", + 1: "repeater", + 2: "access_point" } diff --git a/custom_components/miwifi/core/luci.py b/custom_components/miwifi/core/luci.py index 7781b15..7d1a74c 100644 --- a/custom_components/miwifi/core/luci.py +++ b/custom_components/miwifi/core/luci.py @@ -27,7 +27,8 @@ DEFAULT_MANUFACTURER, CONNECTION_RANGES, CONNECTION_TO_SENSOR, - DEVICES_LIST + DEVICES_LIST, + MODE_MAP ) _LOGGER = logging.getLogger(__name__) @@ -60,8 +61,11 @@ def __init__( self._data = { "switch": {"reboot": False}, "light": {"led": False}, - "binary_sensor": {"state": False, "repeater_mode": False, "wifi_state": False, "wan_state": False}, - "sensor": {"devices": 0, "devices_lan": 0, "devices_5ghz": 0, "devices_2_4ghz": 0, "uptime": "0:00:00"}, + "binary_sensor": {"state": False, "wifi_state": False, "wan_state": False}, + "sensor": { + "devices": 0, "devices_lan": 0, "devices_5ghz": 0, "devices_2_4ghz": 0, "devices_guest": 0, + "mode": "default", "uptime": "0:00:00" + }, } self._device_data = None @@ -161,20 +165,29 @@ async def set_entity_data(self) -> None: uptime = wan_info["info"]["uptime"] if isinstance(wan_info["info"], dict) and "uptime" in wan_info["info"] else 0 self._data["light"]["led"] = led["status"] == 1 if "status" in led else False - self._data["binary_sensor"]["repeater_mode"] = self.is_repeater_mode self._data["binary_sensor"]["wifi_state"] = wifi_state - self._data["binary_sensor"]["wan_state"] = uptime + + if self.is_repeater_mode: + if "wan_state" in self._data["binary_sensor"]: + del self._data["binary_sensor"]["wan_state"] + else: + self._data["binary_sensor"]["wan_state"] = uptime > 0 + + self._data["sensor"]["mode"] = MODE_MAP[mode["mode"]] if mode["mode"] in MODE_MAP else "undefined" async def set_devices_list(self) -> None: wifi_connect_devices = await self.wifi_connect_devices() self._signals = {} + force_devices = {} + if "list" in wifi_connect_devices: for index, device in enumerate(wifi_connect_devices["list"]): self._signals[device["mac"]] = device["signal"] + force_devices[device["mac"]] = device - if self.is_repeater_mode and self.is_force_load: - self.add_devices(self._signals) + if self.is_repeater_mode and self.is_force_load and len(force_devices) > 0: + await self.add_devices(force_devices, True) if self.is_repeater_mode or DOMAIN not in self.hass.data: return @@ -207,26 +220,54 @@ async def set_devices_list(self) -> None: continue if ip == self._ip: - self.add_devices(devices_to_ip[ip]) + await self.add_devices(devices_to_ip[ip]) elif not self.hass.data[DOMAIN][entities_map[ip]].api.is_force_load: - self.hass.data[DOMAIN][entities_map[ip]].api.add_devices(devices_to_ip[ip]) + await self.hass.data[DOMAIN][entities_map[ip]].api.add_devices(devices_to_ip[ip]) await asyncio.sleep(1) self.hass.data[DOMAIN][entities_map[ip]].update_devices() - def add_devices(self, devices: dict) -> None: + async def add_devices(self, devices: dict, is_force: bool = False) -> None: if not self._device_data: return - self._new_devices = [] - self._current_devices = [] - - self._data["sensor"] = { - "devices": 0, "devices_lan": 0, "devices_5ghz": 0, "devices_2_4ghz": 0, + sensor_default = { + "devices": 0, + "devices_lan": 0, + "devices_5ghz": 0, + "devices_2_4ghz": 0, + "devices_guest": 0, + "mode": self._data["sensor"]["mode"], "uptime": self._data["sensor"]["uptime"] } + if is_force: + try: + new_status = await self.new_status() + + if "2g" not in new_status: + del sensor_default["devices_2_4ghz"] + else: + sensor_default["devices_2_4ghz"] = new_status["2g"]["online_sta_count"] + + if "5g" not in new_status: + del sensor_default["devices_5ghz"] + else: + sensor_default["devices_5ghz"] = new_status["5g"]["online_sta_count"] + + del sensor_default["devices_lan"] + del sensor_default["devices_guest"] + except: + del sensor_default["devices_lan"] + del sensor_default["devices_5ghz"] + del sensor_default["devices_2_4ghz"] + del sensor_default["devices_guest"] + + self._data["sensor"] = sensor_default self._data["sensor"]["devices"] = len(devices) + new_devices = [] + current_devices = [] + for mac in devices: devices[mac]["router_mac"] = self._device_data["mac"] devices[mac]["signal"] = self._signals[mac] if mac in self._signals else 0 @@ -235,14 +276,17 @@ def add_devices(self, devices: dict) -> None: devices[mac]["name"] = mac if mac not in self._devices_list: - self._new_devices.append(mac) + new_devices.append(mac) - self._current_devices.append(mac) + current_devices.append(mac) self._devices_list[mac] = devices[mac] if "type" in devices[mac]: self._data["sensor"][CONNECTION_TO_SENSOR[devices[mac]["type"]]] += 1 + self._new_devices = new_devices + self._current_devices = current_devices + async def get_entities_map(self) -> dict: entries_map = {} @@ -279,6 +323,9 @@ async def init_info(self) -> dict: async def status(self) -> dict: return await self.get("misystem/status") + async def new_status(self) -> dict: + return await self.get("misystem/newstatus") + async def mode(self) -> dict: return await self.get("xqnetwork/mode") diff --git a/custom_components/miwifi/device_tracker.py b/custom_components/miwifi/device_tracker.py index c908c29..246319f 100644 --- a/custom_components/miwifi/device_tracker.py +++ b/custom_components/miwifi/device_tracker.py @@ -44,7 +44,6 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn zone_home = hass.states.get(ENTITY_ID_HOME) add_devices = [] - for mac in luci._devices: add_devices.append(MiWiFiDevice(hass, config_entry, luci, mac, luci._devices[mac], zone_home, False)) @@ -69,7 +68,7 @@ def update_devices() -> None: new_device["last_activity"] = datetime.now().replace(microsecond=0).isoformat() - _LOGGER.debug("New device {} ({}) from {}".format(new_device["name"], mac, luci.api._ip)) + _LOGGER.info("New device {} ({}) from {}".format(new_device["name"], mac, luci.api._ip)) new_devices.append(MiWiFiDevice(hass, config_entry, luci, mac, new_device, zone_home)) luci.add_device(mac, new_device) @@ -86,7 +85,7 @@ def update_devices() -> None: def _get_new_device(hass: HomeAssistant, device: dict, legacy_device: dict) -> dict: return { "ip": device["ip"][0]["ip"] if "ip" in device else "0:0:0:0", - "connection": device["connection"] if "connection" in device else "Not detected", + "connection": device["connection"] if "connection" in device else "undefined", "router_mac": device["router_mac"], "name": legacy_device["name"] if "name" in legacy_device else device["name"], "icon": legacy_device["icon"] if "icon" in legacy_device else None, @@ -260,9 +259,9 @@ async def async_update(self) -> None: old_router_mac = self._device["router_mac"] device = self.hass.data[DOMAIN][entry_id].api._devices_list[self._mac] - self._device["ip"] = device["ip"][0]["ip"] - self._device["online"] = device["ip"][0]["online"] - self._device["connection"] = device["connection"] + self._device["ip"] = device["ip"][0]["ip"] if "ip" in device else "0:0:0:0" + self._device["online"] = device["ip"][0]["online"] if "ip" in device else "0" + self._device["connection"] = device["connection"] if "connection" in device else "undefined" self._device["signal"] = device["signal"] self._device["router_mac"] = device["router_mac"] diff --git a/custom_components/miwifi/manifest.json b/custom_components/miwifi/manifest.json index 08b6492..6aaf6d6 100644 --- a/custom_components/miwifi/manifest.json +++ b/custom_components/miwifi/manifest.json @@ -1,7 +1,7 @@ { "domain": "miwifi", "name": "MiWiFi", - "version": "1.0.2", + "version": "1.0.4", "documentation": "https://github.com/dmamontov/hass-miwifi", "config_flow": true, "requirements": [], diff --git a/custom_components/miwifi/sensor.py b/custom_components/miwifi/sensor.py index ae31cba..66c0117 100644 --- a/custom_components/miwifi/sensor.py +++ b/custom_components/miwifi/sensor.py @@ -21,7 +21,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn sensors = [] for sensor, data in SENSORS.items(): - sensors.append(MiWiFiSensor(hass, luci, sensor, data)) + if sensor in luci.api.data["sensor"]: + sensors.append(MiWiFiSensor(hass, luci, sensor, data)) async_add_entities(sensors, True) @@ -94,11 +95,6 @@ async def will_remove_from_hass(self) -> None: async def async_update(self) -> None: try: - if "repeater_mode" in self._data and not self._data["repeater_mode"] and self.luci.api.data["binary_sensor"]["repeater_mode"]: - self._state = STATE_UNAVAILABLE - - return - self._state = self.luci.api.data["sensor"][self._code] except KeyError: self._state = None