From a8762367edaf7b9b755e43a04e85ab74439b1905 Mon Sep 17 00:00:00 2001 From: Andre Basche Date: Sun, 28 May 2023 00:30:08 +0200 Subject: [PATCH] Refactor hon entities --- custom_components/hon/binary_sensor.py | 6 - custom_components/hon/button.py | 6 +- custom_components/hon/climate.py | 4 +- custom_components/hon/hon.py | 8 +- custom_components/hon/number.py | 122 +++++----- custom_components/hon/select.py | 104 +++++---- custom_components/hon/sensor.py | 197 ++++++++-------- custom_components/hon/switch.py | 304 ++++++++++++------------- 8 files changed, 382 insertions(+), 369 deletions(-) diff --git a/custom_components/hon/binary_sensor.py b/custom_components/hon/binary_sensor.py index 856d17d..9cd96c3 100644 --- a/custom_components/hon/binary_sensor.py +++ b/custom_components/hon/binary_sensor.py @@ -263,12 +263,6 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non class HonBinarySensorEntity(HonEntity, BinarySensorEntity): entity_description: HonBinarySensorEntityDescription - def __init__(self, hass, entry, device, description) -> None: - super().__init__(hass, entry, device) - - self.entity_description = description - self._attr_unique_id = f"{super().unique_id}{description.key}" - @property def is_on(self) -> bool: return ( diff --git a/custom_components/hon/button.py b/custom_components/hon/button.py index 10387d8..a4d089d 100644 --- a/custom_components/hon/button.py +++ b/custom_components/hon/button.py @@ -53,11 +53,7 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non class HonButtonEntity(HonEntity, ButtonEntity): - def __init__(self, hass, entry, device: HonAppliance, description) -> None: - super().__init__(hass, entry, device) - - self.entity_description = description - self._attr_unique_id = f"{super().unique_id}{description.key}" + entity_description: ButtonEntityDescription async def async_press(self) -> None: await self._device.commands[self.entity_description.key].send() diff --git a/custom_components/hon/climate.py b/custom_components/hon/climate.py index decbe65..7690e35 100644 --- a/custom_components/hon/climate.py +++ b/custom_components/hon/climate.py @@ -53,9 +53,7 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non class HonClimateEntity(HonEntity, ClimateEntity): def __init__(self, hass, entry, device: HonAppliance, description) -> None: - super().__init__(hass, entry, device) - self.entity_description = description - self._attr_unique_id = f"{super().unique_id}climate" + super().__init__(hass, entry, device, description) self._attr_temperature_unit = TEMP_CELSIUS self._attr_target_temperature_step = PRECISION_WHOLE diff --git a/custom_components/hon/hon.py b/custom_components/hon/hon.py index da7c45a..b3e37d6 100644 --- a/custom_components/hon/hon.py +++ b/custom_components/hon/hon.py @@ -14,7 +14,7 @@ _LOGGER = logging.getLogger(__name__) class HonEntity(CoordinatorEntity): _attr_has_entity_name = True - def __init__(self, hass, entry, device: HonAppliance) -> None: + def __init__(self, hass, entry, device: HonAppliance, description=None) -> None: coordinator = get_coordinator(hass, device) super().__init__(coordinator) @@ -23,7 +23,11 @@ class HonEntity(CoordinatorEntity): self._coordinator = coordinator self._device = device - self._attr_unique_id = self._device.unique_id + 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 @property def device_info(self): diff --git a/custom_components/hon/number.py b/custom_components/hon/number.py index 2932cc1..0d6268b 100644 --- a/custom_components/hon/number.py +++ b/custom_components/hon/number.py @@ -1,5 +1,7 @@ from __future__ import annotations +from dataclasses import dataclass + from homeassistant.components.number import ( NumberEntity, NumberEntityDescription, @@ -7,143 +9,136 @@ from homeassistant.components.number import ( from homeassistant.config_entries import ConfigEntry from homeassistant.const import UnitOfTime, UnitOfTemperature from homeassistant.core import callback -from homeassistant.helpers.entity import EntityCategory -from pyhon.parameter.base import HonParameter -from pyhon.parameter.fixed import HonParameterFixed +from homeassistant.helpers.entity import EntityCategory, Entity from pyhon.parameter.range import HonParameterRange from .const import DOMAIN from .hon import HonEntity, unique_entities + +@dataclass +class HonConfigNumberEntityDescription(NumberEntityDescription): + entity_category: EntityCategory = EntityCategory.CONFIG + + +@dataclass +class HonNumberEntityDescription(NumberEntityDescription): + pass + + NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { "WM": ( - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.delayTime", name="Delay Time", icon="mdi:timer-plus", - entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="delay_time", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.rinseIterations", name="Rinse Iterations", icon="mdi:rotate-right", - entity_category=EntityCategory.CONFIG, translation_key="rinse_iterations", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.mainWashTime", name="Main Wash Time", icon="mdi:clock-start", - entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="wash_time", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.steamLevel", name="Steam Level", icon="mdi:weather-dust", - entity_category=EntityCategory.CONFIG, translation_key="steam_level", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.waterHard", name="Water hard", icon="mdi:water", - entity_category=EntityCategory.CONFIG, translation_key="water_hard", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.lang", name="lang", - entity_category=EntityCategory.CONFIG, ), ), "TD": ( - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.delayTime", name="Delay time", icon="mdi:timer-plus", - entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="delay_time", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.tempLevel", name="Temperature level", - entity_category=EntityCategory.CONFIG, icon="mdi:thermometer", translation_key="tumbledryertemplevel", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.dryTime", name="Dry Time", - entity_category=EntityCategory.CONFIG, translation_key="dry_time", ), ), "OV": ( - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.delayTime", name="Delay time", icon="mdi:timer-plus", - entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="delay_time", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.tempSel", name="Target Temperature", - entity_category=EntityCategory.CONFIG, icon="mdi:thermometer", native_unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="target_temperature", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.prTime", name="Program Duration", - entity_category=EntityCategory.CONFIG, icon="mdi:timelapse", native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="program_duration", ), ), "IH": ( - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.temp", name="Temperature", - entity_category=EntityCategory.CONFIG, icon="mdi:thermometer", translation_key="temperature", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.powerManagement", name="Power Management", - entity_category=EntityCategory.CONFIG, icon="mdi:timelapse", translation_key="power_management", ), ), "DW": ( - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.delayTime", name="Delay time", icon="mdi:timer-plus", - entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="delay_time", ), - NumberEntityDescription( + HonConfigNumberEntityDescription( key="startProgram.waterHard", name="Water hard", icon="mdi:water", - entity_category=EntityCategory.CONFIG, translation_key="water_hard", ), ), "AC": ( - NumberEntityDescription( + HonNumberEntityDescription( key="settings.tempSel", name="Target Temperature", icon="mdi:thermometer", @@ -152,14 +147,14 @@ NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = { ), ), "REF": ( - NumberEntityDescription( + HonNumberEntityDescription( key="settings.tempSelZ1", name="Fridge Temperature", icon="mdi:thermometer", native_unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="fridge_temp_sel", ), - NumberEntityDescription( + HonNumberEntityDescription( key="settings.tempSelZ2", name="Freezer Temperature", icon="mdi:thermometer", @@ -178,20 +173,24 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non for description in NUMBERS.get(device.appliance_type, []): if description.key not in device.available_settings: continue - entity = HonNumberEntity(hass, entry, device, description) + if isinstance(description, HonNumberEntityDescription): + entity = HonNumberEntity(hass, entry, device, description) + elif isinstance(description, HonConfigNumberEntityDescription): + entity = HonConfigNumberEntity(hass, entry, device, description) + else: + continue await entity.coordinator.async_config_entry_first_refresh() entities.append(entity) async_add_entities(entities) class HonNumberEntity(HonEntity, NumberEntity): + entity_description: HonNumberEntityDescription + def __init__(self, hass, entry, device, description) -> None: - super().__init__(hass, entry, device) + super().__init__(hass, entry, device, description) self._data = device.settings[description.key] - self.entity_description = description - self._attr_unique_id = f"{super().unique_id}{description.key}" - if isinstance(self._data, HonParameterRange): self._attr_native_max_value = self._data.max self._attr_native_min_value = self._data.min @@ -203,12 +202,10 @@ class HonNumberEntity(HonEntity, NumberEntity): async def async_set_native_value(self, value: float) -> None: setting = self._device.settings[self.entity_description.key] - if not ( - type(setting) == HonParameter or isinstance(setting, HonParameterFixed) - ): + if isinstance(setting, HonParameterRange): setting.value = value - if "settings." in self.entity_description.key: - await self._device.commands["settings"].send() + command = self.entity_description.key.split(".")[0] + await self._device.commands[command].send() await self.coordinator.async_refresh() @callback @@ -224,12 +221,23 @@ class HonNumberEntity(HonEntity, NumberEntity): @property def available(self) -> bool: """Return True if entity is available.""" - if self.entity_category == EntityCategory.CONFIG: - return super().available - else: - return ( - super().available - and self._device.get("remoteCtrValid", "1") == "1" - and self._device.get("attributes.lastConnEvent.category") - != "DISCONNECTED" - ) + return ( + super().available + and self._device.get("remoteCtrValid", "1") == "1" + and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" + ) + + +class HonConfigNumberEntity(HonNumberEntity): + entity_description: HonConfigNumberEntityDescription + + async def async_set_native_value(self, value: str) -> None: + setting = self._device.settings[self.entity_description.key] + if isinstance(setting, HonParameterRange): + setting.value = value + await self.coordinator.async_refresh() + + @property + def available(self) -> bool: + """Return True if entity is available.""" + return super(NumberEntity, self).available diff --git a/custom_components/hon/select.py b/custom_components/hon/select.py index 9e59d58..327c928 100644 --- a/custom_components/hon/select.py +++ b/custom_components/hon/select.py @@ -1,12 +1,13 @@ from __future__ import annotations import logging +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.helpers.entity import EntityCategory +from homeassistant.helpers.entity import EntityCategory, Entity from pyhon.appliance import HonAppliance from pyhon.parameter.fixed import HonParameterFixed @@ -15,101 +16,101 @@ from .hon import HonEntity, unique_entities _LOGGER = logging.getLogger(__name__) + +@dataclass +class HonSelectEntityDescription(SelectEntityDescription): + pass + + +@dataclass +class HonConfigSelectEntityDescription(SelectEntityDescription): + entity_category: EntityCategory = EntityCategory.CONFIG + + SELECTS = { "WM": ( - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.spinSpeed", name="Spin speed", - entity_category=EntityCategory.CONFIG, icon="mdi:numeric", unit_of_measurement=REVOLUTIONS_PER_MINUTE, translation_key="spin_speed", ), - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.temp", name="Temperature", - entity_category=EntityCategory.CONFIG, icon="mdi:thermometer", unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="temperature", ), - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.program", name="Program", - entity_category=EntityCategory.CONFIG, translation_key="programs_wm", ), ), "TD": ( - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.program", name="Program", - entity_category=EntityCategory.CONFIG, translation_key="programs_td", ), - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.dryTimeMM", name="Dry Time", - entity_category=EntityCategory.CONFIG, icon="mdi:timer", unit_of_measurement=UnitOfTime.MINUTES, translation_key="dry_time", ), - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.dryLevel", name="Dry level", - entity_category=EntityCategory.CONFIG, icon="mdi:hair-dryer", translation_key="dry_levels", ), ), "OV": ( - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.program", name="Program", - entity_category=EntityCategory.CONFIG, translation_key="programs_ov", ), ), "IH": ( - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.program", name="Program", - entity_category=EntityCategory.CONFIG, translation_key="programs_ih", ), ), "DW": ( - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.program", name="Program", - entity_category=EntityCategory.CONFIG, translation_key="programs_dw", ), - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.temp", name="Temperature", - entity_category=EntityCategory.CONFIG, icon="mdi:thermometer", unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="temperature", ), - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.remainingTime", name="Remaining Time", - entity_category=EntityCategory.CONFIG, icon="mdi:timer", unit_of_measurement=UnitOfTime.MINUTES, translation_key="remaining_time", ), ), "AC": ( - SelectEntityDescription( + HonSelectEntityDescription( key="startProgram.program", name="Program", translation_key="programs_ac", ), - SelectEntityDescription( + HonSelectEntityDescription( key="settings.humanSensingStatus", name="Eco Pilot", icon="mdi:run", @@ -117,17 +118,15 @@ SELECTS = { ), ), "REF": ( - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.program", name="Program", - entity_category=EntityCategory.CONFIG, translation_key="programs_ref", ), - SelectEntityDescription( + HonConfigSelectEntityDescription( key="startProgram.zone", name="Zone", icon="mdi:radiobox-marked", - entity_category=EntityCategory.CONFIG, translation_key="ref_zones", ), ), @@ -142,18 +141,22 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non for description in SELECTS.get(device.appliance_type, []): if description.key not in device.available_settings: continue - entity = HonSelectEntity(hass, entry, device, description) + if isinstance(description, HonSelectEntityDescription): + entity = HonSelectEntity(hass, entry, device, description) + elif isinstance(description, HonConfigSelectEntityDescription): + entity = HonConfigSelectEntity(hass, entry, device, description) + else: + continue await entity.coordinator.async_config_entry_first_refresh() entities.append(entity) async_add_entities(entities) class HonSelectEntity(HonEntity, SelectEntity): - def __init__(self, hass, entry, device: HonAppliance, description) -> None: - super().__init__(hass, entry, device) + entity_description: HonSelectEntityDescription - self.entity_description = description - self._attr_unique_id = f"{super().unique_id}{description.key}" + def __init__(self, hass, entry, device: HonAppliance, description) -> None: + super().__init__(hass, entry, device, description) if not (setting := self._device.settings.get(description.key)): self._attr_options: list[str] = [] @@ -171,10 +174,8 @@ class HonSelectEntity(HonEntity, SelectEntity): async def async_select_option(self, option: str) -> None: self._device.settings[self.entity_description.key].value = option - if "settings." in self.entity_description.key: - await self._device.commands["settings"].send() - elif self._device.appliance_type in ["AC"]: - await self._device.commands["startProgram"].send() + command = self.entity_description.key.split(".")[0] + await self._device.commands[command].send() await self.coordinator.async_refresh() @callback @@ -193,12 +194,21 @@ class HonSelectEntity(HonEntity, SelectEntity): @property def available(self) -> bool: """Return True if entity is available.""" - if self.entity_category == EntityCategory.CONFIG: - return super().available - else: - return ( - super().available - and self._device.get("remoteCtrValid", "1") == "1" - and self._device.get("attributes.lastConnEvent.category") - != "DISCONNECTED" - ) + return ( + super().available + and self._device.get("remoteCtrValid", "1") == "1" + and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" + ) + + +class HonConfigSelectEntity(HonSelectEntity): + entity_description: HonConfigSelectEntityDescription + + async def async_select_option(self, option: str) -> None: + self._device.settings[self.entity_description.key].value = option + await self.coordinator.async_refresh() + + @property + def available(self) -> bool: + """Return True if entity is available.""" + return super(SelectEntity, self).available diff --git a/custom_components/hon/sensor.py b/custom_components/hon/sensor.py index 6ddfc62..8ceba4a 100644 --- a/custom_components/hon/sensor.py +++ b/custom_components/hon/sensor.py @@ -1,4 +1,5 @@ import logging +from dataclasses import dataclass from homeassistant.components.sensor import ( SensorEntity, @@ -20,7 +21,6 @@ from homeassistant.const import ( from homeassistant.core import callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.typing import StateType - from . import const from .const import DOMAIN from .hon import HonEntity, unique_entities @@ -28,9 +28,19 @@ from .hon import HonEntity, unique_entities _LOGGER = logging.getLogger(__name__) +@dataclass +class HonConfigSensorEntityDescription(SensorEntityDescription): + entity_category: EntityCategory = EntityCategory.CONFIG + + +@dataclass +class HonSensorEntityDescription(SensorEntityDescription): + pass + + SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { "WM": ( - SensorEntityDescription( + HonSensorEntityDescription( key="prPhase", name="Program Phase", icon="mdi:washing-machine", @@ -38,7 +48,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="program_phases_wm", options=list(const.WASHING_PR_PHASE), ), - SensorEntityDescription( + HonSensorEntityDescription( key="totalElectricityUsed", name="Total Power", device_class=SensorDeviceClass.ENERGY, @@ -46,7 +56,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, translation_key="energy_total", ), - SensorEntityDescription( + HonSensorEntityDescription( key="totalWaterUsed", name="Total Water", device_class=SensorDeviceClass.WATER, @@ -54,14 +64,14 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfVolume.LITERS, translation_key="water_total", ), - SensorEntityDescription( + HonSensorEntityDescription( key="totalWashCycle", name="Total Wash Cycle", state_class=SensorStateClass.TOTAL_INCREASING, icon="mdi:counter", translation_key="cycles_total", ), - SensorEntityDescription( + HonSensorEntityDescription( key="currentElectricityUsed", name="Current Electricity Used", state_class=SensorStateClass.MEASUREMENT, @@ -70,23 +80,22 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { icon="mdi:lightning-bolt", translation_key="energy_current", ), - SensorEntityDescription( + HonSensorEntityDescription( key="currentWaterUsed", name="Current Water Used", state_class=SensorStateClass.MEASUREMENT, icon="mdi:water", translation_key="water_current", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.weight", name="Suggested weight", state_class=SensorStateClass.MEASUREMENT, - entity_category=EntityCategory.CONFIG, native_unit_of_measurement=UnitOfMass.KILOGRAMS, icon="mdi:weight-kilogram", translation_key="suggested_load", ), - SensorEntityDescription( + HonSensorEntityDescription( key="machMode", name="Machine Status", icon="mdi:information", @@ -94,10 +103,10 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="washing_modes", options=list(const.MACH_MODE), ), - SensorEntityDescription( + HonSensorEntityDescription( key="errors", name="Error", icon="mdi:math-log", translation_key="errors" ), - SensorEntityDescription( + HonSensorEntityDescription( key="remainingTimeMM", name="Remaining Time", icon="mdi:timer", @@ -105,7 +114,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="remaining_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="spinSpeed", name="Spin Speed", icon="mdi:speedometer", @@ -113,53 +122,48 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=REVOLUTIONS_PER_MINUTE, translation_key="spin_speed", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.energyLabel", name="Energy Label", icon="mdi:lightning-bolt-circle", state_class=SensorStateClass.MEASUREMENT, - entity_category=EntityCategory.CONFIG, translation_key="energy_label", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.liquidDetergentDose", name="Liquid Detergent Dose", icon="mdi:cup-water", - entity_category=EntityCategory.CONFIG, translation_key="det_liquid", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.powderDetergentDose", name="Powder Detergent Dose", icon="mdi:cup", - entity_category=EntityCategory.CONFIG, translation_key="det_dust", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.remainingTime", name="Remaining Time", icon="mdi:timer", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfTime.MINUTES, - entity_category=EntityCategory.CONFIG, translation_key="remaining_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="dirtyLevel", name="Dirt level", icon="mdi:liquid-spot", translation_key="dirt_level", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.suggestedLoadW", name="Suggested Load", icon="mdi:weight-kilogram", - entity_category=EntityCategory.CONFIG, state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfMass.KILOGRAMS, translation_key="suggested_load", ), - SensorEntityDescription( + HonSensorEntityDescription( key="temp", name="Current Temperature", icon="mdi:thermometer", @@ -169,7 +173,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), ), "TD": ( - SensorEntityDescription( + HonSensorEntityDescription( key="machMode", name="Machine Status", icon="mdi:information", @@ -177,10 +181,10 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="washing_modes", options=list(const.MACH_MODE), ), - SensorEntityDescription( + HonSensorEntityDescription( key="errors", name="Error", icon="mdi:math-log", translation_key="errors" ), - SensorEntityDescription( + HonSensorEntityDescription( key="remainingTimeMM", name="Remaining Time", icon="mdi:timer", @@ -188,7 +192,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="remaining_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="delayTime", name="Start Time", icon="mdi:clock-start", @@ -196,7 +200,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="delay_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="programName", name="Program", icon="mdi:tumble-dryer", @@ -204,7 +208,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="programs_td", options=const.PROGRAMS_TD, ), - SensorEntityDescription( + HonSensorEntityDescription( key="prPhase", name="Program Phase", icon="mdi:washing-machine", @@ -212,7 +216,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="program_phases_td", options=list(const.TUMBLE_DRYER_PR_PHASE), ), - SensorEntityDescription( + HonSensorEntityDescription( key="dryLevel", name="Dry level", icon="mdi:hair-dryer", @@ -220,58 +224,54 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="dry_levels", options=list(const.TUMBLE_DRYER_DRY_LEVEL), ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempLevel", name="Temperature level", icon="mdi:thermometer", translation_key="tumbledryertemplevel", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.suggestedLoadD", name="Suggested Load", icon="mdi:weight-kilogram", - entity_category=EntityCategory.CONFIG, state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfMass.KILOGRAMS, translation_key="suggested_load", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.energyLabel", name="Energy Label", icon="mdi:lightning-bolt-circle", state_class=SensorStateClass.MEASUREMENT, - entity_category=EntityCategory.CONFIG, translation_key="energy_label", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.steamLevel", name="Steam level", icon="mdi:smoke", - entity_category=EntityCategory.CONFIG, translation_key="steam_level", ), - SensorEntityDescription( + HonSensorEntityDescription( key="steamLevel", name="Steam level", icon="mdi:smoke", translation_key="steam_level", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="steamType", name="Steam Type", icon="mdi:weather-dust", - entity_category=EntityCategory.CONFIG, ), ), "OV": ( - SensorEntityDescription( + HonSensorEntityDescription( key="remainingTimeMM", name="Remaining Time", icon="mdi:timer", native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="remaining_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="delayTime", name="Start Time", icon="mdi:clock-start", @@ -279,13 +279,13 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="delay_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="temp", name="Temperature", icon="mdi:thermometer", translation_key="temperature", ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempSel", name="Temperature Selected", icon="mdi:thermometer", @@ -293,14 +293,14 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), ), "IH": ( - SensorEntityDescription( + HonSensorEntityDescription( key="remainingTimeMM", name="Remaining Time", icon="mdi:timer", native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="remaining_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="temp", name="Temperature", icon="mdi:thermometer", @@ -308,10 +308,10 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="temperature", ), - SensorEntityDescription( + HonSensorEntityDescription( key="errors", name="Error", icon="mdi:math-log", translation_key="errors" ), - SensorEntityDescription( + HonSensorEntityDescription( key="power", name="Power", icon="mdi:lightning-bolt", @@ -320,57 +320,51 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), ), "DW": ( - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.ecoIndex", name="Eco Index", icon="mdi:sprout", state_class=SensorStateClass.MEASUREMENT, - entity_category=EntityCategory.CONFIG, ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.waterEfficiency", name="Water Efficiency", icon="mdi:water", state_class=SensorStateClass.MEASUREMENT, - entity_category=EntityCategory.CONFIG, translation_key="water_efficiency", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.waterSaving", name="Water Saving", icon="mdi:water-percent", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=PERCENTAGE, - entity_category=EntityCategory.CONFIG, translation_key="water_saving", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.temp", name="Temperature", icon="mdi:thermometer", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - entity_category=EntityCategory.CONFIG, translation_key="temperature", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.energyLabel", name="Energy Label", icon="mdi:lightning-bolt-circle", state_class=SensorStateClass.MEASUREMENT, - entity_category=EntityCategory.CONFIG, translation_key="energy_label", ), - SensorEntityDescription( + HonConfigSensorEntityDescription( key="startProgram.remainingTime", name="Time", icon="mdi:timer", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfTime.MINUTES, - entity_category=EntityCategory.CONFIG, translation_key="duration", ), - SensorEntityDescription( + HonSensorEntityDescription( key="machMode", name="Machine Status", icon="mdi:information", @@ -378,10 +372,10 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { translation_key="washing_modes", options=list(const.MACH_MODE), ), - SensorEntityDescription( + HonSensorEntityDescription( key="errors", name="Error", icon="mdi:math-log", translation_key="errors" ), - SensorEntityDescription( + HonSensorEntityDescription( key="remainingTimeMM", name="Remaining Time", icon="mdi:timer", @@ -389,7 +383,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTime.MINUTES, translation_key="remaining_time", ), - SensorEntityDescription( + HonSensorEntityDescription( key="prPhase", name="Program Phase", icon="mdi:washing-machine", @@ -399,7 +393,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), ), "AC": ( - SensorEntityDescription( + HonSensorEntityDescription( key="tempAirOutdoor", name="Air Temperature Outdoor", icon="mdi:thermometer", @@ -407,7 +401,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempCoilerIndoor", name="Coiler Temperature Indoor", icon="mdi:thermometer", @@ -415,7 +409,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempCoilerOutdoor", name="Coiler Temperature Outside", icon="mdi:thermometer", @@ -423,7 +417,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempDefrostOutdoor", name="Defrost Temperature Outdoor", icon="mdi:thermometer", @@ -431,7 +425,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempInAirOutdoor", name="In Air Temperature Outdoor", icon="mdi:thermometer", @@ -439,7 +433,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempIndoor", name="Indoor Temperature", icon="mdi:thermometer", @@ -447,7 +441,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempOutdoor", name="Outdoor Temperature", icon="mdi:thermometer", @@ -455,7 +449,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempSel", name="Selected Temperature", icon="mdi:thermometer", @@ -465,7 +459,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { ), ), "REF": ( - SensorEntityDescription( + HonSensorEntityDescription( key="humidityEnv", name="Room Humidity", icon="mdi:water-percent", @@ -474,7 +468,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { state_class=SensorStateClass.MEASUREMENT, translation_key="humidity", ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempEnv", name="Room Temperature", icon="mdi:home-thermometer-outline", @@ -483,7 +477,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="room_temperature", ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempZ1", name="Temperature Fridge", icon="mdi:thermometer", @@ -492,7 +486,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="fridge_temp", ), - SensorEntityDescription( + HonSensorEntityDescription( key="tempZ2", name="Temperature Freezer", icon="mdi:snowflake-thermometer", @@ -501,7 +495,7 @@ SENSORS: dict[str, tuple[SensorEntityDescription, ...]] = { native_unit_of_measurement=UnitOfTemperature.CELSIUS, translation_key="freezer_temp", ), - SensorEntityDescription( + HonSensorEntityDescription( key="errors", name="Error", icon="mdi:math-log", translation_key="errors" ), ), @@ -513,11 +507,16 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non entities = [] for device in hass.data[DOMAIN][entry.unique_id].appliances: for description in SENSORS.get(device.appliance_type, []): - if not device.get(description.key) and not device.settings.get( - description.key - ): + if isinstance(description, HonSensorEntityDescription): + if not device.get(description.key): + continue + entity = HonSensorEntity(hass, entry, device, description) + elif isinstance(description, HonConfigSensorEntityDescription): + if description.key not in device.available_settings: + continue + entity = HonConfigSensorEntity(hass, entry, device, description) + else: continue - entity = HonSensorEntity(hass, entry, device, description) await entity.coordinator.async_config_entry_first_refresh() entities.append(entity) @@ -525,18 +524,7 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non class HonSensorEntity(HonEntity, SensorEntity): - def __init__(self, hass, entry, device, description) -> None: - super().__init__(hass, entry, device) - - self.entity_description = description - self._attr_unique_id = f"{super().unique_id}{description.key}" - - @property - def native_value(self) -> StateType: - value = self._device.get(self.entity_description.key, "") - if not value and self.entity_description.state_class is not None: - return 0 - return value + entity_description: HonSensorEntityDescription @callback def _handle_coordinator_update(self): @@ -545,3 +533,22 @@ class HonSensorEntity(HonEntity, SensorEntity): self._attr_native_value = 0 self._attr_native_value = value self.async_write_ha_state() + + +class HonConfigSensorEntity(HonEntity, SensorEntity): + entity_description: HonConfigSensorEntityDescription + + @callback + def _handle_coordinator_update(self): + value = self._device.settings.get(self.entity_description.key, None) + if self.entity_description.state_class is not None: + if value and value.value: + print(value.value, type(value.value)) + self._attr_native_value = ( + float(value.value) if "." in str(value.value) else int(value.value) + ) + else: + self._attr_native_value = 0 + else: + self._attr_native_value = value.value + self.async_write_ha_state() diff --git a/custom_components/hon/switch.py b/custom_components/hon/switch.py index 56ea512..9c0e9e1 100644 --- a/custom_components/hon/switch.py +++ b/custom_components/hon/switch.py @@ -6,7 +6,6 @@ from homeassistant.components.switch import SwitchEntityDescription, SwitchEntit from homeassistant.config_entries import ConfigEntry from homeassistant.const import EntityCategory from homeassistant.core import callback -from pyhon.appliance import HonAppliance from pyhon.parameter.base import HonParameter from pyhon.parameter.range import HonParameterRange @@ -20,19 +19,27 @@ _LOGGER = logging.getLogger(__name__) class HonSwitchEntityDescriptionMixin: turn_on_key: str = "" turn_off_key: str = "" - status_key: str = "" @dataclass -class HonSwitchEntityDescription( +class HonControlSwitchEntityDescription( HonSwitchEntityDescriptionMixin, SwitchEntityDescription ): pass +class HonSwitchEntityDescription(SwitchEntityDescription): + pass + + +@dataclass +class HonConfigSwitchEntityDescription(SwitchEntityDescription): + entity_category: EntityCategory = EntityCategory.CONFIG + + SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { "WM": ( - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="active", name="Washing Machine", icon="mdi:washing-machine", @@ -40,7 +47,7 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { turn_off_key="stopProgram", translation_key="washing_machine", ), - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="pause", name="Pause Washing Machine", icon="mdi:pause", @@ -48,79 +55,69 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { turn_off_key="resumeProgram", translation_key="pause", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.delayStatus", name="Delay Status", icon="mdi:timer-check", - entity_category=EntityCategory.CONFIG, translation_key="delay_time", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.haier_SoakPrewashSelection", name="Soak Prewash Selection", icon="mdi:tshirt-crew", - entity_category=EntityCategory.CONFIG, translation_key="prewash", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.permanentPressStatus", name="Keep Fresh", - entity_category=EntityCategory.CONFIG, icon="mdi:refresh-circle", translation_key="keep_fresh", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.autoSoftenerStatus", name="Auto Dose Softener", - entity_category=EntityCategory.CONFIG, icon="mdi:teddy-bear", translation_key="auto_dose_softener", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.autoDetergentStatus", name="Auto Dose Detergent", - entity_category=EntityCategory.CONFIG, icon="mdi:cup", translation_key="auto_dose_detergent", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.acquaplus", name="Acqua Plus", - entity_category=EntityCategory.CONFIG, icon="mdi:water-plus", translation_key="acqua_plus", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.extraRinse1", name="Extra Rinse 1", - entity_category=EntityCategory.CONFIG, icon="mdi:numeric-1-box-multiple-outline", translation_key="extra_rinse_1", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.extraRinse2", name="Extra Rinse 2", - entity_category=EntityCategory.CONFIG, icon="mdi:numeric-2-box-multiple-outline", translation_key="extra_rinse_2", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.extraRinse3", name="Extra Rinse 3", - entity_category=EntityCategory.CONFIG, icon="mdi:numeric-3-box-multiple-outline", translation_key="extra_rinse_3", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.goodNight", name="Good Night", icon="mdi:weather-night", - entity_category=EntityCategory.CONFIG, translation_key="good_night", ), ), "TD": ( - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="active", name="Tumble Dryer", icon="mdi:tumble-dryer", @@ -128,7 +125,7 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { turn_off_key="stopProgram", translation_key="tumble_dryer", ), - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="pause", name="Pause Tumble Dryer", icon="mdi:pause", @@ -136,29 +133,26 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { turn_off_key="resumeProgram", translation_key="pause", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.sterilizationStatus", name="Sterilization", icon="mdi:clock-start", - entity_category=EntityCategory.CONFIG, ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.antiCreaseTime", name="Anti-Crease", - entity_category=EntityCategory.CONFIG, icon="mdi:timer", translation_key="anti_crease", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.anticrease", name="Anti-Crease", - entity_category=EntityCategory.CONFIG, icon="mdi:timer", translation_key="anti_crease", ), ), "OV": ( - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="active", name="Oven", icon="mdi:toaster-oven", @@ -166,16 +160,15 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { turn_off_key="stopProgram", translation_key="oven", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.preheatStatus", name="Preheat", icon="mdi:thermometer-chevron-up", - entity_category=EntityCategory.CONFIG, translation_key="preheat", ), ), "WD": ( - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="active", name="Washer Dryer", icon="mdi:washing-machine", @@ -183,7 +176,7 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { turn_off_key="stopProgram", translation_key="washer_dryer", ), - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="pause", name="Pause Washer Dryer", icon="mdi:pause", @@ -193,7 +186,7 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { ), ), "DW": ( - HonSwitchEntityDescription( + HonControlSwitchEntityDescription( key="active", name="Dish Washer", icon="mdi:dishwasher", @@ -201,50 +194,44 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { turn_off_key="stopProgram", translation_key="dish_washer", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.extraDry", name="Extra Dry", icon="mdi:hair-dryer", - entity_category=EntityCategory.CONFIG, translation_key="extra_dry", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.halfLoad", name="Half Load", icon="mdi:fraction-one-half", - entity_category=EntityCategory.CONFIG, translation_key="half_load", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.openDoor", name="Open Door", icon="mdi:door-open", - entity_category=EntityCategory.CONFIG, translation_key="open_door", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.threeInOne", name="Three in One", icon="mdi:numeric-3-box-outline", - entity_category=EntityCategory.CONFIG, translation_key="three_in_one", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.ecoExpress", name="Eco Express", icon="mdi:sprout", - entity_category=EntityCategory.CONFIG, translation_key="eco", ), - HonSwitchEntityDescription( + HonConfigSwitchEntityDescription( key="startProgram.addDish", name="Add Dish", icon="mdi:silverware-fork-knife", - entity_category=EntityCategory.CONFIG, translation_key="add_dish", ), HonSwitchEntityDescription( - key="settings.buzzerDisabled", + key="buzzerDisabled", name="Buzzer Disabled", icon="mdi:volume-off", translation_key="buzzer", @@ -252,65 +239,57 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { ), "AC": ( HonSwitchEntityDescription( - key="settings.10degreeHeatingStatus", - status_key="10degreeHeatingStatus", + key="10degreeHeatingStatus", name="10° Heating", icon="mdi:heat-wave", translation_key="10_degree_heating", ), HonSwitchEntityDescription( - key="settings.echoStatus", - status_key="echoStatus", + key="echoStatus", name="Echo", icon="mdi:account-voice", ), HonSwitchEntityDescription( - key="settings.ecoMode", + key="ecoMode", name="Eco Mode", translation_key="eco_mode", ), HonSwitchEntityDescription( - key="settings.healthMode", - status_key="healthMode", + key="healthMode", name="Health Mode", icon="mdi:medication-outline", ), HonSwitchEntityDescription( - key="settings.muteStatus", - status_key="muteStatus", + key="muteStatus", name="Mute", icon="mdi:volume-off", translation_key="mute_mode", ), HonSwitchEntityDescription( - key="settings.rapidMode", - status_key="rapidMode", + key="rapidMode", name="Rapid Mode", icon="mdi:run-fast", translation_key="rapid_mode", ), HonSwitchEntityDescription( - key="settings.screenDisplayStatus", - status_key="screenDisplayStatus", + key="screenDisplayStatus", name="Screen Display", icon="mdi:monitor-small", ), HonSwitchEntityDescription( - key="settings.selfCleaning56Status", + key="selfCleaning56Status", name="Self Cleaning 56", icon="mdi:air-filter", translation_key="self_clean_56", ), HonSwitchEntityDescription( - key="settings.selfCleaningStatus", - status_key="selfCleaningStatus", + key="selfCleaningStatus", name="Self Cleaning", icon="mdi:air-filter", translation_key="self_clean", ), HonSwitchEntityDescription( - key="settings.silentSleepStatus", - status_key="silentSleepStatus", + key="silentSleepStatus", name="Silent Sleep", icon="mdi:bed", translation_key="silent_mode", @@ -318,29 +297,25 @@ SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = { ), "REF": ( HonSwitchEntityDescription( - key="settings.intelligenceMode", - status_key="intelligenceMode", + key="intelligenceMode", name="Auto-Set Mode", icon="mdi:thermometer-auto", translation_key="auto_set", ), HonSwitchEntityDescription( - key="settings.quickModeZ1", - status_key="quickModeZ1", + key="quickModeZ1", name="Super Freeze", icon="mdi:snowflake-variant", translation_key="super_freeze", ), HonSwitchEntityDescription( - key="settings.quickModeZ2", - status_key="quickModeZ2", + key="quickModeZ2", name="Super Cool", icon="mdi:snowflake", translation_key="super_cool", ), HonSwitchEntityDescription( - key="settings.holidayMode", - status_key="holidayMode", + key="holidayMode", name="Holiday Mode", icon="mdi:palm-tree", translation_key="holiday_mode", @@ -356,19 +331,26 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non entities = [] for device in hass.data[DOMAIN][entry.unique_id].appliances: for description in SWITCHES.get(device.appliance_type, []): - if description.entity_category == EntityCategory.CONFIG: + if isinstance(description, HonConfigSwitchEntityDescription): if description.key not in device.available_settings: continue - else: - if not any( - [ - device.get(description.key) is not None, - description.turn_on_key in list(device.commands), - description.turn_off_key in list(device.commands), - ] + entity = HonConfigSwitchEntity(hass, entry, device, description) + elif isinstance(description, HonControlSwitchEntityDescription): + if not ( + device.get(description.key) is not None + or description.turn_on_key in list(device.commands) + or description.turn_off_key in list(device.commands) ): continue - entity = HonSwitchEntity(hass, entry, device, description) + entity = HonControlSwitchEntity(hass, entry, device, description) + elif isinstance(description, HonSwitchEntityDescription): + if description.key not in device.available_settings or not device.get( + description.key + ): + continue + entity = HonSwitchEntity(hass, entry, device, description) + else: + continue await entity.coordinator.async_config_entry_first_refresh() entities.append(entity) @@ -378,86 +360,100 @@ async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> Non class HonSwitchEntity(HonEntity, SwitchEntity): entity_description: HonSwitchEntityDescription - def __init__( - self, - hass, - entry, - device: HonAppliance, - description: HonSwitchEntityDescription, - ) -> None: - super().__init__(hass, entry, device) - - self.entity_description = description - self._attr_unique_id = f"{super().unique_id}{description.key}" - @property def is_on(self) -> bool | None: """Return True if entity is on.""" - if self.entity_category == EntityCategory.CONFIG: - setting = self._device.settings[self.entity_description.key] - return ( - setting.value == "1" - or hasattr(setting, "min") - and setting.value != setting.min - ) - elif self.entity_description.status_key: - return self._device.get(self.entity_description.status_key, "0") == "1" - return self._device.get(self.entity_description.key, False) + return self._device.get(self.entity_description.key, "0") == "1" async def async_turn_on(self, **kwargs: Any) -> None: - if ( - self.entity_category == EntityCategory.CONFIG - or "settings." in self.entity_description.key - ): - setting = self._device.settings[self.entity_description.key] - if not type(setting) == HonParameter: - setting.value = ( - setting.max if isinstance(setting, HonParameterRange) else "1" - ) - self.async_write_ha_state() - await self.coordinator.async_refresh() - if "settings." in self.entity_description.key: - await self._device.commands["settings"].send() - else: - await self._device.commands[self.entity_description.turn_on_key].send() + setting = self._device.settings[self.entity_description.key] + if type(setting) == HonParameter: + return + setting.value = setting.max if isinstance(setting, HonParameterRange) else "1" + self.async_write_ha_state() + await self._device.commands["settings"].send() + await self.coordinator.async_refresh() async def async_turn_off(self, **kwargs: Any) -> None: - if ( - self.entity_category == EntityCategory.CONFIG - or "settings." in self.entity_description.key - ): - setting = self._device.settings[self.entity_description.key] - if not type(setting) == HonParameter: - setting.value = ( - setting.min if isinstance(setting, HonParameterRange) else "0" - ) - self.async_write_ha_state() - if "settings." in self.entity_description.key: - await self._device.commands["settings"].send() - await self.coordinator.async_refresh() - else: - await self._device.commands[self.entity_description.turn_off_key].send() + setting = self._device.settings[self.entity_description.key] + if type(setting) == HonParameter: + return + setting.value = setting.min if isinstance(setting, HonParameterRange) else "0" + self.async_write_ha_state() + await self._device.commands["settings"].send() + await self.coordinator.async_refresh() @property def available(self) -> bool: """Return True if entity is available.""" - if self.entity_category == EntityCategory.CONFIG: - return super().available - else: - return ( - super().available - and self._device.get("remoteCtrValid", "1") == "1" - and self._device.get("attributes.lastConnEvent.category") - != "DISCONNECTED" - ) + return ( + super().available + and self._device.get("remoteCtrValid", "1") == "1" + and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" + ) @callback def _handle_coordinator_update(self): - if self.entity_description.status_key: - value = self._device.get(self.entity_description.status_key, "0") - elif self.entity_category == EntityCategory.CONFIG: - value = self._device.settings.get(self.entity_description.key, "0") - else: - return + value = self._device.get(self.entity_description.key, "0") + self._attr_state = value == "1" + self.async_write_ha_state() + + +class HonControlSwitchEntity(HonEntity, SwitchEntity): + entity_description: HonControlSwitchEntityDescription + + @property + def is_on(self) -> bool | None: + """Return True if entity is on.""" + return self._device.get(self.entity_description.key, False) + + async def async_turn_on(self, **kwargs: Any) -> None: + await self._device.commands[self.entity_description.turn_on_key].send() + + async def async_turn_off(self, **kwargs: Any) -> None: + await self._device.commands[self.entity_description.turn_off_key].send() + + @property + def available(self) -> bool: + """Return True if entity is available.""" + return ( + super().available + and self._device.get("remoteCtrValid", "1") == "1" + and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" + ) + + +class HonConfigSwitchEntity(HonEntity, SwitchEntity): + entity_description: HonConfigSwitchEntityDescription + + @property + def is_on(self) -> bool | None: + """Return True if entity is on.""" + setting = self._device.settings[self.entity_description.key] + return ( + setting.value == "1" + or hasattr(setting, "min") + and setting.value != setting.min + ) + + async def async_turn_on(self, **kwargs: Any) -> None: + setting = self._device.settings[self.entity_description.key] + if type(setting) == HonParameter: + return + setting.value = setting.max if isinstance(setting, HonParameterRange) else "1" + self.async_write_ha_state() + await self.coordinator.async_refresh() + + async def async_turn_off(self, **kwargs: Any) -> None: + setting = self._device.settings[self.entity_description.key] + if type(setting) == HonParameter: + return + setting.value = setting.min if isinstance(setting, HonParameterRange) else "0" + self.async_write_ha_state() + await self.coordinator.async_refresh() + + @callback + def _handle_coordinator_update(self): + value = self._device.settings.get(self.entity_description.key, "0") self._attr_state = value == "1" self.async_write_ha_state()