Bump evohome-async to 0.4.9 (#103660)
parent
abc05451a2
commit
f50cd5ab5e
|
@ -190,14 +190,14 @@ def _handle_exception(err) -> None:
|
|||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Create a (EMEA/EU-based) Honeywell TCC system."""
|
||||
|
||||
async def load_auth_tokens(store) -> tuple[dict, dict | None]:
|
||||
async def load_auth_tokens(store) -> tuple[dict[str, str | dt], dict[str, str]]:
|
||||
app_storage = await store.async_load()
|
||||
tokens = dict(app_storage or {})
|
||||
|
||||
if tokens.pop(CONF_USERNAME, None) != config[DOMAIN][CONF_USERNAME]:
|
||||
# any tokens won't be valid, and store might be corrupt
|
||||
await store.async_save({})
|
||||
return ({}, None)
|
||||
return ({}, {})
|
||||
|
||||
# evohomeasync2 requires naive/local datetimes as strings
|
||||
if tokens.get(ACCESS_TOKEN_EXPIRES) is not None and (
|
||||
|
@ -205,7 +205,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
):
|
||||
tokens[ACCESS_TOKEN_EXPIRES] = _dt_aware_to_naive(expires)
|
||||
|
||||
user_data = tokens.pop(USER_DATA, None)
|
||||
user_data = tokens.pop(USER_DATA, {})
|
||||
return (tokens, user_data)
|
||||
|
||||
store = Store[dict[str, Any]](hass, STORAGE_VER, STORAGE_KEY)
|
||||
|
@ -214,7 +214,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
client_v2 = evohomeasync2.EvohomeClient(
|
||||
config[DOMAIN][CONF_USERNAME],
|
||||
config[DOMAIN][CONF_PASSWORD],
|
||||
**tokens,
|
||||
**tokens, # type: ignore[arg-type]
|
||||
session=async_get_clientsession(hass),
|
||||
)
|
||||
|
||||
|
@ -253,7 +253,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
client_v1 = evohomeasync.EvohomeClient(
|
||||
client_v2.username,
|
||||
client_v2.password,
|
||||
user_data=user_data,
|
||||
session_id=user_data.get("sessionId") if user_data else None, # STORAGE_VER 1
|
||||
session=async_get_clientsession(hass),
|
||||
)
|
||||
|
||||
|
@ -425,7 +425,7 @@ class EvoBroker:
|
|||
self.tcs_utc_offset = timedelta(
|
||||
minutes=client.locations[loc_idx].timeZone[UTC_OFFSET]
|
||||
)
|
||||
self.temps: dict[str, Any] | None = {}
|
||||
self.temps: dict[str, float | None] = {}
|
||||
|
||||
async def save_auth_tokens(self) -> None:
|
||||
"""Save access tokens and session IDs to the store for later use."""
|
||||
|
@ -441,14 +441,12 @@ class EvoBroker:
|
|||
ACCESS_TOKEN_EXPIRES: access_token_expires.isoformat(),
|
||||
}
|
||||
|
||||
if self.client_v1 and self.client_v1.user_data:
|
||||
user_id = self.client_v1.user_data["userInfo"]["userID"] # type: ignore[index]
|
||||
if self.client_v1:
|
||||
app_storage[USER_DATA] = { # type: ignore[assignment]
|
||||
"userInfo": {"userID": user_id},
|
||||
"sessionId": self.client_v1.user_data["sessionId"],
|
||||
}
|
||||
"sessionId": self.client_v1.broker.session_id,
|
||||
} # this is the schema for STORAGE_VER == 1
|
||||
else:
|
||||
app_storage[USER_DATA] = None
|
||||
app_storage[USER_DATA] = {} # type: ignore[assignment]
|
||||
|
||||
await self._store.async_save(app_storage)
|
||||
|
||||
|
@ -468,16 +466,13 @@ class EvoBroker:
|
|||
async def _update_v1_api_temps(self, *args, **kwargs) -> None:
|
||||
"""Get the latest high-precision temperatures of the default Location."""
|
||||
|
||||
assert self.client_v1
|
||||
assert self.client_v1 # mypy check
|
||||
|
||||
def get_session_id(client_v1) -> str | None:
|
||||
user_data = client_v1.user_data if client_v1 else None
|
||||
return user_data.get("sessionId") if user_data else None
|
||||
|
||||
session_id = get_session_id(self.client_v1)
|
||||
session_id = self.client_v1.broker.session_id # maybe receive a new session_id?
|
||||
|
||||
self.temps = {} # these are now stale, will fall back to v2 temps
|
||||
try:
|
||||
temps = list(await self.client_v1.temperatures(force_refresh=True))
|
||||
temps = await self.client_v1.get_temperatures()
|
||||
|
||||
except evohomeasync.InvalidSchema as exc:
|
||||
_LOGGER.warning(
|
||||
|
@ -489,7 +484,7 @@ class EvoBroker:
|
|||
),
|
||||
exc,
|
||||
)
|
||||
self.temps = self.client_v1 = None
|
||||
self.client_v1 = None
|
||||
|
||||
except evohomeasync.EvohomeError as exc:
|
||||
_LOGGER.warning(
|
||||
|
@ -501,7 +496,6 @@ class EvoBroker:
|
|||
),
|
||||
exc,
|
||||
)
|
||||
self.temps = None # these are now stale, will fall back to v2 temps
|
||||
|
||||
else:
|
||||
if (
|
||||
|
@ -513,19 +507,20 @@ class EvoBroker:
|
|||
"the v1 API's default location (there is more than one location), "
|
||||
"so the high-precision feature will be disabled until next restart"
|
||||
)
|
||||
self.temps = self.client_v1 = None
|
||||
self.client_v1 = None
|
||||
else:
|
||||
self.temps = {str(i["id"]): i["temp"] for i in temps}
|
||||
|
||||
finally:
|
||||
if session_id != get_session_id(self.client_v1):
|
||||
if self.client_v1 and session_id != self.client_v1.broker.session_id:
|
||||
await self.save_auth_tokens()
|
||||
|
||||
_LOGGER.debug("Temperatures = %s", self.temps)
|
||||
|
||||
async def _update_v2_api_state(self, *args, **kwargs) -> None:
|
||||
"""Get the latest modes, temperatures, setpoints of a Location."""
|
||||
access_token = self.client.access_token
|
||||
|
||||
access_token = self.client.access_token # maybe receive a new token?
|
||||
|
||||
loc_idx = self.params[CONF_LOCATION_IDX]
|
||||
try:
|
||||
|
@ -536,9 +531,9 @@ class EvoBroker:
|
|||
async_dispatcher_send(self.hass, DOMAIN)
|
||||
|
||||
_LOGGER.debug("Status = %s", status)
|
||||
|
||||
if access_token != self.client.access_token:
|
||||
await self.save_auth_tokens()
|
||||
finally:
|
||||
if access_token != self.client.access_token:
|
||||
await self.save_auth_tokens()
|
||||
|
||||
async def async_update(self, *args, **kwargs) -> None:
|
||||
"""Get the latest state data of an entire Honeywell TCC Location.
|
||||
|
@ -562,6 +557,8 @@ class EvoDevice(Entity):
|
|||
|
||||
_attr_should_poll = False
|
||||
|
||||
_evo_id: str
|
||||
|
||||
def __init__(self, evo_broker, evo_device) -> None:
|
||||
"""Initialize the evohome entity."""
|
||||
self._evo_device = evo_device
|
||||
|
@ -623,18 +620,10 @@ class EvoChild(EvoDevice):
|
|||
@property
|
||||
def current_temperature(self) -> float | None:
|
||||
"""Return the current temperature of a Zone."""
|
||||
if self._evo_device.TYPE == "domesticHotWater":
|
||||
dev_id = self._evo_device.dhwId
|
||||
else:
|
||||
dev_id = self._evo_device.zoneId
|
||||
|
||||
if self._evo_broker.temps and self._evo_broker.temps[dev_id] is not None:
|
||||
return self._evo_broker.temps[dev_id]
|
||||
|
||||
if self._evo_device.temperatureStatus["isAvailable"]:
|
||||
return self._evo_device.temperatureStatus["temperature"]
|
||||
|
||||
return None
|
||||
if self._evo_broker.temps.get(self._evo_id) is not None:
|
||||
return self._evo_broker.temps[self._evo_id]
|
||||
return self._evo_device.temperature
|
||||
|
||||
@property
|
||||
def setpoints(self) -> dict[str, Any]:
|
||||
|
@ -679,7 +668,7 @@ class EvoChild(EvoDevice):
|
|||
switchpoint_time_of_day = dt_util.parse_datetime(
|
||||
f"{sp_date}T{switchpoint['TimeOfDay']}"
|
||||
)
|
||||
assert switchpoint_time_of_day
|
||||
assert switchpoint_time_of_day # mypy check
|
||||
dt_aware = _dt_evo_to_aware(
|
||||
switchpoint_time_of_day, self._evo_broker.tcs_utc_offset
|
||||
)
|
||||
|
|
|
@ -150,6 +150,7 @@ class EvoZone(EvoChild, EvoClimateEntity):
|
|||
self._attr_unique_id = f"{evo_device.zoneId}z"
|
||||
else:
|
||||
self._attr_unique_id = evo_device.zoneId
|
||||
self._evo_id = evo_device.zoneId
|
||||
|
||||
self._attr_name = evo_device.name
|
||||
|
||||
|
@ -189,24 +190,27 @@ class EvoZone(EvoChild, EvoClimateEntity):
|
|||
)
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
def hvac_mode(self) -> HVACMode | None:
|
||||
"""Return the current operating mode of a Zone."""
|
||||
if self._evo_tcs.systemModeStatus["mode"] in (EVO_AWAY, EVO_HEATOFF):
|
||||
if self._evo_tcs.system_mode in (EVO_AWAY, EVO_HEATOFF):
|
||||
return HVACMode.AUTO
|
||||
is_off = self.target_temperature <= self.min_temp
|
||||
return HVACMode.OFF if is_off else HVACMode.HEAT
|
||||
if self.target_temperature is None:
|
||||
return None
|
||||
if self.target_temperature <= self.min_temp:
|
||||
return HVACMode.OFF
|
||||
return HVACMode.HEAT
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> float:
|
||||
def target_temperature(self) -> float | None:
|
||||
"""Return the target temperature of a Zone."""
|
||||
return self._evo_device.setpointStatus["targetHeatTemperature"]
|
||||
return self._evo_device.target_heat_temperature
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> str | None:
|
||||
"""Return the current preset mode, e.g., home, away, temp."""
|
||||
if self._evo_tcs.systemModeStatus["mode"] in (EVO_AWAY, EVO_HEATOFF):
|
||||
return TCS_PRESET_TO_HA.get(self._evo_tcs.systemModeStatus["mode"])
|
||||
return EVO_PRESET_TO_HA.get(self._evo_device.setpointStatus["setpointMode"])
|
||||
if self._evo_tcs.system_mode in (EVO_AWAY, EVO_HEATOFF):
|
||||
return TCS_PRESET_TO_HA.get(self._evo_tcs.system_mode)
|
||||
return EVO_PRESET_TO_HA.get(self._evo_device.mode)
|
||||
|
||||
@property
|
||||
def min_temp(self) -> float:
|
||||
|
@ -214,7 +218,7 @@ class EvoZone(EvoChild, EvoClimateEntity):
|
|||
|
||||
The default is 5, but is user-configurable within 5-35 (in Celsius).
|
||||
"""
|
||||
return self._evo_device.setpointCapabilities["minHeatSetpoint"]
|
||||
return self._evo_device.min_heat_setpoint
|
||||
|
||||
@property
|
||||
def max_temp(self) -> float:
|
||||
|
@ -222,17 +226,17 @@ class EvoZone(EvoChild, EvoClimateEntity):
|
|||
|
||||
The default is 35, but is user-configurable within 5-35 (in Celsius).
|
||||
"""
|
||||
return self._evo_device.setpointCapabilities["maxHeatSetpoint"]
|
||||
return self._evo_device.max_heat_setpoint
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set a new target temperature."""
|
||||
temperature = kwargs["temperature"]
|
||||
|
||||
if (until := kwargs.get("until")) is None:
|
||||
if self._evo_device.setpointStatus["setpointMode"] == EVO_FOLLOW:
|
||||
if self._evo_device.mode == EVO_FOLLOW:
|
||||
await self._update_schedule()
|
||||
until = dt_util.parse_datetime(self.setpoints.get("next_sp_from", ""))
|
||||
elif self._evo_device.setpointStatus["setpointMode"] == EVO_TEMPOVER:
|
||||
elif self._evo_device.mode == EVO_TEMPOVER:
|
||||
until = dt_util.parse_datetime(self._evo_device.setpointStatus["until"])
|
||||
|
||||
until = dt_util.as_utc(until) if until else None
|
||||
|
@ -272,7 +276,7 @@ class EvoZone(EvoChild, EvoClimateEntity):
|
|||
await self._evo_broker.call_client_api(self._evo_device.reset_mode())
|
||||
return
|
||||
|
||||
temperature = self._evo_device.setpointStatus["targetHeatTemperature"]
|
||||
temperature = self._evo_device.target_heat_temperature
|
||||
|
||||
if evo_preset_mode == EVO_TEMPOVER:
|
||||
await self._update_schedule()
|
||||
|
@ -311,6 +315,7 @@ class EvoController(EvoClimateEntity):
|
|||
super().__init__(evo_broker, evo_device)
|
||||
|
||||
self._attr_unique_id = evo_device.systemId
|
||||
self._evo_id = evo_device.systemId
|
||||
self._attr_name = evo_device.location.name
|
||||
|
||||
modes = [m["systemMode"] for m in evo_broker.config["allowedSystemModes"]]
|
||||
|
@ -352,7 +357,7 @@ class EvoController(EvoClimateEntity):
|
|||
@property
|
||||
def hvac_mode(self) -> HVACMode:
|
||||
"""Return the current operating mode of a Controller."""
|
||||
tcs_mode = self._evo_tcs.systemModeStatus["mode"]
|
||||
tcs_mode = self._evo_tcs.system_mode
|
||||
return HVACMode.OFF if tcs_mode == EVO_HEATOFF else HVACMode.HEAT
|
||||
|
||||
@property
|
||||
|
@ -362,16 +367,18 @@ class EvoController(EvoClimateEntity):
|
|||
Controllers do not have a current temp, but one is expected by HA.
|
||||
"""
|
||||
temps = [
|
||||
z.temperatureStatus["temperature"]
|
||||
z.temperature
|
||||
for z in self._evo_tcs.zones.values()
|
||||
if z.temperatureStatus["isAvailable"]
|
||||
if z.temperature is not None
|
||||
]
|
||||
return round(sum(temps) / len(temps), 1) if temps else None
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> str | None:
|
||||
"""Return the current preset mode, e.g., home, away, temp."""
|
||||
return TCS_PRESET_TO_HA.get(self._evo_tcs.systemModeStatus["mode"])
|
||||
if not self._evo_tcs.system_mode:
|
||||
return None
|
||||
return TCS_PRESET_TO_HA.get(self._evo_tcs.system_mode)
|
||||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Raise exception as Controllers don't have a target temperature."""
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/evohome",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["evohomeasync", "evohomeasync2"],
|
||||
"requirements": ["evohome-async==0.4.6"]
|
||||
"requirements": ["evohome-async==0.4.9"]
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ class EvoDHW(EvoChild, WaterHeaterEntity):
|
|||
super().__init__(evo_broker, evo_device)
|
||||
|
||||
self._attr_unique_id = evo_device.dhwId
|
||||
self._evo_id = evo_device.dhwId
|
||||
|
||||
self._attr_precision = (
|
||||
PRECISION_TENTHS if evo_broker.client_v1 else PRECISION_WHOLE
|
||||
|
@ -79,15 +80,15 @@ class EvoDHW(EvoChild, WaterHeaterEntity):
|
|||
@property
|
||||
def current_operation(self) -> str:
|
||||
"""Return the current operating mode (Auto, On, or Off)."""
|
||||
if self._evo_device.stateStatus["mode"] == EVO_FOLLOW:
|
||||
if self._evo_device.mode == EVO_FOLLOW:
|
||||
return STATE_AUTO
|
||||
return EVO_STATE_TO_HA[self._evo_device.stateStatus["state"]]
|
||||
return EVO_STATE_TO_HA[self._evo_device.state]
|
||||
|
||||
@property
|
||||
def is_away_mode_on(self):
|
||||
"""Return True if away mode is on."""
|
||||
is_off = EVO_STATE_TO_HA[self._evo_device.stateStatus["state"]] == STATE_OFF
|
||||
is_permanent = self._evo_device.stateStatus["mode"] == EVO_PERMOVER
|
||||
is_off = EVO_STATE_TO_HA[self._evo_device.state] == STATE_OFF
|
||||
is_permanent = self._evo_device.mode == EVO_PERMOVER
|
||||
return is_off and is_permanent
|
||||
|
||||
async def async_set_operation_mode(self, operation_mode: str) -> None:
|
||||
|
|
|
@ -789,7 +789,7 @@ eufylife-ble-client==0.1.8
|
|||
# evdev==1.6.1
|
||||
|
||||
# homeassistant.components.evohome
|
||||
evohome-async==0.4.6
|
||||
evohome-async==0.4.9
|
||||
|
||||
# homeassistant.components.faa_delays
|
||||
faadelays==2023.9.1
|
||||
|
|
Loading…
Reference in New Issue