From 25d943d272b8a1de671694960e499917e5190563 Mon Sep 17 00:00:00 2001 From: borky Date: Thu, 28 Jul 2022 13:38:04 +0300 Subject: [PATCH] Add xiaomi air purifier 4 and 4 pro support (#75745) Co-authored-by: Martin Hjelmare --- homeassistant/components/xiaomi_miio/const.py | 14 ++++++ homeassistant/components/xiaomi_miio/fan.py | 11 +++++ .../components/xiaomi_miio/number.py | 5 +++ .../components/xiaomi_miio/sensor.py | 44 +++++++++++++++++++ .../components/xiaomi_miio/switch.py | 32 ++++++++++++++ .../components/xiaomi_miio/vacuum.py | 2 +- 6 files changed, 107 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/xiaomi_miio/const.py b/homeassistant/components/xiaomi_miio/const.py index 3577e7b9907..54289bb8389 100644 --- a/homeassistant/components/xiaomi_miio/const.py +++ b/homeassistant/components/xiaomi_miio/const.py @@ -47,6 +47,8 @@ class SetupException(Exception): # Fan Models +MODEL_AIRPURIFIER_4 = "zhimi.airp.mb5" +MODEL_AIRPURIFIER_4_PRO = "zhimi.airp.vb4" MODEL_AIRPURIFIER_2H = "zhimi.airpurifier.mc2" MODEL_AIRPURIFIER_2S = "zhimi.airpurifier.mc1" MODEL_AIRPURIFIER_3 = "zhimi.airpurifier.ma4" @@ -114,6 +116,8 @@ MODELS_PURIFIER_MIOT = [ MODEL_AIRPURIFIER_3C, MODEL_AIRPURIFIER_3H, MODEL_AIRPURIFIER_PROH, + MODEL_AIRPURIFIER_4, + MODEL_AIRPURIFIER_4_PRO, ] MODELS_PURIFIER_MIIO = [ MODEL_AIRPURIFIER_V1, @@ -316,6 +320,7 @@ FEATURE_SET_FAVORITE_RPM = 262144 FEATURE_SET_IONIZER = 524288 FEATURE_SET_DISPLAY = 1048576 FEATURE_SET_PTC = 2097152 +FEATURE_SET_ANION = 4194304 FEATURE_FLAGS_AIRPURIFIER_MIIO = ( FEATURE_SET_BUZZER @@ -335,6 +340,15 @@ FEATURE_FLAGS_AIRPURIFIER_MIOT = ( | FEATURE_SET_LED_BRIGHTNESS ) +FEATURE_FLAGS_AIRPURIFIER_4 = ( + FEATURE_SET_BUZZER + | FEATURE_SET_CHILD_LOCK + | FEATURE_SET_FAVORITE_LEVEL + | FEATURE_SET_FAN_LEVEL + | FEATURE_SET_LED_BRIGHTNESS + | FEATURE_SET_ANION +) + FEATURE_FLAGS_AIRPURIFIER_3C = ( FEATURE_SET_BUZZER | FEATURE_SET_CHILD_LOCK diff --git a/homeassistant/components/xiaomi_miio/fan.py b/homeassistant/components/xiaomi_miio/fan.py index aa4b8a8a1bc..39988976564 100644 --- a/homeassistant/components/xiaomi_miio/fan.py +++ b/homeassistant/components/xiaomi_miio/fan.py @@ -48,6 +48,7 @@ from .const import ( FEATURE_FLAGS_AIRFRESH_T2017, FEATURE_FLAGS_AIRPURIFIER_2S, FEATURE_FLAGS_AIRPURIFIER_3C, + FEATURE_FLAGS_AIRPURIFIER_4, FEATURE_FLAGS_AIRPURIFIER_MIIO, FEATURE_FLAGS_AIRPURIFIER_MIOT, FEATURE_FLAGS_AIRPURIFIER_PRO, @@ -68,6 +69,8 @@ from .const import ( MODEL_AIRPURIFIER_2H, MODEL_AIRPURIFIER_2S, MODEL_AIRPURIFIER_3C, + MODEL_AIRPURIFIER_4, + MODEL_AIRPURIFIER_4_PRO, MODEL_AIRPURIFIER_PRO, MODEL_AIRPURIFIER_PRO_V7, MODEL_AIRPURIFIER_V3, @@ -411,6 +414,14 @@ class XiaomiAirPurifier(XiaomiGenericAirPurifier): self._preset_modes = PRESET_MODES_AIRPURIFIER_PRO self._attr_supported_features = FanEntityFeature.PRESET_MODE self._speed_count = 1 + elif self._model in [MODEL_AIRPURIFIER_4, MODEL_AIRPURIFIER_4_PRO]: + self._device_features = FEATURE_FLAGS_AIRPURIFIER_4 + self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_MIOT + self._preset_modes = PRESET_MODES_AIRPURIFIER_MIOT + self._attr_supported_features = ( + FanEntityFeature.SET_SPEED | FanEntityFeature.PRESET_MODE + ) + self._speed_count = 3 elif self._model == MODEL_AIRPURIFIER_PRO_V7: self._device_features = FEATURE_FLAGS_AIRPURIFIER_PRO_V7 self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_PRO_V7 diff --git a/homeassistant/components/xiaomi_miio/number.py b/homeassistant/components/xiaomi_miio/number.py index 577e82e3fd8..364bd59772c 100644 --- a/homeassistant/components/xiaomi_miio/number.py +++ b/homeassistant/components/xiaomi_miio/number.py @@ -24,6 +24,7 @@ from .const import ( FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB, FEATURE_FLAGS_AIRPURIFIER_2S, FEATURE_FLAGS_AIRPURIFIER_3C, + FEATURE_FLAGS_AIRPURIFIER_4, FEATURE_FLAGS_AIRPURIFIER_MIIO, FEATURE_FLAGS_AIRPURIFIER_MIOT, FEATURE_FLAGS_AIRPURIFIER_PRO, @@ -55,6 +56,8 @@ from .const import ( MODEL_AIRHUMIDIFIER_CB1, MODEL_AIRPURIFIER_2S, MODEL_AIRPURIFIER_3C, + MODEL_AIRPURIFIER_4, + MODEL_AIRPURIFIER_4_PRO, MODEL_AIRPURIFIER_PRO, MODEL_AIRPURIFIER_PRO_V7, MODEL_AIRPURIFIER_V1, @@ -224,6 +227,8 @@ 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_AIRPURIFIER_4: FEATURE_FLAGS_AIRPURIFIER_4, + MODEL_AIRPURIFIER_4_PRO: FEATURE_FLAGS_AIRPURIFIER_4, MODEL_FAN_1C: FEATURE_FLAGS_FAN_1C, MODEL_FAN_P10: FEATURE_FLAGS_FAN_P10_P11, MODEL_FAN_P11: FEATURE_FLAGS_FAN_P10_P11, diff --git a/homeassistant/components/xiaomi_miio/sensor.py b/homeassistant/components/xiaomi_miio/sensor.py index 235d103b53d..5370357c58c 100644 --- a/homeassistant/components/xiaomi_miio/sensor.py +++ b/homeassistant/components/xiaomi_miio/sensor.py @@ -60,6 +60,8 @@ from .const import ( MODEL_AIRHUMIDIFIER_CA1, MODEL_AIRHUMIDIFIER_CB1, MODEL_AIRPURIFIER_3C, + MODEL_AIRPURIFIER_4, + MODEL_AIRPURIFIER_4_PRO, MODEL_AIRPURIFIER_PRO, MODEL_AIRPURIFIER_PRO_V7, MODEL_AIRPURIFIER_V2, @@ -100,6 +102,7 @@ ATTR_DISPLAY_CLOCK = "display_clock" ATTR_FAVORITE_SPEED = "favorite_speed" ATTR_FILTER_LIFE_REMAINING = "filter_life_remaining" ATTR_FILTER_HOURS_USED = "filter_hours_used" +ATTR_FILTER_LEFT_TIME = "filter_left_time" ATTR_DUST_FILTER_LIFE_REMAINING = "dust_filter_life_remaining" ATTR_DUST_FILTER_LIFE_REMAINING_DAYS = "dust_filter_life_remaining_days" ATTR_UPPER_FILTER_LIFE_REMAINING = "upper_filter_life_remaining" @@ -114,6 +117,7 @@ ATTR_MOTOR_SPEED = "motor_speed" ATTR_NIGHT_MODE = "night_mode" ATTR_NIGHT_TIME_BEGIN = "night_time_begin" ATTR_NIGHT_TIME_END = "night_time_end" +ATTR_PM10 = "pm10_density" ATTR_PM25 = "pm25" ATTR_PM25_2 = "pm25_2" ATTR_POWER = "power" @@ -253,6 +257,13 @@ SENSOR_TYPES = { icon="mdi:cloud", state_class=SensorStateClass.MEASUREMENT, ), + ATTR_PM10: XiaomiMiioSensorDescription( + key=ATTR_PM10, + name="PM10", + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + device_class=SensorDeviceClass.PM10, + state_class=SensorStateClass.MEASUREMENT, + ), ATTR_PM25: XiaomiMiioSensorDescription( key=ATTR_AQI, name="PM2.5", @@ -284,6 +295,14 @@ SENSOR_TYPES = { state_class=SensorStateClass.MEASUREMENT, entity_category=EntityCategory.DIAGNOSTIC, ), + ATTR_FILTER_LEFT_TIME: XiaomiMiioSensorDescription( + key=ATTR_FILTER_LEFT_TIME, + name="Filter time left", + native_unit_of_measurement=TIME_DAYS, + icon="mdi:clock-outline", + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + ), ATTR_DUST_FILTER_LIFE_REMAINING: XiaomiMiioSensorDescription( key=ATTR_DUST_FILTER_LIFE_REMAINING, name="Dust filter life remaining", @@ -385,6 +404,29 @@ PURIFIER_MIOT_SENSORS = ( ATTR_TEMPERATURE, ATTR_USE_TIME, ) +PURIFIER_4_SENSORS = ( + ATTR_FILTER_LIFE_REMAINING, + ATTR_FILTER_LEFT_TIME, + ATTR_FILTER_USE, + ATTR_HUMIDITY, + ATTR_MOTOR_SPEED, + ATTR_PM25, + ATTR_PURIFY_VOLUME, + ATTR_TEMPERATURE, + ATTR_USE_TIME, +) +PURIFIER_4_PRO_SENSORS = ( + ATTR_FILTER_LIFE_REMAINING, + ATTR_FILTER_LEFT_TIME, + ATTR_FILTER_USE, + ATTR_HUMIDITY, + ATTR_MOTOR_SPEED, + ATTR_PM25, + ATTR_PM10, + ATTR_PURIFY_VOLUME, + ATTR_TEMPERATURE, + ATTR_USE_TIME, +) PURIFIER_3C_SENSORS = ( ATTR_FILTER_LIFE_REMAINING, ATTR_FILTER_USE, @@ -478,6 +520,8 @@ MODEL_TO_SENSORS_MAP: dict[str, tuple[str, ...]] = { MODEL_AIRHUMIDIFIER_CA1: HUMIDIFIER_CA1_CB1_SENSORS, MODEL_AIRHUMIDIFIER_CB1: HUMIDIFIER_CA1_CB1_SENSORS, MODEL_AIRPURIFIER_3C: PURIFIER_3C_SENSORS, + MODEL_AIRPURIFIER_4: PURIFIER_4_SENSORS, + MODEL_AIRPURIFIER_4_PRO: PURIFIER_4_PRO_SENSORS, MODEL_AIRPURIFIER_PRO: PURIFIER_PRO_SENSORS, MODEL_AIRPURIFIER_PRO_V7: PURIFIER_PRO_V7_SENSORS, MODEL_AIRPURIFIER_V2: PURIFIER_V2_SENSORS, diff --git a/homeassistant/components/xiaomi_miio/switch.py b/homeassistant/components/xiaomi_miio/switch.py index f80b6343d09..89cc80ce74f 100644 --- a/homeassistant/components/xiaomi_miio/switch.py +++ b/homeassistant/components/xiaomi_miio/switch.py @@ -43,6 +43,7 @@ from .const import ( FEATURE_FLAGS_AIRHUMIDIFIER_MJSSQ, FEATURE_FLAGS_AIRPURIFIER_2S, FEATURE_FLAGS_AIRPURIFIER_3C, + FEATURE_FLAGS_AIRPURIFIER_4, FEATURE_FLAGS_AIRPURIFIER_MIIO, FEATURE_FLAGS_AIRPURIFIER_MIOT, FEATURE_FLAGS_AIRPURIFIER_PRO, @@ -55,6 +56,7 @@ from .const import ( FEATURE_FLAGS_FAN_P9, FEATURE_FLAGS_FAN_P10_P11, FEATURE_FLAGS_FAN_ZA5, + FEATURE_SET_ANION, FEATURE_SET_AUTO_DETECT, FEATURE_SET_BUZZER, FEATURE_SET_CHILD_LOCK, @@ -76,6 +78,8 @@ from .const import ( MODEL_AIRPURIFIER_2H, MODEL_AIRPURIFIER_2S, MODEL_AIRPURIFIER_3C, + MODEL_AIRPURIFIER_4, + MODEL_AIRPURIFIER_4_PRO, MODEL_AIRPURIFIER_PRO, MODEL_AIRPURIFIER_PRO_V7, MODEL_AIRPURIFIER_V1, @@ -128,6 +132,7 @@ ATTR_DRY = "dry" ATTR_LEARN_MODE = "learn_mode" ATTR_LED = "led" ATTR_IONIZER = "ionizer" +ATTR_ANION = "anion" ATTR_LOAD_POWER = "load_power" ATTR_MODEL = "model" ATTR_POWER = "power" @@ -188,6 +193,8 @@ 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_AIRPURIFIER_4: FEATURE_FLAGS_AIRPURIFIER_4, + MODEL_AIRPURIFIER_4_PRO: FEATURE_FLAGS_AIRPURIFIER_4, MODEL_FAN_1C: FEATURE_FLAGS_FAN_1C, MODEL_FAN_P10: FEATURE_FLAGS_FAN_P10_P11, MODEL_FAN_P11: FEATURE_FLAGS_FAN_P10_P11, @@ -300,6 +307,15 @@ SWITCH_TYPES = ( method_off="async_set_ionizer_off", entity_category=EntityCategory.CONFIG, ), + XiaomiMiioSwitchDescription( + key=ATTR_ANION, + feature=FEATURE_SET_ANION, + name="Ionizer", + icon="mdi:shimmer", + method_on="async_set_anion_on", + method_off="async_set_anion_off", + entity_category=EntityCategory.CONFIG, + ), XiaomiMiioSwitchDescription( key=ATTR_PTC, feature=FEATURE_SET_PTC, @@ -678,6 +694,22 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity): False, ) + async def async_set_anion_on(self) -> bool: + """Turn ionizer on.""" + return await self._try_command( + "Turning ionizer of the miio device on failed.", + self._device.set_anion, + True, + ) + + async def async_set_anion_off(self) -> bool: + """Turn ionizer off.""" + return await self._try_command( + "Turning ionizer of the miio device off failed.", + self._device.set_anion, + False, + ) + async def async_set_ptc_on(self) -> bool: """Turn ionizer on.""" return await self._try_command( diff --git a/homeassistant/components/xiaomi_miio/vacuum.py b/homeassistant/components/xiaomi_miio/vacuum.py index e8f4b334544..7b866d5ff71 100644 --- a/homeassistant/components/xiaomi_miio/vacuum.py +++ b/homeassistant/components/xiaomi_miio/vacuum.py @@ -21,10 +21,10 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.util.dt import as_utc from . import VacuumCoordinatorData -from ...helpers.update_coordinator import DataUpdateCoordinator from .const import ( CONF_DEVICE, CONF_FLOW_TYPE,