hOn/custom_components/hon/switch.py

500 lines
17 KiB
Python
Raw Normal View History

2023-04-08 04:44:47 +02:00
import logging
2023-03-05 00:54:57 +01:00
from dataclasses import dataclass
2023-06-08 20:01:55 +02:00
from datetime import datetime, timedelta
2023-03-05 00:54:57 +01:00
from typing import Any
2023-05-25 00:52:54 +02:00
from homeassistant.components.switch import SwitchEntityDescription, SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import callback
2023-06-22 13:31:26 +02:00
from homeassistant.helpers.entity import EntityCategory
2023-05-21 20:51:20 +02:00
from pyhon.parameter.base import HonParameter
2023-04-16 13:55:08 +02:00
from pyhon.parameter.range import HonParameterRange
2023-03-05 00:54:57 +01:00
from .const import DOMAIN
2023-05-25 01:30:33 +02:00
from .hon import HonEntity, unique_entities
2023-03-05 00:54:57 +01:00
2023-04-08 04:44:47 +02:00
_LOGGER = logging.getLogger(__name__)
2023-03-05 00:54:57 +01:00
2023-04-08 06:15:33 +02:00
2023-03-05 00:54:57 +01:00
@dataclass
class HonSwitchEntityDescriptionMixin:
turn_on_key: str = ""
turn_off_key: str = ""
@dataclass
2023-05-28 00:30:08 +02:00
class HonControlSwitchEntityDescription(
2023-04-10 19:51:16 +02:00
HonSwitchEntityDescriptionMixin, SwitchEntityDescription
):
2023-03-05 00:54:57 +01:00
pass
2023-05-28 00:30:08 +02:00
class HonSwitchEntityDescription(SwitchEntityDescription):
pass
@dataclass
class HonConfigSwitchEntityDescription(SwitchEntityDescription):
entity_category: EntityCategory = EntityCategory.CONFIG
2023-03-05 00:54:57 +01:00
SWITCHES: dict[str, tuple[HonSwitchEntityDescription, ...]] = {
"WM": (
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-03-08 23:00:55 +01:00
key="active",
name="Washing Machine",
icon="mdi:washing-machine",
2023-03-05 00:54:57 +01:00
turn_on_key="startProgram",
turn_off_key="stopProgram",
2023-04-23 02:01:14 +02:00
translation_key="washing_machine",
2023-03-05 00:54:57 +01:00
),
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-03-08 23:00:55 +01:00
key="pause",
name="Pause Washing Machine",
icon="mdi:pause",
turn_on_key="pauseProgram",
turn_off_key="resumeProgram",
2023-04-23 02:01:14 +02:00
translation_key="pause",
2023-03-08 23:00:55 +01:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-03-05 00:54:57 +01:00
key="startProgram.delayStatus",
name="Delay Status",
2023-03-08 23:00:55 +01:00
icon="mdi:timer-check",
2023-04-24 21:38:05 +02:00
translation_key="delay_time",
2023-03-05 00:54:57 +01:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-03-05 00:54:57 +01:00
key="startProgram.haier_SoakPrewashSelection",
name="Soak Prewash Selection",
2023-03-08 23:00:55 +01:00
icon="mdi:tshirt-crew",
2023-04-23 02:01:14 +02:00
translation_key="prewash",
2023-03-05 00:54:57 +01:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-05-13 01:20:02 +02:00
key="startProgram.permanentPressStatus",
name="Keep Fresh",
icon="mdi:refresh-circle",
translation_key="keep_fresh",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-05-13 01:20:02 +02:00
key="startProgram.autoSoftenerStatus",
name="Auto Dose Softener",
icon="mdi:teddy-bear",
translation_key="auto_dose_softener",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.autoDetergentStatus",
2023-05-13 01:20:02 +02:00
name="Auto Dose Detergent",
icon="mdi:cup",
2023-05-13 01:20:02 +02:00
translation_key="auto_dose_detergent",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.acquaplus",
name="Acqua Plus",
icon="mdi:water-plus",
translation_key="acqua_plus",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.extraRinse1",
name="Extra Rinse 1",
icon="mdi:numeric-1-box-multiple-outline",
translation_key="extra_rinse_1",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.extraRinse2",
name="Extra Rinse 2",
icon="mdi:numeric-2-box-multiple-outline",
translation_key="extra_rinse_2",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.extraRinse3",
name="Extra Rinse 3",
icon="mdi:numeric-3-box-multiple-outline",
translation_key="extra_rinse_3",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.goodNight",
name="Good Night",
icon="mdi:weather-night",
translation_key="good_night",
),
2023-03-05 00:54:57 +01:00
),
2023-03-21 13:01:41 +01:00
"TD": (
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-03-21 13:01:41 +01:00
key="active",
name="Tumble Dryer",
icon="mdi:tumble-dryer",
turn_on_key="startProgram",
turn_off_key="stopProgram",
2023-04-23 02:01:14 +02:00
translation_key="tumble_dryer",
2023-03-21 13:01:41 +01:00
),
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-03-21 13:01:41 +01:00
key="pause",
name="Pause Tumble Dryer",
icon="mdi:pause",
turn_on_key="pauseProgram",
turn_off_key="resumeProgram",
2023-04-23 02:01:14 +02:00
translation_key="pause",
2023-03-21 13:01:41 +01:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.sterilizationStatus",
name="Sterilization",
icon="mdi:clock-start",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.antiCreaseTime",
name="Anti-Crease",
icon="mdi:timer",
translation_key="anti_crease",
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
key="startProgram.anticrease",
name="Anti-Crease",
icon="mdi:timer",
2023-04-23 02:01:14 +02:00
translation_key="anti_crease",
),
2023-03-21 13:01:41 +01:00
),
2023-04-16 16:59:37 +02:00
"OV": (
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-04-16 16:59:37 +02:00
key="active",
name="Oven",
icon="mdi:toaster-oven",
turn_on_key="startProgram",
turn_off_key="stopProgram",
2023-04-23 02:01:14 +02:00
translation_key="oven",
2023-04-16 16:59:37 +02:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-04-19 19:31:45 +02:00
key="startProgram.preheatStatus",
name="Preheat",
icon="mdi:thermometer-chevron-up",
2023-04-23 02:01:14 +02:00
translation_key="preheat",
2023-04-19 19:31:45 +02:00
),
2023-04-16 16:59:37 +02:00
),
2023-04-08 04:44:47 +02:00
"WD": (
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-04-08 04:44:47 +02:00
key="active",
2023-05-07 16:39:45 +02:00
name="Washer Dryer",
2023-04-08 04:44:47 +02:00
icon="mdi:washing-machine",
turn_on_key="startProgram",
turn_off_key="stopProgram",
2023-04-23 02:01:14 +02:00
translation_key="washer_dryer",
2023-04-08 04:44:47 +02:00
),
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-04-08 04:44:47 +02:00
key="pause",
2023-05-07 16:39:45 +02:00
name="Pause Washer Dryer",
2023-04-08 04:44:47 +02:00
icon="mdi:pause",
turn_on_key="pauseProgram",
turn_off_key="resumeProgram",
2023-04-23 02:01:14 +02:00
translation_key="pause",
2023-04-08 04:44:47 +02:00
),
),
2023-04-16 21:46:17 +02:00
"DW": (
2023-05-28 00:30:08 +02:00
HonControlSwitchEntityDescription(
2023-04-16 21:46:17 +02:00
key="active",
name="Dish Washer",
icon="mdi:dishwasher",
turn_on_key="startProgram",
turn_off_key="stopProgram",
2023-04-23 02:01:14 +02:00
translation_key="dish_washer",
2023-04-16 21:46:17 +02:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-04-16 21:46:17 +02:00
key="startProgram.extraDry",
name="Extra Dry",
icon="mdi:hair-dryer",
2023-04-23 02:01:14 +02:00
translation_key="extra_dry",
2023-04-16 21:46:17 +02:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-04-16 21:46:17 +02:00
key="startProgram.halfLoad",
name="Half Load",
icon="mdi:fraction-one-half",
2023-04-23 02:01:14 +02:00
translation_key="half_load",
2023-04-16 21:46:17 +02:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-04-16 21:46:17 +02:00
key="startProgram.openDoor",
name="Open Door",
icon="mdi:door-open",
2023-04-23 02:01:14 +02:00
translation_key="open_door",
2023-04-16 21:46:17 +02:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-04-16 21:46:17 +02:00
key="startProgram.threeInOne",
name="Three in One",
icon="mdi:numeric-3-box-outline",
2023-04-23 02:01:14 +02:00
translation_key="three_in_one",
2023-04-16 21:46:17 +02:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-04-16 21:46:17 +02:00
key="startProgram.ecoExpress",
name="Eco Express",
icon="mdi:sprout",
2023-04-23 02:01:14 +02:00
translation_key="eco",
2023-04-16 21:46:17 +02:00
),
2023-05-28 00:30:08 +02:00
HonConfigSwitchEntityDescription(
2023-04-16 21:46:17 +02:00
key="startProgram.addDish",
name="Add Dish",
icon="mdi:silverware-fork-knife",
2023-04-23 02:01:14 +02:00
translation_key="add_dish",
2023-04-16 21:46:17 +02:00
),
2023-05-14 03:17:58 +02:00
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="buzzerDisabled",
2023-05-14 03:17:58 +02:00
name="Buzzer Disabled",
icon="mdi:volume-off",
translation_key="buzzer",
),
2023-04-16 21:46:17 +02:00
),
2023-04-26 23:57:44 +02:00
"AC": (
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="10degreeHeatingStatus",
2023-04-26 23:57:44 +02:00
name="10° Heating",
2023-05-08 02:05:04 +02:00
icon="mdi:heat-wave",
2023-04-26 23:57:44 +02:00
translation_key="10_degree_heating",
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="echoStatus",
2023-04-26 23:57:44 +02:00
name="Echo",
2023-05-08 02:05:04 +02:00
icon="mdi:account-voice",
2023-04-26 23:57:44 +02:00
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="ecoMode",
2023-04-26 23:57:44 +02:00
name="Eco Mode",
translation_key="eco_mode",
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="healthMode",
2023-04-26 23:57:44 +02:00
name="Health Mode",
2023-05-08 02:05:04 +02:00
icon="mdi:medication-outline",
2023-04-26 23:57:44 +02:00
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="muteStatus",
2023-06-22 13:31:26 +02:00
name="Silent Mode",
2023-05-08 02:05:04 +02:00
icon="mdi:volume-off",
2023-06-22 13:31:26 +02:00
translation_key="silent_mode",
2023-04-26 23:57:44 +02:00
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="rapidMode",
2023-04-26 23:57:44 +02:00
name="Rapid Mode",
2023-05-08 02:05:04 +02:00
icon="mdi:run-fast",
2023-04-26 23:57:44 +02:00
translation_key="rapid_mode",
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="screenDisplayStatus",
2023-04-26 23:57:44 +02:00
name="Screen Display",
2023-05-08 02:05:04 +02:00
icon="mdi:monitor-small",
2023-04-26 23:57:44 +02:00
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="selfCleaning56Status",
2023-04-26 23:57:44 +02:00
name="Self Cleaning 56",
2023-05-08 02:05:04 +02:00
icon="mdi:air-filter",
2023-04-26 23:57:44 +02:00
translation_key="self_clean_56",
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="selfCleaningStatus",
2023-04-26 23:57:44 +02:00
name="Self Cleaning",
2023-05-08 02:05:04 +02:00
icon="mdi:air-filter",
2023-04-26 23:57:44 +02:00
translation_key="self_clean",
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="silentSleepStatus",
2023-06-22 13:31:26 +02:00
name="Night Mode",
2023-05-08 02:05:04 +02:00
icon="mdi:bed",
2023-06-22 13:31:26 +02:00
translation_key="night_mode",
2023-04-26 23:57:44 +02:00
),
),
"REF": (
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="intelligenceMode",
name="Auto-Set Mode",
icon="mdi:thermometer-auto",
translation_key="auto_set",
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="quickModeZ1",
name="Super Freeze",
icon="mdi:snowflake-variant",
translation_key="super_freeze",
),
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="quickModeZ2",
name="Super Cool",
icon="mdi:snowflake",
translation_key="super_cool",
),
2023-05-21 20:51:20 +02:00
HonSwitchEntityDescription(
2023-05-28 00:30:08 +02:00
key="holidayMode",
2023-05-21 20:51:20 +02:00
name="Holiday Mode",
icon="mdi:palm-tree",
translation_key="holiday_mode",
),
),
2023-06-10 06:44:19 +02:00
"WC": (
HonSwitchEntityDescription(
key="sabbathStatus",
name="Sabbath Mode",
icon="mdi:palm-tree",
translation_key="holiday_mode",
),
),
2023-06-21 00:59:00 +02:00
"AP": (
HonSwitchEntityDescription(
key="touchToneStatus",
name="Touch Tone",
2023-07-01 01:45:32 +02:00
translation_key="touch_tone",
2023-06-21 00:59:00 +02:00
),
HonSwitchEntityDescription(
key="lockStatus",
name="Lock Status",
2023-07-01 01:45:32 +02:00
translation_key="mode",
2023-06-21 00:59:00 +02:00
),
),
2023-03-05 00:54:57 +01:00
}
2023-05-07 16:39:45 +02:00
SWITCHES["WD"] = unique_entities(SWITCHES["WD"], SWITCHES["WM"])
SWITCHES["WD"] = unique_entities(SWITCHES["WD"], SWITCHES["TD"])
2023-03-05 00:54:57 +01:00
async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities) -> None:
2023-05-25 01:30:33 +02:00
entities = []
for device in hass.data[DOMAIN][entry.unique_id].appliances:
for description in SWITCHES.get(device.appliance_type, []):
2023-05-28 00:30:08 +02:00
if isinstance(description, HonConfigSwitchEntityDescription):
2023-05-25 01:30:33 +02:00
if description.key not in device.available_settings:
continue
2023-05-28 00:30:08 +02:00
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 = HonControlSwitchEntity(hass, entry, device, description)
elif isinstance(description, HonSwitchEntityDescription):
2023-05-28 07:50:59 +02:00
if (
f"settings.{description.key}" not in device.available_settings
2023-06-13 00:14:51 +02:00
or device.get(description.key) is None
2023-05-25 01:30:33 +02:00
):
continue
2023-05-28 00:30:08 +02:00
entity = HonSwitchEntity(hass, entry, device, description)
else:
continue
2023-05-25 01:30:33 +02:00
await entity.coordinator.async_config_entry_first_refresh()
entities.append(entity)
2023-03-05 00:54:57 +01:00
2023-05-25 01:30:33 +02:00
async_add_entities(entities)
2023-03-05 00:54:57 +01:00
class HonSwitchEntity(HonEntity, SwitchEntity):
entity_description: HonSwitchEntityDescription
2023-05-28 00:30:08 +02:00
@property
def is_on(self) -> bool | None:
"""Return True if entity is on."""
2023-06-13 00:14:51 +02:00
return self._device.get(self.entity_description.key, 0) == 1
2023-05-19 01:27:44 +02:00
2023-05-28 00:30:08 +02:00
async def async_turn_on(self, **kwargs: Any) -> None:
2023-05-28 07:50:59 +02:00
setting = self._device.settings[f"settings.{self.entity_description.key}"]
2023-05-28 00:30:08 +02:00
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:
2023-05-28 07:50:59 +02:00
setting = self._device.settings[f"settings.{self.entity_description.key}"]
2023-05-28 00:30:08 +02:00
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."""
return (
super().available
2023-06-13 00:14:51 +02:00
and int(self._device.get("remoteCtrValid", 1)) == 1
2023-05-28 00:30:08 +02:00
and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED"
)
@callback
2023-06-08 20:01:55 +02:00
def _handle_coordinator_update(self, update=True) -> None:
2023-06-13 00:14:51 +02:00
value = self._device.get(self.entity_description.key, 0)
self._attr_state = value == 1
2023-06-08 20:01:55 +02:00
if update:
self.async_write_ha_state()
2023-05-28 00:30:08 +02:00
class HonControlSwitchEntity(HonEntity, SwitchEntity):
entity_description: HonControlSwitchEntityDescription
2023-03-05 00:54:57 +01:00
@property
def is_on(self) -> bool | None:
"""Return True if entity is on."""
2023-03-08 23:00:55 +01:00
return self._device.get(self.entity_description.key, False)
2023-03-05 00:54:57 +01:00
async def async_turn_on(self, **kwargs: Any) -> None:
2023-05-28 00:30:08 +02:00
await self._device.commands[self.entity_description.turn_on_key].send()
2023-06-08 20:01:55 +02:00
self._device.attributes[self.entity_description.key] = True
self.async_write_ha_state()
2023-03-05 00:54:57 +01:00
async def async_turn_off(self, **kwargs: Any) -> None:
2023-05-28 00:30:08 +02:00
await self._device.commands[self.entity_description.turn_off_key].send()
2023-06-08 20:01:55 +02:00
self._device.attributes[self.entity_description.key] = False
self.async_write_ha_state()
@property
def available(self) -> bool:
"""Return True if entity is available."""
2023-05-28 00:30:08 +02:00
return (
super().available
2023-06-13 00:14:51 +02:00
and int(self._device.get("remoteCtrValid", 1)) == 1
2023-05-28 00:30:08 +02:00
and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED"
)
2023-06-08 20:01:55 +02:00
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the optional state attributes."""
result = {}
2023-06-13 00:14:51 +02:00
if remaining_time := self._device.get("remainingTimeMM", 0):
delay_time = self._device.get("delayTime", 0)
2023-06-08 20:01:55 +02:00
result["start_time"] = datetime.now() + timedelta(minutes=delay_time)
result["end_time"] = datetime.now() + timedelta(
minutes=delay_time + remaining_time
)
return result
2023-05-28 00:30:08 +02:00
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 (
2023-05-28 07:50:59 +02:00
setting.value != setting.min
if hasattr(setting, "min")
else setting.value == "1"
2023-05-28 00:30:08 +02:00
)
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()
2023-05-17 00:01:33 +02:00
@callback
2023-06-08 20:01:55 +02:00
def _handle_coordinator_update(self, update=True) -> None:
2023-05-28 00:30:08 +02:00
value = self._device.settings.get(self.entity_description.key, "0")
2023-05-17 00:01:33 +02:00
self._attr_state = value == "1"
2023-06-08 20:01:55 +02:00
if update:
self.async_write_ha_state()