From cfab7c07562ddd87a68136b5d3ee5f430790deee Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:19:48 +0200 Subject: [PATCH 01/27] No force refresh Do ha state update with no force refresh, should only update if there has been a change. --- custom_components/dantherm/device.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 57a7dc6..e030269 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -279,8 +279,6 @@ async def async_refresh_entity(self, entity: DanthermEntity) -> None: return _LOGGER.debug("Refresh entity=%s", entity.name) - - await entity.async_update_ha_state(True) entity.async_write_ha_state() @property From 8688cd428b169a46f5c1f680d194dc09cc940cc3 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:21:43 +0200 Subject: [PATCH 02/27] Update select.py --- custom_components/dantherm/select.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/dantherm/select.py b/custom_components/dantherm/select.py index 07ca103..2d1dff1 100644 --- a/custom_components/dantherm/select.py +++ b/custom_components/dantherm/select.py @@ -59,7 +59,6 @@ async def async_select_option(self, option: str) -> None: await self._device.write_holding_registers( description=self.entity_description, value=int(option) ) - self._attr_force_update = True async def async_update(self) -> None: """Fetch new state data for the select.""" From 180d7a7ae146e4f487ed180da1def37d5374a938 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:21:47 +0200 Subject: [PATCH 03/27] Update sensor.py --- custom_components/dantherm/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/dantherm/sensor.py b/custom_components/dantherm/sensor.py index 33b8722..11c79f0 100644 --- a/custom_components/dantherm/sensor.py +++ b/custom_components/dantherm/sensor.py @@ -78,4 +78,4 @@ async def async_update(self) -> None: self._attr_available = False else: self._attr_available = True - self._device.data[self.key] = self._attr_state = result + self._device.data[self.key] = result From deec6cd7105167bb650a96652e02a73e76440bf4 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:21:52 +0200 Subject: [PATCH 04/27] Update switch.py --- custom_components/dantherm/switch.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/custom_components/dantherm/switch.py b/custom_components/dantherm/switch.py index 36006ae..78f0bde 100644 --- a/custom_components/dantherm/switch.py +++ b/custom_components/dantherm/switch.py @@ -109,5 +109,3 @@ async def async_update(self) -> None: self._attr_is_on = True else: self._attr_is_on = False - - self._device.data[self.key] = self._attr_is_on From 5c98f260906de4f55584235406c038b2e67c09b8 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:36:34 +0200 Subject: [PATCH 05/27] Don't use generic update service --- custom_components/dantherm/cover.py | 3 +-- custom_components/dantherm/device.py | 2 ++ custom_components/dantherm/number.py | 4 ++-- custom_components/dantherm/select.py | 4 ++-- custom_components/dantherm/sensor.py | 4 ++-- custom_components/dantherm/switch.py | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/custom_components/dantherm/cover.py b/custom_components/dantherm/cover.py index 78ac7c4..0aea1f4 100644 --- a/custom_components/dantherm/cover.py +++ b/custom_components/dantherm/cover.py @@ -1,6 +1,5 @@ """Cover implementation.""" -from datetime import datetime import logging from typing import Any @@ -114,7 +113,7 @@ def native_value(self): return self._device.data.get(self.key, None) - async def async_update(self, now: datetime | None = None) -> None: + async def async_refresh_callback(self) -> None: """Update the state of the cover.""" if self.entity_description.data_getinternal: diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index e030269..163a117 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -279,6 +279,8 @@ async def async_refresh_entity(self, entity: DanthermEntity) -> None: return _LOGGER.debug("Refresh entity=%s", entity.name) + if hasattr(entity, "async_refresh_callback"): + await getattr(entity, "async_refresh_callback")() entity.async_write_ha_state() @property diff --git a/custom_components/dantherm/number.py b/custom_components/dantherm/number.py index 80e8977..f25aecb 100644 --- a/custom_components/dantherm/number.py +++ b/custom_components/dantherm/number.py @@ -55,8 +55,8 @@ async def async_set_native_value(self, value: int) -> None: description=self.entity_description ) - async def async_update(self) -> None: - """Read holding register.""" + async def async_refresh_callback(self) -> None: + """Update the state of the number.""" if hasattr(self._device, f"get_{self.key}_attrs"): self._attr_extra_state_attributes = getattr( diff --git a/custom_components/dantherm/select.py b/custom_components/dantherm/select.py index 2d1dff1..51b0697 100644 --- a/custom_components/dantherm/select.py +++ b/custom_components/dantherm/select.py @@ -60,8 +60,8 @@ async def async_select_option(self, option: str) -> None: description=self.entity_description, value=int(option) ) - async def async_update(self) -> None: - """Fetch new state data for the select.""" + async def async_refresh_callback(self) -> None: + """Update state of the select.""" if self.entity_description.data_getinternal: result = getattr(self._device, self.entity_description.data_getinternal) diff --git a/custom_components/dantherm/sensor.py b/custom_components/dantherm/sensor.py index 11c79f0..a248e7a 100644 --- a/custom_components/dantherm/sensor.py +++ b/custom_components/dantherm/sensor.py @@ -57,8 +57,8 @@ def icon(self) -> str | None: return result - async def async_update(self) -> None: - """Read holding register.""" + async def async_refresh_callback(self) -> None: + """Update the state of the sensor.""" if hasattr(self._device, f"get_{self.key}_attrs"): self._attr_extra_state_attributes = getattr( diff --git a/custom_components/dantherm/switch.py b/custom_components/dantherm/switch.py index 78f0bde..4fa8afb 100644 --- a/custom_components/dantherm/switch.py +++ b/custom_components/dantherm/switch.py @@ -82,8 +82,8 @@ async def async_turn_on(self, **kwargs): description=self.entity_description, value=state ) - async def async_update(self) -> None: - """Read holding register.""" + async def async_refresh_callback(self) -> None: + """Update the state of the switch.""" if self.attr_suspend_refresh: if self.attr_suspend_refresh > datetime.now(): From 3b2deb532f8f17c61cb61ea6e61fcd9973bd7325 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Tue, 30 Jul 2024 12:41:14 +0200 Subject: [PATCH 06/27] Fix zero icon --- custom_components/dantherm/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/dantherm/sensor.py b/custom_components/dantherm/sensor.py index a248e7a..9a64199 100644 --- a/custom_components/dantherm/sensor.py +++ b/custom_components/dantherm/sensor.py @@ -52,7 +52,7 @@ def icon(self) -> str | None: result = super().icon if hasattr(self._device, f"get_{self.key}_icon"): result = getattr(self._device, f"get_{self.key}_icon") - elif self.entity_description.data_zero_icon and not self._attr_state: + elif self.entity_description.data_zero_icon and not self.native_value: result = self.entity_description.data_zero_icon return result From 48cefb4338ed818ca2ae617461bb810daba97f4b Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:51:27 +0200 Subject: [PATCH 07/27] Reverts to generic update --- custom_components/dantherm/cover.py | 2 +- custom_components/dantherm/device.py | 4 +--- custom_components/dantherm/number.py | 2 +- custom_components/dantherm/select.py | 2 +- custom_components/dantherm/sensor.py | 2 +- custom_components/dantherm/switch.py | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/custom_components/dantherm/cover.py b/custom_components/dantherm/cover.py index 0aea1f4..84606cd 100644 --- a/custom_components/dantherm/cover.py +++ b/custom_components/dantherm/cover.py @@ -113,7 +113,7 @@ def native_value(self): return self._device.data.get(self.key, None) - async def async_refresh_callback(self) -> None: + async def async_update(self) -> None: """Update the state of the cover.""" if self.entity_description.data_getinternal: diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 163a117..99bf345 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -279,9 +279,7 @@ async def async_refresh_entity(self, entity: DanthermEntity) -> None: return _LOGGER.debug("Refresh entity=%s", entity.name) - if hasattr(entity, "async_refresh_callback"): - await getattr(entity, "async_refresh_callback")() - entity.async_write_ha_state() + await entity.async_update_ha_state(True) @property def available(self) -> bool: diff --git a/custom_components/dantherm/number.py b/custom_components/dantherm/number.py index f25aecb..ce4e21e 100644 --- a/custom_components/dantherm/number.py +++ b/custom_components/dantherm/number.py @@ -55,7 +55,7 @@ async def async_set_native_value(self, value: int) -> None: description=self.entity_description ) - async def async_refresh_callback(self) -> None: + async def async_update(self) -> None: """Update the state of the number.""" if hasattr(self._device, f"get_{self.key}_attrs"): diff --git a/custom_components/dantherm/select.py b/custom_components/dantherm/select.py index 51b0697..0d3c076 100644 --- a/custom_components/dantherm/select.py +++ b/custom_components/dantherm/select.py @@ -60,7 +60,7 @@ async def async_select_option(self, option: str) -> None: description=self.entity_description, value=int(option) ) - async def async_refresh_callback(self) -> None: + async def async_update(self) -> None: """Update state of the select.""" if self.entity_description.data_getinternal: diff --git a/custom_components/dantherm/sensor.py b/custom_components/dantherm/sensor.py index 9a64199..ffb392b 100644 --- a/custom_components/dantherm/sensor.py +++ b/custom_components/dantherm/sensor.py @@ -57,7 +57,7 @@ def icon(self) -> str | None: return result - async def async_refresh_callback(self) -> None: + async def async_update(self) -> None: """Update the state of the sensor.""" if hasattr(self._device, f"get_{self.key}_attrs"): diff --git a/custom_components/dantherm/switch.py b/custom_components/dantherm/switch.py index 4fa8afb..08c1903 100644 --- a/custom_components/dantherm/switch.py +++ b/custom_components/dantherm/switch.py @@ -82,7 +82,7 @@ async def async_turn_on(self, **kwargs): description=self.entity_description, value=state ) - async def async_refresh_callback(self) -> None: + async def async_update(self) -> None: """Update the state of the switch.""" if self.attr_suspend_refresh: From 310ab1bd8869ffc3fe1cc2ebf5bcafed437e01f6 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:46:24 +0200 Subject: [PATCH 08/27] Fan 1 and 2 hidden by default --- custom_components/dantherm/const.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_components/dantherm/const.py b/custom_components/dantherm/const.py index d1a3fb6..1c86b44 100644 --- a/custom_components/dantherm/const.py +++ b/custom_components/dantherm/const.py @@ -346,6 +346,8 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): native_unit_of_measurement="rpm", data_precision=0, state_class=SensorStateClass.MEASUREMENT, + entity_registry_visible_default=True, + entity_registry_enabled_default=False, ), DanthermSensorEntityDescription( key="fan2_speed", @@ -356,6 +358,8 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): native_unit_of_measurement="rpm", data_precision=0, state_class=SensorStateClass.MEASUREMENT, + entity_registry_visible_default=True, + entity_registry_enabled_default=False, ), DanthermSensorEntityDescription( key="humidity", From 9182309db005f46cbff114f5ab3ad1bebc6a1c39 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sun, 4 Aug 2024 06:53:20 +0200 Subject: [PATCH 09/27] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7c1cb85..37a9adc 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ Known supported units: | operation_mode | Operation mode sensor | | alarm | Alarm sensor | | fan_level | Fan level sensor | -| fan1_speed | Fan 1 speed sensor | -| fan2_speed | Fan 2 speed sensor | +| fan1_speed | Fan 1 speed sensor | +| fan2_speed | Fan 2 speed sensor | | humidity | Humidity sensor\* | | air_quality | Air quality sensor\* | | exhaust_temperature | Exhaust temperature sensor | From b567975fb4ef09d04391d55733e0a34bf74d96b1 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sun, 4 Aug 2024 07:50:58 +0200 Subject: [PATCH 10/27] Replace deprecated async_forward_entry_setup call --- custom_components/dantherm/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/custom_components/dantherm/__init__.py b/custom_components/dantherm/__init__.py index fdb33cd..75d7ceb 100644 --- a/custom_components/dantherm/__init__.py +++ b/custom_components/dantherm/__init__.py @@ -66,9 +66,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): raise ConfigEntryNotReady(f"Timeout while connecting {host}") from ex hass.data[DOMAIN][entry.entry_id] = device - hass.async_create_task( - hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - ) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + return True From 3362fd61ca72d84b2bff68aebdb092e0e61774b5 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sun, 4 Aug 2024 07:56:21 +0200 Subject: [PATCH 11/27] Stop polling deactivated entities Stop polling bypass, filter_lifetime and filter_remain if their entity are deactivated. --- custom_components/dantherm/device.py | 55 +++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 99bf345..5c5a0b9 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -44,11 +44,11 @@ def __init__( async def async_added_to_hass(self): """Register entity for refresh interval.""" - self._device.async_add_refresh_entity(self) + await self._device.async_add_refresh_entity(self) async def async_will_remove_from_hass(self) -> None: """Unregister entity for refresh interval.""" - self._device.async_remove_refresh_entity(self) + await self._device.async_remove_refresh_entity(self) def suspend_refresh(self, seconds: int): """Suspend entity refresh for specified number of seconds.""" @@ -132,8 +132,12 @@ def __init__( self._active_unit_mode = None self._fan_level = None self._alarm = None + self._bypass_damper_enabled = False + self._manual_bypass_mode_enabled = False self._bypass_damper = None + self._filter_lifetime_enabled = False self._filter_lifetime = None + self._filter_remain_enabled = False self._filter_remain = None self._available = True self._read_errors = 0 @@ -214,18 +218,40 @@ async def async_install_entity(self, description: EntityDescription) -> bool: _LOGGER.debug("Excluding an entity=%s", description.key) return False - def async_add_refresh_entity(self, entity): + async def async_add_refresh_entity(self, entity): """Add entity for refresh.""" + # This is the first entity, set up interval. if not self._entities: self._entity_refresh_method = async_track_time_interval( self._hass, self.async_refresh_entities, self._scan_interval ) + if entity.key == "bypass_damper": + self._bypass_damper_enabled = True + elif entity.key == "manual_bypass_mode": + self._manual_bypass_mode_enabled = True + elif entity.key == "filter_lifetime": + self._filter_lifetime_enabled = True + elif entity.key == "filter_remain": + self._filter_remain_enabled = True + + _LOGGER.debug("Adding refresh entity=%s", entity.name) self._entities.append(entity) - def async_remove_refresh_entity(self, entity): + async def async_remove_refresh_entity(self, entity): """Remove entity for refresh.""" + + if entity.key == "bypass_damper": + self._bypass_damper_enabled = False + elif entity.key == "manual_bypass_mode": + self._manual_bypass_mode_enabled = False + elif entity.key == "filter_lifetime": + self._filter_lifetime_enabled = False + elif entity.key == "filter_remain": + self._filter_remain_enabled = False + + _LOGGER.debug("Removing refresh entity=%s", entity.name) self._entities.remove(entity) if not self._entities: @@ -255,14 +281,23 @@ async def async_refresh_entities(self, _now: int | None = None) -> None: self._alarm = await self._read_holding_uint32(516) _LOGGER.debug("Alarm = %s", self._alarm) - self._bypass_damper = await self._read_holding_int32(198) - _LOGGER.debug("Bypass damper = %s", self._bypass_damper) + if self._bypass_damper_enabled or self._manual_bypass_mode_enabled: + self._bypass_damper = await self._read_holding_int32(198) + _LOGGER.debug("Bypass damper = %s", self._bypass_damper) + else: + self._bypass_damper = None - self._filter_lifetime = await self._read_holding_uint32(556) - _LOGGER.debug("Filter lifetime = %s", self._filter_lifetime) + if self._filter_lifetime_enabled: + self._filter_lifetime = await self._read_holding_uint32(556) + _LOGGER.debug("Filter lifetime = %s", self._filter_lifetime) + else: + self._filter_lifetime = None - self._filter_remain = await self._read_holding_uint32(554) - _LOGGER.debug("Filter remain = %s", self._filter_remain) + if self._filter_remain_enabled: + self._filter_remain = await self._read_holding_uint32(554) + _LOGGER.debug("Filter remain = %s", self._filter_remain) + else: + self._filter_remain = None for entity in self._entities: await self.async_refresh_entity(entity) From 48f7f80b305c39f374ee511938d44a2cf2dc64f6 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sun, 4 Aug 2024 09:18:27 +0200 Subject: [PATCH 12/27] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 37a9adc..a88e58d 100644 --- a/README.md +++ b/README.md @@ -96,11 +96,12 @@ If you encounter any issues or have questions regarding the Dantherm integration ### Screenshots -![Skærmbillede 2024-05-04 090219](https://github.com/Tvalley71/dantherm/assets/83084467/fa9b31b6-5ec8-4c3b-a381-ef7061495560) +![Skærmbillede 2024-05-04 090219](https://github.com/user-attachments/assets/e8750622-f33c-4652-b3d5-33c2f3f13c54) -![Skærmbillede 2024-05-13 070737](https://github.com/Tvalley71/dantherm/assets/83084467/d6493c4e-ab10-493d-b2ec-c4f192383192) -![Skærmbillede 2024-05-13 070838](https://github.com/Tvalley71/dantherm/assets/83084467/8032983f-f55e-425e-8c55-c8d2ae918ea7) -![Skærmbillede 2024-05-04 090422](https://github.com/Tvalley71/dantherm/assets/83084467/4b2665b1-6abe-491b-8c3b-e5b3322402ee) +![Skærmbillede 2024-08-04 084300](https://github.com/user-attachments/assets/ef216a93-bdd6-4746-8515-83772554f0fe) +![Skærmbillede 2024-08-04 084328](https://github.com/user-attachments/assets/b888c8b9-53b9-45e6-8018-3e1147218ead) +![Skærmbillede 2024-08-04 084347](https://github.com/user-attachments/assets/0224a83e-b937-42e6-99d9-3e6fd0e1fe1e) +![Skærmbillede 2024-08-04 084404](https://github.com/user-attachments/assets/64e127e1-7933-46a7-8886-b5880d267788) > [!NOTE] > Preheater and HAC module functions are currently unsupported due to limited testing possibilities. If support for these functions are desired, please contact me for potential collaborative efforts to provide the support. @@ -289,7 +290,7 @@ Next, insert the following code into your dashboard. If your Home Assistant setu Example of a Mushroom-chips card displaying the current state of operation and fan level, in the order automatic, week program, manual, and standby mode. -![Skærmbillede 2024-05-21 104804](https://github.com/Tvalley71/dantherm/assets/83084467/075df325-03e1-4855-bb74-a4cf90780266) +![Skærmbillede 2024-05-21 104804](https://github.com/user-attachments/assets/2e35c5f9-46cf-4a77-a13c-56992ecccf3e)
From f62400b570542df43a2ea4309bb33f45dc5646e9 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sun, 4 Aug 2024 11:25:48 +0200 Subject: [PATCH 13/27] Update README.md --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a88e58d..cc5a2a8 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,9 @@ After installation, add the Dantherm integration to your Home Assistant configur 3. Search for "Dantherm" and select it from the list of available integrations. 4. Follow the on-screen instructions to complete the integration setup. -![Skærmbillede 2024-05-04 090018](https://github.com/Tvalley71/dantherm/assets/83084467/f085a769-c55c-45f1-952e-6ee8884eaad1) -![Skærmbillede 2024-05-04 090125](https://github.com/Tvalley71/dantherm/assets/83084467/1a66e37c-3c0e-498d-995f-c2bb5c778f35) +![Skærmbillede 2024-05-04 090018](https://github.com/user-attachments/assets/a5c2faad-2b96-438b-a761-4e24075efbf3) +![Skærmbillede 2024-05-04 090125](https://github.com/user-attachments/assets/7869346c-04e0-4980-9536-bf2cdd27cbc0) + ### Support @@ -98,13 +99,17 @@ If you encounter any issues or have questions regarding the Dantherm integration ![Skærmbillede 2024-05-04 090219](https://github.com/user-attachments/assets/e8750622-f33c-4652-b3d5-33c2f3f13c54) -![Skærmbillede 2024-08-04 084300](https://github.com/user-attachments/assets/ef216a93-bdd6-4746-8515-83772554f0fe) -![Skærmbillede 2024-08-04 084328](https://github.com/user-attachments/assets/b888c8b9-53b9-45e6-8018-3e1147218ead) -![Skærmbillede 2024-08-04 084347](https://github.com/user-attachments/assets/0224a83e-b937-42e6-99d9-3e6fd0e1fe1e) -![Skærmbillede 2024-08-04 084404](https://github.com/user-attachments/assets/64e127e1-7933-46a7-8886-b5880d267788) +![Skærmbillede 2024-08-04 084300](https://github.com/user-attachments/assets/1f1ce55b-4a9a-4b4c-b09d-4e18e34a08a2) +![Skærmbillede 2024-08-04 084328](https://github.com/user-attachments/assets/cb4c686b-ed84-42f2-896e-6c5f0b126f52) + +![Skærmbillede 2024-08-04 084347](https://github.com/user-attachments/assets/6ecca514-7595-4b64-8e1d-1e1fffa5aae4) +![Skærmbillede 2024-08-04 084404](https://github.com/user-attachments/assets/b84b9ac7-3586-40da-9a74-2808ced478e2) + +![Skærmbillede 2024-08-04 084430](https://github.com/user-attachments/assets/814bafd5-e03f-496f-98ce-7faafe2e4729) + > [!NOTE] -> Preheater and HAC module functions are currently unsupported due to limited testing possibilities. If support for these functions are desired, please contact me for potential collaborative efforts to provide the support. +> The HAC module functions are currently unsupported due to limited testing possibilities. If support for these functions are desired, please contact me for potential collaborative efforts to provide the support. ### Languages @@ -262,27 +267,29 @@ Next, insert the following code into your dashboard. If your Home Assistant setu top: 45% left: 36% font-weight: bold - text-align: center; + font-style: italic + text-align: center font-size: 100% - type: state-label entity: sensor.dantherm_humidity style: top: 29% left: 38% - font-size: 125% + font-size: 100% - type: state-label entity: select.dantherm_fan_selection style: top: 29% left: 63% font-weight: bold + font-style: italic font-size: 100% ``` #### Helper template sensor. -![Skærmbillede 2024-05-04 094747](https://github.com/Tvalley71/dantherm/assets/83084467/49b4e3b5-e419-458d-ada8-ffc3a92e0395) +![Skærmbillede 2024-05-04 094747](https://github.com/user-attachments/assets/5fc0c6dc-a1e5-4579-8453-7837037b3f9a)
From ee1c2baa997671d9e4d9c708f5b07ba58d278f8c Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Tue, 6 Aug 2024 09:13:30 +0200 Subject: [PATCH 14/27] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc5a2a8..55318f9 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Known supported units: - RCV320 P1/P2 > [!NOTE] -> The listed units are known to have been tested with the integration. Basicly all unit that use the _Dantherm Residential_ app ought to work with the integration. +> The listed units are known to have been used with the integration. Basicly all units that use the _Dantherm Residential_ app ought to work with the integration. > ([Google Play](https://play.google.com/store/apps/details?id=com.dantherm.ventilation) or [Apple Store](https://apps.apple.com/dk/app/dantherm-residential/id1368468353)). > If you know of any not included in the list, please feel free to contact me [here](https://github.com/Tvalley71/dantherm/discussions/new?category=general). From c4e969039654b134538328409a6b95c4272659af Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Thu, 8 Aug 2024 08:05:57 +0200 Subject: [PATCH 15/27] Renamed data_zero_icon Renamed data_zero_icon to icon_zero. --- custom_components/dantherm/const.py | 8 ++++---- custom_components/dantherm/sensor.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_components/dantherm/const.py b/custom_components/dantherm/const.py index 1c86b44..91f6a70 100644 --- a/custom_components/dantherm/const.py +++ b/custom_components/dantherm/const.py @@ -202,6 +202,7 @@ class DanthermSelectEntityDescription(SelectEntityDescription): class DanthermSensorEntityDescription(SensorEntityDescription): """Dantherm Sensor Entity Description.""" + icon_zero: str | None = None data_address: int | None = None data_getinternal: str | None = None data_precision: int | None = None @@ -210,7 +211,6 @@ class DanthermSensorEntityDescription(SensorEntityDescription): data_exclude_if_above: int | None = None data_exclude_if_below: int | None = None data_entity: str | None = None - data_zero_icon: str | None = None data_class: DataClass = DataClass.UInt16 component_class: ComponentClass = None @@ -330,8 +330,8 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): DanthermSensorEntityDescription( key="alarm", icon="mdi:alert-circle-outline", + icon_zero="mdi:alert-circle-check-outline", data_getinternal="get_alarm", - data_zero_icon="mdi:alert-circle-check-outline", ), DanthermSensorEntityDescription( key="fan_level", @@ -340,9 +340,9 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): DanthermSensorEntityDescription( key="fan1_speed", icon="mdi:fan", + icon_zero="mdi:fan-off", data_class=DataClass.Float32, data_address=100, - data_zero_icon="mdi:fan-off", native_unit_of_measurement="rpm", data_precision=0, state_class=SensorStateClass.MEASUREMENT, @@ -352,9 +352,9 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): DanthermSensorEntityDescription( key="fan2_speed", icon="mdi:fan", + icon_zero="mdi:fan-off", data_class=DataClass.Float32, data_address=102, - data_zero_icon="mdi:fan-off", native_unit_of_measurement="rpm", data_precision=0, state_class=SensorStateClass.MEASUREMENT, diff --git a/custom_components/dantherm/sensor.py b/custom_components/dantherm/sensor.py index ffb392b..6737bf9 100644 --- a/custom_components/dantherm/sensor.py +++ b/custom_components/dantherm/sensor.py @@ -52,8 +52,8 @@ def icon(self) -> str | None: result = super().icon if hasattr(self._device, f"get_{self.key}_icon"): result = getattr(self._device, f"get_{self.key}_icon") - elif self.entity_description.data_zero_icon and not self.native_value: - result = self.entity_description.data_zero_icon + elif self.entity_description.icon_zero and not self.native_value: + result = self.entity_description.icon_zero return result From 243f9c35c30598f881e80d8de879c9451e54b23e Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Thu, 8 Aug 2024 08:06:39 +0200 Subject: [PATCH 16/27] Added icon to operation_mode. --- custom_components/dantherm/device.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 5c5a0b9..9560de6 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -362,6 +362,15 @@ def get_operation_selection(self): _LOGGER.debug("Unknown mode of operation=%s", self._active_unit_mode) return STATE_MANUAL # manual + @property + def get_operation_mode_icon(self) -> str: + """Get operation mode icon.""" + + result = self.get_operation_selection + if not result or result == STATE_STANDBY: + return "mdi:hvac-off" + return "mdi:hvac" + @property def get_fan_level_selection_icon(self) -> str: """Get fan level selection icon.""" From 264769e2126f68c4d33e286c948145d295a9e878 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Thu, 8 Aug 2024 08:31:51 +0200 Subject: [PATCH 17/27] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 55318f9..4f05e95 100644 --- a/README.md +++ b/README.md @@ -295,7 +295,7 @@ Next, insert the following code into your dashboard. If your Home Assistant setu #### Mushroom-chips card -Example of a Mushroom-chips card displaying the current state of operation and fan level, in the order automatic, week program, manual, and standby mode. +An example of a Mushroom-chips card showing the current state of operation and fan level in a single display. This can also be achieved with many of the other entities. ![Skærmbillede 2024-05-21 104804](https://github.com/user-attachments/assets/2e35c5f9-46cf-4a77-a13c-56992ecccf3e) @@ -356,6 +356,8 @@ Alert chip displaying any current alert along with its descriptions. A hold acti +Starting from version 2024.8 of Home Assistant, the new badges can be used to achieve the same result. + ## Disclaimer The trademark "Dantherm" is owned by Dantherm Group A/S, a leading supplier of climate control solutions. From d0521936599e466dbd5e15d9ab423c4d64e7d009 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:13:44 +0200 Subject: [PATCH 18/27] Added night to operation_selection. --- custom_components/dantherm/translations/da.json | 3 ++- custom_components/dantherm/translations/en.json | 3 ++- custom_components/dantherm/translations/fr.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/custom_components/dantherm/translations/da.json b/custom_components/dantherm/translations/da.json index 7ba8459..fe98cfa 100644 --- a/custom_components/dantherm/translations/da.json +++ b/custom_components/dantherm/translations/da.json @@ -39,7 +39,8 @@ "week_program": "Ugeprogram", "away": "Rejse", "summer": "Sommer", - "fireplace": "Brændeovn" + "fireplace": "Brændeovn", + "night": "Nat" } }, "fan_level_selection": { diff --git a/custom_components/dantherm/translations/en.json b/custom_components/dantherm/translations/en.json index f47f43f..088280a 100644 --- a/custom_components/dantherm/translations/en.json +++ b/custom_components/dantherm/translations/en.json @@ -39,7 +39,8 @@ "week_program": "Week Program", "away": "Away", "summer": "Summer", - "fireplace": "Fireplace" + "fireplace": "Fireplace", + "night": "Night" } }, "fan_level_selection": { diff --git a/custom_components/dantherm/translations/fr.json b/custom_components/dantherm/translations/fr.json index d8657ee..17485f5 100644 --- a/custom_components/dantherm/translations/fr.json +++ b/custom_components/dantherm/translations/fr.json @@ -39,7 +39,8 @@ "week_program": "Programme hebdo", "away": "Absent", "summer": "Été", - "fireplace": "Cheminée" + "fireplace": "Cheminée", + "night": "Nuit" } }, "fan_level_selection": { From f50029976592ae193f891168d2cc03d65ca4e2f6 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sat, 10 Aug 2024 05:37:02 +0200 Subject: [PATCH 19/27] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f05e95..e9934a2 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ _† The entity is disabled by default._ ### Installation > [!IMPORTANT] -> Installation directly through HACS is not yet available because the integration is not yet included. This process will take some time. In the meantime, please use the manual installation method or click the below **Open HACS Repository** button. +> Installation directly through HACS is not yet available because the integration is not yet official included into HACS. This process will take some time. In the meantime, please use the manual installation method or click the below **Open HACS Repository** button. Open your Home Assistant instance and open a repository inside the Home Assistant Community Store. From e4045403af03e298bd2a8b2c868d16716a5f4eea Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sat, 10 Aug 2024 05:41:02 +0200 Subject: [PATCH 20/27] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e9934a2..8698737 100644 --- a/README.md +++ b/README.md @@ -356,7 +356,8 @@ Alert chip displaying any current alert along with its descriptions. A hold acti -Starting from version 2024.8 of Home Assistant, the new badges can be used to achieve the same result. +> [!NOTE] +> Starting from version 2024.8 of Home Assistant, the new badges can be used to achieve the same result. ## Disclaimer From 991ae0a6e8ef57a50aeb554b1019b22a2165d123 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sat, 10 Aug 2024 06:30:29 +0200 Subject: [PATCH 21/27] Improved switch platform --- custom_components/dantherm/const.py | 59 +++++++++----- custom_components/dantherm/device.py | 115 ++++++++++++++++++++------- custom_components/dantherm/switch.py | 4 +- 3 files changed, 132 insertions(+), 46 deletions(-) diff --git a/custom_components/dantherm/const.py b/custom_components/dantherm/const.py index 91f6a70..969d62d 100644 --- a/custom_components/dantherm/const.py +++ b/custom_components/dantherm/const.py @@ -82,8 +82,8 @@ class DataClass(Enum): Float32 = 8 -class OpMode(int): - """Dantherm mode of operation class.""" +class CurrentUnitMode(int): + """Dantherm current unit mode class.""" Standby = 0 Manual = 1 @@ -95,6 +95,29 @@ class OpMode(int): Night = 16 +class ActiveUnitMode(int): + """Dantherm active unit mode class.""" + + Automatic = 0x0002 + Manuel = 0x0004 + WeekProgram = 0x0008 + + Away = StartAway = 0x0010 + EndAway = 0x8010 + + Night = NightEnable = 0x0020 + NightDisable = 0x8020 + + Fireplace = StartFireplace = 0x0040 + EndFireplace = 0x8040 + + ManuelBypass = SelectManuelBypass = 0x0080 + DeselectManuelBypass = 0x8080 + + Summer = StartSummer = 0x0800 + EndSummer = 0x8800 + + STATE_STANDBY: Final = "standby" STATE_AUTOMATIC: Final = "automatic" STATE_MANUAL: Final = "manual" @@ -102,6 +125,7 @@ class OpMode(int): STATE_AWAY: Final = "away" STATE_SUMMER: Final = "summer" STATE_FIREPLACE: Final = "fireplace" +STATE_NIGHT: Final = "night" class BypassDamperState(int): @@ -302,6 +326,7 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): "away", "summer", "fireplace", + "night", ], ), DanthermSelectEntityDescription( @@ -470,12 +495,11 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): DanthermSwitchEntityDescription( key="away_mode", data_setinternal="set_active_unit_mode", - state_seton=0x10, - state_setoff=0x8010, - data_getinternal="get_current_unit_mode", - state_on=OpMode.Away, + data_getinternal="get_away_mode", state_suspend_for=30, + state_on=ActiveUnitMode.StartAway, icon_on="mdi:bag-suitcase-outline", + state_off=ActiveUnitMode.EndAway, icon_off="mdi:bag-suitcase-off-outline", device_class=SwitchDeviceClass.SWITCH, ), @@ -484,9 +508,9 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): data_setinternal="set_active_unit_mode", data_getinternal="get_active_unit_mode", state_suspend_for=30, - state_on=0x20, + state_on=ActiveUnitMode.NightEnable, icon_on="mdi:sleep", - state_off=0x8020, + state_off=ActiveUnitMode.NightDisable, icon_off="mdi:sleep-off", device_class=SwitchDeviceClass.SWITCH, entity_category=EntityCategory.CONFIG, @@ -494,12 +518,12 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): DanthermSwitchEntityDescription( key="fireplace_mode", data_setinternal="set_active_unit_mode", - state_seton=0x40, - state_setoff=0x8040, - data_getinternal="get_current_unit_mode", - state_on=OpMode.Fireplace, + data_getinternal="get_fireplace_mode", state_suspend_for=30, + state_seton=ActiveUnitMode.StartFireplace, icon_on="mdi:fireplace", + state_setoff=ActiveUnitMode.EndFireplace, + # state_on=OpMode.Fireplace, icon_off="mdi:fireplace-off", device_class=SwitchDeviceClass.SWITCH, ), @@ -508,9 +532,9 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): data_setinternal="set_active_unit_mode", data_getinternal="get_active_unit_mode", state_suspend_for=30, - state_on=0x80, + state_on=ActiveUnitMode.SelectManuelBypass, icon_on="mdi:hand-back-right-outline", - state_off=0x8080, + state_off=ActiveUnitMode.DeselectManuelBypass, icon_off="mdi:hand-back-right-off-outline", component_class=ComponentClass.Bypass, device_class=SwitchDeviceClass.SWITCH, @@ -518,12 +542,11 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): DanthermSwitchEntityDescription( key="summer_mode", data_setinternal="set_active_unit_mode", - state_seton=0x800, - state_setoff=0x8800, - data_getinternal="get_current_unit_mode", - state_on=OpMode.Summer, + data_getinternal="get_summer_mode", state_suspend_for=30, + state_seton=ActiveUnitMode.StartSummer, icon_on="mdi:weather-sunny", + state_setoff=ActiveUnitMode.EndSummer, icon_off="mdi:weather-sunny-off", device_class=SwitchDeviceClass.SWITCH, ), diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 9560de6..5666e45 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -20,12 +20,14 @@ STATE_AWAY, STATE_FIREPLACE, STATE_MANUAL, + STATE_NIGHT, STATE_STANDBY, STATE_SUMMER, STATE_WEEKPROGRAM, + ActiveUnitMode, BypassDamperState, + CurrentUnitMode, DataClass, - OpMode, ) _LOGGER = logging.getLogger(__name__) @@ -340,23 +342,34 @@ def get_active_unit_mode(self): def get_operation_selection(self): """Get operation selection.""" - if self._active_unit_mode is None: + if (self._active_unit_mode or self._current_unit_mode) is None: return None - if self._active_unit_mode == 0: - return STATE_STANDBY - if self._active_unit_mode & 0x10 == 0x10: # away mode + + if self._current_unit_mode == CurrentUnitMode.Away: return STATE_AWAY - if self._active_unit_mode & 0x800 == 0x800: # summer mode + if self._current_unit_mode == CurrentUnitMode.Summer: return STATE_SUMMER - if self._active_unit_mode & 0x40 == 0x40: # boost fireplace mode + if self._current_unit_mode == CurrentUnitMode.Fireplace: return STATE_FIREPLACE - if self._active_unit_mode & 2 == 2: # demand mode + if self._current_unit_mode == CurrentUnitMode.Night: + return STATE_NIGHT + + if (self._active_unit_mode or self._fan_level) == 0: + return STATE_STANDBY + + if ( + self._active_unit_mode & ActiveUnitMode.Automatic + == ActiveUnitMode.Automatic + ): return STATE_AUTOMATIC - if self._active_unit_mode & 4 == 4: # manual mode - if self._fan_level == 0: - return STATE_STANDBY # if fan level is 0 return standby - return STATE_MANUAL # manual - if self._active_unit_mode & 8 == 8: # week program + + if self._active_unit_mode & ActiveUnitMode.Manuel == ActiveUnitMode.Manuel: + return STATE_MANUAL + + if ( + self._active_unit_mode & ActiveUnitMode.WeekProgram + == ActiveUnitMode.WeekProgram + ): return STATE_WEEKPROGRAM _LOGGER.debug("Unknown mode of operation=%s", self._active_unit_mode) @@ -400,19 +413,19 @@ def get_fan_level_icon(self) -> str: return "mdi:fan-alert" result = self.get_current_unit_mode - if result == OpMode.Standby: + if result == CurrentUnitMode.Standby: return "mdi:fan-off" - if result == OpMode.Away: + if result == CurrentUnitMode.Away: return "mdi:bag-suitcase" - if result == OpMode.Summer: + if result == CurrentUnitMode.Summer: return "mdi:weather-sunny" - if result == OpMode.Fireplace: + if result == CurrentUnitMode.Fireplace: return "mdi:fire" - if result == OpMode.Night: + if result == CurrentUnitMode.Night: return "mdi:weather-night" - if result == OpMode.Automatic: + if result == CurrentUnitMode.Automatic: return "mdi:fan-auto" - if result == OpMode.WeekProgram: + if result == CurrentUnitMode.WeekProgram: return "mdi:fan-clock" result = self.get_operation_selection @@ -447,6 +460,49 @@ def get_bypass_damper_icon(self) -> str: return "mdi:valve-open" return "mdi:valve" + @property + def get_away_mode(self) -> bool | None: + """Get away mode.""" + + if (self._current_unit_mode or self._active_unit_mode) is None: + return None + + if ( + self._current_unit_mode == CurrentUnitMode.Away + or self._active_unit_mode & ActiveUnitMode.Away == ActiveUnitMode.Away + ): + return True + return False + + @property + def get_fireplace_mode(self) -> bool | None: + """Get fireplace mode.""" + + if (self._current_unit_mode or self._active_unit_mode) is None: + return None + + if ( + self._current_unit_mode == CurrentUnitMode.Fireplace + or self._active_unit_mode & ActiveUnitMode.Fireplace + == ActiveUnitMode.Fireplace + ): + return True + return False + + @property + def get_summer_mode(self) -> bool | None: + """Get summer mode.""" + + if (self._current_unit_mode or self._active_unit_mode) is None: + return None + + if ( + self._current_unit_mode == CurrentUnitMode.Summer + or self._active_unit_mode & ActiveUnitMode.Summer == ActiveUnitMode.Summer + ): + return True + return False + @property def get_filter_lifetime(self): """Get filter lifetime.""" @@ -483,21 +539,26 @@ async def set_operation_selection(self, value): """Set operation mode selection.""" if value == STATE_STANDBY: - await self.set_active_unit_mode(4) # manual mode + await self.set_active_unit_mode(ActiveUnitMode.Manuel) if self._fan_level != 0: await self.set_fan_level(0) + elif value == STATE_AUTOMATIC: - await self.set_active_unit_mode(2) # demand mode + await self.set_active_unit_mode(ActiveUnitMode.Automatic) elif value == STATE_MANUAL: - await self.set_active_unit_mode(4) # manual mode + await self.set_active_unit_mode(ActiveUnitMode.Manuel) elif value == STATE_WEEKPROGRAM: - await self.set_active_unit_mode(8) # week program mode + await self.set_active_unit_mode(ActiveUnitMode.WeekProgram) + elif value == STATE_AWAY: - await self.set_active_unit_mode(0x0010) # away mode + await self.set_active_unit_mode(ActiveUnitMode.StartAway) elif value == STATE_SUMMER: - await self.set_active_unit_mode(0x0800) # summer mode + await self.set_active_unit_mode(ActiveUnitMode.StartSummer) elif value == STATE_FIREPLACE: - await self.set_active_unit_mode(0x0040) # boost fireplace mode + await self.set_active_unit_mode(ActiveUnitMode.StartFireplace) + + elif value == STATE_NIGHT: + await self.set_active_unit_mode(ActiveUnitMode.NightEnable) async def set_fan_level(self, value): """Set fan level.""" diff --git a/custom_components/dantherm/switch.py b/custom_components/dantherm/switch.py index 08c1903..a8bf44d 100644 --- a/custom_components/dantherm/switch.py +++ b/custom_components/dantherm/switch.py @@ -103,7 +103,9 @@ async def async_update(self) -> None: self._attr_available = False else: self._attr_available = True - if ( + if type(result) is bool: + self._attr_is_on = result + elif ( result & self.entity_description.state_on ) == self.entity_description.state_on: self._attr_is_on = True From ab4125c98081582d09b881bfc2269f886f0ed18e Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sat, 10 Aug 2024 07:27:51 +0200 Subject: [PATCH 22/27] New icons on Operation Mode --- custom_components/dantherm/device.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 5666e45..41e9d55 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -379,10 +379,16 @@ def get_operation_selection(self): def get_operation_mode_icon(self) -> str: """Get operation mode icon.""" - result = self.get_operation_selection - if not result or result == STATE_STANDBY: - return "mdi:hvac-off" - return "mdi:hvac" + result = self.get_fan_level + if not result: + return "mdi:fan-off" + if result == 1: + return "mdi:fan-speed-1" + if result == 2: + return "mdi:fan-speed-2" + if result == 3: + return "mdi:fan-speed-3" + return "mdi:fan-plus" @property def get_fan_level_selection_icon(self) -> str: From 4e7b2dca840723101dc4f0cc14e8bdba0c553aaa Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sat, 10 Aug 2024 08:50:56 +0200 Subject: [PATCH 23/27] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8698737..8a2f457 100644 --- a/README.md +++ b/README.md @@ -357,7 +357,14 @@ Alert chip displaying any current alert along with its descriptions. A hold acti > [!NOTE] -> Starting from version 2024.8 of Home Assistant, the new badges can be used to achieve the same result. +> Starting from version 2024.8 of Home Assistant, the new badges can be used to achieve same results as the Mushroom chips card. + +#### Dashboard Badges + +Here are some examples of badges added to the dashboard. The pop-up that appears when clicking on a badge will vary depending on the selected entities, either displaying information or enabling manipulation of the Dantherm unit. + +![Skærmbillede badge example](https://github.com/user-attachments/assets/77ae39a9-edb2-4648-bb88-feac6a997087) + ## Disclaimer From 017e27aad37c0f5489a1c271dc66d7c3482c4b9f Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sat, 10 Aug 2024 11:26:32 +0200 Subject: [PATCH 24/27] Update const.py --- custom_components/dantherm/const.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/dantherm/const.py b/custom_components/dantherm/const.py index 969d62d..5509d69 100644 --- a/custom_components/dantherm/const.py +++ b/custom_components/dantherm/const.py @@ -523,7 +523,6 @@ class DanthermSwitchEntityDescription(SwitchEntityDescription): state_seton=ActiveUnitMode.StartFireplace, icon_on="mdi:fireplace", state_setoff=ActiveUnitMode.EndFireplace, - # state_on=OpMode.Fireplace, icon_off="mdi:fireplace-off", device_class=SwitchDeviceClass.SWITCH, ), From fbd8a680a5fa7bff3778e48a590cf4839ad7d5eb Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sat, 10 Aug 2024 11:29:30 +0200 Subject: [PATCH 25/27] Updated Operation Selection Removed Summer, Night and Fireplace mode change in Operation Selection. --- custom_components/dantherm/device.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 41e9d55..42e9cd2 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -373,7 +373,7 @@ def get_operation_selection(self): return STATE_WEEKPROGRAM _LOGGER.debug("Unknown mode of operation=%s", self._active_unit_mode) - return STATE_MANUAL # manual + return STATE_MANUAL @property def get_operation_mode_icon(self) -> str: @@ -548,23 +548,14 @@ async def set_operation_selection(self, value): await self.set_active_unit_mode(ActiveUnitMode.Manuel) if self._fan_level != 0: await self.set_fan_level(0) - elif value == STATE_AUTOMATIC: await self.set_active_unit_mode(ActiveUnitMode.Automatic) elif value == STATE_MANUAL: await self.set_active_unit_mode(ActiveUnitMode.Manuel) elif value == STATE_WEEKPROGRAM: await self.set_active_unit_mode(ActiveUnitMode.WeekProgram) - elif value == STATE_AWAY: await self.set_active_unit_mode(ActiveUnitMode.StartAway) - elif value == STATE_SUMMER: - await self.set_active_unit_mode(ActiveUnitMode.StartSummer) - elif value == STATE_FIREPLACE: - await self.set_active_unit_mode(ActiveUnitMode.StartFireplace) - - elif value == STATE_NIGHT: - await self.set_active_unit_mode(ActiveUnitMode.NightEnable) async def set_fan_level(self, value): """Set fan level.""" From 8a3eb0818602346f89cd1fe52cbda29af91edd83 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sun, 11 Aug 2024 07:43:40 +0200 Subject: [PATCH 26/27] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a2f457..fe1141f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Known supported units: - RCV320 P1/P2 > [!NOTE] -> The listed units are known to have been used with the integration. Basicly all units that use the _Dantherm Residential_ app ought to work with the integration. +> The listed units are known to have been used with the integration. Basicly all units that use the _Dantherm Residential_ app ought to work with the integration > ([Google Play](https://play.google.com/store/apps/details?id=com.dantherm.ventilation) or [Apple Store](https://apps.apple.com/dk/app/dantherm-residential/id1368468353)). > If you know of any not included in the list, please feel free to contact me [here](https://github.com/Tvalley71/dantherm/discussions/new?category=general). From 4408dbfb67f770acbc5f1f424cec021d7785c069 Mon Sep 17 00:00:00 2001 From: Tvalley71 <83084467+Tvalley71@users.noreply.github.com> Date: Sun, 11 Aug 2024 08:41:39 +0200 Subject: [PATCH 27/27] Update device.py --- custom_components/dantherm/device.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/dantherm/device.py b/custom_components/dantherm/device.py index 42e9cd2..412efd1 100644 --- a/custom_components/dantherm/device.py +++ b/custom_components/dantherm/device.py @@ -342,7 +342,7 @@ def get_active_unit_mode(self): def get_operation_selection(self): """Get operation selection.""" - if (self._active_unit_mode or self._current_unit_mode) is None: + if self._active_unit_mode is None or self._current_unit_mode is None: return None if self._current_unit_mode == CurrentUnitMode.Away: @@ -354,7 +354,7 @@ def get_operation_selection(self): if self._current_unit_mode == CurrentUnitMode.Night: return STATE_NIGHT - if (self._active_unit_mode or self._fan_level) == 0: + if self._active_unit_mode == 0 or self._fan_level == 0: return STATE_STANDBY if ( @@ -470,7 +470,7 @@ def get_bypass_damper_icon(self) -> str: def get_away_mode(self) -> bool | None: """Get away mode.""" - if (self._current_unit_mode or self._active_unit_mode) is None: + if self._current_unit_mode is None or self._active_unit_mode is None: return None if ( @@ -484,7 +484,7 @@ def get_away_mode(self) -> bool | None: def get_fireplace_mode(self) -> bool | None: """Get fireplace mode.""" - if (self._current_unit_mode or self._active_unit_mode) is None: + if self._current_unit_mode is None or self._active_unit_mode is None: return None if ( @@ -499,7 +499,7 @@ def get_fireplace_mode(self) -> bool | None: def get_summer_mode(self) -> bool | None: """Get summer mode.""" - if (self._current_unit_mode or self._active_unit_mode) is None: + if self._current_unit_mode is None or self._active_unit_mode is None: return None if (