From 9dafd6a43b3bb6381a9d9b2bdd35c860ba4bcabd Mon Sep 17 00:00:00 2001 From: Sanjoy Ghosh Date: Fri, 19 Apr 2024 19:29:18 +0530 Subject: [PATCH] Water Sensor Support --- .../dirigera_platform/binary_sensor.py | 111 +++++++++++++++++- .../dirigera_platform/common_sensors.py | 34 ++++++ .../dirigera_platform/hub_event_listener.py | 3 +- .../dirigera_platform/manifest.json | 2 +- .../dirigera_platform/requirements.txt | 2 +- 5 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 custom_components/dirigera_platform/common_sensors.py diff --git a/custom_components/dirigera_platform/binary_sensor.py b/custom_components/dirigera_platform/binary_sensor.py index 358809a..269c790 100644 --- a/custom_components/dirigera_platform/binary_sensor.py +++ b/custom_components/dirigera_platform/binary_sensor.py @@ -13,6 +13,7 @@ from .mocks.ikea_motion_sensor_mock import ikea_motion_sensor_mock from .mocks.ikea_open_close_mock import ikea_open_close_mock from .hub_event_listener import hub_event_listener +from .common_sensors import battery_percentage_sensor logger = logging.getLogger("custom_components.dirigera_platform") @@ -56,15 +57,24 @@ async def async_setup_entry( for open_close_sensor in hub_open_close_sensors ] - logger.debug( - "Found {} motion_sensor entities to setup...".format(len(motion_sensors)) - ) + hub_water_sensors = await hass.async_add_executor_job(hub.get_water_sensors) + water_sensor_devices = [ ikea_water_sensor_device(hass, hub, hub_water_sensor) + for hub_water_sensor in hub_water_sensors + ] + water_sensors = [] + for water_sensor_device in water_sensor_devices: + water_sensors.append(battery_percentage_sensor(water_sensor_device)) + water_sensors.append(ikea_water_sensor(water_sensor_device)) + + logger.debug("Found {} motion_sensor entities to setup...".format(len(motion_sensors))) async_add_entities(motion_sensors) - logger.debug( - "Found {} open close entities to setup...".format(len(open_close_sensors)) - ) + + logger.debug("Found {} open close entities to setup...".format(len(open_close_sensors))) async_add_entities(open_close_sensors) + logger.debug(f"Found {len(hub_water_sensors)} water sensors to setup....") + async_add_entities(water_sensors) + logger.debug("Binary Sensor Complete async_setup_entry") class ikea_motion_sensor(BinarySensorEntity): @@ -156,3 +166,92 @@ async def async_update(self): logger.error("error encountered running update on : {}".format(self.name)) logger.error(ex) raise HomeAssistantError(ex, DOMAIN, "hub_exception") + +class ikea_water_sensor_device: + def __init__(self, hass, hub, json_data) -> None: + self._hass = hass + self._json_data = json_data + self._updated_at = None + self._hub = hub + self._listeners = [] + + # Register the device for updates + hub_event_listener.register(self._json_data.id, self) + + async def async_update(self): + try: + logger.debug("water sensor update called...") + self._json_data = await self._hass.async_add_executor_job(self._hub.get_water_sensor_by_id, self._json_data.id) + except Exception as ex: + logger.error( + "error encountered running update on : {}".format(self.name) + ) + logger.error(ex) + raise HomeAssistantError(ex, DOMAIN, "hub_exception") + + #Hack for faster update + def async_schedule_update_ha_state(self, force_refresh:bool = False) ->None : + for listener in self._listeners: + listener.async_schedule_update_ha_state(force_refresh) + + @property + def water_leak_detected(self) -> bool: + return self._json_data.attributes.water_leak_detected + + @property + def battery_percentage(self) -> int: + return self._json_data.attributes.battery_percentage + + @property + def available(self): + return self._json_data.is_reachable + + @property + def device_info(self) -> DeviceInfo: + + return DeviceInfo( + identifiers={("dirigera_platform", self._json_data.id)}, + name=self.name, + manufacturer=self._json_data.attributes.manufacturer, + model=self._json_data.attributes.model, + sw_version=self._json_data.attributes.firmware_version, + ) + + @property + def name(self) -> str: + if self._json_data.attributes.custom_name is None or len(self._json_data.attributes.custom_name) == 0: + return self.unique_id + return self._json_data.attributes.custom_name + + @property + def unique_id(self): + return f"{self._json_data.id}_WL01" + +class ikea_water_sensor(BinarySensorEntity): + def __init__(self, device : ikea_water_sensor_device): + logger.debug("ikea_water_sensor ctor...") + self._device = device + + @property + def unique_id(self): + return self._device.unique_id + + @property + def available(self): + return self._device.available + + @property + def device_info(self) -> DeviceInfo: + return self._device.device_info + + @property + def name(self): + return f"{self._device.name} Water Leak Detected" + + @property + def is_on(self): + # Note: the `is_detected` attribute is not present for Trådfri Motion Sensor E1745, only in the webhook events + return self._device.water_leak_detected + + async def async_update(self): + await self._device.async_update() \ No newline at end of file diff --git a/custom_components/dirigera_platform/common_sensors.py b/custom_components/dirigera_platform/common_sensors.py new file mode 100644 index 0000000..fde8eff --- /dev/null +++ b/custom_components/dirigera_platform/common_sensors.py @@ -0,0 +1,34 @@ +from homeassistant.components.sensor import SensorDeviceClass, SensorEntity +from homeassistant.helpers.entity import DeviceInfo + +class battery_percentage_sensor(SensorEntity): + def __init__(self, device): + self._device = device + + @property + def available(self): + return self._device.available + + @property + def device_info(self) -> DeviceInfo: + return self._device.device_info + + @property + def unique_id(self): + return f"{self._device.unique_id}_BP01" + + @property + def device_class(self) -> str: + return SensorDeviceClass.BATTERY + + @property + def native_unit_of_measurement(self) -> str: + return "%" + + @property + def name(self) -> str: + return f"{self._device.name} Battery" + + @property + def native_value(self): + return getattr(self._device, "battery_percentage", 0) \ No newline at end of file diff --git a/custom_components/dirigera_platform/hub_event_listener.py b/custom_components/dirigera_platform/hub_event_listener.py index 340effa..ddd3ed8 100644 --- a/custom_components/dirigera_platform/hub_event_listener.py +++ b/custom_components/dirigera_platform/hub_event_listener.py @@ -15,7 +15,8 @@ "motionSensor" : ["isDetected","isOn"], "outlet" : ["isOn"], "light" : ["isOn"], - "openCloseSensor" : ["isOpen"] + "openCloseSensor" : ["isOpen"], + "waterSensor" : ["waterLeakDetected"] } def to_snake_case(name:str) -> str: diff --git a/custom_components/dirigera_platform/manifest.json b/custom_components/dirigera_platform/manifest.json index 60502d8..675aaae 100755 --- a/custom_components/dirigera_platform/manifest.json +++ b/custom_components/dirigera_platform/manifest.json @@ -8,6 +8,6 @@ "iot_class": "local_polling", "issue_tracker": "https://github.com/sanjoyg/dirigera_platform", "loggers": ["custom_components.dirigera_platform"], - "requirements": ["dirigera==1.1.1"], + "requirements": ["dirigera==1.1.4"], "version": "0.0.1" } diff --git a/custom_components/dirigera_platform/requirements.txt b/custom_components/dirigera_platform/requirements.txt index b9add35..3835fd2 100644 --- a/custom_components/dirigera_platform/requirements.txt +++ b/custom_components/dirigera_platform/requirements.txt @@ -1 +1 @@ -dirigera==1.1.1 +dirigera==1.1.4