diff --git a/README.md b/README.md index bd636e0..5f8cef6 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Translation of internal names like programs are available for all languages whic ## Supported Models Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8). - Haier AD105S2SM3FA +- Haier AS20HPL1HRA - Haier AS25PBAHRA - Haier AS25S2SF1FA-WH - Haier AS25TADHRA-2 diff --git a/custom_components/hon/binary_sensor.py b/custom_components/hon/binary_sensor.py index 9cd96c3..c30e02d 100644 --- a/custom_components/hon/binary_sensor.py +++ b/custom_components/hon/binary_sensor.py @@ -271,9 +271,10 @@ def is_on(self) -> bool: ) @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self, update=True) -> None: self._attr_native_value = ( self._device.get(self.entity_description.key, "") == self.entity_description.on_value ) - self.async_write_ha_state() + if update: + self.async_write_ha_state() diff --git a/custom_components/hon/const.py b/custom_components/hon/const.py index 6c14aa9..1a2d022 100644 --- a/custom_components/hon/const.py +++ b/custom_components/hon/const.py @@ -7,6 +7,7 @@ ) DOMAIN = "hon" +UPDATE_INTERVAL = 10 PLATFORMS = [ "sensor", diff --git a/custom_components/hon/hon.py b/custom_components/hon/hon.py index b3e37d6..feffd8d 100644 --- a/custom_components/hon/hon.py +++ b/custom_components/hon/hon.py @@ -1,12 +1,13 @@ import logging from datetime import timedelta +from homeassistant.core import callback from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from pyhon.appliance import HonAppliance -from .const import DOMAIN +from .const import DOMAIN, UPDATE_INTERVAL _LOGGER = logging.getLogger(__name__) @@ -21,13 +22,14 @@ def __init__(self, hass, entry, device: HonAppliance, description=None) -> None: self._hon = hass.data[DOMAIN][entry.unique_id] self._hass = hass self._coordinator = coordinator - self._device = device + self._device: HonAppliance = device if description is not None: self.entity_description = description self._attr_unique_id = f"{self._device.unique_id}{description.key}" else: self._attr_unique_id = self._device.unique_id + self._handle_coordinator_update(update=False) @property def device_info(self): @@ -41,6 +43,11 @@ def device_info(self): sw_version=self._device.get("fwVersion", ""), ) + @callback + def _handle_coordinator_update(self, update: bool = True) -> None: + if update: + self.async_write_ha_state() + class HonCoordinator(DataUpdateCoordinator): def __init__(self, hass, device: HonAppliance): @@ -49,7 +56,7 @@ def __init__(self, hass, device: HonAppliance): hass, _LOGGER, name=device.unique_id, - update_interval=timedelta(seconds=30), + update_interval=timedelta(seconds=UPDATE_INTERVAL), ) self._device = device diff --git a/custom_components/hon/manifest.json b/custom_components/hon/manifest.json index 55f2d4b..1577cdd 100644 --- a/custom_components/hon/manifest.json +++ b/custom_components/hon/manifest.json @@ -9,7 +9,7 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/Andre0512/hon/issues", "requirements": [ - "pyhOn==0.12.1" + "pyhOn==0.12.2" ], - "version": "0.8.0-beta.9" + "version": "0.8.0-beta.10" } diff --git a/custom_components/hon/number.py b/custom_components/hon/number.py index ad1c6bc..cd9f182 100644 --- a/custom_components/hon/number.py +++ b/custom_components/hon/number.py @@ -9,7 +9,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import UnitOfTime, UnitOfTemperature from homeassistant.core import callback -from homeassistant.helpers.entity import EntityCategory, Entity +from homeassistant.helpers.entity import EntityCategory from pyhon.parameter.range import HonParameterRange from .const import DOMAIN @@ -223,14 +223,15 @@ async def async_set_native_value(self, value: float) -> None: await self.coordinator.async_refresh() @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self, update=True) -> None: setting = self._device.settings[self.entity_description.key] if isinstance(setting, HonParameterRange): self._attr_native_max_value = setting.max self._attr_native_min_value = setting.min self._attr_native_step = setting.step self._attr_native_value = setting.value - self.async_write_ha_state() + if update: + self.async_write_ha_state() @property def available(self) -> bool: diff --git a/custom_components/hon/select.py b/custom_components/hon/select.py index 327c928..947db9a 100644 --- a/custom_components/hon/select.py +++ b/custom_components/hon/select.py @@ -7,7 +7,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import UnitOfTemperature, UnitOfTime, REVOLUTIONS_PER_MINUTE from homeassistant.core import callback -from homeassistant.helpers.entity import EntityCategory, Entity +from homeassistant.helpers.entity import EntityCategory from pyhon.appliance import HonAppliance from pyhon.parameter.fixed import HonParameterFixed @@ -179,7 +179,7 @@ async def async_select_option(self, option: str) -> None: await self.coordinator.async_refresh() @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self, update=True) -> None: setting = self._device.settings.get(self.entity_description.key) if setting is None: self._attr_available = False @@ -189,7 +189,8 @@ def _handle_coordinator_update(self): self._attr_available = True self._attr_options: list[str] = setting.values self._attr_native_value = setting.value - self.async_write_ha_state() + if update: + self.async_write_ha_state() @property def available(self) -> bool: diff --git a/custom_components/hon/sensor.py b/custom_components/hon/sensor.py index 31affd8..58eddd5 100644 --- a/custom_components/hon/sensor.py +++ b/custom_components/hon/sensor.py @@ -1,8 +1,6 @@ import logging from dataclasses import dataclass -from pyhon.appliance import HonAppliance - from homeassistant.components.sensor import ( SensorEntity, SensorDeviceClass, @@ -22,7 +20,8 @@ ) from homeassistant.core import callback from homeassistant.helpers.entity import EntityCategory -from homeassistant.helpers.typing import StateType +from pyhon.appliance import HonAppliance + from . import const from .const import DOMAIN from .hon import HonEntity, unique_entities @@ -635,19 +634,20 @@ def __init__(self, hass, entry, device: HonAppliance, description): ).values + ["No Program"] @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self, update=True) -> None: value = self._device.get(self.entity_description.key, "") if not value and self.entity_description.state_class is not None: self._attr_native_value = 0 self._attr_native_value = value - self.async_write_ha_state() + if update: + self.async_write_ha_state() class HonConfigSensorEntity(HonEntity, SensorEntity): entity_description: HonConfigSensorEntityDescription @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self, update=True) -> None: value = self._device.settings.get(self.entity_description.key, None) if self.entity_description.state_class is not None: if value and value.value: @@ -658,4 +658,5 @@ def _handle_coordinator_update(self): self._attr_native_value = 0 else: self._attr_native_value = value.value - self.async_write_ha_state() + if update: + self.async_write_ha_state() diff --git a/custom_components/hon/switch.py b/custom_components/hon/switch.py index 01d3f81..b0af92e 100644 --- a/custom_components/hon/switch.py +++ b/custom_components/hon/switch.py @@ -1,5 +1,6 @@ import logging from dataclasses import dataclass +from datetime import datetime, timedelta from typing import Any from homeassistant.components.switch import SwitchEntityDescription, SwitchEntity @@ -394,10 +395,11 @@ def available(self) -> bool: ) @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self, update=True) -> None: value = self._device.get(self.entity_description.key, "0") self._attr_state = value == "1" - self.async_write_ha_state() + if update: + self.async_write_ha_state() class HonControlSwitchEntity(HonEntity, SwitchEntity): @@ -410,9 +412,13 @@ def is_on(self) -> bool | None: async def async_turn_on(self, **kwargs: Any) -> None: await self._device.commands[self.entity_description.turn_on_key].send() + self._device.attributes[self.entity_description.key] = True + self.async_write_ha_state() async def async_turn_off(self, **kwargs: Any) -> None: await self._device.commands[self.entity_description.turn_off_key].send() + self._device.attributes[self.entity_description.key] = False + self.async_write_ha_state() @property def available(self) -> bool: @@ -423,6 +429,18 @@ def available(self) -> bool: and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" ) + @property + def extra_state_attributes(self) -> dict[str, Any]: + """Return the optional state attributes.""" + result = {} + if remaining_time := int(self._device.get("remainingTimeMM", 0)): + delay_time = int(self._device.get("delayTime", 0)) + result["start_time"] = datetime.now() + timedelta(minutes=delay_time) + result["end_time"] = datetime.now() + timedelta( + minutes=delay_time + remaining_time + ) + return result + class HonConfigSwitchEntity(HonEntity, SwitchEntity): entity_description: HonConfigSwitchEntityDescription @@ -454,7 +472,8 @@ async def async_turn_off(self, **kwargs: Any) -> None: await self.coordinator.async_refresh() @callback - def _handle_coordinator_update(self): + def _handle_coordinator_update(self, update=True) -> None: value = self._device.settings.get(self.entity_description.key, "0") self._attr_state = value == "1" - self.async_write_ha_state() + if update: + self.async_write_ha_state() diff --git a/info.md b/info.md index 73f8e0a..ba5827c 100644 --- a/info.md +++ b/info.md @@ -51,6 +51,7 @@ Translation of internal names like programs are available for all languages whic ## Supported Models Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8). - Haier AD105S2SM3FA +- Haier AS20HPL1HRA - Haier AS25PBAHRA - Haier AS25S2SF1FA-WH - Haier AS25TADHRA-2