Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor entity value updates to support new ha property caching
Browse files Browse the repository at this point in the history
zlangbert committed Jan 20, 2024

Verified

This commit was signed with the committer’s verified signature.
zlangbert Zach Langbert
1 parent 2fe9b33 commit 596fe85
Showing 4 changed files with 88 additions and 127 deletions.
188 changes: 79 additions & 109 deletions custom_components/daikinone/climate.py
Original file line number Diff line number Diff line change
@@ -68,94 +68,21 @@ def __init__(
self._data = data
self._thermostat = thermostat

@property
def unique_id(self):
"""Return a unique identifier for this sensor."""
return f"{self._thermostat.id}-climate"

@property
def device_info(self) -> DeviceInfo | None:
"""Return device information for this sensor."""

return DeviceInfo(
self._attr_unique_id = f"{self._thermostat.id}-climate"
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
self._attr_supported_features = (
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self._thermostat.id)},
name=f"{self._thermostat.name} Thermostat",
manufacturer=MANUFACTURER,
model=self._thermostat.model,
sw_version=self._thermostat.firmware_version,
)
self._attr_hvac_modes = self.get_hvac_modes()

@property
def available(self):
"""Return if device is available."""
return self._thermostat.online

@property
def supported_features(self):
return ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.TARGET_TEMPERATURE_RANGE

@property
def temperature_unit(self):
return UnitOfTemperature.CELSIUS

@property
def current_temperature(self) -> float | None:
return self._thermostat.indoor_temperature.celsius

@property
def target_temperature(self) -> float | None:
match self._thermostat.mode:
case DaikinThermostatMode.HEAT | DaikinThermostatMode.AUX_HEAT:
return self._thermostat.set_point_heat.celsius
case DaikinThermostatMode.COOL:
return self._thermostat.set_point_cool.celsius
case _:
pass

return None

@property
def target_temperature_low(self) -> float | None:
match self._thermostat.mode:
case DaikinThermostatMode.AUTO:
return self._thermostat.set_point_heat.celsius
case _:
pass

return None

@property
def target_temperature_high(self) -> float | None:
match self._thermostat.mode:
case DaikinThermostatMode.AUTO:
return self._thermostat.set_point_cool.celsius
case _:
pass

return None

@property
def min_temp(self) -> float:
# these should be the same but just in case, take the larger of the two for the min
return max(
self._thermostat.set_point_heat_min.celsius,
self._thermostat.set_point_cool_min.celsius,
)

@property
def max_temp(self) -> float:
# these should be the same but just in case, take the smaller of the two for the max
return min(
self._thermostat.set_point_heat_max.celsius,
self._thermostat.set_point_cool_max.celsius,
)

@property
def current_humidity(self) -> int:
return self._thermostat.indoor_humidity

@property
def hvac_modes(self) -> list[HVACMode]:
def get_hvac_modes(self) -> list[HVACMode]:
modes: list[HVACMode] = []

if (
@@ -173,34 +100,6 @@ def hvac_modes(self) -> list[HVACMode]:

return modes

@property
def hvac_mode(self):
match self._thermostat.mode:
case DaikinThermostatMode.AUTO:
return HVACMode.HEAT_COOL
case DaikinThermostatMode.HEAT:
return HVACMode.HEAT
case DaikinThermostatMode.COOL:
return HVACMode.COOL
case DaikinThermostatMode.AUX_HEAT:
return HVACMode.HEAT
case DaikinThermostatMode.OFF:
return HVACMode.OFF

@property
def hvac_action(self):
match self._thermostat.status:
case DaikinThermostatStatus.HEATING:
return HVACAction.HEATING
case DaikinThermostatStatus.COOLING:
return HVACAction.COOLING
case DaikinThermostatStatus.CIRCULATING_AIR:
return HVACAction.FAN
case DaikinThermostatStatus.DRYING:
return HVACAction.DRYING
case DaikinThermostatStatus.IDLE:
return HVACAction.IDLE

async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
target_mode: DaikinThermostatMode
@@ -312,6 +211,77 @@ async def async_update(self, no_throttle: bool = False) -> None:
await self._data.update(no_throttle=no_throttle)
self._thermostat = self._data.daikin.get_thermostat(self._thermostat.id)

# update entity data
#
self._attr_available = self._thermostat.online
self._attr_current_temperature = self._thermostat.indoor_temperature.celsius
self._attr_current_humidity = self._thermostat.indoor_humidity

# hvac mode
#
match self._thermostat.mode:
case DaikinThermostatMode.AUTO:
self._attr_hvac_mode = HVACMode.HEAT_COOL
case DaikinThermostatMode.HEAT:
self._attr_hvac_mode = HVACMode.HEAT
case DaikinThermostatMode.COOL:
self._attr_hvac_mode = HVACMode.COOL
case DaikinThermostatMode.AUX_HEAT:
self._attr_hvac_mode = HVACMode.HEAT
case DaikinThermostatMode.OFF:
self._attr_hvac_mode = HVACMode.OFF

# hvac action
#
match self._thermostat.status:
case DaikinThermostatStatus.HEATING:
self._attr_hvac_action = HVACAction.HEATING
case DaikinThermostatStatus.COOLING:
self._attr_hvac_action = HVACAction.COOLING
case DaikinThermostatStatus.CIRCULATING_AIR:
self._attr_hvac_action = HVACAction.FAN
case DaikinThermostatStatus.DRYING:
self._attr_hvac_action = HVACAction.DRYING
case DaikinThermostatStatus.IDLE:
self._attr_hvac_action = HVACAction.IDLE

# target temperature
#
match self._thermostat.mode:
case DaikinThermostatMode.HEAT | DaikinThermostatMode.AUX_HEAT:
self._attr_target_temperature = self._thermostat.set_point_heat.celsius
case DaikinThermostatMode.COOL:
self._attr_target_temperature = self._thermostat.set_point_cool.celsius
case _:
pass

# target temperature range
#
match self._thermostat.mode:
case DaikinThermostatMode.AUTO:
self._attr_target_temperature_low = self._thermostat.set_point_heat.celsius
case _:
pass
match self._thermostat.mode:
case DaikinThermostatMode.AUTO:
self._attr_target_temperature_high = self._thermostat.set_point_cool.celsius
case _:
pass

# temperature bounds
#

# these should be the same but just in case, take the larger of the two for the min
self._attr_min_temp = max(
self._thermostat.set_point_heat_min.celsius,
self._thermostat.set_point_cool_min.celsius,
)
# these should be the same but just in case, take the smaller of the two for the max
self._attr_max_temp = min(
self._thermostat.set_point_heat_max.celsius,
self._thermostat.set_point_cool_max.celsius,
)

async def update_state_optimistically(
self, update: Callable[[DaikinThermostat], None], check: Callable[[DaikinThermostat], bool]
) -> None:
2 changes: 1 addition & 1 deletion custom_components/daikinone/config_flow.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ def schema(self):
return vol.Schema({vol.Required(CONF_EMAIL): str, vol.Required(CONF_PASSWORD): str})

async def async_step_user(self, user_input: dict[str, Any] | None = None):
errors = {}
errors: dict[str, str] = {}

if user_input is not None:
email = user_input[CONF_EMAIL]
2 changes: 1 addition & 1 deletion custom_components/daikinone/daikinone.py
Original file line number Diff line number Diff line change
@@ -202,7 +202,7 @@ async def set_thermostat_home_set_points(
if not heat and not cool:
raise ValueError("At least one of heat or cool set points must be set")

payload = {}
payload: dict[str, Any] = {}
if heat:
payload["hspHome"] = heat.celsius
if cool:
23 changes: 7 additions & 16 deletions custom_components/daikinone/sensor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from typing import Callable, TypeVar, Generic
from functools import cached_property
from typing import Callable, Generic, TypeVar

from homeassistant.components.sensor import SensorEntity, SensorEntityDescription, SensorDeviceClass, SensorStateClass
from homeassistant.config_entries import ConfigEntry
@@ -547,8 +548,6 @@ async def async_setup_entry(


class DaikinOneSensor(SensorEntity, Generic[D]):
_state: StateType = None

def __init__(
self, description: SensorEntityDescription, data: DaikinOneData, device: D, attribute: Callable[[D], StateType]
) -> None:
@@ -559,13 +558,10 @@ def __init__(
self._device: D = device
self._attribute = attribute

@property
def unique_id(self):
"""Return a unique identifier for this sensor."""
return f"{self._device.id}-{self.name}"
self._attr_unique_id = f"{self._device.id}-{self.name}"
self._attr_device_info = self.get_device_info()

@property
def device_info(self) -> DeviceInfo | None:
def get_device_info(self) -> DeviceInfo | None:
"""Return device information for this sensor."""

info = DeviceInfo(
@@ -591,11 +587,6 @@ def device_parent(self) -> str | None:
"""Return the name of the device."""
return None

@property
def native_value(self):
"""Return the state of the sensor."""
return self._state


class DaikinOneThermostatSensor(DaikinOneSensor[DaikinThermostat]):
def __init__(
@@ -615,7 +606,7 @@ async def async_update(self) -> None:
"""Get the latest state of the sensor."""
await self._data.update()
self._device = self._data.daikin.get_thermostat(self._device.id)
self._state = self._attribute(self._device)
self._attr_native_value = self._attribute(self._device)


E = TypeVar("E", bound=DaikinEquipment)
@@ -637,4 +628,4 @@ async def async_update(self) -> None:
await self._data.update()
thermostat = self._data.daikin.get_thermostat(self._device.thermostat_id)
self._device = thermostat.equipment[self._device.id]
self._state = self._attribute(self._device)
self._attr_native_value = self._attribute(self._device)

0 comments on commit 596fe85

Please sign in to comment.