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:
Maciej Bieniek 2021-09-28 10:21:14 +02:00 committed by GitHub
parent b179301152
commit 0044fa9fb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 291 additions and 33 deletions

View file

@ -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:

View file

@ -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

View file

@ -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
)

View file

@ -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

View file

@ -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}",

View file

@ -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,
}

View file

@ -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."""