Add init type hints to XiaomiCoordinatedMiioEntity derived entities (#145612)

This commit is contained in:
epenet 2025-05-26 14:45:55 +02:00 committed by GitHub
parent 970359c6a0
commit 2d2e0d0fb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 328 additions and 137 deletions

View File

@ -5,7 +5,9 @@ from __future__ import annotations
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Any
from miio import Device as MiioDevice
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass, BinarySensorDeviceClass,
@ -15,6 +17,7 @@ from homeassistant.components.binary_sensor import (
from homeassistant.const import CONF_DEVICE, CONF_MODEL, EntityCategory from homeassistant.const import CONF_DEVICE, CONF_MODEL, EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from . import VacuumCoordinatorDataAttributes from . import VacuumCoordinatorDataAttributes
from .const import ( from .const import (
@ -213,12 +216,21 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class XiaomiGenericBinarySensor(XiaomiCoordinatedMiioEntity, BinarySensorEntity): class XiaomiGenericBinarySensor(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], BinarySensorEntity
):
"""Representation of a Xiaomi Humidifier binary sensor.""" """Representation of a Xiaomi Humidifier binary sensor."""
entity_description: XiaomiMiioBinarySensorDescription entity_description: XiaomiMiioBinarySensorDescription
def __init__(self, device, entry, unique_id, coordinator, description): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str,
coordinator: DataUpdateCoordinator[Any],
description: XiaomiMiioBinarySensorDescription,
) -> None:
"""Initialize the entity.""" """Initialize the entity."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)

View File

@ -3,7 +3,9 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
from miio import Device as MiioDevice
from miio.integrations.vacuum.roborock.vacuum import Consumable from miio.integrations.vacuum.roborock.vacuum import Consumable
from homeassistant.components.button import ( from homeassistant.components.button import (
@ -14,6 +16,7 @@ from homeassistant.components.button import (
from homeassistant.const import CONF_MODEL, EntityCategory from homeassistant.const import CONF_MODEL, EntityCategory
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import MODEL_AIRFRESH_A1, MODEL_AIRFRESH_T2017, MODELS_VACUUM from .const import MODEL_AIRFRESH_A1, MODEL_AIRFRESH_T2017, MODELS_VACUUM
from .entity import XiaomiCoordinatedMiioEntity from .entity import XiaomiCoordinatedMiioEntity
@ -148,14 +151,23 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class XiaomiGenericCoordinatedButton(XiaomiCoordinatedMiioEntity, ButtonEntity): class XiaomiGenericCoordinatedButton(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], ButtonEntity
):
"""A button implementation for Xiaomi.""" """A button implementation for Xiaomi."""
entity_description: XiaomiMiioButtonDescription entity_description: XiaomiMiioButtonDescription
_attr_device_class = ButtonDeviceClass.RESTART _attr_device_class = ButtonDeviceClass.RESTART
def __init__(self, device, entry, unique_id, coordinator, description): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str,
coordinator: DataUpdateCoordinator[Any],
description: XiaomiMiioButtonDescription,
) -> None:
"""Initialize the plug switch.""" """Initialize the plug switch."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
self.entity_description = description self.entity_description = description

View File

@ -6,7 +6,7 @@ from functools import partial
import logging import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from miio import DeviceException from miio import Device as MiioDevice, DeviceException
from miio.gateway.devices import SubDevice from miio.gateway.devices import SubDevice
from homeassistant.const import ATTR_CONNECTIONS, CONF_MAC, CONF_MODEL from homeassistant.const import ATTR_CONNECTIONS, CONF_MAC, CONF_MODEL
@ -70,7 +70,13 @@ class XiaomiCoordinatedMiioEntity[_T: DataUpdateCoordinator[Any]](
_attr_has_entity_name = True _attr_has_entity_name = True
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: _T,
) -> None:
"""Initialize the coordinated Xiaomi Miio Device.""" """Initialize the coordinated Xiaomi Miio Device."""
super().__init__(coordinator) super().__init__(coordinator)
self._device = device self._device = device
@ -88,6 +94,8 @@ class XiaomiCoordinatedMiioEntity[_T: DataUpdateCoordinator[Any]](
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
"""Return the device info.""" """Return the device info."""
if TYPE_CHECKING:
assert self._device_id is not None
device_info = DeviceInfo( device_info = DeviceInfo(
identifiers={(DOMAIN, self._device_id)}, identifiers={(DOMAIN, self._device_id)},
manufacturer="Xiaomi", manufacturer="Xiaomi",

View File

@ -8,6 +8,7 @@ import logging
import math import math
from typing import Any from typing import Any
from miio import Device as MiioDevice
from miio.fan_common import ( from miio.fan_common import (
MoveDirection as FanMoveDirection, MoveDirection as FanMoveDirection,
OperationMode as FanOperationMode, OperationMode as FanOperationMode,
@ -34,6 +35,7 @@ from homeassistant.const import ATTR_ENTITY_ID, CONF_DEVICE, CONF_MODEL
from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.util.percentage import ( from homeassistant.util.percentage import (
percentage_to_ranged_value, percentage_to_ranged_value,
ranged_value_to_percentage, ranged_value_to_percentage,
@ -293,22 +295,30 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity): class XiaomiGenericDevice(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], FanEntity
):
"""Representation of a generic Xiaomi device.""" """Representation of a generic Xiaomi device."""
_attr_name = None _attr_name = None
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the generic Xiaomi device.""" """Initialize the generic Xiaomi device."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
self._available_attributes = {} self._available_attributes: dict[str, Any] = {}
self._state = None self._state: bool | None = None
self._mode = None self._mode: str | None = None
self._fan_level = None self._fan_level: int | None = None
self._state_attrs = {} self._state_attrs: dict[str, Any] = {}
self._device_features = 0 self._device_features = 0
self._preset_modes = [] self._preset_modes: list[str] = []
@property @property
@abstractmethod @abstractmethod
@ -343,7 +353,8 @@ class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity):
) -> None: ) -> None:
"""Turn the device on.""" """Turn the device on."""
result = await self._try_command( result = await self._try_command(
"Turning the miio device on failed.", self._device.on "Turning the miio device on failed.",
self._device.on, # type: ignore[attr-defined]
) )
# If operation mode was set the device must not be turned on. # If operation mode was set the device must not be turned on.
@ -359,7 +370,8 @@ class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity):
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off.""" """Turn the device off."""
result = await self._try_command( result = await self._try_command(
"Turning the miio device off failed.", self._device.off "Turning the miio device off failed.",
self._device.off, # type: ignore[attr-defined]
) )
if result: if result:
@ -370,7 +382,13 @@ class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity):
class XiaomiGenericAirPurifier(XiaomiGenericDevice): class XiaomiGenericAirPurifier(XiaomiGenericDevice):
"""Representation of a generic AirPurifier device.""" """Representation of a generic AirPurifier device."""
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the generic AirPurifier device.""" """Initialize the generic AirPurifier device."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -417,7 +435,13 @@ class XiaomiAirPurifier(XiaomiGenericAirPurifier):
REVERSE_SPEED_MODE_MAPPING = {v: k for k, v in SPEED_MODE_MAPPING.items()} REVERSE_SPEED_MODE_MAPPING = {v: k for k, v in SPEED_MODE_MAPPING.items()}
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the plug switch.""" """Initialize the plug switch."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -528,7 +552,7 @@ class XiaomiAirPurifier(XiaomiGenericAirPurifier):
if speed_mode: if speed_mode:
await self._try_command( await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.operation_mode_class(self.SPEED_MODE_MAPPING[speed_mode]), self.operation_mode_class(self.SPEED_MODE_MAPPING[speed_mode]),
) )
@ -539,7 +563,7 @@ class XiaomiAirPurifier(XiaomiGenericAirPurifier):
""" """
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.operation_mode_class[preset_mode], self.operation_mode_class[preset_mode],
): ):
self._mode = self.operation_mode_class[preset_mode].value self._mode = self.operation_mode_class[preset_mode].value
@ -552,7 +576,7 @@ class XiaomiAirPurifier(XiaomiGenericAirPurifier):
await self._try_command( await self._try_command(
"Setting the extra features of the miio device failed.", "Setting the extra features of the miio device failed.",
self._device.set_extra_features, self._device.set_extra_features, # type: ignore[attr-defined]
features, features,
) )
@ -599,7 +623,7 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
return return
if await self._try_command( if await self._try_command(
"Setting fan level of the miio device failed.", "Setting fan level of the miio device failed.",
self._device.set_fan_level, self._device.set_fan_level, # type: ignore[attr-defined]
fan_level, fan_level,
): ):
self._fan_level = fan_level self._fan_level = fan_level
@ -609,7 +633,13 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
class XiaomiAirPurifierMB4(XiaomiGenericAirPurifier): class XiaomiAirPurifierMB4(XiaomiGenericAirPurifier):
"""Representation of a Xiaomi Air Purifier MB4.""" """Representation of a Xiaomi Air Purifier MB4."""
def __init__(self, device, entry, unique_id, coordinator) -> None: def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize Air Purifier MB4.""" """Initialize Air Purifier MB4."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -659,7 +689,7 @@ class XiaomiAirPurifierMB4(XiaomiGenericAirPurifier):
return return
if await self._try_command( if await self._try_command(
"Setting fan level of the miio device failed.", "Setting fan level of the miio device failed.",
self._device.set_favorite_rpm, self._device.set_favorite_rpm, # type: ignore[attr-defined]
favorite_rpm, favorite_rpm,
): ):
self._favorite_rpm = favorite_rpm self._favorite_rpm = favorite_rpm
@ -673,7 +703,7 @@ class XiaomiAirPurifierMB4(XiaomiGenericAirPurifier):
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.operation_mode_class[preset_mode], self.operation_mode_class[preset_mode],
): ):
self._mode = self.operation_mode_class[preset_mode].value self._mode = self.operation_mode_class[preset_mode].value
@ -712,7 +742,13 @@ class XiaomiAirFresh(XiaomiGenericAirPurifier):
"Interval": AirfreshOperationMode.Interval, "Interval": AirfreshOperationMode.Interval,
} }
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the miio device.""" """Initialize the miio device."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -764,7 +800,7 @@ class XiaomiAirFresh(XiaomiGenericAirPurifier):
if speed_mode: if speed_mode:
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
AirfreshOperationMode(self.SPEED_MODE_MAPPING[speed_mode]), AirfreshOperationMode(self.SPEED_MODE_MAPPING[speed_mode]),
): ):
self._mode = AirfreshOperationMode( self._mode = AirfreshOperationMode(
@ -779,7 +815,7 @@ class XiaomiAirFresh(XiaomiGenericAirPurifier):
""" """
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.operation_mode_class[preset_mode], self.operation_mode_class[preset_mode],
): ):
self._mode = self.operation_mode_class[preset_mode].value self._mode = self.operation_mode_class[preset_mode].value
@ -792,7 +828,7 @@ class XiaomiAirFresh(XiaomiGenericAirPurifier):
await self._try_command( await self._try_command(
"Setting the extra features of the miio device failed.", "Setting the extra features of the miio device failed.",
self._device.set_extra_features, self._device.set_extra_features, # type: ignore[attr-defined]
features, features,
) )
@ -810,10 +846,16 @@ class XiaomiAirFresh(XiaomiGenericAirPurifier):
class XiaomiAirFreshA1(XiaomiGenericAirPurifier): class XiaomiAirFreshA1(XiaomiGenericAirPurifier):
"""Representation of a Xiaomi Air Fresh A1.""" """Representation of a Xiaomi Air Fresh A1."""
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the miio device.""" """Initialize the miio device."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
self._favorite_speed = None self._favorite_speed: int | None = None
self._device_features = FEATURE_FLAGS_AIRFRESH_A1 self._device_features = FEATURE_FLAGS_AIRFRESH_A1
self._preset_modes = PRESET_MODES_AIRFRESH_A1 self._preset_modes = PRESET_MODES_AIRFRESH_A1
self._attr_supported_features = ( self._attr_supported_features = (
@ -857,7 +899,7 @@ class XiaomiAirFreshA1(XiaomiGenericAirPurifier):
return return
if await self._try_command( if await self._try_command(
"Setting fan level of the miio device failed.", "Setting fan level of the miio device failed.",
self._device.set_favorite_speed, self._device.set_favorite_speed, # type: ignore[attr-defined]
favorite_speed, favorite_speed,
): ):
self._favorite_speed = favorite_speed self._favorite_speed = favorite_speed
@ -867,7 +909,7 @@ class XiaomiAirFreshA1(XiaomiGenericAirPurifier):
"""Set the preset mode of the fan. This method is a coroutine.""" """Set the preset mode of the fan. This method is a coroutine."""
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.operation_mode_class[preset_mode], self.operation_mode_class[preset_mode],
): ):
self._mode = self.operation_mode_class[preset_mode].value self._mode = self.operation_mode_class[preset_mode].value
@ -885,7 +927,13 @@ class XiaomiAirFreshA1(XiaomiGenericAirPurifier):
class XiaomiAirFreshT2017(XiaomiAirFreshA1): class XiaomiAirFreshT2017(XiaomiAirFreshA1):
"""Representation of a Xiaomi Air Fresh T2017.""" """Representation of a Xiaomi Air Fresh T2017."""
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the miio device.""" """Initialize the miio device."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
self._device_features = FEATURE_FLAGS_AIRFRESH_T2017 self._device_features = FEATURE_FLAGS_AIRFRESH_T2017
@ -897,7 +945,13 @@ class XiaomiGenericFan(XiaomiGenericDevice):
_attr_translation_key = "generic_fan" _attr_translation_key = "generic_fan"
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the fan.""" """Initialize the fan."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -922,9 +976,9 @@ class XiaomiGenericFan(XiaomiGenericDevice):
) )
if self._model != MODEL_FAN_1C: if self._model != MODEL_FAN_1C:
self._attr_supported_features |= FanEntityFeature.DIRECTION self._attr_supported_features |= FanEntityFeature.DIRECTION
self._preset_mode = None self._preset_mode: str | None = None
self._oscillating = None self._oscillating: bool | None = None
self._percentage = None self._percentage: int | None = None
@property @property
def preset_mode(self) -> str | None: def preset_mode(self) -> str | None:
@ -953,7 +1007,7 @@ class XiaomiGenericFan(XiaomiGenericDevice):
"""Set oscillation.""" """Set oscillation."""
await self._try_command( await self._try_command(
"Setting oscillate on/off of the miio device failed.", "Setting oscillate on/off of the miio device failed.",
self._device.set_oscillate, self._device.set_oscillate, # type: ignore[attr-defined]
oscillating, oscillating,
) )
self._oscillating = oscillating self._oscillating = oscillating
@ -966,7 +1020,7 @@ class XiaomiGenericFan(XiaomiGenericDevice):
await self._try_command( await self._try_command(
"Setting move direction of the miio device failed.", "Setting move direction of the miio device failed.",
self._device.set_rotate, self._device.set_rotate, # type: ignore[attr-defined]
FanMoveDirection(FAN_DIRECTIONS_MAP[direction]), FanMoveDirection(FAN_DIRECTIONS_MAP[direction]),
) )
@ -974,7 +1028,13 @@ class XiaomiGenericFan(XiaomiGenericDevice):
class XiaomiFan(XiaomiGenericFan): class XiaomiFan(XiaomiGenericFan):
"""Representation of a Xiaomi Fan.""" """Representation of a Xiaomi Fan."""
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the fan.""" """Initialize the fan."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -1018,13 +1078,13 @@ class XiaomiFan(XiaomiGenericFan):
if preset_mode == ATTR_MODE_NATURE: if preset_mode == ATTR_MODE_NATURE:
await self._try_command( await self._try_command(
"Setting natural fan speed percentage of the miio device failed.", "Setting natural fan speed percentage of the miio device failed.",
self._device.set_natural_speed, self._device.set_natural_speed, # type: ignore[attr-defined]
self._percentage, self._percentage,
) )
else: else:
await self._try_command( await self._try_command(
"Setting direct fan speed percentage of the miio device failed.", "Setting direct fan speed percentage of the miio device failed.",
self._device.set_direct_speed, self._device.set_direct_speed, # type: ignore[attr-defined]
self._percentage, self._percentage,
) )
@ -1041,13 +1101,13 @@ class XiaomiFan(XiaomiGenericFan):
if self._nature_mode: if self._nature_mode:
await self._try_command( await self._try_command(
"Setting fan speed percentage of the miio device failed.", "Setting fan speed percentage of the miio device failed.",
self._device.set_natural_speed, self._device.set_natural_speed, # type: ignore[attr-defined]
percentage, percentage,
) )
else: else:
await self._try_command( await self._try_command(
"Setting fan speed percentage of the miio device failed.", "Setting fan speed percentage of the miio device failed.",
self._device.set_direct_speed, self._device.set_direct_speed, # type: ignore[attr-defined]
percentage, percentage,
) )
self._percentage = percentage self._percentage = percentage
@ -1061,7 +1121,13 @@ class XiaomiFan(XiaomiGenericFan):
class XiaomiFanP5(XiaomiGenericFan): class XiaomiFanP5(XiaomiGenericFan):
"""Representation of a Xiaomi Fan P5.""" """Representation of a Xiaomi Fan P5."""
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the fan.""" """Initialize the fan."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -1089,7 +1155,7 @@ class XiaomiFanP5(XiaomiGenericFan):
"""Set the preset mode of the fan.""" """Set the preset mode of the fan."""
await self._try_command( await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.operation_mode_class[preset_mode], self.operation_mode_class[preset_mode],
) )
self._preset_mode = preset_mode self._preset_mode = preset_mode
@ -1104,7 +1170,7 @@ class XiaomiFanP5(XiaomiGenericFan):
await self._try_command( await self._try_command(
"Setting fan speed percentage of the miio device failed.", "Setting fan speed percentage of the miio device failed.",
self._device.set_speed, self._device.set_speed, # type: ignore[attr-defined]
percentage, percentage,
) )
self._percentage = percentage self._percentage = percentage
@ -1145,7 +1211,7 @@ class XiaomiFanMiot(XiaomiGenericFan):
"""Set the preset mode of the fan.""" """Set the preset mode of the fan."""
await self._try_command( await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.operation_mode_class[preset_mode], self.operation_mode_class[preset_mode],
) )
self._preset_mode = preset_mode self._preset_mode = preset_mode
@ -1160,7 +1226,7 @@ class XiaomiFanMiot(XiaomiGenericFan):
result = await self._try_command( result = await self._try_command(
"Setting fan speed percentage of the miio device failed.", "Setting fan speed percentage of the miio device failed.",
self._device.set_speed, self._device.set_speed, # type: ignore[attr-defined]
percentage, percentage,
) )
if result: if result:
@ -1184,7 +1250,13 @@ class XiaomiFanZA5(XiaomiFanMiot):
class XiaomiFan1C(XiaomiFanMiot): class XiaomiFan1C(XiaomiFanMiot):
"""Representation of a Xiaomi Fan 1C (Standing Fan 2 Lite).""" """Representation of a Xiaomi Fan 1C (Standing Fan 2 Lite)."""
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize MIOT fan with speed count.""" """Initialize MIOT fan with speed count."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
self._speed_count = 3 self._speed_count = 3
@ -1221,7 +1293,7 @@ class XiaomiFan1C(XiaomiFanMiot):
result = await self._try_command( result = await self._try_command(
"Setting fan speed percentage of the miio device failed.", "Setting fan speed percentage of the miio device failed.",
self._device.set_speed, self._device.set_speed, # type: ignore[attr-defined]
speed, speed,
) )

View File

@ -4,6 +4,7 @@ import logging
import math import math
from typing import Any from typing import Any
from miio import Device as MiioDevice
from miio.integrations.humidifier.deerma.airhumidifier_mjjsq import ( from miio.integrations.humidifier.deerma.airhumidifier_mjjsq import (
OperationMode as AirhumidifierMjjsqOperationMode, OperationMode as AirhumidifierMjjsqOperationMode,
) )
@ -23,6 +24,7 @@ from homeassistant.components.humidifier import (
from homeassistant.const import ATTR_MODE, CONF_DEVICE, CONF_MODEL from homeassistant.const import ATTR_MODE, CONF_DEVICE, CONF_MODEL
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.util.percentage import percentage_to_ranged_value from homeassistant.util.percentage import percentage_to_ranged_value
from .const import ( from .const import (
@ -108,26 +110,35 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class XiaomiGenericHumidifier(XiaomiCoordinatedMiioEntity, HumidifierEntity): class XiaomiGenericHumidifier(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], HumidifierEntity
):
"""Representation of a generic Xiaomi humidifier device.""" """Representation of a generic Xiaomi humidifier device."""
_attr_device_class = HumidifierDeviceClass.HUMIDIFIER _attr_device_class = HumidifierDeviceClass.HUMIDIFIER
_attr_supported_features = HumidifierEntityFeature.MODES _attr_supported_features = HumidifierEntityFeature.MODES
_attr_name = None _attr_name = None
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the generic Xiaomi device.""" """Initialize the generic Xiaomi device."""
super().__init__(device, entry, unique_id, coordinator=coordinator) super().__init__(device, entry, unique_id, coordinator=coordinator)
self._attributes = {} self._attributes: dict[str, Any] = {}
self._mode = None self._mode: str | int | None = None
self._humidity_steps = 100 self._humidity_steps = 100
self._target_humidity: float | None = None self._target_humidity: float | None = None
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on.""" """Turn the device on."""
result = await self._try_command( result = await self._try_command(
"Turning the miio device on failed.", self._device.on "Turning the miio device on failed.",
self._device.on, # type: ignore[attr-defined]
) )
if result: if result:
self._attr_is_on = True self._attr_is_on = True
@ -136,7 +147,8 @@ class XiaomiGenericHumidifier(XiaomiCoordinatedMiioEntity, HumidifierEntity):
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off.""" """Turn the device off."""
result = await self._try_command( result = await self._try_command(
"Turning the miio device off failed.", self._device.off "Turning the miio device off failed.",
self._device.off, # type: ignore[attr-defined]
) )
if result: if result:
@ -159,7 +171,13 @@ class XiaomiAirHumidifier(XiaomiGenericHumidifier, HumidifierEntity):
available_modes: list[str] available_modes: list[str]
def __init__(self, device, entry, unique_id, coordinator): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str | None,
coordinator: DataUpdateCoordinator[Any],
) -> None:
"""Initialize the plug switch.""" """Initialize the plug switch."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -228,7 +246,7 @@ class XiaomiAirHumidifier(XiaomiGenericHumidifier, HumidifierEntity):
_LOGGER.debug("Setting the target humidity to: %s", target_humidity) _LOGGER.debug("Setting the target humidity to: %s", target_humidity)
if await self._try_command( if await self._try_command(
"Setting target humidity of the miio device failed.", "Setting target humidity of the miio device failed.",
self._device.set_target_humidity, self._device.set_target_humidity, # type: ignore[attr-defined]
target_humidity, target_humidity,
): ):
self._target_humidity = target_humidity self._target_humidity = target_humidity
@ -243,7 +261,7 @@ class XiaomiAirHumidifier(XiaomiGenericHumidifier, HumidifierEntity):
_LOGGER.debug("Setting the operation mode to: Auto") _LOGGER.debug("Setting the operation mode to: Auto")
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device to MODE_AUTO failed.", "Setting operation mode of the miio device to MODE_AUTO failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
AirhumidifierOperationMode.Auto, AirhumidifierOperationMode.Auto,
): ):
self._mode = AirhumidifierOperationMode.Auto.value self._mode = AirhumidifierOperationMode.Auto.value
@ -261,7 +279,7 @@ class XiaomiAirHumidifier(XiaomiGenericHumidifier, HumidifierEntity):
_LOGGER.debug("Setting the operation mode to: %s", mode) _LOGGER.debug("Setting the operation mode to: %s", mode)
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
AirhumidifierOperationMode[mode], AirhumidifierOperationMode[mode],
): ):
self._mode = mode.lower() self._mode = mode.lower()
@ -306,7 +324,7 @@ class XiaomiAirHumidifierMiot(XiaomiAirHumidifier):
_LOGGER.debug("Setting the humidity to: %s", target_humidity) _LOGGER.debug("Setting the humidity to: %s", target_humidity)
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_target_humidity, self._device.set_target_humidity, # type: ignore[attr-defined]
target_humidity, target_humidity,
): ):
self._target_humidity = target_humidity self._target_humidity = target_humidity
@ -320,7 +338,7 @@ class XiaomiAirHumidifierMiot(XiaomiAirHumidifier):
_LOGGER.debug("Setting the operation mode to: Auto") _LOGGER.debug("Setting the operation mode to: Auto")
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device to MODE_AUTO failed.", "Setting operation mode of the miio device to MODE_AUTO failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
AirhumidifierMiotOperationMode.Auto, AirhumidifierMiotOperationMode.Auto,
): ):
self._mode = 0 self._mode = 0
@ -339,7 +357,7 @@ class XiaomiAirHumidifierMiot(XiaomiAirHumidifier):
if self.is_on: if self.is_on:
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.REVERSE_MODE_MAPPING[mode], self.REVERSE_MODE_MAPPING[mode],
): ):
self._mode = self.REVERSE_MODE_MAPPING[mode].value self._mode = self.REVERSE_MODE_MAPPING[mode].value
@ -381,7 +399,7 @@ class XiaomiAirHumidifierMjjsq(XiaomiAirHumidifier):
_LOGGER.debug("Setting the humidity to: %s", target_humidity) _LOGGER.debug("Setting the humidity to: %s", target_humidity)
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_target_humidity, self._device.set_target_humidity, # type: ignore[attr-defined]
target_humidity, target_humidity,
): ):
self._target_humidity = target_humidity self._target_humidity = target_humidity
@ -395,7 +413,7 @@ class XiaomiAirHumidifierMjjsq(XiaomiAirHumidifier):
_LOGGER.debug("Setting the operation mode to: Humidity") _LOGGER.debug("Setting the operation mode to: Humidity")
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device to MODE_HUMIDITY failed.", "Setting operation mode of the miio device to MODE_HUMIDITY failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
AirhumidifierMjjsqOperationMode.Humidity, AirhumidifierMjjsqOperationMode.Humidity,
): ):
self._mode = 3 self._mode = 3
@ -411,7 +429,7 @@ class XiaomiAirHumidifierMjjsq(XiaomiAirHumidifier):
if self.is_on: if self.is_on:
if await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode, # type: ignore[attr-defined]
self.MODE_MAPPING[mode], self.MODE_MAPPING[mode],
): ):
self._mode = self.MODE_MAPPING[mode].value self._mode = self.MODE_MAPPING[mode].value

View File

@ -4,8 +4,9 @@ from __future__ import annotations
import dataclasses import dataclasses
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
from miio import Device from miio import Device as MiioDevice
from homeassistant.components.number import ( from homeassistant.components.number import (
DOMAIN as PLATFORM_DOMAIN, DOMAIN as PLATFORM_DOMAIN,
@ -350,17 +351,19 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity): class XiaomiNumberEntity(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], NumberEntity
):
"""Representation of a generic Xiaomi attribute selector.""" """Representation of a generic Xiaomi attribute selector."""
entity_description: XiaomiMiioNumberDescription entity_description: XiaomiMiioNumberDescription
def __init__( def __init__(
self, self,
device: Device, device: MiioDevice,
entry: XiaomiMiioConfigEntry, entry: XiaomiMiioConfigEntry,
unique_id: str, unique_id: str,
coordinator: DataUpdateCoordinator, coordinator: DataUpdateCoordinator[Any],
description: XiaomiMiioNumberDescription, description: XiaomiMiioNumberDescription,
) -> None: ) -> None:
"""Initialize the generic Xiaomi attribute selector.""" """Initialize the generic Xiaomi attribute selector."""
@ -402,7 +405,7 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Set the target motor speed.""" """Set the target motor speed."""
return await self._try_command( return await self._try_command(
"Setting the target motor speed of the miio device failed.", "Setting the target motor speed of the miio device failed.",
self._device.set_speed, self._device.set_speed, # type: ignore[attr-defined]
motor_speed, motor_speed,
) )
@ -410,7 +413,7 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Set the favorite level.""" """Set the favorite level."""
return await self._try_command( return await self._try_command(
"Setting the favorite level of the miio device failed.", "Setting the favorite level of the miio device failed.",
self._device.set_favorite_level, self._device.set_favorite_level, # type: ignore[attr-defined]
level, level,
) )
@ -418,7 +421,7 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Set the fan level.""" """Set the fan level."""
return await self._try_command( return await self._try_command(
"Setting the fan level of the miio device failed.", "Setting the fan level of the miio device failed.",
self._device.set_fan_level, self._device.set_fan_level, # type: ignore[attr-defined]
level, level,
) )
@ -426,21 +429,23 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Set the volume.""" """Set the volume."""
return await self._try_command( return await self._try_command(
"Setting the volume of the miio device failed.", "Setting the volume of the miio device failed.",
self._device.set_volume, self._device.set_volume, # type: ignore[attr-defined]
volume, volume,
) )
async def async_set_oscillation_angle(self, angle: int) -> bool: async def async_set_oscillation_angle(self, angle: int) -> bool:
"""Set the volume.""" """Set the volume."""
return await self._try_command( return await self._try_command(
"Setting angle of the miio device failed.", self._device.set_angle, angle "Setting angle of the miio device failed.",
self._device.set_angle, # type: ignore[attr-defined]
angle,
) )
async def async_set_delay_off_countdown(self, delay_off_countdown: int) -> bool: async def async_set_delay_off_countdown(self, delay_off_countdown: int) -> bool:
"""Set the delay off countdown.""" """Set the delay off countdown."""
return await self._try_command( return await self._try_command(
"Setting delay off miio device failed.", "Setting delay off miio device failed.",
self._device.delay_off, self._device.delay_off, # type: ignore[attr-defined]
delay_off_countdown, delay_off_countdown,
) )
@ -448,7 +453,7 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Set the led brightness level.""" """Set the led brightness level."""
return await self._try_command( return await self._try_command(
"Setting the led brightness level of the miio device failed.", "Setting the led brightness level of the miio device failed.",
self._device.set_led_brightness_level, self._device.set_led_brightness_level, # type: ignore[attr-defined]
level, level,
) )
@ -456,7 +461,7 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Set the led brightness level.""" """Set the led brightness level."""
return await self._try_command( return await self._try_command(
"Setting the led brightness level of the miio device failed.", "Setting the led brightness level of the miio device failed.",
self._device.set_led_brightness, self._device.set_led_brightness, # type: ignore[attr-defined]
level, level,
) )
@ -464,6 +469,6 @@ class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Set the target motor speed.""" """Set the target motor speed."""
return await self._try_command( return await self._try_command(
"Setting the favorite rpm of the miio device failed.", "Setting the favorite rpm of the miio device failed.",
self._device.set_favorite_rpm, self._device.set_favorite_rpm, # type: ignore[attr-defined]
rpm, rpm,
) )

View File

@ -4,8 +4,9 @@ from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
import logging import logging
from typing import NamedTuple from typing import Any, NamedTuple
from miio import Device as MiioDevice
from miio.fan_common import LedBrightness as FanLedBrightness from miio.fan_common import LedBrightness as FanLedBrightness
from miio.integrations.airpurifier.dmaker.airfresh_t2017 import ( from miio.integrations.airpurifier.dmaker.airfresh_t2017 import (
DisplayOrientation as AirfreshT2017DisplayOrientation, DisplayOrientation as AirfreshT2017DisplayOrientation,
@ -32,6 +33,7 @@ from homeassistant.components.select import SelectEntity, SelectEntityDescriptio
from homeassistant.const import CONF_DEVICE, CONF_MODEL, EntityCategory from homeassistant.const import CONF_DEVICE, CONF_MODEL, EntityCategory
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import ( from .const import (
CONF_FLOW_TYPE, CONF_FLOW_TYPE,
@ -87,7 +89,7 @@ class AttributeEnumMapping(NamedTuple):
enum_class: type enum_class: type
MODEL_TO_ATTR_MAP: dict[str, list] = { MODEL_TO_ATTR_MAP: dict[str, list[AttributeEnumMapping]] = {
MODEL_AIRFRESH_T2017: [ MODEL_AIRFRESH_T2017: [
AttributeEnumMapping(ATTR_DISPLAY_ORIENTATION, AirfreshT2017DisplayOrientation), AttributeEnumMapping(ATTR_DISPLAY_ORIENTATION, AirfreshT2017DisplayOrientation),
AttributeEnumMapping(ATTR_PTC_LEVEL, AirfreshT2017PtcLevel), AttributeEnumMapping(ATTR_PTC_LEVEL, AirfreshT2017PtcLevel),
@ -232,10 +234,21 @@ async def async_setup_entry(
) )
class XiaomiSelector(XiaomiCoordinatedMiioEntity, SelectEntity): class XiaomiSelector(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], SelectEntity
):
"""Representation of a generic Xiaomi attribute selector.""" """Representation of a generic Xiaomi attribute selector."""
def __init__(self, device, entry, unique_id, coordinator, description): entity_description: XiaomiMiioSelectDescription
def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str,
coordinator: DataUpdateCoordinator[Any],
description: XiaomiMiioSelectDescription,
) -> None:
"""Initialize the generic Xiaomi attribute selector.""" """Initialize the generic Xiaomi attribute selector."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
self.entity_description = description self.entity_description = description
@ -244,9 +257,15 @@ class XiaomiSelector(XiaomiCoordinatedMiioEntity, SelectEntity):
class XiaomiGenericSelector(XiaomiSelector): class XiaomiGenericSelector(XiaomiSelector):
"""Representation of a Xiaomi generic selector.""" """Representation of a Xiaomi generic selector."""
entity_description: XiaomiMiioSelectDescription def __init__(
self,
def __init__(self, device, entry, unique_id, coordinator, description, enum_class): device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str,
coordinator: DataUpdateCoordinator[Any],
description: XiaomiMiioSelectDescription,
enum_class: type,
) -> None:
"""Initialize the generic Xiaomi attribute selector.""" """Initialize the generic Xiaomi attribute selector."""
super().__init__(device, entry, unique_id, coordinator, description) super().__init__(device, entry, unique_id, coordinator, description)
self._current_attr = enum_class( self._current_attr = enum_class(
@ -257,10 +276,10 @@ class XiaomiGenericSelector(XiaomiSelector):
if description.options_map: if description.options_map:
self._options_map = {} self._options_map = {}
for key, val in enum_class._member_map_.items(): for key, val in enum_class._member_map_.items(): # type: ignore[attr-defined]
self._options_map[description.options_map[key]] = val self._options_map[description.options_map[key]] = val
else: else:
self._options_map = enum_class._member_map_ self._options_map = enum_class._member_map_ # type: ignore[attr-defined]
self._reverse_map = {val: key for key, val in self._options_map.items()} self._reverse_map = {val: key for key, val in self._options_map.items()}
self._enum_class = enum_class self._enum_class = enum_class

View File

@ -5,7 +5,7 @@ from __future__ import annotations
from collections.abc import Iterable from collections.abc import Iterable
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Any
from miio import AirQualityMonitor, Device as MiioDevice, DeviceException from miio import AirQualityMonitor, Device as MiioDevice, DeviceException
from miio.gateway.devices import SubDevice from miio.gateway.devices import SubDevice
@ -854,12 +854,21 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class XiaomiGenericSensor(XiaomiCoordinatedMiioEntity, SensorEntity): class XiaomiGenericSensor(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], SensorEntity
):
"""Representation of a Xiaomi generic sensor.""" """Representation of a Xiaomi generic sensor."""
entity_description: XiaomiMiioSensorDescription entity_description: XiaomiMiioSensorDescription
def __init__(self, device, entry, unique_id, coordinator, description): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str,
coordinator: DataUpdateCoordinator[Any],
description: XiaomiMiioSensorDescription,
) -> None:
"""Initialize the entity.""" """Initialize the entity."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
self.entity_description = description self.entity_description = description

View File

@ -8,7 +8,13 @@ from functools import partial
import logging import logging
from typing import Any from typing import Any
from miio import AirConditioningCompanionV3, ChuangmiPlug, DeviceException, PowerStrip from miio import (
AirConditioningCompanionV3,
ChuangmiPlug,
Device as MiioDevice,
DeviceException,
PowerStrip,
)
from miio.gateway.devices import SubDevice from miio.gateway.devices import SubDevice
from miio.gateway.devices.switch import Switch from miio.gateway.devices.switch import Switch
from miio.powerstrip import PowerMode from miio.powerstrip import PowerMode
@ -520,12 +526,21 @@ async def async_setup_other_entry(
async_add_entities(entities) async_add_entities(entities)
class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity): class XiaomiGenericCoordinatedSwitch(
XiaomiCoordinatedMiioEntity[DataUpdateCoordinator[Any]], SwitchEntity
):
"""Representation of a Xiaomi Plug Generic.""" """Representation of a Xiaomi Plug Generic."""
entity_description: XiaomiMiioSwitchDescription entity_description: XiaomiMiioSwitchDescription
def __init__(self, device, entry, unique_id, coordinator, description): def __init__(
self,
device: MiioDevice,
entry: XiaomiMiioConfigEntry,
unique_id: str,
coordinator: DataUpdateCoordinator[Any],
description: XiaomiMiioSwitchDescription,
) -> None:
"""Initialize the plug switch.""" """Initialize the plug switch."""
super().__init__(device, entry, unique_id, coordinator) super().__init__(device, entry, unique_id, coordinator)
@ -574,7 +589,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the buzzer on.""" """Turn the buzzer on."""
return await self._try_command( return await self._try_command(
"Turning the buzzer of the miio device on failed.", "Turning the buzzer of the miio device on failed.",
self._device.set_buzzer, self._device.set_buzzer, # type: ignore[attr-defined]
True, True,
) )
@ -582,7 +597,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the buzzer off.""" """Turn the buzzer off."""
return await self._try_command( return await self._try_command(
"Turning the buzzer of the miio device off failed.", "Turning the buzzer of the miio device off failed.",
self._device.set_buzzer, self._device.set_buzzer, # type: ignore[attr-defined]
False, False,
) )
@ -590,7 +605,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the child lock on.""" """Turn the child lock on."""
return await self._try_command( return await self._try_command(
"Turning the child lock of the miio device on failed.", "Turning the child lock of the miio device on failed.",
self._device.set_child_lock, self._device.set_child_lock, # type: ignore[attr-defined]
True, True,
) )
@ -598,7 +613,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the child lock off.""" """Turn the child lock off."""
return await self._try_command( return await self._try_command(
"Turning the child lock of the miio device off failed.", "Turning the child lock of the miio device off failed.",
self._device.set_child_lock, self._device.set_child_lock, # type: ignore[attr-defined]
False, False,
) )
@ -606,7 +621,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the display on.""" """Turn the display on."""
return await self._try_command( return await self._try_command(
"Turning the display of the miio device on failed.", "Turning the display of the miio device on failed.",
self._device.set_display, self._device.set_display, # type: ignore[attr-defined]
True, True,
) )
@ -614,7 +629,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the display off.""" """Turn the display off."""
return await self._try_command( return await self._try_command(
"Turning the display of the miio device off failed.", "Turning the display of the miio device off failed.",
self._device.set_display, self._device.set_display, # type: ignore[attr-defined]
False, False,
) )
@ -622,7 +637,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the dry mode on.""" """Turn the dry mode on."""
return await self._try_command( return await self._try_command(
"Turning the dry mode of the miio device on failed.", "Turning the dry mode of the miio device on failed.",
self._device.set_dry, self._device.set_dry, # type: ignore[attr-defined]
True, True,
) )
@ -630,7 +645,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the dry mode off.""" """Turn the dry mode off."""
return await self._try_command( return await self._try_command(
"Turning the dry mode of the miio device off failed.", "Turning the dry mode of the miio device off failed.",
self._device.set_dry, self._device.set_dry, # type: ignore[attr-defined]
False, False,
) )
@ -638,7 +653,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the dry mode on.""" """Turn the dry mode on."""
return await self._try_command( return await self._try_command(
"Turning the clean mode of the miio device on failed.", "Turning the clean mode of the miio device on failed.",
self._device.set_clean_mode, self._device.set_clean_mode, # type: ignore[attr-defined]
True, True,
) )
@ -646,7 +661,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the dry mode off.""" """Turn the dry mode off."""
return await self._try_command( return await self._try_command(
"Turning the clean mode of the miio device off failed.", "Turning the clean mode of the miio device off failed.",
self._device.set_clean_mode, self._device.set_clean_mode, # type: ignore[attr-defined]
False, False,
) )
@ -654,7 +669,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the led on.""" """Turn the led on."""
return await self._try_command( return await self._try_command(
"Turning the led of the miio device on failed.", "Turning the led of the miio device on failed.",
self._device.set_led, self._device.set_led, # type: ignore[attr-defined]
True, True,
) )
@ -662,7 +677,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the led off.""" """Turn the led off."""
return await self._try_command( return await self._try_command(
"Turning the led of the miio device off failed.", "Turning the led of the miio device off failed.",
self._device.set_led, self._device.set_led, # type: ignore[attr-defined]
False, False,
) )
@ -670,7 +685,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the learn mode on.""" """Turn the learn mode on."""
return await self._try_command( return await self._try_command(
"Turning the learn mode of the miio device on failed.", "Turning the learn mode of the miio device on failed.",
self._device.set_learn_mode, self._device.set_learn_mode, # type: ignore[attr-defined]
True, True,
) )
@ -678,7 +693,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn the learn mode off.""" """Turn the learn mode off."""
return await self._try_command( return await self._try_command(
"Turning the learn mode of the miio device off failed.", "Turning the learn mode of the miio device off failed.",
self._device.set_learn_mode, self._device.set_learn_mode, # type: ignore[attr-defined]
False, False,
) )
@ -686,7 +701,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn auto detect on.""" """Turn auto detect on."""
return await self._try_command( return await self._try_command(
"Turning auto detect of the miio device on failed.", "Turning auto detect of the miio device on failed.",
self._device.set_auto_detect, self._device.set_auto_detect, # type: ignore[attr-defined]
True, True,
) )
@ -694,7 +709,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn auto detect off.""" """Turn auto detect off."""
return await self._try_command( return await self._try_command(
"Turning auto detect of the miio device off failed.", "Turning auto detect of the miio device off failed.",
self._device.set_auto_detect, self._device.set_auto_detect, # type: ignore[attr-defined]
False, False,
) )
@ -702,7 +717,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn ionizer on.""" """Turn ionizer on."""
return await self._try_command( return await self._try_command(
"Turning ionizer of the miio device on failed.", "Turning ionizer of the miio device on failed.",
self._device.set_ionizer, self._device.set_ionizer, # type: ignore[attr-defined]
True, True,
) )
@ -710,7 +725,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn ionizer off.""" """Turn ionizer off."""
return await self._try_command( return await self._try_command(
"Turning ionizer of the miio device off failed.", "Turning ionizer of the miio device off failed.",
self._device.set_ionizer, self._device.set_ionizer, # type: ignore[attr-defined]
False, False,
) )
@ -718,7 +733,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn ionizer on.""" """Turn ionizer on."""
return await self._try_command( return await self._try_command(
"Turning ionizer of the miio device on failed.", "Turning ionizer of the miio device on failed.",
self._device.set_anion, self._device.set_anion, # type: ignore[attr-defined]
True, True,
) )
@ -726,7 +741,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn ionizer off.""" """Turn ionizer off."""
return await self._try_command( return await self._try_command(
"Turning ionizer of the miio device off failed.", "Turning ionizer of the miio device off failed.",
self._device.set_anion, self._device.set_anion, # type: ignore[attr-defined]
False, False,
) )
@ -734,7 +749,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn ionizer on.""" """Turn ionizer on."""
return await self._try_command( return await self._try_command(
"Turning ionizer of the miio device on failed.", "Turning ionizer of the miio device on failed.",
self._device.set_ptc, self._device.set_ptc, # type: ignore[attr-defined]
True, True,
) )
@ -742,7 +757,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
"""Turn ionizer off.""" """Turn ionizer off."""
return await self._try_command( return await self._try_command(
"Turning ionizer of the miio device off failed.", "Turning ionizer of the miio device off failed.",
self._device.set_ptc, self._device.set_ptc, # type: ignore[attr-defined]
False, False,
) )

View File

@ -6,7 +6,7 @@ from functools import partial
import logging import logging
from typing import Any from typing import Any
from miio import DeviceException from miio import Device as MiioDevice, DeviceException
import voluptuous as vol import voluptuous as vol
from homeassistant.components.vacuum import ( from homeassistant.components.vacuum import (
@ -196,9 +196,9 @@ class MiroboVacuum(
def __init__( def __init__(
self, self,
device, device: MiioDevice,
entry, entry: XiaomiMiioConfigEntry,
unique_id, unique_id: str | None,
coordinator: DataUpdateCoordinator[VacuumCoordinatorData], coordinator: DataUpdateCoordinator[VacuumCoordinatorData],
) -> None: ) -> None:
"""Initialize the Xiaomi vacuum cleaner robot handler.""" """Initialize the Xiaomi vacuum cleaner robot handler."""
@ -281,16 +281,23 @@ class MiroboVacuum(
async def async_start(self) -> None: async def async_start(self) -> None:
"""Start or resume the cleaning task.""" """Start or resume the cleaning task."""
await self._try_command( await self._try_command(
"Unable to start the vacuum: %s", self._device.resume_or_start "Unable to start the vacuum: %s",
self._device.resume_or_start, # type: ignore[attr-defined]
) )
async def async_pause(self) -> None: async def async_pause(self) -> None:
"""Pause the cleaning task.""" """Pause the cleaning task."""
await self._try_command("Unable to set start/pause: %s", self._device.pause) await self._try_command(
"Unable to set start/pause: %s",
self._device.pause, # type: ignore[attr-defined]
)
async def async_stop(self, **kwargs: Any) -> None: async def async_stop(self, **kwargs: Any) -> None:
"""Stop the vacuum cleaner.""" """Stop the vacuum cleaner."""
await self._try_command("Unable to stop: %s", self._device.stop) await self._try_command(
"Unable to stop: %s",
self._device.stop, # type: ignore[attr-defined]
)
async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None: async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
"""Set fan speed.""" """Set fan speed."""
@ -307,22 +314,31 @@ class MiroboVacuum(
) )
return return
await self._try_command( await self._try_command(
"Unable to set fan speed: %s", self._device.set_fan_speed, fan_speed_int "Unable to set fan speed: %s",
self._device.set_fan_speed, # type: ignore[attr-defined]
fan_speed_int,
) )
async def async_return_to_base(self, **kwargs: Any) -> None: async def async_return_to_base(self, **kwargs: Any) -> None:
"""Set the vacuum cleaner to return to the dock.""" """Set the vacuum cleaner to return to the dock."""
await self._try_command("Unable to return home: %s", self._device.home) await self._try_command(
"Unable to return home: %s",
self._device.home, # type: ignore[attr-defined]
)
async def async_clean_spot(self, **kwargs: Any) -> None: async def async_clean_spot(self, **kwargs: Any) -> None:
"""Perform a spot clean-up.""" """Perform a spot clean-up."""
await self._try_command( await self._try_command(
"Unable to start the vacuum for a spot clean-up: %s", self._device.spot "Unable to start the vacuum for a spot clean-up: %s",
self._device.spot, # type: ignore[attr-defined]
) )
async def async_locate(self, **kwargs: Any) -> None: async def async_locate(self, **kwargs: Any) -> None:
"""Locate the vacuum cleaner.""" """Locate the vacuum cleaner."""
await self._try_command("Unable to locate the botvac: %s", self._device.find) await self._try_command(
"Unable to locate the botvac: %s",
self._device.find, # type: ignore[attr-defined]
)
async def async_send_command( async def async_send_command(
self, self,
@ -341,13 +357,15 @@ class MiroboVacuum(
async def async_remote_control_start(self) -> None: async def async_remote_control_start(self) -> None:
"""Start remote control mode.""" """Start remote control mode."""
await self._try_command( await self._try_command(
"Unable to start remote control the vacuum: %s", self._device.manual_start "Unable to start remote control the vacuum: %s",
self._device.manual_start, # type: ignore[attr-defined]
) )
async def async_remote_control_stop(self) -> None: async def async_remote_control_stop(self) -> None:
"""Stop remote control mode.""" """Stop remote control mode."""
await self._try_command( await self._try_command(
"Unable to stop remote control the vacuum: %s", self._device.manual_stop "Unable to stop remote control the vacuum: %s",
self._device.manual_stop, # type: ignore[attr-defined]
) )
async def async_remote_control_move( async def async_remote_control_move(
@ -356,7 +374,7 @@ class MiroboVacuum(
"""Move vacuum with remote control mode.""" """Move vacuum with remote control mode."""
await self._try_command( await self._try_command(
"Unable to move with remote control the vacuum: %s", "Unable to move with remote control the vacuum: %s",
self._device.manual_control, self._device.manual_control, # type: ignore[attr-defined]
velocity=velocity, velocity=velocity,
rotation=rotation, rotation=rotation,
duration=duration, duration=duration,
@ -368,7 +386,7 @@ class MiroboVacuum(
"""Move vacuum one step with remote control mode.""" """Move vacuum one step with remote control mode."""
await self._try_command( await self._try_command(
"Unable to remote control the vacuum: %s", "Unable to remote control the vacuum: %s",
self._device.manual_control_once, self._device.manual_control_once, # type: ignore[attr-defined]
velocity=velocity, velocity=velocity,
rotation=rotation, rotation=rotation,
duration=duration, duration=duration,
@ -378,7 +396,7 @@ class MiroboVacuum(
"""Goto the specified coordinates.""" """Goto the specified coordinates."""
await self._try_command( await self._try_command(
"Unable to send the vacuum cleaner to the specified coordinates: %s", "Unable to send the vacuum cleaner to the specified coordinates: %s",
self._device.goto, self._device.goto, # type: ignore[attr-defined]
x_coord=x_coord, x_coord=x_coord,
y_coord=y_coord, y_coord=y_coord,
) )
@ -390,7 +408,7 @@ class MiroboVacuum(
await self._try_command( await self._try_command(
"Unable to start cleaning of the specified segments: %s", "Unable to start cleaning of the specified segments: %s",
self._device.segment_clean, self._device.segment_clean, # type: ignore[attr-defined]
segments=segments, segments=segments,
) )
@ -400,7 +418,10 @@ class MiroboVacuum(
_zone.append(repeats) _zone.append(repeats)
_LOGGER.debug("Zone with repeats: %s", zone) _LOGGER.debug("Zone with repeats: %s", zone)
try: try:
await self.hass.async_add_executor_job(self._device.zoned_clean, zone) await self.hass.async_add_executor_job(
self._device.zoned_clean, # type: ignore[attr-defined]
zone,
)
await self.coordinator.async_refresh() await self.coordinator.async_refresh()
except (OSError, DeviceException) as exc: except (OSError, DeviceException) as exc:
_LOGGER.error("Unable to send zoned_clean command to the vacuum: %s", exc) _LOGGER.error("Unable to send zoned_clean command to the vacuum: %s", exc)