From e2314cd4369e33f625189b81c33228ae8319e7b5 Mon Sep 17 00:00:00 2001 From: Gurkengewuerz Date: Tue, 21 Jan 2025 21:11:32 +0100 Subject: [PATCH] feat: add dm117 --- custom_components/smart_home/binary_sensor.py | 33 +++++++++- custom_components/smart_home/light.py | 66 ++++++++++++++++++- custom_components/smart_home/switch.py | 64 +++++++++++++++++- 3 files changed, 159 insertions(+), 4 deletions(-) diff --git a/custom_components/smart_home/binary_sensor.py b/custom_components/smart_home/binary_sensor.py index 2a1fb3b..fab62c9 100644 --- a/custom_components/smart_home/binary_sensor.py +++ b/custom_components/smart_home/binary_sensor.py @@ -26,7 +26,12 @@ async def async_setup_entry( entities = [] for device_id, device in coordinator._devices.items(): if device["device_type"] == "binary_sensor": - entities.append(SmartHomeBinarySensor(coordinator, device_id)) + if device["module_type"] == "digital": + # Create two binary sensors for port A and B + entities.append(SmartHomeDigitalBinarySensor(coordinator, device_id, "port_a")) + entities.append(SmartHomeDigitalBinarySensor(coordinator, device_id, "port_b")) + else: + entities.append(SmartHomeBinarySensor(coordinator, device_id)) async_add_entities(entities) @@ -37,3 +42,29 @@ class SmartHomeBinarySensor(SmartHomeEntity, BinarySensorEntity): def is_on(self) -> bool | None: """Return true if the binary sensor is on.""" return self.device_state.get("state", False) + + +class SmartHomeDigitalBinarySensor(SmartHomeEntity, BinarySensorEntity): + """Representation of a Smart Home digital binary sensor.""" + + def __init__(self, coordinator, device_id, port_name): + super().__init__(coordinator, device_id) + self._port_name = port_name + self._attr_name = port_name.replace("_", " ").title() + _LOGGER.debug("Initialized digital sensor %s port %s", self.device_data["name"], self.name) + + @property + def unique_id(self) -> str: + """Return a unique ID to use for this entity.""" + return self.device_data["uuid"] + "_" + self._port_name + + @property + def is_on(self) -> bool | None: + """Return true if the binary sensor is on.""" + if not self.device_state or "multistate" not in self.device_state: + return None + + # Check relevant port state + if self._port_name == "port_a": + return self.device_state["multistate"]["port_a"] + return self.device_state["multistate"]["port_b"] diff --git a/custom_components/smart_home/light.py b/custom_components/smart_home/light.py index 6ea4e9d..b508904 100644 --- a/custom_components/smart_home/light.py +++ b/custom_components/smart_home/light.py @@ -56,6 +56,8 @@ async def async_setup_entry( for device_id, device in coordinator._devices.items(): if device["device_type"] == "rgb_led": entities.append(SmartHomeLight(coordinator, device_id, effect_map)) + elif device["device_type"] == "dimmer": + entities.append(SmartHomeDimmerLight(coordinator, device_id)) async_add_entities(entities) except HomeAssistantError as e: @@ -184,7 +186,8 @@ class SmartHomeLight(SmartHomeEntity, LightEntity): # get effect key from value data["animation"] = effect_key else: - _LOGGER.warning("Unknown effect name: %s (%s). Valid effects are: %s", effect_name, effect_key, list(self._effect_map.keys())) + _LOGGER.warning("Unknown effect name: %s (%s). Valid effects are: %s", effect_name, effect_key, + list(self._effect_map.keys())) _LOGGER.debug("Sending data to API: %s", data) async with aiohttp.ClientSession() as session: @@ -200,3 +203,64 @@ class SmartHomeLight(SmartHomeEntity, LightEntity): async with session.put(url, json={"state": False}) as response: if response.status != 200: _LOGGER.error("Failed to turn off light: %s", response.status) + + +class SmartHomeDimmerLight(SmartHomeEntity, LightEntity): + """Representation of a Smart Home dimmer light.""" + + def __init__( + self, + coordinator: SmartHomeDataUpdateCoordinator, + device_id: str, + ) -> None: + """Initialize the light.""" + super().__init__(coordinator, device_id) + + # Set color modes + self._attr_supported_color_modes = {ColorMode.BRIGHTNESS} + self._attr_color_mode = ColorMode.BRIGHTNESS + + @property + def is_on(self) -> bool | None: + """Return if the light is on.""" + if not self.device_state: + return None + + if "value" in self.device_state: + return self.device_state["value"] > 0 + + return False + + @property + def brightness(self) -> int | None: + """Return the brightness of the light.""" + if not self.device_state or "value" not in self.device_state: + return None + + # Convert 0-100 to 0-255 range + return int(self.device_state["value"] * 255 / 100) + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn on the light.""" + data = {} + + if ATTR_BRIGHTNESS in kwargs: + # Convert brightness to percentage + brightness = kwargs[ATTR_BRIGHTNESS] + data["value"] = round((brightness * 100) / 255) + else: + data["value"] = 100 + + async with aiohttp.ClientSession() as session: + url = f"{self.coordinator.api_url}/api/devices/{self._device_id}/state" + async with session.put(url, json=data) as response: + if response.status != 200: + _LOGGER.error("Failed to turn on light: %s", response.status) + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn off the light.""" + async with aiohttp.ClientSession() as session: + url = f"{self.coordinator.api_url}/api/devices/{self._device_id}/state" + async with session.put(url, json={"value": 0}) as response: + if response.status != 200: + _LOGGER.error("Failed to turn off light: %s", response.status) diff --git a/custom_components/smart_home/switch.py b/custom_components/smart_home/switch.py index f108c5a..5d7f8d0 100644 --- a/custom_components/smart_home/switch.py +++ b/custom_components/smart_home/switch.py @@ -26,8 +26,13 @@ async def async_setup_entry( entities = [] for device_id, device in coordinator._devices.items(): - if device["device_type"] == "switch" or device["device_type"] == "pushbutton": - entities.append(SmartHomeSwitch(coordinator, device_id)) + if device["device_type"] in ["switch", "pushbutton"]: + if device["module_type"] == "digital": + # Create two switches for port A and B + entities.append(SmartHomeDigitalSwitch(coordinator, device_id, "port_a")) + entities.append(SmartHomeDigitalSwitch(coordinator, device_id, "port_b")) + else: + entities.append(SmartHomeSwitch(coordinator, device_id)) async_add_entities(entities) @@ -54,3 +59,58 @@ class SmartHomeSwitch(SmartHomeEntity, SwitchEntity): def is_on(self) -> bool | None: """Return true if switch is on.""" return self.device_state.get("state", False) + + +class SmartHomeDigitalSwitch(SmartHomeEntity, SwitchEntity): + """Representation of a Smart Home digital switch.""" + + def __init__(self, coordinator, device_id, port_name): + super().__init__(coordinator, device_id) + self._port_name = port_name + self._attr_name = port_name.replace("_", " ").title() + _LOGGER.debug("Initialized switch digital switch %s port %s", self.device_data["name"], self.name) + + @property + def unique_id(self) -> str: + """Return a unique ID to use for this entity.""" + return self.device_data["uuid"] + "_" + self._port_name + + @property + def is_on(self) -> bool | None: + """Return if the switch is on.""" + if not self.device_state or "multistate" not in self.device_state: + return None + + if self._port_name == "port_a": + return self.device_state["multistate"]["port_a"] + return self.device_state["multistate"]["port_b"] + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the switch on.""" + state = {} + + if self._port_name == "port_a": + state["port_a"] = True + else: + state["port_b"] = True + + async with aiohttp.ClientSession() as session: + url = f"{self.coordinator.api_url}/api/devices/{self._device_id}/state" + async with session.put(url, json=state) as response: + if response.status != 200: + _LOGGER.error("Failed to turn on switch: %s", response.status) + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the switch off.""" + state = {} + + if self._port_name == "port_a": + state["port_a"] = False + else: + state["port_b"] = False + + async with aiohttp.ClientSession() as session: + url = f"{self.coordinator.api_url}/api/devices/{self._device_id}/state" + async with session.put(url, json=state) as response: + if response.status != 200: + _LOGGER.error("Failed to turn off switch: %s", response.status)