diff --git a/.strict-typing b/.strict-typing index 625f80e38c0..13f3e5b8f72 100644 --- a/.strict-typing +++ b/.strict-typing @@ -53,6 +53,7 @@ homeassistant.components.air_quality.* homeassistant.components.airgradient.* homeassistant.components.airly.* homeassistant.components.airnow.* +homeassistant.components.airobot.* homeassistant.components.airos.* homeassistant.components.airq.* homeassistant.components.airthings.* diff --git a/homeassistant/components/airobot/climate.py b/homeassistant/components/airobot/climate.py index 9da653509f9..6570b56fe9d 100644 --- a/homeassistant/components/airobot/climate.py +++ b/homeassistant/components/airobot/climate.py @@ -29,6 +29,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from . import AirobotConfigEntry from .const import DOMAIN +from .coordinator import AirobotDataUpdateCoordinator from .entity import AirobotEntity PARALLEL_UPDATES = 1 @@ -63,7 +64,7 @@ class AirobotClimate(AirobotEntity, ClimateEntity): _attr_min_temp = SETPOINT_TEMP_MIN _attr_max_temp = SETPOINT_TEMP_MAX - def __init__(self, coordinator) -> None: + def __init__(self, coordinator: AirobotDataUpdateCoordinator) -> None: """Initialize the climate entity.""" super().__init__(coordinator) self._attr_unique_id = coordinator.data.status.device_id diff --git a/homeassistant/components/airobot/config_flow.py b/homeassistant/components/airobot/config_flow.py index 1b3485c8b4e..f86b96ca94c 100644 --- a/homeassistant/components/airobot/config_flow.py +++ b/homeassistant/components/airobot/config_flow.py @@ -2,6 +2,7 @@ from __future__ import annotations +import asyncio from collections.abc import Mapping from dataclasses import dataclass import logging @@ -60,11 +61,17 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> DeviceInf try: # Try to fetch data to validate connection and authentication - status = await client.get_statuses() - settings = await client.get_settings() + status, settings = await asyncio.gather( + client.get_statuses(), client.get_settings() + ) except AirobotAuthError as err: raise InvalidAuth from err - except (AirobotConnectionError, AirobotTimeoutError, AirobotError) as err: + except ( + AirobotConnectionError, + AirobotTimeoutError, + AirobotError, + TimeoutError, + ) as err: raise CannotConnect from err # Use device name or device ID as title diff --git a/homeassistant/components/airobot/coordinator.py b/homeassistant/components/airobot/coordinator.py index 617a564aa7c..ea7a974aa5d 100644 --- a/homeassistant/components/airobot/coordinator.py +++ b/homeassistant/components/airobot/coordinator.py @@ -2,6 +2,7 @@ from __future__ import annotations +import asyncio from datetime import timedelta import logging @@ -52,8 +53,10 @@ class AirobotDataUpdateCoordinator(DataUpdateCoordinator[AirobotData]): async def _async_update_data(self) -> AirobotData: """Fetch data from API endpoint.""" try: - status = await self.client.get_statuses() - settings = await self.client.get_settings() + status, settings = await asyncio.gather( + self.client.get_statuses(), + self.client.get_settings(), + ) except AirobotAuthError as err: raise ConfigEntryAuthFailed( translation_domain=DOMAIN, diff --git a/homeassistant/components/airobot/manifest.json b/homeassistant/components/airobot/manifest.json index e10d599f38f..6a2e01f0732 100644 --- a/homeassistant/components/airobot/manifest.json +++ b/homeassistant/components/airobot/manifest.json @@ -12,6 +12,6 @@ "integration_type": "device", "iot_class": "local_polling", "loggers": ["pyairobotrest"], - "quality_scale": "gold", + "quality_scale": "platinum", "requirements": ["pyairobotrest==0.3.0"] } diff --git a/homeassistant/components/airobot/quality_scale.yaml b/homeassistant/components/airobot/quality_scale.yaml index a85e668ef93..a4966e5b8b1 100644 --- a/homeassistant/components/airobot/quality_scale.yaml +++ b/homeassistant/components/airobot/quality_scale.yaml @@ -69,4 +69,4 @@ rules: # Platinum async-dependency: done inject-websession: done - strict-typing: todo + strict-typing: done diff --git a/homeassistant/components/airobot/sensor.py b/homeassistant/components/airobot/sensor.py index a8c784ed399..8afb78b3c76 100644 --- a/homeassistant/components/airobot/sensor.py +++ b/homeassistant/components/airobot/sensor.py @@ -28,6 +28,7 @@ from homeassistant.util.dt import utcnow from homeassistant.util.variance import ignore_variance from . import AirobotConfigEntry +from .coordinator import AirobotDataUpdateCoordinator from .entity import AirobotEntity PARALLEL_UPDATES = 0 @@ -53,6 +54,7 @@ SENSOR_TYPES: tuple[AirobotSensorEntityDescription, ...] = ( device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=1, value_fn=lambda status: status.temp_air, ), AirobotSensorEntityDescription( @@ -136,7 +138,7 @@ class AirobotSensor(AirobotEntity, SensorEntity): def __init__( self, - coordinator, + coordinator: AirobotDataUpdateCoordinator, description: AirobotSensorEntityDescription, ) -> None: """Initialize the sensor.""" diff --git a/mypy.ini b/mypy.ini index da80d719894..7b8d76cd23d 100644 --- a/mypy.ini +++ b/mypy.ini @@ -285,6 +285,16 @@ disallow_untyped_defs = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.airobot.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.airos.*] check_untyped_defs = true disallow_incomplete_defs = true diff --git a/tests/components/airobot/test_climate.py b/tests/components/airobot/test_climate.py index a4ecd94ae05..e3e75ca017b 100644 --- a/tests/components/airobot/test_climate.py +++ b/tests/components/airobot/test_climate.py @@ -22,7 +22,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import ServiceValidationError import homeassistant.helpers.entity_registry as er -from tests.common import MockConfigEntry, snapshot_platform +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform @pytest.fixture @@ -231,8 +231,9 @@ async def test_climate_unavailable_on_update_failure( ) # Advance time to trigger coordinator update (30 second interval) - freezer.tick(timedelta(seconds=35)) - await hass.async_block_till_done() + freezer.tick(timedelta(seconds=30)) + async_fire_time_changed(hass) + await hass.async_block_till_done(wait_background_tasks=True) # Entity should now be unavailable state = hass.states.get("climate.test_thermostat")