Ensure Guardian is strictly typed (#53253)
parent
560bde94ef
commit
1bde914075
|
@ -43,6 +43,7 @@ homeassistant.components.fritz.*
|
|||
homeassistant.components.geo_location.*
|
||||
homeassistant.components.gios.*
|
||||
homeassistant.components.group.*
|
||||
homeassistant.components.guardian.*
|
||||
homeassistant.components.history.*
|
||||
homeassistant.components.homeassistant.triggers.event
|
||||
homeassistant.components.http.*
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Awaitable, MutableMapping
|
||||
from typing import Any, cast
|
||||
|
||||
from aioguardian import Client
|
||||
|
||||
|
@ -89,7 +91,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
await paired_sensor_manager.async_process_latest_paired_sensor_uids()
|
||||
|
||||
@callback
|
||||
def async_process_paired_sensor_uids():
|
||||
def async_process_paired_sensor_uids() -> None:
|
||||
"""Define a callback for when new paired sensor data is received."""
|
||||
hass.async_create_task(
|
||||
paired_sensor_manager.async_process_latest_paired_sensor_uids()
|
||||
|
@ -133,8 +135,7 @@ class PairedSensorManager:
|
|||
self._client = client
|
||||
self._entry = entry
|
||||
self._hass = hass
|
||||
self._listeners = []
|
||||
self._paired_uids = set()
|
||||
self._paired_uids: set[str] = set()
|
||||
|
||||
async def async_pair_sensor(self, uid: str) -> None:
|
||||
"""Add a new paired sensor coordinator."""
|
||||
|
@ -148,7 +149,9 @@ class PairedSensorManager:
|
|||
self._hass,
|
||||
client=self._client,
|
||||
api_name=f"{API_SENSOR_PAIRED_SENSOR_STATUS}_{uid}",
|
||||
api_coro=lambda: self._client.sensor.paired_sensor_status(uid),
|
||||
api_coro=lambda: cast(
|
||||
Awaitable, self._client.sensor.paired_sensor_status(uid)
|
||||
),
|
||||
api_lock=self._api_lock,
|
||||
valve_controller_uid=self._entry.data[CONF_UID],
|
||||
)
|
||||
|
@ -208,12 +211,19 @@ class GuardianEntity(CoordinatorEntity):
|
|||
"""Define a base Guardian entity."""
|
||||
|
||||
def __init__( # pylint: disable=super-init-not-called
|
||||
self, entry: ConfigEntry, kind: str, name: str, device_class: str, icon: str
|
||||
self,
|
||||
entry: ConfigEntry,
|
||||
kind: str,
|
||||
name: str,
|
||||
device_class: str | None,
|
||||
icon: str | None,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
self._attr_device_class = device_class
|
||||
self._attr_device_info = {"manufacturer": "Elexa"}
|
||||
self._attr_extra_state_attributes = {ATTR_ATTRIBUTION: "Data provided by Elexa"}
|
||||
self._attr_extra_state_attributes: MutableMapping[str, Any] = {
|
||||
ATTR_ATTRIBUTION: "Data provided by Elexa"
|
||||
}
|
||||
self._attr_icon = icon
|
||||
self._attr_name = name
|
||||
self._entry = entry
|
||||
|
@ -236,16 +246,18 @@ class PairedSensorEntity(GuardianEntity):
|
|||
coordinator: DataUpdateCoordinator,
|
||||
kind: str,
|
||||
name: str,
|
||||
device_class: str,
|
||||
icon: str,
|
||||
device_class: str | None,
|
||||
icon: str | None,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(entry, kind, name, device_class, icon)
|
||||
|
||||
paired_sensor_uid = coordinator.data["uid"]
|
||||
self._attr_device_info["identifiers"] = {(DOMAIN, paired_sensor_uid)}
|
||||
self._attr_device_info["name"] = f"Guardian Paired Sensor {paired_sensor_uid}"
|
||||
self._attr_device_info["via_device"] = (DOMAIN, entry.data[CONF_UID])
|
||||
self._attr_device_info = {
|
||||
"identifiers": {(DOMAIN, paired_sensor_uid)},
|
||||
"name": f"Guardian Paired Sensor {paired_sensor_uid}",
|
||||
"via_device": (DOMAIN, entry.data[CONF_UID]),
|
||||
}
|
||||
self._attr_name = f"Guardian Paired Sensor {paired_sensor_uid}: {name}"
|
||||
self._attr_unique_id = f"{paired_sensor_uid}_{kind}"
|
||||
self._kind = kind
|
||||
|
@ -271,13 +283,11 @@ class ValveControllerEntity(GuardianEntity):
|
|||
"""Initialize."""
|
||||
super().__init__(entry, kind, name, device_class, icon)
|
||||
|
||||
self._attr_device_info["identifiers"] = {(DOMAIN, entry.data[CONF_UID])}
|
||||
self._attr_device_info[
|
||||
"name"
|
||||
] = f"Guardian Valve Controller {entry.data[CONF_UID]}"
|
||||
self._attr_device_info["model"] = coordinators[API_SYSTEM_DIAGNOSTICS].data[
|
||||
"firmware"
|
||||
]
|
||||
self._attr_device_info = {
|
||||
"identifiers": {(DOMAIN, entry.data[CONF_UID])},
|
||||
"name": f"Guardian Valve Controller {entry.data[CONF_UID]}",
|
||||
"model": coordinators[API_SYSTEM_DIAGNOSTICS].data["firmware"],
|
||||
}
|
||||
self._attr_name = f"Guardian {entry.data[CONF_UID]}: {name}"
|
||||
self._attr_unique_id = f"{entry.data[CONF_UID]}_{kind}"
|
||||
self._kind = kind
|
||||
|
@ -304,7 +314,7 @@ class ValveControllerEntity(GuardianEntity):
|
|||
"""Add a listener to a DataUpdateCoordinator based on the API referenced."""
|
||||
|
||||
@callback
|
||||
def update():
|
||||
def update() -> None:
|
||||
"""Update the entity's state."""
|
||||
self._async_update_from_latest_data()
|
||||
self.async_write_ha_state()
|
||||
|
@ -327,6 +337,7 @@ class ValveControllerEntity(GuardianEntity):
|
|||
return
|
||||
|
||||
refresh_tasks = [
|
||||
coordinator.async_request_refresh() for coordinator in self.coordinators
|
||||
coordinator.async_request_refresh()
|
||||
for coordinator in self.coordinators.values()
|
||||
]
|
||||
await asyncio.gather(*refresh_tasks)
|
||||
|
|
|
@ -78,7 +78,7 @@ async def async_setup_entry(
|
|||
)
|
||||
)
|
||||
|
||||
sensors = []
|
||||
sensors: list[PairedSensorBinarySensor | ValveControllerBinarySensor] = []
|
||||
|
||||
# Add all valve controller-specific binary sensors:
|
||||
for kind in VALVE_CONTROLLER_SENSORS:
|
||||
|
|
|
@ -40,7 +40,7 @@ def async_get_pin_from_uid(uid: str) -> str:
|
|||
return uid[-4:]
|
||||
|
||||
|
||||
async def validate_input(hass: HomeAssistant, data: dict[str, Any]):
|
||||
async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Validate the user input allows us to connect.
|
||||
|
||||
Data has the keys from DATA_SCHEMA with values provided by the user.
|
||||
|
@ -60,7 +60,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize."""
|
||||
self.discovery_info = {}
|
||||
self.discovery_info: dict[str, Any] = {}
|
||||
|
||||
async def _async_set_unique_id(self, pin: str) -> None:
|
||||
"""Set the config entry's unique ID (based on the device's 4-digit PIN)."""
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Elexa Guardian",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/guardian",
|
||||
"requirements": ["aioguardian==1.0.4"],
|
||||
"requirements": ["aioguardian==1.0.8"],
|
||||
"zeroconf": ["_api._udp.local."],
|
||||
"codeowners": ["@bachya"],
|
||||
"iot_class": "local_polling",
|
||||
|
|
|
@ -78,7 +78,7 @@ async def async_setup_entry(
|
|||
)
|
||||
)
|
||||
|
||||
sensors = []
|
||||
sensors: list[PairedSensorSensor | ValveControllerSensor] = []
|
||||
|
||||
# Add all valve controller-specific binary sensors:
|
||||
for kind in VALVE_CONTROLLER_SENSORS:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""Switches for the Elexa Guardian integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from aioguardian import Client
|
||||
from aioguardian.errors import GuardianError
|
||||
import voluptuous as vol
|
||||
|
@ -95,7 +97,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
self._attr_is_on = True
|
||||
self._client = client
|
||||
|
||||
async def _async_continue_entity_setup(self):
|
||||
async def _async_continue_entity_setup(self) -> None:
|
||||
"""Register API interest (and related tasks) when the entity is added."""
|
||||
self.async_add_coordinator_update_listener(API_VALVE_STATUS)
|
||||
|
||||
|
@ -127,7 +129,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
}
|
||||
)
|
||||
|
||||
async def async_disable_ap(self):
|
||||
async def async_disable_ap(self) -> None:
|
||||
"""Disable the device's onboard access point."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -135,7 +137,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
except GuardianError as err:
|
||||
LOGGER.error("Error while disabling valve controller AP: %s", err)
|
||||
|
||||
async def async_enable_ap(self):
|
||||
async def async_enable_ap(self) -> None:
|
||||
"""Enable the device's onboard access point."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -143,7 +145,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
except GuardianError as err:
|
||||
LOGGER.error("Error while enabling valve controller AP: %s", err)
|
||||
|
||||
async def async_pair_sensor(self, *, uid):
|
||||
async def async_pair_sensor(self, *, uid: str) -> None:
|
||||
"""Add a new paired sensor."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -156,7 +158,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
self._entry.entry_id
|
||||
].async_pair_sensor(uid)
|
||||
|
||||
async def async_reboot(self):
|
||||
async def async_reboot(self) -> None:
|
||||
"""Reboot the device."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -164,7 +166,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
except GuardianError as err:
|
||||
LOGGER.error("Error while rebooting valve controller: %s", err)
|
||||
|
||||
async def async_reset_valve_diagnostics(self):
|
||||
async def async_reset_valve_diagnostics(self) -> None:
|
||||
"""Fully reset system motor diagnostics."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -172,7 +174,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
except GuardianError as err:
|
||||
LOGGER.error("Error while resetting valve diagnostics: %s", err)
|
||||
|
||||
async def async_unpair_sensor(self, *, uid):
|
||||
async def async_unpair_sensor(self, *, uid: str) -> None:
|
||||
"""Add a new paired sensor."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -185,7 +187,9 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
self._entry.entry_id
|
||||
].async_unpair_sensor(uid)
|
||||
|
||||
async def async_upgrade_firmware(self, *, url, port, filename):
|
||||
async def async_upgrade_firmware(
|
||||
self, *, url: str, port: int, filename: str
|
||||
) -> None:
|
||||
"""Upgrade the device firmware."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -197,7 +201,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
except GuardianError as err:
|
||||
LOGGER.error("Error while upgrading firmware: %s", err)
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
async def async_turn_off(self, **kwargs: dict[str, Any]) -> None:
|
||||
"""Turn the valve off (closed)."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
@ -209,7 +213,7 @@ class ValveControllerSwitch(ValveControllerEntity, SwitchEntity):
|
|||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
async def async_turn_on(self, **kwargs: dict[str, Any]) -> None:
|
||||
"""Turn the valve on (open)."""
|
||||
try:
|
||||
async with self._client:
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||
import asyncio
|
||||
from collections.abc import Awaitable
|
||||
from datetime import timedelta
|
||||
from typing import Callable
|
||||
from typing import Any, Callable, Dict, cast
|
||||
|
||||
from aioguardian import Client
|
||||
from aioguardian.errors import GuardianError
|
||||
|
@ -42,11 +42,11 @@ class GuardianDataUpdateCoordinator(DataUpdateCoordinator[dict]):
|
|||
self._api_lock = api_lock
|
||||
self._client = client
|
||||
|
||||
async def _async_update_data(self) -> dict:
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Execute a "locked" API request against the valve controller."""
|
||||
async with self._api_lock, self._client:
|
||||
try:
|
||||
resp = await self._api_coro()
|
||||
except GuardianError as err:
|
||||
raise UpdateFailed(err) from err
|
||||
return resp["data"]
|
||||
return cast(Dict[str, Any], resp["data"])
|
||||
|
|
14
mypy.ini
14
mypy.ini
|
@ -484,6 +484,17 @@ no_implicit_optional = true
|
|||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
[mypy-homeassistant.components.guardian.*]
|
||||
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.history.*]
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
|
@ -1252,9 +1263,6 @@ ignore_errors = true
|
|||
[mypy-homeassistant.components.gtfs.*]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.guardian.*]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-homeassistant.components.habitica.*]
|
||||
ignore_errors = true
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ aioflo==0.4.1
|
|||
aioftp==0.12.0
|
||||
|
||||
# homeassistant.components.guardian
|
||||
aioguardian==1.0.4
|
||||
aioguardian==1.0.8
|
||||
|
||||
# homeassistant.components.harmony
|
||||
aioharmony==0.2.7
|
||||
|
|
|
@ -109,7 +109,7 @@ aioesphomeapi==5.0.1
|
|||
aioflo==0.4.1
|
||||
|
||||
# homeassistant.components.guardian
|
||||
aioguardian==1.0.4
|
||||
aioguardian==1.0.8
|
||||
|
||||
# homeassistant.components.harmony
|
||||
aioharmony==0.2.7
|
||||
|
|
|
@ -61,7 +61,6 @@ IGNORED_MODULES: Final[list[str]] = [
|
|||
"homeassistant.components.gree.*",
|
||||
"homeassistant.components.growatt_server.*",
|
||||
"homeassistant.components.gtfs.*",
|
||||
"homeassistant.components.guardian.*",
|
||||
"homeassistant.components.habitica.*",
|
||||
"homeassistant.components.harmony.*",
|
||||
"homeassistant.components.hassio.*",
|
||||
|
|
Loading…
Reference in New Issue