Compare commits

..

2 Commits

Author SHA1 Message Date
80b3741f2f Reduce lagging update 2023-06-08 20:01:55 +02:00
c433714a94 Refactor and update for lagging climate 2023-06-08 19:59:43 +02:00
11 changed files with 112 additions and 66 deletions

View File

@ -62,6 +62,7 @@ Translation of internal names like programs are available for all languages whic
## Supported Models ## Supported Models
Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8). Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).
- Haier AD105S2SM3FA - Haier AD105S2SM3FA
- Haier AS20HPL1HRA
- Haier AS25PBAHRA - Haier AS25PBAHRA
- Haier AS25S2SF1FA-WH - Haier AS25S2SF1FA-WH
- Haier AS25TADHRA-2 - Haier AS25TADHRA-2

View File

@ -271,9 +271,10 @@ class HonBinarySensorEntity(HonEntity, BinarySensorEntity):
) )
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self, update=True) -> None:
self._attr_native_value = ( self._attr_native_value = (
self._device.get(self.entity_description.key, "") self._device.get(self.entity_description.key, "")
== self.entity_description.on_value == self.entity_description.on_value
) )
if update:
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -1,8 +1,6 @@
import logging import logging
from dataclasses import dataclass from dataclasses import dataclass
from pyhon.appliance import HonAppliance
from homeassistant.components.climate import ( from homeassistant.components.climate import (
ClimateEntity, ClimateEntity,
ClimateEntityDescription, ClimateEntityDescription,
@ -22,6 +20,8 @@ from homeassistant.const import (
TEMP_CELSIUS, TEMP_CELSIUS,
) )
from homeassistant.core import callback from homeassistant.core import callback
from pyhon.appliance import HonAppliance
from .const import HON_HVAC_MODE, HON_FAN, HON_HVAC_PROGRAM, DOMAIN from .const import HON_HVAC_MODE, HON_FAN, HON_HVAC_PROGRAM, DOMAIN
from .hon import HonEntity from .hon import HonEntity
@ -103,12 +103,12 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
self._attr_max_temp = device.settings["settings.tempSel"].max self._attr_max_temp = device.settings["settings.tempSel"].max
self._attr_min_temp = device.settings["settings.tempSel"].min self._attr_min_temp = device.settings["settings.tempSel"].min
self._attr_hvac_modes = [HVACMode.OFF] + [ self._attr_hvac_modes = [HVACMode.OFF]
HON_HVAC_MODE[mode] for mode in device.settings["settings.machMode"].values for mode in device.settings["settings.machMode"].values:
] self._attr_hvac_modes.append(HON_HVAC_MODE[mode])
self._attr_fan_modes = [FAN_OFF] + [ self._attr_fan_modes = [FAN_OFF]
HON_FAN[mode] for mode in device.settings["settings.windSpeed"].values for mode in device.settings["settings.windSpeed"].values:
] self._attr_fan_modes.append(HON_FAN[mode])
self._attr_swing_modes = [ self._attr_swing_modes = [
SWING_OFF, SWING_OFF,
SWING_VERTICAL, SWING_VERTICAL,
@ -123,6 +123,23 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
self._handle_coordinator_update(update=False) self._handle_coordinator_update(update=False)
@property
def target_temperature(self) -> int | None:
"""Return the temperature we try to reach."""
return int(float(self._device.get("tempSel")))
@property
def current_temperature(self) -> float | None:
"""Return the current temperature."""
return float(self._device.get("tempIndoor"))
async def async_set_temperature(self, **kwargs):
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
return False
self._device.settings["settings.tempSel"].value = str(int(temperature))
await self._device.commands["settings"].send()
self.async_write_ha_state()
@property @property
def hvac_mode(self) -> HVACMode | str | None: def hvac_mode(self) -> HVACMode | str | None:
if self._device.get("onOffStatus") == "0": if self._device.get("onOffStatus") == "0":
@ -131,24 +148,42 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
return HON_HVAC_MODE[self._device.get("machMode")] return HON_HVAC_MODE[self._device.get("machMode")]
async def async_set_hvac_mode(self, hvac_mode): async def async_set_hvac_mode(self, hvac_mode):
self._attr_hvac_mode = hvac_mode
if hvac_mode == HVACMode.OFF: if hvac_mode == HVACMode.OFF:
await self._device.commands["stopProgram"].send() await self._device.commands["stopProgram"].send()
else: else:
self._device.settings["startProgram.program"].value = HON_HVAC_PROGRAM[ mode = HON_HVAC_PROGRAM[hvac_mode]
hvac_mode self._device.settings["startProgram.program"].value = mode
]
await self._device.commands["startProgram"].send() await self._device.commands["startProgram"].send()
self._attr_hvac_mode = hvac_mode
self.async_write_ha_state() self.async_write_ha_state()
@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): async def async_set_fan_mode(self, fan_mode):
mode_number = list(HON_FAN.values()).index(fan_mode) mode_number = list(HON_FAN.values()).index(fan_mode)
self._device.settings["settings.windSpeed"].value = list(HON_FAN.keys())[ mode = list(HON_FAN.keys())[mode_number]
mode_number self._device.settings["settings.windSpeed"].value = mode
] self._attr_fan_mode = fan_mode
await self._device.commands["settings"].send() await self._device.commands["settings"].send()
self.async_write_ha_state() 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
elif horizontal == "7":
return SWING_HORIZONTAL
elif vertical == "8":
return SWING_VERTICAL
else:
return SWING_OFF
async def async_set_swing_mode(self, swing_mode): async def async_set_swing_mode(self, swing_mode):
horizontal = self._device.settings["settings.windDirectionHorizontal"] horizontal = self._device.settings["settings.windDirectionHorizontal"]
vertical = self._device.settings["settings.windDirectionVertical"] vertical = self._device.settings["settings.windDirectionVertical"]
@ -164,35 +199,13 @@ class HonACClimateEntity(HonEntity, ClimateEntity):
await self._device.commands["settings"].send() await self._device.commands["settings"].send()
self.async_write_ha_state() self.async_write_ha_state()
async def async_set_temperature(self, **kwargs):
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
return False
self._device.settings["settings.tempSel"].value = str(int(temperature))
await self._device.commands["settings"].send()
self.async_write_ha_state()
@callback @callback
def _handle_coordinator_update(self, update=True) -> None: def _handle_coordinator_update(self, update=True) -> None:
self._attr_target_temperature = int(float(self._device.get("tempSel"))) self._attr_target_temperature = self.target_temperature
self._attr_current_temperature = float(self._device.get("tempIndoor")) self._attr_current_temperature = self.current_temperature
self._attr_hvac_mode = self.hvac_mode
if self._device.get("onOffStatus") == "0": self._attr_fan_mode = self.fan_mode
self._attr_hvac_mode = HVACMode.OFF self._attr_swing_mode = self.swing_mode
else:
self._attr_hvac_mode = HON_HVAC_MODE[self._device.get("machMode")]
self._attr_fan_mode = HON_FAN[self._device.get("windSpeed")]
horizontal = self._device.get("windDirectionHorizontal")
vertical = self._device.get("windDirectionVertical")
if horizontal == "7" and vertical == "8":
self._attr_swing_mode = SWING_BOTH
elif horizontal == "7":
self._attr_swing_mode = SWING_HORIZONTAL
elif vertical == "8":
self._attr_swing_mode = SWING_VERTICAL
else:
self._attr_swing_mode = SWING_OFF
if update: if update:
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -7,6 +7,7 @@ from homeassistant.components.climate import (
) )
DOMAIN = "hon" DOMAIN = "hon"
UPDATE_INTERVAL = 10
PLATFORMS = [ PLATFORMS = [
"sensor", "sensor",

View File

@ -1,12 +1,13 @@
import logging import logging
from datetime import timedelta from datetime import timedelta
from homeassistant.core import callback
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from pyhon.appliance import HonAppliance from pyhon.appliance import HonAppliance
from .const import DOMAIN from .const import DOMAIN, UPDATE_INTERVAL
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -21,13 +22,14 @@ class HonEntity(CoordinatorEntity):
self._hon = hass.data[DOMAIN][entry.unique_id] self._hon = hass.data[DOMAIN][entry.unique_id]
self._hass = hass self._hass = hass
self._coordinator = coordinator self._coordinator = coordinator
self._device = device self._device: HonAppliance = device
if description is not None: if description is not None:
self.entity_description = description self.entity_description = description
self._attr_unique_id = f"{self._device.unique_id}{description.key}" self._attr_unique_id = f"{self._device.unique_id}{description.key}"
else: else:
self._attr_unique_id = self._device.unique_id self._attr_unique_id = self._device.unique_id
self._handle_coordinator_update(update=False)
@property @property
def device_info(self): def device_info(self):
@ -41,6 +43,11 @@ class HonEntity(CoordinatorEntity):
sw_version=self._device.get("fwVersion", ""), sw_version=self._device.get("fwVersion", ""),
) )
@callback
def _handle_coordinator_update(self, update: bool = True) -> None:
if update:
self.async_write_ha_state()
class HonCoordinator(DataUpdateCoordinator): class HonCoordinator(DataUpdateCoordinator):
def __init__(self, hass, device: HonAppliance): def __init__(self, hass, device: HonAppliance):
@ -49,7 +56,7 @@ class HonCoordinator(DataUpdateCoordinator):
hass, hass,
_LOGGER, _LOGGER,
name=device.unique_id, name=device.unique_id,
update_interval=timedelta(seconds=30), update_interval=timedelta(seconds=UPDATE_INTERVAL),
) )
self._device = device self._device = device

View File

@ -9,7 +9,7 @@
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"issue_tracker": "https://github.com/Andre0512/hon/issues", "issue_tracker": "https://github.com/Andre0512/hon/issues",
"requirements": [ "requirements": [
"pyhOn==0.12.1" "pyhOn==0.12.2"
], ],
"version": "0.8.0-beta.9" "version": "0.8.0-beta.10"
} }

View File

@ -9,7 +9,7 @@ from homeassistant.components.number import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfTime, UnitOfTemperature from homeassistant.const import UnitOfTime, UnitOfTemperature
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.entity import EntityCategory, Entity from homeassistant.helpers.entity import EntityCategory
from pyhon.parameter.range import HonParameterRange from pyhon.parameter.range import HonParameterRange
from .const import DOMAIN from .const import DOMAIN
@ -223,13 +223,14 @@ class HonNumberEntity(HonEntity, NumberEntity):
await self.coordinator.async_refresh() await self.coordinator.async_refresh()
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self, update=True) -> None:
setting = self._device.settings[self.entity_description.key] setting = self._device.settings[self.entity_description.key]
if isinstance(setting, HonParameterRange): if isinstance(setting, HonParameterRange):
self._attr_native_max_value = setting.max self._attr_native_max_value = setting.max
self._attr_native_min_value = setting.min self._attr_native_min_value = setting.min
self._attr_native_step = setting.step self._attr_native_step = setting.step
self._attr_native_value = setting.value self._attr_native_value = setting.value
if update:
self.async_write_ha_state() self.async_write_ha_state()
@property @property

View File

@ -7,7 +7,7 @@ from homeassistant.components.select import SelectEntity, SelectEntityDescriptio
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfTemperature, UnitOfTime, REVOLUTIONS_PER_MINUTE from homeassistant.const import UnitOfTemperature, UnitOfTime, REVOLUTIONS_PER_MINUTE
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.entity import EntityCategory, Entity from homeassistant.helpers.entity import EntityCategory
from pyhon.appliance import HonAppliance from pyhon.appliance import HonAppliance
from pyhon.parameter.fixed import HonParameterFixed from pyhon.parameter.fixed import HonParameterFixed
@ -179,7 +179,7 @@ class HonSelectEntity(HonEntity, SelectEntity):
await self.coordinator.async_refresh() await self.coordinator.async_refresh()
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self, update=True) -> None:
setting = self._device.settings.get(self.entity_description.key) setting = self._device.settings.get(self.entity_description.key)
if setting is None: if setting is None:
self._attr_available = False self._attr_available = False
@ -189,6 +189,7 @@ class HonSelectEntity(HonEntity, SelectEntity):
self._attr_available = True self._attr_available = True
self._attr_options: list[str] = setting.values self._attr_options: list[str] = setting.values
self._attr_native_value = setting.value self._attr_native_value = setting.value
if update:
self.async_write_ha_state() self.async_write_ha_state()
@property @property

View File

@ -1,8 +1,6 @@
import logging import logging
from dataclasses import dataclass from dataclasses import dataclass
from pyhon.appliance import HonAppliance
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorEntity, SensorEntity,
SensorDeviceClass, SensorDeviceClass,
@ -22,7 +20,8 @@ from homeassistant.const import (
) )
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.typing import StateType from pyhon.appliance import HonAppliance
from . import const from . import const
from .const import DOMAIN from .const import DOMAIN
from .hon import HonEntity, unique_entities from .hon import HonEntity, unique_entities
@ -635,11 +634,12 @@ class HonSensorEntity(HonEntity, SensorEntity):
).values + ["No Program"] ).values + ["No Program"]
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self, update=True) -> None:
value = self._device.get(self.entity_description.key, "") value = self._device.get(self.entity_description.key, "")
if not value and self.entity_description.state_class is not None: if not value and self.entity_description.state_class is not None:
self._attr_native_value = 0 self._attr_native_value = 0
self._attr_native_value = value self._attr_native_value = value
if update:
self.async_write_ha_state() self.async_write_ha_state()
@ -647,7 +647,7 @@ class HonConfigSensorEntity(HonEntity, SensorEntity):
entity_description: HonConfigSensorEntityDescription entity_description: HonConfigSensorEntityDescription
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self, update=True) -> None:
value = self._device.settings.get(self.entity_description.key, None) value = self._device.settings.get(self.entity_description.key, None)
if self.entity_description.state_class is not None: if self.entity_description.state_class is not None:
if value and value.value: if value and value.value:
@ -658,4 +658,5 @@ class HonConfigSensorEntity(HonEntity, SensorEntity):
self._attr_native_value = 0 self._attr_native_value = 0
else: else:
self._attr_native_value = value.value self._attr_native_value = value.value
if update:
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -1,5 +1,6 @@
import logging import logging
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import Any from typing import Any
from homeassistant.components.switch import SwitchEntityDescription, SwitchEntity from homeassistant.components.switch import SwitchEntityDescription, SwitchEntity
@ -394,9 +395,10 @@ class HonSwitchEntity(HonEntity, SwitchEntity):
) )
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self, update=True) -> None:
value = self._device.get(self.entity_description.key, "0") value = self._device.get(self.entity_description.key, "0")
self._attr_state = value == "1" self._attr_state = value == "1"
if update:
self.async_write_ha_state() self.async_write_ha_state()
@ -410,9 +412,13 @@ class HonControlSwitchEntity(HonEntity, SwitchEntity):
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
await self._device.commands[self.entity_description.turn_on_key].send() await self._device.commands[self.entity_description.turn_on_key].send()
self._device.attributes[self.entity_description.key] = True
self.async_write_ha_state()
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
await self._device.commands[self.entity_description.turn_off_key].send() await self._device.commands[self.entity_description.turn_off_key].send()
self._device.attributes[self.entity_description.key] = False
self.async_write_ha_state()
@property @property
def available(self) -> bool: def available(self) -> bool:
@ -423,6 +429,18 @@ class HonControlSwitchEntity(HonEntity, SwitchEntity):
and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED" and self._device.get("attributes.lastConnEvent.category") != "DISCONNECTED"
) )
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the optional state attributes."""
result = {}
if remaining_time := int(self._device.get("remainingTimeMM", 0)):
delay_time = int(self._device.get("delayTime", 0))
result["start_time"] = datetime.now() + timedelta(minutes=delay_time)
result["end_time"] = datetime.now() + timedelta(
minutes=delay_time + remaining_time
)
return result
class HonConfigSwitchEntity(HonEntity, SwitchEntity): class HonConfigSwitchEntity(HonEntity, SwitchEntity):
entity_description: HonConfigSwitchEntityDescription entity_description: HonConfigSwitchEntityDescription
@ -454,7 +472,8 @@ class HonConfigSwitchEntity(HonEntity, SwitchEntity):
await self.coordinator.async_refresh() await self.coordinator.async_refresh()
@callback @callback
def _handle_coordinator_update(self): def _handle_coordinator_update(self, update=True) -> None:
value = self._device.settings.get(self.entity_description.key, "0") value = self._device.settings.get(self.entity_description.key, "0")
self._attr_state = value == "1" self._attr_state = value == "1"
if update:
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -51,6 +51,7 @@ Translation of internal names like programs are available for all languages whic
## Supported Models ## Supported Models
Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8). Support has been confirmed for these models, but many more will work. Please add already supported devices [with this form to complete the list](https://forms.gle/bTSD8qFotdZFytbf8).
- Haier AD105S2SM3FA - Haier AD105S2SM3FA
- Haier AS20HPL1HRA
- Haier AS25PBAHRA - Haier AS25PBAHRA
- Haier AS25S2SF1FA-WH - Haier AS25S2SF1FA-WH
- Haier AS25TADHRA-2 - Haier AS25TADHRA-2