diff --git a/custom_components/hon/__init__.py b/custom_components/hon/__init__.py index 1e38a2d..e29abd7 100644 --- a/custom_components/hon/__init__.py +++ b/custom_components/hon/__init__.py @@ -6,7 +6,7 @@ import voluptuous as vol # type: ignore[import-untyped] from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_EMAIL, CONF_PASSWORD from homeassistant.helpers import config_validation as cv, aiohttp_client -from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from pyhon import Hon @@ -27,7 +27,7 @@ CONFIG_SCHEMA = vol.Schema( ) -async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool: +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: session = aiohttp_client.async_get_clientsession(hass) if (config_dir := hass.config.config_dir) is None: raise ValueError("Missing Config Dir") @@ -53,14 +53,12 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.unique_id] = {"hon": hon, "coordinator": coordinator} - for platform in PLATFORMS: - hass.async_create_task( - hass.config_entries.async_forward_entry_setup(entry, platform) - ) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + return True -async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: refresh_token = hass.data[DOMAIN][entry.unique_id]["hon"].api.auth.refresh_token hass.config_entries.async_update_entry( diff --git a/custom_components/hon/binary_sensor.py b/custom_components/hon/binary_sensor.py index 3907325..33a0526 100644 --- a/custom_components/hon/binary_sensor.py +++ b/custom_components/hon/binary_sensor.py @@ -9,7 +9,7 @@ from homeassistant.components.binary_sensor import ( from homeassistant.config_entries import ConfigEntry from homeassistant.core import callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.core import HomeAssistant from .const import DOMAIN from .entity import HonEntity @@ -285,6 +285,16 @@ BINARY_SENSORS: dict[str, tuple[HonBinarySensorEntityDescription, ...]] = { translation_key="on", ), ), + "WH": ( + HonBinarySensorEntityDescription( + key="onOffStatus", + name="Power State", + icon="mdi:power-standby", + device_class=BinarySensorDeviceClass.POWER, + on_value=1, + translation_key="power-state", + ), + ), "FRE": ( HonBinarySensorEntityDescription( key="quickModeZ1", @@ -317,7 +327,7 @@ BINARY_SENSORS["WD"] = unique_entities(BINARY_SENSORS["WM"], BINARY_SENSORS["TD" async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances: @@ -346,4 +356,4 @@ class HonBinarySensorEntity(HonEntity, BinarySensorEntity): == self.entity_description.on_value ) if update: - self.async_write_ha_state() + self.schedule_update_ha_state() diff --git a/custom_components/hon/button.py b/custom_components/hon/button.py index ce0f548..4a30ef8 100644 --- a/custom_components/hon/button.py +++ b/custom_components/hon/button.py @@ -6,7 +6,7 @@ from homeassistant.components.button import ButtonEntityDescription, ButtonEntit from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.core import HomeAssistant from pyhon.appliance import HonAppliance from .const import DOMAIN @@ -56,7 +56,7 @@ BUTTONS: dict[str, tuple[ButtonEntityDescription, ...]] = { async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities: list[HonButtonType] = [] for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances: @@ -88,7 +88,7 @@ class HonButtonEntity(HonEntity, ButtonEntity): class HonDeviceInfo(HonEntity, ButtonEntity): def __init__( - self, hass: HomeAssistantType, entry: ConfigEntry, device: HonAppliance + self, hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance ) -> None: super().__init__(hass, entry, device) @@ -108,7 +108,7 @@ class HonDeviceInfo(HonEntity, ButtonEntity): class HonDataArchive(HonEntity, ButtonEntity): def __init__( - self, hass: HomeAssistantType, entry: ConfigEntry, device: HonAppliance + self, hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance ) -> None: super().__init__(hass, entry, device) diff --git a/custom_components/hon/climate.py b/custom_components/hon/climate.py index f3ce937..94c03de 100644 --- a/custom_components/hon/climate.py +++ b/custom_components/hon/climate.py @@ -19,9 +19,8 @@ from homeassistant.const import ( ATTR_TEMPERATURE, UnitOfTemperature, ) -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType from pyhon.appliance import HonAppliance from pyhon.parameter.range import HonParameterRange @@ -104,7 +103,7 @@ CLIMATES: dict[ async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] entity: HonClimateEntity | HonACClimateEntity @@ -130,7 +129,7 @@ class HonACClimateEntity(HonEntity, ClimateEntity): def __init__( self, - hass: HomeAssistantType, + hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance, description: HonACClimateEntityDescription, @@ -299,7 +298,7 @@ class HonClimateEntity(HonEntity, ClimateEntity): def __init__( self, - hass: HomeAssistantType, + hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance, description: HonClimateEntityDescription, diff --git a/custom_components/hon/const.py b/custom_components/hon/const.py index 69ba158..490c41a 100644 --- a/custom_components/hon/const.py +++ b/custom_components/hon/const.py @@ -294,3 +294,9 @@ AC_POSITION_VERTICAL = { 7: "position_5", 8: "swing", } + +WH_MACH_MODE: dict[int, str] = { + 1: "eco", + 2: "max", + 3: "bps", +} diff --git a/custom_components/hon/entity.py b/custom_components/hon/entity.py index a597052..18880c9 100644 --- a/custom_components/hon/entity.py +++ b/custom_components/hon/entity.py @@ -1,9 +1,8 @@ from typing import Optional, Any from homeassistant.config_entries import ConfigEntry -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import DeviceInfo -from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, ) @@ -20,7 +19,7 @@ class HonEntity(CoordinatorEntity[DataUpdateCoordinator[dict[str, Any]]]): def __init__( self, - hass: HomeAssistantType, + hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance, description: Optional[HonEntityDescription] = None, @@ -53,4 +52,4 @@ class HonEntity(CoordinatorEntity[DataUpdateCoordinator[dict[str, Any]]]): @callback def _handle_coordinator_update(self, update: bool = True) -> None: if update: - self.async_write_ha_state() + self.schedule_update_ha_state() diff --git a/custom_components/hon/fan.py b/custom_components/hon/fan.py index a07a08f..f0ac960 100644 --- a/custom_components/hon/fan.py +++ b/custom_components/hon/fan.py @@ -8,9 +8,8 @@ from homeassistant.components.fan import ( FanEntityFeature, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType from homeassistant.util.percentage import ( percentage_to_ranged_value, ranged_value_to_percentage, @@ -36,7 +35,7 @@ FANS: dict[str, tuple[FanEntityDescription, ...]] = { async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances: @@ -56,7 +55,7 @@ class HonFanEntity(HonEntity, FanEntity): def __init__( self, - hass: HomeAssistantType, + hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance, description: FanEntityDescription, diff --git a/custom_components/hon/light.py b/custom_components/hon/light.py index d38a994..a23f781 100644 --- a/custom_components/hon/light.py +++ b/custom_components/hon/light.py @@ -8,9 +8,8 @@ from homeassistant.components.light import ( ATTR_BRIGHTNESS, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType from pyhon.appliance import HonAppliance from pyhon.parameter.range import HonParameterRange @@ -53,7 +52,7 @@ LIGHTS: dict[str, tuple[LightEntityDescription, ...]] = { async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances: @@ -73,7 +72,7 @@ class HonLightEntity(HonEntity, LightEntity): def __init__( self, - hass: HomeAssistantType, + hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance, description: LightEntityDescription, diff --git a/custom_components/hon/lock.py b/custom_components/hon/lock.py index 1ecb744..a98aebe 100644 --- a/custom_components/hon/lock.py +++ b/custom_components/hon/lock.py @@ -3,9 +3,8 @@ from typing import Any from homeassistant.components.lock import LockEntity, LockEntityDescription from homeassistant.config_entries import ConfigEntry -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType from pyhon.parameter.base import HonParameter from pyhon.parameter.range import HonParameterRange @@ -26,7 +25,7 @@ LOCKS: dict[str, tuple[LockEntityDescription, ...]] = { async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances: diff --git a/custom_components/hon/number.py b/custom_components/hon/number.py index b646b75..213aa2b 100644 --- a/custom_components/hon/number.py +++ b/custom_components/hon/number.py @@ -5,13 +5,13 @@ from dataclasses import dataclass from homeassistant.components.number import ( NumberEntity, NumberEntityDescription, + NumberDeviceClass, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import UnitOfTime, UnitOfTemperature -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType from pyhon.appliance import HonAppliance from pyhon.parameter.range import HonParameterRange @@ -27,7 +27,7 @@ class HonConfigNumberEntityDescription(NumberEntityDescription): @dataclass(frozen=True) class HonNumberEntityDescription(NumberEntityDescription): - pass + send_key_only: bool = False NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { @@ -201,13 +201,24 @@ NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { translation_key="pollen_level", ), ), + "WH": ( + HonNumberEntityDescription( + key="settings.tempSel", + name="Target Temperature", + icon="mdi:thermometer", + device_class=NumberDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="target_temperature", + send_key_only=True, + ), + ), } NUMBERS["WD"] = unique_entities(NUMBERS["WM"], NUMBERS["TD"]) async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] entity: HonNumberEntity | HonConfigNumberEntity @@ -230,7 +241,7 @@ class HonNumberEntity(HonEntity, NumberEntity): def __init__( self, - hass: HomeAssistantType, + hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance, description: HonNumberEntityDescription, @@ -253,8 +264,12 @@ class HonNumberEntity(HonEntity, NumberEntity): setting = self._device.settings[self.entity_description.key] if isinstance(setting, HonParameterRange): setting.value = value - command = self.entity_description.key.split(".")[0] - await self._device.commands[command].send() + key_parts = self.entity_description.key.split(".") + command = key_parts[0] + if self.entity_description.send_key_only: + await self._device.commands[command].send_specific([key_parts[1]]) + else: + await self._device.commands[command].send() if command != "settings": self._device.sync_command(command, "settings") self.coordinator.async_set_updated_data({}) @@ -268,7 +283,7 @@ class HonNumberEntity(HonEntity, NumberEntity): self._attr_native_step = setting.step self._attr_native_value = self.native_value if update: - self.async_write_ha_state() + self.schedule_update_ha_state() @property def available(self) -> bool: @@ -285,7 +300,7 @@ class HonConfigNumberEntity(HonEntity, NumberEntity): def __init__( self, - hass: HomeAssistantType, + hass: HomeAssistant, entry: ConfigEntry, device: HonAppliance, description: HonConfigNumberEntityDescription, @@ -324,4 +339,4 @@ class HonConfigNumberEntity(HonEntity, NumberEntity): self._attr_native_step = setting.step self._attr_native_value = self.native_value if update: - self.async_write_ha_state() + self.schedule_update_ha_state() diff --git a/custom_components/hon/select.py b/custom_components/hon/select.py index c7da326..9417c63 100644 --- a/custom_components/hon/select.py +++ b/custom_components/hon/select.py @@ -6,10 +6,9 @@ from dataclasses import dataclass from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.config_entries import ConfigEntry from homeassistant.const import UnitOfTemperature, UnitOfTime, REVOLUTIONS_PER_MINUTE -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType from . import const from .const import DOMAIN @@ -22,6 +21,7 @@ _LOGGER = logging.getLogger(__name__) @dataclass(frozen=True) class HonSelectEntityDescription(SelectEntityDescription): option_list: dict[int, str] | None = None + send_key_only: bool = False @dataclass(frozen=True) @@ -185,6 +185,16 @@ SELECTS: dict[str, tuple[SelectEntityDescription, ...]] = { translation_key="mode", ), ), + "WH": ( + HonSelectEntityDescription( + key="settings.machMode", + name="Mode", + send_key_only=True, + icon="mdi:information", + option_list=const.WH_MACH_MODE, + translation_key="mach_modes_wh", + ), + ), "FRE": ( HonConfigSelectEntityDescription( key="startProgram.program", @@ -211,7 +221,7 @@ SELECTS["WD"] = unique_entities(SELECTS["WM"], SELECTS["TD"]) async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] entity: HonSelectEntity | HonConfigSelectEntity @@ -284,9 +294,16 @@ class HonSelectEntity(HonEntity, SelectEntity): @property def current_option(self) -> str | None: - if not (setting := self._device.settings.get(self.entity_description.key)): - return None - value = get_readable(self.entity_description, setting.value) + key = self.entity_description.key + if self.entity_description.send_key_only: + key = key.split('.')[1] + value = self._device.get(key, "") + value = get_readable(self.entity_description, value) + else: + if not (setting := self._device.settings.get(self.entity_description.key)): + return None + value = get_readable(self.entity_description, setting.value) + if value not in self._attr_options: return None return str(value) @@ -313,8 +330,12 @@ class HonSelectEntity(HonEntity, SelectEntity): async def async_select_option(self, option: str) -> None: setting = self._device.settings[self.entity_description.key] setting.value = self._option_to_number(option, setting.values) - command = self.entity_description.key.split(".")[0] - await self._device.commands[command].send() + key_parts = self.entity_description.key.split(".") + command = key_parts[0] + if self.entity_description.send_key_only: + await self._device.commands[command].send_specific([key_parts[1]]) + else: + await self._device.commands[command].send() if command != "settings": self._device.sync_command(command, "settings") self.coordinator.async_set_updated_data({}) @@ -334,4 +355,4 @@ class HonSelectEntity(HonEntity, SelectEntity): self._attr_options = self.options self._attr_current_option = self.current_option if update: - self.async_write_ha_state() + self.schedule_update_ha_state() diff --git a/custom_components/hon/sensor.py b/custom_components/hon/sensor.py index 4039282..091b49c 100644 --- a/custom_components/hon/sensor.py +++ b/custom_components/hon/sensor.py @@ -21,10 +21,10 @@ from homeassistant.const import ( UnitOfTime, UnitOfTemperature, ) -from homeassistant.core import callback +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType +from pyhon.attributes import HonAttribute from . import const from .const import DOMAIN @@ -780,6 +780,63 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="air_quality", ), ), + "WH": ( + HonSensorEntityDescription( + key="temp", + name="Temperature", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="temperature", + ), + HonSensorEntityDescription( + key="tempZ1", + name="Temp Z1", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + ), + HonSensorEntityDescription( + key="tempZ2", + name="Temp Z2", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + ), + HonSensorEntityDescription( + key="tempSel", + name="Target Temperature", + icon="mdi:thermometer", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + translation_key="target_temperature", + ), + HonSensorEntityDescription( + key="machMode", + name="Mode", + icon="mdi:information", + device_class=SensorDeviceClass.ENUM, + option_list=const.WH_MACH_MODE, + translation_key="mach_modes_wh", + ), + HonSensorEntityDescription( + key="smartTestStatus", + name="Smart Test Status", + ), + HonSensorEntityDescription( + key="anodeMaintenanceStatus", + name="Anode Maintenance Status", + ), + HonSensorEntityDescription( + key="tankMaintenanceStatus", + name="Tank Maintenance Status", + ), + HonSensorEntityDescription( + key="heatingStatus", + name="Heating Status", + ), + ), "FRE": ( HonSensorEntityDescription( key="tempEnv", @@ -808,7 +865,7 @@ SENSORS["WD"] = unique_entities(SENSORS["WM"], SENSORS["TD"]) async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] entity: HonSensorEntity | HonConfigSensorEntity @@ -846,7 +903,7 @@ class HonSensorEntity(HonEntity, SensorEntity): self._attr_native_value = 0 self._attr_native_value = value if update: - self.async_write_ha_state() + self.schedule_update_ha_state() class HonConfigSensorEntity(HonEntity, SensorEntity): @@ -874,4 +931,4 @@ class HonConfigSensorEntity(HonEntity, SensorEntity): value = get_readable(self.entity_description, value) self._attr_native_value = value if update: - self.async_write_ha_state() + self.schedule_update_ha_state() diff --git a/custom_components/hon/switch.py b/custom_components/hon/switch.py index 359e505..94ff523 100644 --- a/custom_components/hon/switch.py +++ b/custom_components/hon/switch.py @@ -8,7 +8,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.core import HomeAssistant from pyhon.parameter.base import HonParameter from pyhon.parameter.range import HonParameterRange @@ -23,6 +23,10 @@ _LOGGER = logging.getLogger(__name__) class HonControlSwitchEntityDescription(SwitchEntityDescription): turn_on_key: str = "" turn_off_key: str = "" + only_mandatory_parameters: bool = False + on_value: bool | float = True + off_value: bool | float = False + to_sync: bool = False @dataclass(frozen=True) @@ -382,6 +386,20 @@ SWITCHES: dict[str, tuple[SwitchEntityDescription, ...]] = { translation_key="touch_tone", ), ), + "WH": ( + HonControlSwitchEntityDescription( + key="onOffStatus", + name="Power", + icon="mdi:power-standby", + turn_on_key="startProgram", + turn_off_key="stopProgram", + translation_key="power", + only_mandatory_parameters=False, + on_value=1, + off_value=0, + to_sync=True, + ), + ), "FRE": ( HonSwitchEntityDescription( key="quickModeZ2", @@ -403,7 +421,7 @@ SWITCHES["WD"] = unique_entities(SWITCHES["WD"], SWITCHES["TD"]) async def async_setup_entry( - hass: HomeAssistantType, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: entities = [] entity: HonConfigSwitchEntity | HonControlSwitchEntity | HonSwitchEntity @@ -476,7 +494,7 @@ class HonSwitchEntity(HonEntity, SwitchEntity): def _handle_coordinator_update(self, update: bool = True) -> None: self._attr_is_on = self.is_on if update: - self.async_write_ha_state() + self.schedule_update_ha_state() class HonControlSwitchEntity(HonEntity, SwitchEntity): @@ -485,21 +503,31 @@ class HonControlSwitchEntity(HonEntity, SwitchEntity): @property def is_on(self) -> bool | None: """Return True if entity is on.""" - return self._device.get(self.entity_description.key, False) + on_value = self.entity_description.on_value + off_value = self.entity_description.off_value + return self._device.get(self.entity_description.key, off_value) == on_value async def async_turn_on(self, **kwargs: Any) -> None: - self._device.sync_command(self.entity_description.turn_on_key, "settings") + desc = self.entity_description + self._device.sync_command(desc.turn_on_key, "settings", desc.to_sync) self.coordinator.async_set_updated_data({}) - await self._device.commands[self.entity_description.turn_on_key].send() - self._device.attributes[self.entity_description.key] = True - self.async_write_ha_state() + command = self._device.commands[desc.turn_on_key] + if self._device.appliance_type == "WH": + command.settings["machMode"].value = self._device.get("machMode", "") + command.settings["tempSel"].value = self._device.get("tempSel", "") + + await command.send(desc.only_mandatory_parameters) + self._device.attributes[desc.key] = desc.on_value + self.schedule_update_ha_state() async def async_turn_off(self, **kwargs: Any) -> None: - self._device.sync_command(self.entity_description.turn_off_key, "settings") + desc = self.entity_description + self._device.sync_command(desc.turn_off_key, "settings", desc.to_sync) self.coordinator.async_set_updated_data({}) - await self._device.commands[self.entity_description.turn_off_key].send() - self._device.attributes[self.entity_description.key] = False - self.async_write_ha_state() + command = self._device.commands[desc.turn_off_key] + await command.send(desc.only_mandatory_parameters) + self._device.attributes[desc.key] = desc.off_value + self.schedule_update_ha_state() @property def available(self) -> bool: @@ -542,7 +570,7 @@ class HonConfigSwitchEntity(HonEntity, SwitchEntity): return setting.value = setting.max if isinstance(setting, HonParameterRange) else "1" self.coordinator.async_set_updated_data({}) - self.async_write_ha_state() + self.schedule_update_ha_state() async def async_turn_off(self, **kwargs: Any) -> None: setting = self._device.settings[self.entity_description.key] @@ -550,10 +578,10 @@ class HonConfigSwitchEntity(HonEntity, SwitchEntity): return setting.value = setting.min if isinstance(setting, HonParameterRange) else "0" self.coordinator.async_set_updated_data({}) - self.async_write_ha_state() + self.schedule_update_ha_state() @callback def _handle_coordinator_update(self, update: bool = True) -> None: self._attr_is_on = self.is_on if update: - self.async_write_ha_state() + self.schedule_update_ha_state() diff --git a/custom_components/hon/translations/bg.json b/custom_components/hon/translations/bg.json index 4e73c4e..8be523e 100644 --- a/custom_components/hon/translations/bg.json +++ b/custom_components/hon/translations/bg.json @@ -9,6 +9,79 @@ } } } + } + } + }, + "entity": { + "sensor": { + "mode": { + "state": { + "0": "Изключен", + "1": "Готов", + "2": "Работи", + "3": "На пауза", + "5": "Scheduled", + "6": "Грешка", + "7": "Завършен" + } + }, + "errors": { + "state": { + "00": "Няма грешки", + "100000000000": "E2: Провери дали вратата е затворена", + "8000000000000": "E4: Провери подаването на вода" + } + }, + "programs": { + "state": { + "0": "Стандартна", + "62": "Памук", + "63": "Синтетика", + "64": "Смесен тип", + "66": "Чаршафи", + "71": "Пердета", + "72": "Спорт", + "74": "i-time", + "75": "Олекотени завивки", + "76": "Вълна", + "78": "i-Refresh", + "83": "Хавлиена кърпа", + "85": "Бързо Сушене", + "92": "Деликатно пране", + "103": "Отдалечен" + } + }, + "program_phases_td": { + "state": { + "0": "Изчаване", + "2": "Сушене", + "3": "Охлажане", + "11": "11" + } + }, + "tumbledryertemplevel": { + "state": { + "1": "Хладен въздух", + "2": "Ниска температура L-1", + "3": "Средна температура L-2", + "4": "Висока температура L-3" + } + }, + "dry_levels": { + "state": { + "3": "Готови за съхранение", + "12": "Готови за гладене H-1", + "13": "Готови за съхранение H-2", + "14": "Екстра сухо H-3" + } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } + } }, "entity": { "sensor": { @@ -2326,5 +2399,18 @@ "name": "Light" } } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } + } + }, + "binary_sensor": { + "power-state": { + "name": "Power State" + } } } \ No newline at end of file diff --git a/custom_components/hon/translations/cs.json b/custom_components/hon/translations/cs.json index 6d44cbe..6023666 100644 --- a/custom_components/hon/translations/cs.json +++ b/custom_components/hon/translations/cs.json @@ -931,6 +931,13 @@ "high": "Vysoká" }, "name": "Úroveň vlhkosti" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Pevný - Poloha 5", "swing": "Pohyb lamel" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Výměna filtru" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/de.json b/custom_components/hon/translations/de.json index 0358ede..de9dfa6 100644 --- a/custom_components/hon/translations/de.json +++ b/custom_components/hon/translations/de.json @@ -931,6 +931,13 @@ "high": "Hoch" }, "name": "Grad der Luftfeuchtigkeit" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fest - Position 5", "swing": "Schwenkbewegung" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Filteraustausch" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/el.json b/custom_components/hon/translations/el.json index 07e158a..6ac0e0e 100644 --- a/custom_components/hon/translations/el.json +++ b/custom_components/hon/translations/el.json @@ -931,6 +931,13 @@ "high": "Υψηλός" }, "name": "Επίπεδο υγρασίας" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Σταθερός - Θέση 5", "swing": "Ταλάντευση" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Αντικατάσταση φίλτρου" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/en.json b/custom_components/hon/translations/en.json index f606c51..de54fdc 100644 --- a/custom_components/hon/translations/en.json +++ b/custom_components/hon/translations/en.json @@ -964,6 +964,13 @@ "high": "High" }, "name": "Humidity level" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1869,6 +1876,13 @@ "position_5": "Fixed - Position 5", "swing": "Swing" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2068,6 +2082,9 @@ }, "filter_replacement": { "name": "Filter replacement" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/es.json b/custom_components/hon/translations/es.json index f21e0c0..bfc98e1 100644 --- a/custom_components/hon/translations/es.json +++ b/custom_components/hon/translations/es.json @@ -931,6 +931,13 @@ "high": "Alto" }, "name": "Nivel de humedad" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fijo - Posición 5", "swing": "Oscilar" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Sustitución del filtro" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/fr.json b/custom_components/hon/translations/fr.json index 06c417a..dda121c 100644 --- a/custom_components/hon/translations/fr.json +++ b/custom_components/hon/translations/fr.json @@ -931,6 +931,13 @@ "high": "Élevé" }, "name": "Niveau d’humidité" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fixe - Position 5", "swing": "Oscillation" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Remplacement du filtre" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/he.json b/custom_components/hon/translations/he.json index f14d36d..0fa536f 100644 --- a/custom_components/hon/translations/he.json +++ b/custom_components/hon/translations/he.json @@ -448,6 +448,13 @@ "high": "גָבוֹהַ" }, "name": "Humidity level" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -859,6 +866,13 @@ "position_5": "Fixed - Position 5", "swing": "Swing" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -1058,6 +1072,9 @@ }, "filter_replacement": { "name": "Filter replacement" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/hr.json b/custom_components/hon/translations/hr.json index 930b12f..889f5e7 100644 --- a/custom_components/hon/translations/hr.json +++ b/custom_components/hon/translations/hr.json @@ -931,6 +931,13 @@ "high": "Visoko" }, "name": "Razina vlažnosti" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fiksno - Položaj 5", "swing": "Njihanje" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Zamjena filtra" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/it.json b/custom_components/hon/translations/it.json index 53efe9a..a4c3fe4 100644 --- a/custom_components/hon/translations/it.json +++ b/custom_components/hon/translations/it.json @@ -940,6 +940,13 @@ "high": "Alto" }, "name": "Livello di umidità" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1829,6 +1836,13 @@ "position_5": "Fissa - Posizione 5", "swing": "Swing" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2028,6 +2042,9 @@ }, "filter_replacement": { "name": "Sostituzione filtro" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/nl.json b/custom_components/hon/translations/nl.json index 97b1d21..6d34b87 100644 --- a/custom_components/hon/translations/nl.json +++ b/custom_components/hon/translations/nl.json @@ -931,6 +931,13 @@ "high": "Hoog" }, "name": "Vochtigheidsniveau" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Vast - Positie 5", "swing": "Draaiend" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Filter vervangen" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/pl.json b/custom_components/hon/translations/pl.json index 31cfa8f..abc9ad6 100644 --- a/custom_components/hon/translations/pl.json +++ b/custom_components/hon/translations/pl.json @@ -931,6 +931,13 @@ "high": "Wysokie" }, "name": "Poziom wilgotności" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Stały - Pozycja 5", "swing": "Swing" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Wymiana filtra" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/pt.json b/custom_components/hon/translations/pt.json index c866f0a..93fc777 100644 --- a/custom_components/hon/translations/pt.json +++ b/custom_components/hon/translations/pt.json @@ -931,6 +931,13 @@ "high": "Alta" }, "name": "Nível de humidade" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fixa - Posição 5", "swing": "Oscilação" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Substituição do filtro" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/ro.json b/custom_components/hon/translations/ro.json index 1c8b7a9..255e7fd 100644 --- a/custom_components/hon/translations/ro.json +++ b/custom_components/hon/translations/ro.json @@ -931,6 +931,13 @@ "high": "Crescută" }, "name": "Nivelul de umiditate" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fix - Poziție 5", "swing": "Baleiere" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Înlocuirea filtrului" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/ru.json b/custom_components/hon/translations/ru.json index 488799a..3d1ac07 100644 --- a/custom_components/hon/translations/ru.json +++ b/custom_components/hon/translations/ru.json @@ -931,6 +931,13 @@ "high": "Высок." }, "name": "Уровень влажности" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Фиксированное - Позиция 5", "swing": "Качание" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Замена фильтра" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/sk.json b/custom_components/hon/translations/sk.json index 0d97e22..1eba254 100644 --- a/custom_components/hon/translations/sk.json +++ b/custom_components/hon/translations/sk.json @@ -931,6 +931,13 @@ "high": "Vysoké" }, "name": "Úroveň vlhkosti" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Pevný - Poloha 5", "swing": "Otáčanie" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Výmena filtra" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/sl.json b/custom_components/hon/translations/sl.json index 0f8f985..9002cc7 100644 --- a/custom_components/hon/translations/sl.json +++ b/custom_components/hon/translations/sl.json @@ -931,6 +931,13 @@ "high": "High" }, "name": "Nivo vlažnosti" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fiksno - Položaj 5", "swing": "Nihanje" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Menjava filtra" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/sr.json b/custom_components/hon/translations/sr.json index 38173ea..a85bb32 100644 --- a/custom_components/hon/translations/sr.json +++ b/custom_components/hon/translations/sr.json @@ -931,6 +931,13 @@ "high": "Visoka" }, "name": "Nivo vlage" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Fiksiran - Položaj 5", "swing": "Njihanje" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Zamena filtera" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/tr.json b/custom_components/hon/translations/tr.json index d8b78de..a32944b 100644 --- a/custom_components/hon/translations/tr.json +++ b/custom_components/hon/translations/tr.json @@ -931,6 +931,13 @@ "high": "Yüksek" }, "name": "Nem seviyesi" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1816,6 +1823,13 @@ "position_5": "Sabit - Pozisyon 5", "swing": "Salınım" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2015,6 +2029,9 @@ }, "filter_replacement": { "name": "Filtre değişimi" + }, + "power-state": { + "name": "Power State" } }, "button": { diff --git a/custom_components/hon/translations/zh.json b/custom_components/hon/translations/zh.json index f7156ec..4b8db31 100644 --- a/custom_components/hon/translations/zh.json +++ b/custom_components/hon/translations/zh.json @@ -924,6 +924,13 @@ "high": "高" }, "name": "湿度水平" + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "select": { @@ -1802,6 +1809,13 @@ "position_5": "固定 - 位置 5", "swing": "摆动" } + }, + "mach_modes_wh": { + "state": { + "eco": "Eco", + "max": "Max", + "bps": "BPS" + } } }, "switch": { @@ -2001,6 +2015,9 @@ }, "filter_replacement": { "name": "更换过滤器" + }, + "power-state": { + "name": "Power State" } }, "button": {