Add support for pedestal MIOT fans to Xiaomi Miio integration (#56555)
* Add initial support for Xiaomi Fan ZA5 * Add sensor, number and switch platform * Addionizer switch * Improve ionizer icon * Fix parent of XiaomiFanMiot class * Add another MIOT models * Fix consts * Add powersupply attached binary sensor * Simplify async_create_miio_device_and_coordinator * Simplify XiaomiGenericFan * Fix XiaomiFanZA5 parent * Remove pass * Remove unused _available variable * 1C doesn't support direction * Suggested change * Use elif * Clean up oscillation angle * Fix typo
This commit is contained in:
parent
b179301152
commit
0044fa9fb9
7 changed files with 291 additions and 33 deletions
|
@ -13,7 +13,12 @@ from miio import (
|
|||
AirPurifierMiot,
|
||||
DeviceException,
|
||||
Fan,
|
||||
Fan1C,
|
||||
FanP5,
|
||||
FanP9,
|
||||
FanP10,
|
||||
FanP11,
|
||||
FanZA5,
|
||||
)
|
||||
from miio.gateway.gateway import GatewayException
|
||||
|
||||
|
@ -33,7 +38,12 @@ from .const import (
|
|||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRPURIFIER_3C,
|
||||
MODEL_FAN_1C,
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_P9,
|
||||
MODEL_FAN_P10,
|
||||
MODEL_FAN_P11,
|
||||
MODEL_FAN_ZA5,
|
||||
MODELS_AIR_MONITOR,
|
||||
MODELS_FAN,
|
||||
MODELS_FAN_MIIO,
|
||||
|
@ -52,7 +62,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
GATEWAY_PLATFORMS = ["alarm_control_panel", "light", "sensor", "switch"]
|
||||
SWITCH_PLATFORMS = ["switch"]
|
||||
FAN_PLATFORMS = ["fan", "number", "select", "sensor", "switch"]
|
||||
FAN_PLATFORMS = ["binary_sensor", "fan", "number", "select", "sensor", "switch"]
|
||||
HUMIDIFIER_PLATFORMS = [
|
||||
"binary_sensor",
|
||||
"humidifier",
|
||||
|
@ -65,6 +75,15 @@ LIGHT_PLATFORMS = ["light"]
|
|||
VACUUM_PLATFORMS = ["vacuum"]
|
||||
AIR_MONITOR_PLATFORMS = ["air_quality", "sensor"]
|
||||
|
||||
MODEL_TO_CLASS_MAP = {
|
||||
MODEL_FAN_1C: Fan1C,
|
||||
MODEL_FAN_P10: FanP10,
|
||||
MODEL_FAN_P11: FanP11,
|
||||
MODEL_FAN_P5: FanP5,
|
||||
MODEL_FAN_P9: FanP9,
|
||||
MODEL_FAN_ZA5: FanZA5,
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: core.HomeAssistant, entry: config_entries.ConfigEntry
|
||||
|
@ -150,8 +169,8 @@ async def async_create_miio_device_and_coordinator(
|
|||
elif model.startswith("zhimi.airfresh."):
|
||||
device = AirFresh(host, token)
|
||||
# Pedestal fans
|
||||
elif model == MODEL_FAN_P5:
|
||||
device = FanP5(host, token)
|
||||
elif model in MODEL_TO_CLASS_MAP:
|
||||
device = MODEL_TO_CLASS_MAP[model](host, token)
|
||||
elif model in MODELS_FAN_MIIO:
|
||||
device = Fan(host, token, model=model)
|
||||
else:
|
||||
|
|
|
@ -7,6 +7,7 @@ from typing import Callable
|
|||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DEVICE_CLASS_CONNECTIVITY,
|
||||
DEVICE_CLASS_PLUG,
|
||||
BinarySensorEntity,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
|
@ -18,6 +19,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_FAN_ZA5,
|
||||
MODELS_HUMIDIFIER_MIIO,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
|
@ -25,6 +27,7 @@ from .const import (
|
|||
from .device import XiaomiCoordinatedMiioEntity
|
||||
|
||||
ATTR_NO_WATER = "no_water"
|
||||
ATTR_POWERSUPPLY_ATTACHED = "powersupply_attached"
|
||||
ATTR_WATER_TANK_DETACHED = "water_tank_detached"
|
||||
|
||||
|
||||
|
@ -48,8 +51,14 @@ BINARY_SENSOR_TYPES = (
|
|||
device_class=DEVICE_CLASS_CONNECTIVITY,
|
||||
value=lambda value: not value,
|
||||
),
|
||||
XiaomiMiioBinarySensorDescription(
|
||||
key=ATTR_POWERSUPPLY_ATTACHED,
|
||||
name="Power Supply",
|
||||
device_class=DEVICE_CLASS_PLUG,
|
||||
),
|
||||
)
|
||||
|
||||
FAN_ZA5_BINARY_SENSORS = (ATTR_POWERSUPPLY_ATTACHED,)
|
||||
HUMIDIFIER_MIIO_BINARY_SENSORS = (ATTR_WATER_TANK_DETACHED,)
|
||||
HUMIDIFIER_MIOT_BINARY_SENSORS = (ATTR_WATER_TANK_DETACHED,)
|
||||
HUMIDIFIER_MJJSQ_BINARY_SENSORS = (ATTR_NO_WATER, ATTR_WATER_TANK_DETACHED)
|
||||
|
@ -62,7 +71,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
if config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE:
|
||||
model = config_entry.data[CONF_MODEL]
|
||||
sensors = []
|
||||
if model in MODELS_HUMIDIFIER_MIIO:
|
||||
if model in MODEL_FAN_ZA5:
|
||||
sensors = FAN_ZA5_BINARY_SENSORS
|
||||
elif model in MODELS_HUMIDIFIER_MIIO:
|
||||
sensors = HUMIDIFIER_MIIO_BINARY_SENSORS
|
||||
elif model in MODELS_HUMIDIFIER_MIOT:
|
||||
sensors = HUMIDIFIER_MIOT_BINARY_SENSORS
|
||||
|
|
|
@ -59,13 +59,18 @@ MODEL_AIRHUMIDIFIER_MJJSQ = "deerma.humidifier.mjjsq"
|
|||
|
||||
MODEL_AIRFRESH_VA2 = "zhimi.airfresh.va2"
|
||||
|
||||
MODEL_FAN_1C = "dmaker.fan.1c"
|
||||
MODEL_FAN_P10 = "dmaker.fan.p10"
|
||||
MODEL_FAN_P11 = "dmaker.fan.p11"
|
||||
MODEL_FAN_P5 = "dmaker.fan.p5"
|
||||
MODEL_FAN_P9 = "dmaker.fan.p9"
|
||||
MODEL_FAN_SA1 = "zhimi.fan.sa1"
|
||||
MODEL_FAN_V2 = "zhimi.fan.v2"
|
||||
MODEL_FAN_V3 = "zhimi.fan.v3"
|
||||
MODEL_FAN_ZA1 = "zhimi.fan.za1"
|
||||
MODEL_FAN_ZA3 = "zhimi.fan.za3"
|
||||
MODEL_FAN_ZA4 = "zhimi.fan.za4"
|
||||
MODEL_FAN_ZA5 = "zhimi.fan.za5"
|
||||
|
||||
MODELS_FAN_MIIO = [
|
||||
MODEL_FAN_P5,
|
||||
|
@ -77,6 +82,14 @@ MODELS_FAN_MIIO = [
|
|||
MODEL_FAN_ZA4,
|
||||
]
|
||||
|
||||
MODELS_FAN_MIOT = [
|
||||
MODEL_FAN_1C,
|
||||
MODEL_FAN_P10,
|
||||
MODEL_FAN_P11,
|
||||
MODEL_FAN_P9,
|
||||
MODEL_FAN_ZA5,
|
||||
]
|
||||
|
||||
MODELS_PURIFIER_MIOT = [
|
||||
MODEL_AIRPURIFIER_3,
|
||||
MODEL_AIRPURIFIER_3C,
|
||||
|
@ -151,7 +164,9 @@ MODELS_SWITCH = [
|
|||
"chuangmi.plug.hmi205",
|
||||
"chuangmi.plug.hmi206",
|
||||
]
|
||||
MODELS_FAN = MODELS_PURIFIER_MIIO + MODELS_PURIFIER_MIOT + MODELS_FAN_MIIO
|
||||
MODELS_FAN = (
|
||||
MODELS_PURIFIER_MIIO + MODELS_PURIFIER_MIOT + MODELS_FAN_MIIO + MODELS_FAN_MIOT
|
||||
)
|
||||
MODELS_HUMIDIFIER = (
|
||||
MODELS_HUMIDIFIER_MIOT + MODELS_HUMIDIFIER_MIIO + MODELS_HUMIDIFIER_MJJSQ
|
||||
)
|
||||
|
@ -236,10 +251,10 @@ FEATURE_SET_FAN_LEVEL = 4096
|
|||
FEATURE_SET_MOTOR_SPEED = 8192
|
||||
FEATURE_SET_CLEAN = 16384
|
||||
FEATURE_SET_OSCILLATION_ANGLE = 32768
|
||||
FEATURE_SET_OSCILLATION_ANGLE_MAX_140 = 65536
|
||||
FEATURE_SET_DELAY_OFF_COUNTDOWN = 131072
|
||||
FEATURE_SET_LED_BRIGHTNESS_LEVEL = 262144
|
||||
FEATURE_SET_FAVORITE_RPM = 524288
|
||||
FEATURE_SET_DELAY_OFF_COUNTDOWN = 65536
|
||||
FEATURE_SET_LED_BRIGHTNESS_LEVEL = 131072
|
||||
FEATURE_SET_FAVORITE_RPM = 262144
|
||||
FEATURE_SET_IONIZER = 524288
|
||||
|
||||
FEATURE_FLAGS_AIRPURIFIER_MIIO = (
|
||||
FEATURE_SET_BUZZER
|
||||
|
@ -324,7 +339,7 @@ FEATURE_FLAGS_AIRFRESH = (
|
|||
FEATURE_FLAGS_FAN_P5 = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
| FEATURE_SET_OSCILLATION_ANGLE_MAX_140
|
||||
| FEATURE_SET_OSCILLATION_ANGLE
|
||||
| FEATURE_SET_LED
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
)
|
||||
|
@ -336,3 +351,35 @@ FEATURE_FLAGS_FAN = (
|
|||
| FEATURE_SET_LED_BRIGHTNESS
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_FAN_ZA5 = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
| FEATURE_SET_OSCILLATION_ANGLE
|
||||
| FEATURE_SET_LED_BRIGHTNESS
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
| FEATURE_SET_IONIZER
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_FAN_1C = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
| FEATURE_SET_LED
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_FAN_P9 = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
| FEATURE_SET_OSCILLATION_ANGLE
|
||||
| FEATURE_SET_LED
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_FAN_P10_P11 = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
| FEATURE_SET_OSCILLATION_ANGLE
|
||||
| FEATURE_SET_LED
|
||||
| FEATURE_SET_DELAY_OFF_COUNTDOWN
|
||||
)
|
||||
|
|
|
@ -11,6 +11,10 @@ from miio.fan import (
|
|||
MoveDirection as FanMoveDirection,
|
||||
OperationMode as FanOperationMode,
|
||||
)
|
||||
from miio.fan_miot import (
|
||||
OperationMode as FanMiotOperationMode,
|
||||
OperationModeFanZA5 as FanZA5OperationMode,
|
||||
)
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
|
@ -41,7 +45,11 @@ from .const import (
|
|||
FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
FEATURE_FLAGS_FAN,
|
||||
FEATURE_FLAGS_FAN_1C,
|
||||
FEATURE_FLAGS_FAN_P5,
|
||||
FEATURE_FLAGS_FAN_P9,
|
||||
FEATURE_FLAGS_FAN_P10_P11,
|
||||
FEATURE_FLAGS_FAN_ZA5,
|
||||
FEATURE_RESET_FILTER,
|
||||
FEATURE_SET_EXTRA_FEATURES,
|
||||
KEY_COORDINATOR,
|
||||
|
@ -52,8 +60,14 @@ from .const import (
|
|||
MODEL_AIRPURIFIER_PRO,
|
||||
MODEL_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V3,
|
||||
MODEL_FAN_1C,
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_P9,
|
||||
MODEL_FAN_P10,
|
||||
MODEL_FAN_P11,
|
||||
MODEL_FAN_ZA5,
|
||||
MODELS_FAN_MIIO,
|
||||
MODELS_FAN_MIOT,
|
||||
MODELS_PURIFIER_MIOT,
|
||||
SERVICE_RESET_FILTER,
|
||||
SERVICE_SET_EXTRA_FEATURES,
|
||||
|
@ -197,6 +211,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
entity = XiaomiFanP5(name, device, config_entry, unique_id, coordinator)
|
||||
elif model in MODELS_FAN_MIIO:
|
||||
entity = XiaomiFan(name, device, config_entry, unique_id, coordinator)
|
||||
elif model == MODEL_FAN_ZA5:
|
||||
entity = XiaomiFanZA5(name, device, config_entry, unique_id, coordinator)
|
||||
elif model in MODELS_FAN_MIOT:
|
||||
entity = XiaomiFanMiot(name, device, config_entry, unique_id, coordinator)
|
||||
else:
|
||||
return
|
||||
|
||||
|
@ -264,6 +282,11 @@ class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity):
|
|||
"""Flag supported features."""
|
||||
return self._supported_features
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def operation_mode_class(self):
|
||||
"""Hold operation mode class."""
|
||||
|
||||
@property
|
||||
def preset_modes(self) -> list:
|
||||
"""Get the list of available preset modes."""
|
||||
|
@ -326,11 +349,6 @@ class XiaomiGenericAirPurifier(XiaomiGenericDevice):
|
|||
|
||||
self._speed_count = 100
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def operation_mode_class(self):
|
||||
"""Hold operation mode class."""
|
||||
|
||||
@property
|
||||
def speed_count(self):
|
||||
"""Return the number of speeds of the fan supported."""
|
||||
|
@ -695,16 +713,21 @@ class XiaomiGenericFan(XiaomiGenericDevice):
|
|||
|
||||
if self._model == MODEL_FAN_P5:
|
||||
self._device_features = FEATURE_FLAGS_FAN_P5
|
||||
self._preset_modes = [mode.name for mode in FanOperationMode]
|
||||
elif self._model == MODEL_FAN_ZA5:
|
||||
self._device_features = FEATURE_FLAGS_FAN_ZA5
|
||||
elif self._model == MODEL_FAN_1C:
|
||||
self._device_features = FEATURE_FLAGS_FAN_1C
|
||||
elif self._model == MODEL_FAN_P9:
|
||||
self._device_features = FEATURE_FLAGS_FAN_P9
|
||||
elif self._model in (MODEL_FAN_P10, MODEL_FAN_P11):
|
||||
self._device_features = FEATURE_FLAGS_FAN_P10_P11
|
||||
else:
|
||||
self._device_features = FEATURE_FLAGS_FAN
|
||||
self._preset_modes = [ATTR_MODE_NATURE, ATTR_MODE_NORMAL]
|
||||
self._supported_features = (
|
||||
SUPPORT_SET_SPEED
|
||||
| SUPPORT_OSCILLATE
|
||||
| SUPPORT_PRESET_MODE
|
||||
| SUPPORT_DIRECTION
|
||||
SUPPORT_SET_SPEED | SUPPORT_OSCILLATE | SUPPORT_PRESET_MODE
|
||||
)
|
||||
if self._model != MODEL_FAN_1C:
|
||||
self._supported_features |= SUPPORT_DIRECTION
|
||||
self._preset_mode = None
|
||||
self._oscillating = None
|
||||
self._percentage = None
|
||||
|
@ -714,6 +737,11 @@ class XiaomiGenericFan(XiaomiGenericDevice):
|
|||
"""Get the active preset mode."""
|
||||
return self._preset_mode
|
||||
|
||||
@property
|
||||
def preset_modes(self) -> list:
|
||||
"""Get the list of available preset modes."""
|
||||
return [mode.name for mode in self.operation_mode_class]
|
||||
|
||||
@property
|
||||
def percentage(self):
|
||||
"""Return the current speed as a percentage."""
|
||||
|
@ -764,11 +792,20 @@ class XiaomiFan(XiaomiGenericFan):
|
|||
else:
|
||||
self._percentage = self.coordinator.data.direct_speed
|
||||
|
||||
@property
|
||||
def operation_mode_class(self):
|
||||
"""Hold operation mode class."""
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Get the active preset mode."""
|
||||
return ATTR_MODE_NATURE if self._nature_mode else ATTR_MODE_NORMAL
|
||||
|
||||
@property
|
||||
def preset_modes(self) -> list:
|
||||
"""Get the list of available preset modes."""
|
||||
return [ATTR_MODE_NATURE, ATTR_MODE_NORMAL]
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self):
|
||||
"""Fetch state from the device."""
|
||||
|
@ -843,6 +880,11 @@ class XiaomiFanP5(XiaomiGenericFan):
|
|||
self._oscillating = self.coordinator.data.oscillate
|
||||
self._percentage = self.coordinator.data.speed
|
||||
|
||||
@property
|
||||
def operation_mode_class(self):
|
||||
"""Hold operation mode class."""
|
||||
return FanOperationMode
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self):
|
||||
"""Fetch state from the device."""
|
||||
|
@ -861,7 +903,7 @@ class XiaomiFanP5(XiaomiGenericFan):
|
|||
await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_mode,
|
||||
FanOperationMode[preset_mode],
|
||||
self.operation_mode_class[preset_mode],
|
||||
)
|
||||
self._preset_mode = preset_mode
|
||||
self.async_write_ha_state()
|
||||
|
@ -884,3 +926,71 @@ class XiaomiFanP5(XiaomiGenericFan):
|
|||
await self.async_turn_on()
|
||||
else:
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class XiaomiFanMiot(XiaomiGenericFan):
|
||||
"""Representation of a Xiaomi Fan Miot."""
|
||||
|
||||
@property
|
||||
def operation_mode_class(self):
|
||||
"""Hold operation mode class."""
|
||||
return FanMiotOperationMode
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Get the active preset mode."""
|
||||
return self._preset_mode
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self):
|
||||
"""Fetch state from the device."""
|
||||
self._state = self.coordinator.data.is_on
|
||||
self._preset_mode = self.coordinator.data.mode.name
|
||||
self._oscillating = self.coordinator.data.oscillate
|
||||
if self.coordinator.data.is_on:
|
||||
self._percentage = self.coordinator.data.fan_speed
|
||||
else:
|
||||
self._percentage = 0
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode of the fan."""
|
||||
if preset_mode not in self.preset_modes:
|
||||
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
|
||||
return
|
||||
await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_mode,
|
||||
self.operation_mode_class[preset_mode],
|
||||
)
|
||||
self._preset_mode = preset_mode
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the percentage of the fan."""
|
||||
if percentage == 0:
|
||||
self._percentage = 0
|
||||
await self.async_turn_off()
|
||||
return
|
||||
|
||||
await self._try_command(
|
||||
"Setting fan speed percentage of the miio device failed.",
|
||||
self._device.set_speed,
|
||||
percentage,
|
||||
)
|
||||
self._percentage = percentage
|
||||
|
||||
if not self.is_on:
|
||||
await self.async_turn_on()
|
||||
else:
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class XiaomiFanZA5(XiaomiFanMiot):
|
||||
"""Representation of a Xiaomi Fan ZA5."""
|
||||
|
||||
@property
|
||||
def operation_mode_class(self):
|
||||
"""Hold operation mode class."""
|
||||
return FanZA5OperationMode
|
||||
|
|
|
@ -25,7 +25,11 @@ from .const import (
|
|||
FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
FEATURE_FLAGS_FAN,
|
||||
FEATURE_FLAGS_FAN_1C,
|
||||
FEATURE_FLAGS_FAN_P5,
|
||||
FEATURE_FLAGS_FAN_P9,
|
||||
FEATURE_FLAGS_FAN_P10_P11,
|
||||
FEATURE_FLAGS_FAN_ZA5,
|
||||
FEATURE_SET_DELAY_OFF_COUNTDOWN,
|
||||
FEATURE_SET_FAN_LEVEL,
|
||||
FEATURE_SET_FAVORITE_LEVEL,
|
||||
|
@ -33,7 +37,6 @@ from .const import (
|
|||
FEATURE_SET_LED_BRIGHTNESS_LEVEL,
|
||||
FEATURE_SET_MOTOR_SPEED,
|
||||
FEATURE_SET_OSCILLATION_ANGLE,
|
||||
FEATURE_SET_OSCILLATION_ANGLE_MAX_140,
|
||||
FEATURE_SET_VOLUME,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
|
@ -47,13 +50,18 @@ from .const import (
|
|||
MODEL_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3,
|
||||
MODEL_FAN_1C,
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_P9,
|
||||
MODEL_FAN_P10,
|
||||
MODEL_FAN_P11,
|
||||
MODEL_FAN_SA1,
|
||||
MODEL_FAN_V2,
|
||||
MODEL_FAN_V3,
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODEL_FAN_ZA5,
|
||||
MODELS_PURIFIER_MIIO,
|
||||
MODELS_PURIFIER_MIOT,
|
||||
)
|
||||
|
@ -80,6 +88,15 @@ class XiaomiMiioNumberDescription(NumberEntityDescription):
|
|||
method: str | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class OscillationAngleValues:
|
||||
"""A class that describes oscillation angle values."""
|
||||
|
||||
max_value: float | None = None
|
||||
min_value: float | None = None
|
||||
step: float | None = None
|
||||
|
||||
|
||||
NUMBER_TYPES = {
|
||||
FEATURE_SET_MOTOR_SPEED: XiaomiMiioNumberDescription(
|
||||
key=ATTR_MOTOR_SPEED,
|
||||
|
@ -129,16 +146,6 @@ NUMBER_TYPES = {
|
|||
step=1,
|
||||
method="async_set_oscillation_angle",
|
||||
),
|
||||
FEATURE_SET_OSCILLATION_ANGLE_MAX_140: XiaomiMiioNumberDescription(
|
||||
key=ATTR_OSCILLATION_ANGLE,
|
||||
name="Oscillation Angle",
|
||||
icon="mdi:angle-acute",
|
||||
unit_of_measurement=DEGREE,
|
||||
min_value=30,
|
||||
max_value=140,
|
||||
step=30,
|
||||
method="async_set_oscillation_angle",
|
||||
),
|
||||
FEATURE_SET_DELAY_OFF_COUNTDOWN: XiaomiMiioNumberDescription(
|
||||
key=ATTR_DELAY_OFF_COUNTDOWN,
|
||||
name="Delay Off Countdown",
|
||||
|
@ -181,13 +188,26 @@ MODEL_TO_FEATURES_MAP = {
|
|||
MODEL_AIRPURIFIER_PRO_V7: FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1: FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3: FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
MODEL_FAN_1C: FEATURE_FLAGS_FAN_1C,
|
||||
MODEL_FAN_P10: FEATURE_FLAGS_FAN_P10_P11,
|
||||
MODEL_FAN_P11: FEATURE_FLAGS_FAN_P10_P11,
|
||||
MODEL_FAN_P5: FEATURE_FLAGS_FAN_P5,
|
||||
MODEL_FAN_P9: FEATURE_FLAGS_FAN_P9,
|
||||
MODEL_FAN_SA1: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_V2: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_V3: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA1: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA3: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA4: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA5: FEATURE_FLAGS_FAN_ZA5,
|
||||
}
|
||||
|
||||
OSCILLATION_ANGLE_VALUES = {
|
||||
MODEL_FAN_P5: OscillationAngleValues(max_value=140, min_value=30, step=30),
|
||||
MODEL_FAN_ZA5: OscillationAngleValues(max_value=120, min_value=30, step=30),
|
||||
MODEL_FAN_P9: OscillationAngleValues(max_value=150, min_value=30, step=30),
|
||||
MODEL_FAN_P10: OscillationAngleValues(max_value=140, min_value=30, step=30),
|
||||
MODEL_FAN_P11: OscillationAngleValues(max_value=140, min_value=30, step=30),
|
||||
}
|
||||
|
||||
|
||||
|
@ -210,6 +230,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
|
||||
for feature, description in NUMBER_TYPES.items():
|
||||
if feature & features:
|
||||
if (
|
||||
description.key == ATTR_OSCILLATION_ANGLE
|
||||
and model in OSCILLATION_ANGLE_VALUES
|
||||
):
|
||||
description.max_value = OSCILLATION_ANGLE_VALUES[model].max_value
|
||||
description.min_value = OSCILLATION_ANGLE_VALUES[model].min_value
|
||||
description.step = OSCILLATION_ANGLE_VALUES[model].step
|
||||
entities.append(
|
||||
XiaomiNumberEntity(
|
||||
f"{config_entry.title} {description.name}",
|
||||
|
|
|
@ -68,6 +68,7 @@ from .const import (
|
|||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODEL_FAN_ZA5,
|
||||
MODELS_AIR_QUALITY_MONITOR,
|
||||
MODELS_HUMIDIFIER_MIIO,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
|
@ -331,6 +332,8 @@ FAN_V2_V3_SENSORS = (
|
|||
ATTR_TEMPERATURE,
|
||||
)
|
||||
|
||||
FAN_ZA5_SENSORS = (ATTR_HUMIDITY, ATTR_TEMPERATURE)
|
||||
|
||||
MODEL_TO_SENSORS_MAP = {
|
||||
MODEL_AIRFRESH_VA2: AIRFRESH_SENSORS,
|
||||
MODEL_AIRHUMIDIFIER_CA1: HUMIDIFIER_CA1_CB1_SENSORS,
|
||||
|
@ -342,6 +345,7 @@ MODEL_TO_SENSORS_MAP = {
|
|||
MODEL_AIRPURIFIER_V3: PURIFIER_V3_SENSORS,
|
||||
MODEL_FAN_V2: FAN_V2_V3_SENSORS,
|
||||
MODEL_FAN_V3: FAN_V2_V3_SENSORS,
|
||||
MODEL_FAN_ZA5: FAN_ZA5_SENSORS,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,12 +46,17 @@ from .const import (
|
|||
FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
FEATURE_FLAGS_FAN,
|
||||
FEATURE_FLAGS_FAN_1C,
|
||||
FEATURE_FLAGS_FAN_P5,
|
||||
FEATURE_FLAGS_FAN_P9,
|
||||
FEATURE_FLAGS_FAN_P10_P11,
|
||||
FEATURE_FLAGS_FAN_ZA5,
|
||||
FEATURE_SET_AUTO_DETECT,
|
||||
FEATURE_SET_BUZZER,
|
||||
FEATURE_SET_CHILD_LOCK,
|
||||
FEATURE_SET_CLEAN,
|
||||
FEATURE_SET_DRY,
|
||||
FEATURE_SET_IONIZER,
|
||||
FEATURE_SET_LEARN_MODE,
|
||||
FEATURE_SET_LED,
|
||||
KEY_COORDINATOR,
|
||||
|
@ -67,10 +72,15 @@ from .const import (
|
|||
MODEL_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3,
|
||||
MODEL_FAN_1C,
|
||||
MODEL_FAN_P5,
|
||||
MODEL_FAN_P9,
|
||||
MODEL_FAN_P10,
|
||||
MODEL_FAN_P11,
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODEL_FAN_ZA5,
|
||||
MODELS_FAN,
|
||||
MODELS_HUMIDIFIER,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
|
@ -108,6 +118,7 @@ ATTR_CLEAN = "clean_mode"
|
|||
ATTR_DRY = "dry"
|
||||
ATTR_LEARN_MODE = "learn_mode"
|
||||
ATTR_LED = "led"
|
||||
ATTR_IONIZER = "ionizer"
|
||||
ATTR_LOAD_POWER = "load_power"
|
||||
ATTR_MODEL = "model"
|
||||
ATTR_POWER = "power"
|
||||
|
@ -165,10 +176,15 @@ MODEL_TO_FEATURES_MAP = {
|
|||
MODEL_AIRPURIFIER_PRO_V7: FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
|
||||
MODEL_AIRPURIFIER_V1: FEATURE_FLAGS_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V3: FEATURE_FLAGS_AIRPURIFIER_V3,
|
||||
MODEL_FAN_1C: FEATURE_FLAGS_FAN_1C,
|
||||
MODEL_FAN_P10: FEATURE_FLAGS_FAN_P10_P11,
|
||||
MODEL_FAN_P11: FEATURE_FLAGS_FAN_P10_P11,
|
||||
MODEL_FAN_P5: FEATURE_FLAGS_FAN_P5,
|
||||
MODEL_FAN_P9: FEATURE_FLAGS_FAN_P9,
|
||||
MODEL_FAN_ZA1: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA3: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA4: FEATURE_FLAGS_FAN,
|
||||
MODEL_FAN_ZA5: FEATURE_FLAGS_FAN_ZA5,
|
||||
}
|
||||
|
||||
|
||||
|
@ -239,6 +255,14 @@ SWITCH_TYPES = (
|
|||
method_on="async_set_auto_detect_on",
|
||||
method_off="async_set_auto_detect_off",
|
||||
),
|
||||
XiaomiMiioSwitchDescription(
|
||||
key=ATTR_IONIZER,
|
||||
feature=FEATURE_SET_IONIZER,
|
||||
name="Ionizer",
|
||||
icon="mdi:shimmer",
|
||||
method_on="async_set_ionizer_on",
|
||||
method_off="async_set_ionizer_off",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -578,6 +602,22 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
|
|||
False,
|
||||
)
|
||||
|
||||
async def async_set_ionizer_on(self) -> bool:
|
||||
"""Turn ionizer on."""
|
||||
return await self._try_command(
|
||||
"Turning ionizer of the miio device on failed.",
|
||||
self._device.set_ionizer,
|
||||
True,
|
||||
)
|
||||
|
||||
async def async_set_ionizer_off(self) -> bool:
|
||||
"""Turn ionizer off."""
|
||||
return await self._try_command(
|
||||
"Turning ionizer of the miio device off failed.",
|
||||
self._device.set_ionizer,
|
||||
False,
|
||||
)
|
||||
|
||||
|
||||
class XiaomiGatewaySwitch(XiaomiGatewayDevice, SwitchEntity):
|
||||
"""Representation of a XiaomiGatewaySwitch."""
|
||||
|
|
Loading…
Add table
Reference in a new issue