mirror of
https://github.com/Andre0512/hon.git
synced 2026-02-24 11:02:17 +00:00
Replace deprecated HomeAssistantType with HomeAssistant from homeassistant.core. HomeAssistantType was removed in newer Home Assistant versions, causing ImportError. This updates all imports from homeassistant.helpers.typing to homeassistant.core. Fixes compatibility with Home Assistant 2026.x and later versions. Files updated: - __init__.py - binary_sensor.py - button.py - climate.py - entity.py - fan.py - light.py - lock.py - number.py - select.py - sensor.py - switch.py
427 lines
15 KiB
Python
427 lines
15 KiB
Python
import logging
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from homeassistant.components.climate import (
|
|
ClimateEntity,
|
|
ClimateEntityDescription,
|
|
)
|
|
from homeassistant.components.climate.const import (
|
|
SWING_OFF,
|
|
SWING_BOTH,
|
|
SWING_VERTICAL,
|
|
SWING_HORIZONTAL,
|
|
ClimateEntityFeature,
|
|
HVACMode,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import (
|
|
ATTR_TEMPERATURE,
|
|
UnitOfTemperature,
|
|
)
|
|
from homeassistant.core import callback
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.core import HomeAssistant
|
|
from pyhon.appliance import HonAppliance
|
|
from pyhon.parameter.range import HonParameterRange
|
|
|
|
from .const import HON_HVAC_MODE, HON_FAN, DOMAIN, HON_HVAC_PROGRAM
|
|
from .entity import HonEntity
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class HonACClimateEntityDescription(ClimateEntityDescription):
|
|
pass
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class HonClimateEntityDescription(ClimateEntityDescription):
|
|
mode: HVACMode = HVACMode.AUTO
|
|
|
|
|
|
CLIMATES: dict[
|
|
str, tuple[HonACClimateEntityDescription | HonClimateEntityDescription, ...]
|
|
] = {
|
|
"AC": (
|
|
HonACClimateEntityDescription(
|
|
key="settings",
|
|
name="Air Conditioner",
|
|
icon="mdi:air-conditioner",
|
|
translation_key="air_conditioner",
|
|
),
|
|
),
|
|
"REF": (
|
|
HonClimateEntityDescription(
|
|
key="settings.tempSelZ1",
|
|
mode=HVACMode.COOL,
|
|
name="Fridge",
|
|
icon="mdi:thermometer",
|
|
translation_key="fridge",
|
|
),
|
|
HonClimateEntityDescription(
|
|
key="settings.tempSelZ2",
|
|
mode=HVACMode.COOL,
|
|
name="Freezer",
|
|
icon="mdi:snowflake-thermometer",
|
|
translation_key="freezer",
|
|
),
|
|
HonClimateEntityDescription(
|
|
key="settings.tempSelZ3",
|
|
mode=HVACMode.COOL,
|
|
name="MyZone",
|
|
icon="mdi:thermometer",
|
|
translation_key="my_zone",
|
|
),
|
|
),
|
|
"OV": (
|
|
HonClimateEntityDescription(
|
|
key="settings.tempSel",
|
|
mode=HVACMode.HEAT,
|
|
name="Oven",
|
|
icon="mdi:thermometer",
|
|
translation_key="oven",
|
|
),
|
|
),
|
|
"WC": (
|
|
HonClimateEntityDescription(
|
|
key="settings.tempSel",
|
|
mode=HVACMode.COOL,
|
|
name="Wine Cellar",
|
|
icon="mdi:thermometer",
|
|
translation_key="wine",
|
|
),
|
|
HonClimateEntityDescription(
|
|
key="settings.tempSelZ2",
|
|
mode=HVACMode.COOL,
|
|
name="Wine Cellar",
|
|
icon="mdi:thermometer",
|
|
translation_key="wine",
|
|
),
|
|
),
|
|
}
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
|
) -> None:
|
|
entities = []
|
|
entity: HonClimateEntity | HonACClimateEntity
|
|
for device in hass.data[DOMAIN][entry.unique_id]["hon"].appliances:
|
|
for description in CLIMATES.get(device.appliance_type, []):
|
|
if isinstance(description, HonACClimateEntityDescription):
|
|
if description.key not in list(device.commands):
|
|
continue
|
|
entity = HonACClimateEntity(hass, entry, device, description)
|
|
elif isinstance(description, HonClimateEntityDescription):
|
|
if description.key not in device.available_settings:
|
|
continue
|
|
entity = HonClimateEntity(hass, entry, device, description)
|
|
else:
|
|
continue # type: ignore[unreachable]
|
|
entities.append(entity)
|
|
async_add_entities(entities)
|
|
|
|
|
|
class HonACClimateEntity(HonEntity, ClimateEntity):
|
|
entity_description: HonACClimateEntityDescription
|
|
_enable_turn_on_off_backwards_compatibility = False
|
|
|
|
def __init__(
|
|
self,
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
device: HonAppliance,
|
|
description: HonACClimateEntityDescription,
|
|
) -> None:
|
|
super().__init__(hass, entry, device, description)
|
|
|
|
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
|
self._set_temperature_bound()
|
|
|
|
self._attr_hvac_modes = [HVACMode.OFF]
|
|
for mode in device.settings["settings.machMode"].values:
|
|
self._attr_hvac_modes.append(HON_HVAC_MODE[int(mode)])
|
|
self._attr_preset_modes = []
|
|
for mode in device.settings["startProgram.program"].values:
|
|
self._attr_preset_modes.append(mode)
|
|
self._attr_swing_modes = [
|
|
SWING_OFF,
|
|
SWING_VERTICAL,
|
|
SWING_HORIZONTAL,
|
|
SWING_BOTH,
|
|
]
|
|
self._attr_supported_features = (
|
|
ClimateEntityFeature.TURN_ON
|
|
| ClimateEntityFeature.TURN_OFF
|
|
| ClimateEntityFeature.TARGET_TEMPERATURE
|
|
| ClimateEntityFeature.FAN_MODE
|
|
| ClimateEntityFeature.SWING_MODE
|
|
| ClimateEntityFeature.PRESET_MODE
|
|
)
|
|
|
|
self._handle_coordinator_update(update=False)
|
|
|
|
def _set_temperature_bound(self) -> None:
|
|
temperature = self._device.settings["settings.tempSel"]
|
|
if not isinstance(temperature, HonParameterRange):
|
|
raise ValueError
|
|
self._attr_max_temp = temperature.max
|
|
self._attr_target_temperature_step = temperature.step
|
|
self._attr_min_temp = temperature.min
|
|
|
|
@property
|
|
def target_temperature(self) -> float | None:
|
|
"""Return the temperature we try to reach."""
|
|
return self._device.get("tempSel", 0.0)
|
|
|
|
@property
|
|
def current_temperature(self) -> float | None:
|
|
"""Return the current temperature."""
|
|
return self._device.get("tempIndoor", 0.0)
|
|
|
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
|
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
|
|
return
|
|
self._device.settings["settings.tempSel"].value = str(int(temperature))
|
|
await self._device.commands["settings"].send()
|
|
self.async_write_ha_state()
|
|
|
|
@property
|
|
def hvac_mode(self) -> HVACMode:
|
|
if self._device.get("onOffStatus") == 0:
|
|
return HVACMode.OFF
|
|
else:
|
|
return HON_HVAC_MODE[self._device.get("machMode")]
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
self._attr_hvac_mode = hvac_mode
|
|
if hvac_mode == HVACMode.OFF:
|
|
await self._device.commands["stopProgram"].send()
|
|
self._device.sync_command("stopProgram", "settings")
|
|
else:
|
|
self._device.settings["settings.onOffStatus"].value = "1"
|
|
setting = self._device.settings["settings.machMode"]
|
|
modes = {HON_HVAC_MODE[int(number)]: number for number in setting.values}
|
|
if hvac_mode in modes:
|
|
setting.value = modes[hvac_mode]
|
|
else:
|
|
await self.async_set_preset_mode(HON_HVAC_PROGRAM[hvac_mode])
|
|
return
|
|
await self._device.commands["settings"].send()
|
|
self.async_write_ha_state()
|
|
|
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
await self._device.commands["startProgram"].send()
|
|
self._device.sync_command("startProgram", "settings")
|
|
|
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
await self._device.commands["stopProgram"].send()
|
|
self._device.sync_command("stopProgram", "settings")
|
|
|
|
@property
|
|
def preset_mode(self) -> str | None:
|
|
"""Return the current Preset for this channel."""
|
|
return None
|
|
|
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
|
"""Set the new preset mode."""
|
|
if program := self._device.settings.get("startProgram.program"):
|
|
program.value = preset_mode
|
|
self._device.sync_command("startProgram", "settings")
|
|
self._set_temperature_bound()
|
|
self._handle_coordinator_update(update=False)
|
|
self.coordinator.async_set_updated_data({})
|
|
self._attr_preset_mode = preset_mode
|
|
await self._device.commands["startProgram"].send()
|
|
self.async_write_ha_state()
|
|
|
|
@property
|
|
def fan_modes(self) -> list[str]:
|
|
"""Return the list of available fan modes."""
|
|
fan_modes = []
|
|
for mode in reversed(self._device.settings["settings.windSpeed"].values):
|
|
fan_modes.append(HON_FAN[int(mode)])
|
|
return fan_modes
|
|
|
|
@property
|
|
def fan_mode(self) -> str | None:
|
|
"""Return the fan setting."""
|
|
return HON_FAN[self._device.get("windSpeed")]
|
|
|
|
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
|
fan_modes = {}
|
|
for mode in reversed(self._device.settings["settings.windSpeed"].values):
|
|
fan_modes[HON_FAN[int(mode)]] = mode
|
|
self._device.settings["settings.windSpeed"].value = str(fan_modes[fan_mode])
|
|
self._attr_fan_mode = fan_mode
|
|
await self._device.commands["settings"].send()
|
|
self.async_write_ha_state()
|
|
|
|
@property
|
|
def swing_mode(self) -> str | None:
|
|
"""Return the swing setting."""
|
|
horizontal = self._device.get("windDirectionHorizontal")
|
|
vertical = self._device.get("windDirectionVertical")
|
|
if horizontal == 7 and vertical == 8:
|
|
return SWING_BOTH
|
|
if horizontal == 7:
|
|
return SWING_HORIZONTAL
|
|
if vertical == 8:
|
|
return SWING_VERTICAL
|
|
return SWING_OFF
|
|
|
|
async def async_set_swing_mode(self, swing_mode: str) -> None:
|
|
horizontal = self._device.settings["settings.windDirectionHorizontal"]
|
|
vertical = self._device.settings["settings.windDirectionVertical"]
|
|
if swing_mode in [SWING_BOTH, SWING_HORIZONTAL]:
|
|
horizontal.value = "7"
|
|
if swing_mode in [SWING_BOTH, SWING_VERTICAL]:
|
|
vertical.value = "8"
|
|
if swing_mode in [SWING_OFF, SWING_HORIZONTAL] and vertical.value == "8":
|
|
vertical.value = "5"
|
|
if swing_mode in [SWING_OFF, SWING_VERTICAL] and horizontal.value == "7":
|
|
horizontal.value = "0"
|
|
self._attr_swing_mode = swing_mode
|
|
await self._device.commands["settings"].send()
|
|
self.async_write_ha_state()
|
|
|
|
@callback
|
|
def _handle_coordinator_update(self, update: bool = True) -> None:
|
|
if update:
|
|
self.async_write_ha_state()
|
|
|
|
|
|
class HonClimateEntity(HonEntity, ClimateEntity):
|
|
entity_description: HonClimateEntityDescription
|
|
_enable_turn_on_off_backwards_compatibility = False
|
|
|
|
def __init__(
|
|
self,
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
device: HonAppliance,
|
|
description: HonClimateEntityDescription,
|
|
) -> None:
|
|
super().__init__(hass, entry, device, description)
|
|
|
|
self._attr_supported_features = (
|
|
ClimateEntityFeature.TURN_ON | ClimateEntityFeature.TARGET_TEMPERATURE
|
|
)
|
|
|
|
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
|
self._set_temperature_bound()
|
|
|
|
self._attr_hvac_modes = [description.mode]
|
|
if "stopProgram" in device.commands:
|
|
self._attr_supported_features |= ClimateEntityFeature.TURN_OFF
|
|
self._attr_hvac_modes += [HVACMode.OFF]
|
|
modes = []
|
|
else:
|
|
modes = ["no_mode"]
|
|
|
|
for mode, data in device.commands["startProgram"].categories.items():
|
|
if mode not in data.parameters["program"].values:
|
|
continue
|
|
if (zone := data.parameters.get("zone")) and isinstance(
|
|
self.entity_description.name, str
|
|
):
|
|
if self.entity_description.name.lower() in zone.values:
|
|
modes.append(mode)
|
|
else:
|
|
modes.append(mode)
|
|
|
|
if modes:
|
|
self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE
|
|
self._attr_preset_modes = modes
|
|
|
|
self._handle_coordinator_update(update=False)
|
|
|
|
@property
|
|
def target_temperature(self) -> float | None:
|
|
"""Return the temperature we try to reach."""
|
|
return self._device.get(self.entity_description.key, 0.0)
|
|
|
|
@property
|
|
def current_temperature(self) -> float | None:
|
|
"""Return the current temperature."""
|
|
temp_key = self.entity_description.key.split(".")[-1].replace("Sel", "")
|
|
return self._device.get(temp_key, 0.0)
|
|
|
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
|
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
|
|
return
|
|
self._device.settings[self.entity_description.key].value = str(int(temperature))
|
|
await self._device.commands["settings"].send()
|
|
self.async_write_ha_state()
|
|
|
|
@property
|
|
def hvac_mode(self) -> HVACMode:
|
|
if self._device.get("onOffStatus") == 0:
|
|
return HVACMode.OFF
|
|
else:
|
|
return self.entity_description.mode
|
|
|
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
|
if len(self.hvac_modes) <= 1:
|
|
return
|
|
if hvac_mode == HVACMode.OFF:
|
|
await self._device.commands["stopProgram"].send()
|
|
else:
|
|
await self._device.commands["startProgram"].send()
|
|
self._attr_hvac_mode = hvac_mode
|
|
self.async_write_ha_state()
|
|
|
|
async def async_turn_on(self) -> None:
|
|
"""Set the HVAC State to on."""
|
|
await self._device.commands["startProgram"].send()
|
|
|
|
async def async_turn_off(self) -> None:
|
|
"""Set the HVAC State to off."""
|
|
await self._device.commands["stopProgram"].send()
|
|
|
|
@property
|
|
def preset_mode(self) -> str | None:
|
|
"""Return the current Preset for this channel."""
|
|
if self._device.get("onOffStatus") is not None:
|
|
return self._device.get("programName", "")
|
|
else:
|
|
return self._device.get(
|
|
f"mode{self.entity_description.key[-2:]}", "no_mode"
|
|
)
|
|
|
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
|
"""Set the new preset mode."""
|
|
if preset_mode == "no_mode" and HVACMode.OFF in self.hvac_modes:
|
|
command = "stopProgram"
|
|
elif preset_mode == "no_mode":
|
|
command = "settings"
|
|
self._device.commands["settings"].reset()
|
|
else:
|
|
command = "startProgram"
|
|
if program := self._device.settings.get(f"{command}.program"):
|
|
program.value = preset_mode
|
|
zone = self._device.settings.get(f"{command}.zone")
|
|
if zone and isinstance(self.entity_description.name, str):
|
|
zone.value = self.entity_description.name.lower()
|
|
self._device.sync_command(command, "settings")
|
|
self._set_temperature_bound()
|
|
self._attr_preset_mode = preset_mode
|
|
self.coordinator.async_set_updated_data({})
|
|
await self._device.commands[command].send()
|
|
self.async_write_ha_state()
|
|
|
|
def _set_temperature_bound(self) -> None:
|
|
temperature = self._device.settings[self.entity_description.key]
|
|
if not isinstance(temperature, HonParameterRange):
|
|
raise ValueError
|
|
self._attr_max_temp = temperature.max
|
|
self._attr_target_temperature_step = temperature.step
|
|
self._attr_min_temp = temperature.min
|
|
|
|
@callback
|
|
def _handle_coordinator_update(self, update: bool = True) -> None:
|
|
if update:
|
|
self.async_write_ha_state()
|