diff --git a/.strict-typing b/.strict-typing index 67efdfa7953..2aa336afb9e 100644 --- a/.strict-typing +++ b/.strict-typing @@ -43,6 +43,7 @@ homeassistant.components.aftership.* homeassistant.components.air_quality.* homeassistant.components.airly.* homeassistant.components.airvisual.* +homeassistant.components.airzone.* homeassistant.components.aladdin_connect.* homeassistant.components.alarm_control_panel.* homeassistant.components.amazon_polly.* diff --git a/homeassistant/components/airzone/binary_sensor.py b/homeassistant/components/airzone/binary_sensor.py index 4dbfc764664..d1885e0edf9 100644 --- a/homeassistant/components/airzone/binary_sensor.py +++ b/homeassistant/components/airzone/binary_sensor.py @@ -1,7 +1,6 @@ """Support for the Airzone sensors.""" from __future__ import annotations -from collections.abc import Mapping from dataclasses import dataclass from typing import Any, Final @@ -22,7 +21,7 @@ from homeassistant.components.binary_sensor import ( BinarySensorEntityDescription, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -120,20 +119,15 @@ class AirzoneBinarySensor(AirzoneEntity, BinarySensorEntity): entity_description: AirzoneBinarySensorEntityDescription - @property - def extra_state_attributes(self) -> Mapping[str, Any] | None: - """Return state attributes.""" - if not self.entity_description.attributes: - return None - return { - key: self.get_airzone_value(val) - for key, val in self.entity_description.attributes.items() - } - - @property - def is_on(self) -> bool | None: - """Return true if the binary sensor is on.""" - return self.get_airzone_value(self.entity_description.key) + @callback + def _async_update_attrs(self) -> None: + """Update binary sensor attributes.""" + self._attr_is_on = self.get_airzone_value(self.entity_description.key) + if self.entity_description.attributes: + self._attr_extra_state_attributes = { + key: self.get_airzone_value(val) + for key, val in self.entity_description.attributes.items() + } class AirzoneSystemBinarySensor(AirzoneSystemEntity, AirzoneBinarySensor): @@ -152,6 +146,7 @@ class AirzoneSystemBinarySensor(AirzoneSystemEntity, AirzoneBinarySensor): self._attr_name = f"System {system_id} {description.name}" self._attr_unique_id = f"{self._attr_unique_id}_{system_id}_{description.key}" self.entity_description = description + self._async_update_attrs() class AirzoneZoneBinarySensor(AirzoneZoneEntity, AirzoneBinarySensor): @@ -173,3 +168,4 @@ class AirzoneZoneBinarySensor(AirzoneZoneEntity, AirzoneBinarySensor): f"{self._attr_unique_id}_{system_zone_id}_{description.key}" ) self.entity_description = description + self._async_update_attrs() diff --git a/homeassistant/components/airzone/climate.py b/homeassistant/components/airzone/climate.py index 21bb08f08c9..e264df18e0c 100644 --- a/homeassistant/components/airzone/climate.py +++ b/homeassistant/components/airzone/climate.py @@ -162,7 +162,7 @@ class AirzoneClimate(AirzoneZoneEntity, ClimateEntity): params[API_ON] = 1 await self._async_update_hvac_params(params) - async def async_set_temperature(self, **kwargs) -> None: + async def async_set_temperature(self, **kwargs: dict[str, Any]) -> None: """Set new target temperature.""" params = { API_SET_POINT: kwargs.get(ATTR_TEMPERATURE), diff --git a/homeassistant/components/airzone/coordinator.py b/homeassistant/components/airzone/coordinator.py index 9e1dc44bb6c..f9f7322a3eb 100644 --- a/homeassistant/components/airzone/coordinator.py +++ b/homeassistant/components/airzone/coordinator.py @@ -3,6 +3,7 @@ from __future__ import annotations from datetime import timedelta import logging +from typing import Any, cast from aioairzone.exceptions import AirzoneError from aioairzone.localapi import AirzoneLocalApi @@ -18,7 +19,7 @@ SCAN_INTERVAL = timedelta(seconds=60) _LOGGER = logging.getLogger(__name__) -class AirzoneUpdateCoordinator(DataUpdateCoordinator): +class AirzoneUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]): """Class to manage fetching data from the Airzone device.""" def __init__(self, hass: HomeAssistant, airzone: AirzoneLocalApi) -> None: @@ -30,13 +31,14 @@ class AirzoneUpdateCoordinator(DataUpdateCoordinator): _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL, + update_method=self._async_update, ) - async def _async_update_data(self): + async def _async_update(self) -> dict[str, Any]: """Update data via library.""" async with async_timeout.timeout(AIOAIRZONE_DEVICE_TIMEOUT_SEC): try: await self.airzone.update() except AirzoneError as error: raise UpdateFailed(error) from error - return self.airzone.data() + return cast(dict[str, Any], self.airzone.data()) diff --git a/homeassistant/components/airzone/entity.py b/homeassistant/components/airzone/entity.py index bf1512f3801..687d7873ece 100644 --- a/homeassistant/components/airzone/entity.py +++ b/homeassistant/components/airzone/entity.py @@ -27,7 +27,7 @@ from .coordinator import AirzoneUpdateCoordinator class AirzoneEntity(CoordinatorEntity[AirzoneUpdateCoordinator]): """Define an Airzone entity.""" - def get_airzone_value(self, key) -> Any: + def get_airzone_value(self, key: str) -> Any: """Return Airzone entity value by key.""" raise NotImplementedError() @@ -58,7 +58,7 @@ class AirzoneSystemEntity(AirzoneEntity): entry.entry_id if entry.unique_id is None else entry.unique_id ) - def get_airzone_value(self, key) -> Any: + def get_airzone_value(self, key: str) -> Any: """Return system value by key.""" value = None if system := self.coordinator.data[AZD_SYSTEMS].get(self.system_id): @@ -96,7 +96,7 @@ class AirzoneZoneEntity(AirzoneEntity): entry.entry_id if entry.unique_id is None else entry.unique_id ) - def get_airzone_value(self, key) -> Any: + def get_airzone_value(self, key: str) -> Any: """Return zone value by key.""" value = None if zone := self.coordinator.data[AZD_ZONES].get(self.system_zone_id): diff --git a/homeassistant/components/airzone/sensor.py b/homeassistant/components/airzone/sensor.py index 81dcea5098e..3e81f5df094 100644 --- a/homeassistant/components/airzone/sensor.py +++ b/homeassistant/components/airzone/sensor.py @@ -13,7 +13,7 @@ from homeassistant.components.sensor import ( ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import PERCENTAGE, TEMP_CELSIUS -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN, TEMP_UNIT_LIB_TO_HASS @@ -64,10 +64,10 @@ async def async_setup_entry( class AirzoneSensor(AirzoneEntity, SensorEntity): """Define an Airzone sensor.""" - @property - def native_value(self): - """Return the state.""" - return self.get_airzone_value(self.entity_description.key) + @callback + def _async_update_attrs(self) -> None: + """Update sensor attributes.""" + self._attr_native_value = self.get_airzone_value(self.entity_description.key) class AirzoneZoneSensor(AirzoneZoneEntity, AirzoneSensor): @@ -94,3 +94,5 @@ class AirzoneZoneSensor(AirzoneZoneEntity, AirzoneSensor): self._attr_native_unit_of_measurement = TEMP_UNIT_LIB_TO_HASS.get( self.get_airzone_value(AZD_TEMP_UNIT) ) + + self._async_update_attrs() diff --git a/mypy.ini b/mypy.ini index 81677b8d8ff..0232e1eec15 100644 --- a/mypy.ini +++ b/mypy.ini @@ -236,6 +236,17 @@ no_implicit_optional = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.airzone.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +no_implicit_optional = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.aladdin_connect.*] check_untyped_defs = true disallow_incomplete_defs = true