Add support for Mi AirPurifier 3 (#31729)
* Adding support for Mi AirPurifier 3 * Adding support for Mi AirPurifier 3H * Enabled setting fan level for AirPurifier 3/3H * Get rid of isinstance for MIOT AirPurifier * Bumping xiaomi-miio dependency * Fixed lint error * Update manifest.json * Fixed requirements files for 0.5.0.1 Co-authored-by: Piotr Król <Piotr@gorszyportal.pl>pull/33586/head
parent
c0315e32bd
commit
912eb321d9
|
@ -10,6 +10,7 @@ SERVICE_SET_CHILD_LOCK_ON = "fan_set_child_lock_on"
|
||||||
SERVICE_SET_CHILD_LOCK_OFF = "fan_set_child_lock_off"
|
SERVICE_SET_CHILD_LOCK_OFF = "fan_set_child_lock_off"
|
||||||
SERVICE_SET_LED_BRIGHTNESS = "fan_set_led_brightness"
|
SERVICE_SET_LED_BRIGHTNESS = "fan_set_led_brightness"
|
||||||
SERVICE_SET_FAVORITE_LEVEL = "fan_set_favorite_level"
|
SERVICE_SET_FAVORITE_LEVEL = "fan_set_favorite_level"
|
||||||
|
SERVICE_SET_FAN_LEVEL = "fan_set_fan_level"
|
||||||
SERVICE_SET_AUTO_DETECT_ON = "fan_set_auto_detect_on"
|
SERVICE_SET_AUTO_DETECT_ON = "fan_set_auto_detect_on"
|
||||||
SERVICE_SET_AUTO_DETECT_OFF = "fan_set_auto_detect_off"
|
SERVICE_SET_AUTO_DETECT_OFF = "fan_set_auto_detect_off"
|
||||||
SERVICE_SET_LEARN_MODE_ON = "fan_set_learn_mode_on"
|
SERVICE_SET_LEARN_MODE_ON = "fan_set_learn_mode_on"
|
||||||
|
|
|
@ -8,6 +8,7 @@ from miio import ( # pylint: disable=import-error
|
||||||
AirFresh,
|
AirFresh,
|
||||||
AirHumidifier,
|
AirHumidifier,
|
||||||
AirPurifier,
|
AirPurifier,
|
||||||
|
AirPurifierMiot,
|
||||||
Device,
|
Device,
|
||||||
DeviceException,
|
DeviceException,
|
||||||
)
|
)
|
||||||
|
@ -23,6 +24,10 @@ from miio.airpurifier import ( # pylint: disable=import-error, import-error
|
||||||
LedBrightness as AirpurifierLedBrightness,
|
LedBrightness as AirpurifierLedBrightness,
|
||||||
OperationMode as AirpurifierOperationMode,
|
OperationMode as AirpurifierOperationMode,
|
||||||
)
|
)
|
||||||
|
from miio.airpurifier_miot import ( # pylint: disable=import-error, import-error
|
||||||
|
LedBrightness as AirpurifierMiotLedBrightness,
|
||||||
|
OperationMode as AirpurifierMiotOperationMode,
|
||||||
|
)
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.fan import PLATFORM_SCHEMA, SUPPORT_SET_SPEED, FanEntity
|
from homeassistant.components.fan import PLATFORM_SCHEMA, SUPPORT_SET_SPEED, FanEntity
|
||||||
|
@ -48,6 +53,7 @@ from .const import (
|
||||||
SERVICE_SET_DRY_OFF,
|
SERVICE_SET_DRY_OFF,
|
||||||
SERVICE_SET_DRY_ON,
|
SERVICE_SET_DRY_ON,
|
||||||
SERVICE_SET_EXTRA_FEATURES,
|
SERVICE_SET_EXTRA_FEATURES,
|
||||||
|
SERVICE_SET_FAN_LEVEL,
|
||||||
SERVICE_SET_FAVORITE_LEVEL,
|
SERVICE_SET_FAVORITE_LEVEL,
|
||||||
SERVICE_SET_LEARN_MODE_OFF,
|
SERVICE_SET_LEARN_MODE_OFF,
|
||||||
SERVICE_SET_LEARN_MODE_ON,
|
SERVICE_SET_LEARN_MODE_ON,
|
||||||
|
@ -77,6 +83,8 @@ MODEL_AIRPURIFIER_MA2 = "zhimi.airpurifier.ma2"
|
||||||
MODEL_AIRPURIFIER_SA1 = "zhimi.airpurifier.sa1"
|
MODEL_AIRPURIFIER_SA1 = "zhimi.airpurifier.sa1"
|
||||||
MODEL_AIRPURIFIER_SA2 = "zhimi.airpurifier.sa2"
|
MODEL_AIRPURIFIER_SA2 = "zhimi.airpurifier.sa2"
|
||||||
MODEL_AIRPURIFIER_2S = "zhimi.airpurifier.mc1"
|
MODEL_AIRPURIFIER_2S = "zhimi.airpurifier.mc1"
|
||||||
|
MODEL_AIRPURIFIER_3 = "zhimi.airpurifier.ma4"
|
||||||
|
MODEL_AIRPURIFIER_3H = "zhimi.airpurifier.mb3"
|
||||||
|
|
||||||
MODEL_AIRHUMIDIFIER_V1 = "zhimi.humidifier.v1"
|
MODEL_AIRHUMIDIFIER_V1 = "zhimi.humidifier.v1"
|
||||||
MODEL_AIRHUMIDIFIER_CA1 = "zhimi.humidifier.ca1"
|
MODEL_AIRHUMIDIFIER_CA1 = "zhimi.humidifier.ca1"
|
||||||
|
@ -104,6 +112,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
MODEL_AIRPURIFIER_SA1,
|
MODEL_AIRPURIFIER_SA1,
|
||||||
MODEL_AIRPURIFIER_SA2,
|
MODEL_AIRPURIFIER_SA2,
|
||||||
MODEL_AIRPURIFIER_2S,
|
MODEL_AIRPURIFIER_2S,
|
||||||
|
MODEL_AIRPURIFIER_3,
|
||||||
|
MODEL_AIRPURIFIER_3H,
|
||||||
MODEL_AIRHUMIDIFIER_V1,
|
MODEL_AIRHUMIDIFIER_V1,
|
||||||
MODEL_AIRHUMIDIFIER_CA1,
|
MODEL_AIRHUMIDIFIER_CA1,
|
||||||
MODEL_AIRHUMIDIFIER_CB1,
|
MODEL_AIRHUMIDIFIER_CB1,
|
||||||
|
@ -131,6 +141,7 @@ ATTR_AVERAGE_AIR_QUALITY_INDEX = "average_aqi"
|
||||||
ATTR_PURIFY_VOLUME = "purify_volume"
|
ATTR_PURIFY_VOLUME = "purify_volume"
|
||||||
ATTR_BRIGHTNESS = "brightness"
|
ATTR_BRIGHTNESS = "brightness"
|
||||||
ATTR_LEVEL = "level"
|
ATTR_LEVEL = "level"
|
||||||
|
ATTR_FAN_LEVEL = "fan_level"
|
||||||
ATTR_MOTOR2_SPEED = "motor2_speed"
|
ATTR_MOTOR2_SPEED = "motor2_speed"
|
||||||
ATTR_ILLUMINANCE = "illuminance"
|
ATTR_ILLUMINANCE = "illuminance"
|
||||||
ATTR_FILTER_RFID_PRODUCT_ID = "filter_rfid_product_id"
|
ATTR_FILTER_RFID_PRODUCT_ID = "filter_rfid_product_id"
|
||||||
|
@ -154,13 +165,15 @@ ATTR_TRANS_LEVEL = "trans_level"
|
||||||
ATTR_HARDWARE_VERSION = "hardware_version"
|
ATTR_HARDWARE_VERSION = "hardware_version"
|
||||||
|
|
||||||
# Air Humidifier CA
|
# Air Humidifier CA
|
||||||
ATTR_MOTOR_SPEED = "motor_speed"
|
# ATTR_MOTOR_SPEED = "motor_speed"
|
||||||
ATTR_DEPTH = "depth"
|
ATTR_DEPTH = "depth"
|
||||||
ATTR_DRY = "dry"
|
ATTR_DRY = "dry"
|
||||||
|
|
||||||
# Air Fresh
|
# Air Fresh
|
||||||
ATTR_CO2 = "co2"
|
ATTR_CO2 = "co2"
|
||||||
|
|
||||||
|
PURIFIER_MIOT = [MODEL_AIRPURIFIER_3, MODEL_AIRPURIFIER_3H]
|
||||||
|
|
||||||
# Map attributes to properties of the state object
|
# Map attributes to properties of the state object
|
||||||
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
|
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
|
||||||
ATTR_TEMPERATURE: "temperature",
|
ATTR_TEMPERATURE: "temperature",
|
||||||
|
@ -227,6 +240,28 @@ AVAILABLE_ATTRIBUTES_AIRPURIFIER_2S = {
|
||||||
ATTR_ILLUMINANCE: "illuminance",
|
ATTR_ILLUMINANCE: "illuminance",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AVAILABLE_ATTRIBUTES_AIRPURIFIER_3 = {
|
||||||
|
ATTR_TEMPERATURE: "temperature",
|
||||||
|
ATTR_HUMIDITY: "humidity",
|
||||||
|
ATTR_AIR_QUALITY_INDEX: "aqi",
|
||||||
|
ATTR_MODE: "mode",
|
||||||
|
ATTR_FILTER_HOURS_USED: "filter_hours_used",
|
||||||
|
ATTR_FILTER_LIFE: "filter_life_remaining",
|
||||||
|
ATTR_FAVORITE_LEVEL: "favorite_level",
|
||||||
|
ATTR_CHILD_LOCK: "child_lock",
|
||||||
|
ATTR_LED: "led",
|
||||||
|
ATTR_MOTOR_SPEED: "motor_speed",
|
||||||
|
ATTR_AVERAGE_AIR_QUALITY_INDEX: "average_aqi",
|
||||||
|
ATTR_PURIFY_VOLUME: "purify_volume",
|
||||||
|
ATTR_USE_TIME: "use_time",
|
||||||
|
ATTR_BUZZER: "buzzer",
|
||||||
|
ATTR_LED_BRIGHTNESS: "led_brightness",
|
||||||
|
ATTR_FILTER_RFID_PRODUCT_ID: "filter_rfid_product_id",
|
||||||
|
ATTR_FILTER_RFID_TAG: "filter_rfid_tag",
|
||||||
|
ATTR_FILTER_TYPE: "filter_type",
|
||||||
|
ATTR_FAN_LEVEL: "fan_level",
|
||||||
|
}
|
||||||
|
|
||||||
AVAILABLE_ATTRIBUTES_AIRPURIFIER_V3 = {
|
AVAILABLE_ATTRIBUTES_AIRPURIFIER_V3 = {
|
||||||
# Common set isn't used here. It's a very basic version of the device.
|
# Common set isn't used here. It's a very basic version of the device.
|
||||||
ATTR_AIR_QUALITY_INDEX: "aqi",
|
ATTR_AIR_QUALITY_INDEX: "aqi",
|
||||||
|
@ -302,6 +337,7 @@ OPERATION_MODES_AIRPURIFIER = ["Auto", "Silent", "Favorite", "Idle"]
|
||||||
OPERATION_MODES_AIRPURIFIER_PRO = ["Auto", "Silent", "Favorite"]
|
OPERATION_MODES_AIRPURIFIER_PRO = ["Auto", "Silent", "Favorite"]
|
||||||
OPERATION_MODES_AIRPURIFIER_PRO_V7 = OPERATION_MODES_AIRPURIFIER_PRO
|
OPERATION_MODES_AIRPURIFIER_PRO_V7 = OPERATION_MODES_AIRPURIFIER_PRO
|
||||||
OPERATION_MODES_AIRPURIFIER_2S = ["Auto", "Silent", "Favorite"]
|
OPERATION_MODES_AIRPURIFIER_2S = ["Auto", "Silent", "Favorite"]
|
||||||
|
OPERATION_MODES_AIRPURIFIER_3 = ["Auto", "Silent", "Favorite", "Fan"]
|
||||||
OPERATION_MODES_AIRPURIFIER_V3 = [
|
OPERATION_MODES_AIRPURIFIER_V3 = [
|
||||||
"Auto",
|
"Auto",
|
||||||
"Silent",
|
"Silent",
|
||||||
|
@ -327,6 +363,7 @@ FEATURE_RESET_FILTER = 256
|
||||||
FEATURE_SET_EXTRA_FEATURES = 512
|
FEATURE_SET_EXTRA_FEATURES = 512
|
||||||
FEATURE_SET_TARGET_HUMIDITY = 1024
|
FEATURE_SET_TARGET_HUMIDITY = 1024
|
||||||
FEATURE_SET_DRY = 2048
|
FEATURE_SET_DRY = 2048
|
||||||
|
FEATURE_SET_FAN_LEVEL = 4096
|
||||||
|
|
||||||
FEATURE_FLAGS_AIRPURIFIER = (
|
FEATURE_FLAGS_AIRPURIFIER = (
|
||||||
FEATURE_SET_BUZZER
|
FEATURE_SET_BUZZER
|
||||||
|
@ -361,6 +398,15 @@ FEATURE_FLAGS_AIRPURIFIER_2S = (
|
||||||
| FEATURE_SET_FAVORITE_LEVEL
|
| FEATURE_SET_FAVORITE_LEVEL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FEATURE_FLAGS_AIRPURIFIER_3 = (
|
||||||
|
FEATURE_SET_BUZZER
|
||||||
|
| FEATURE_SET_CHILD_LOCK
|
||||||
|
| FEATURE_SET_LED
|
||||||
|
| FEATURE_SET_FAVORITE_LEVEL
|
||||||
|
| FEATURE_SET_FAN_LEVEL
|
||||||
|
| FEATURE_SET_LED_BRIGHTNESS
|
||||||
|
)
|
||||||
|
|
||||||
FEATURE_FLAGS_AIRPURIFIER_V3 = (
|
FEATURE_FLAGS_AIRPURIFIER_V3 = (
|
||||||
FEATURE_SET_BUZZER | FEATURE_SET_CHILD_LOCK | FEATURE_SET_LED
|
FEATURE_SET_BUZZER | FEATURE_SET_CHILD_LOCK | FEATURE_SET_LED
|
||||||
)
|
)
|
||||||
|
@ -394,6 +440,10 @@ SERVICE_SCHEMA_FAVORITE_LEVEL = AIRPURIFIER_SERVICE_SCHEMA.extend(
|
||||||
{vol.Required(ATTR_LEVEL): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=17))}
|
{vol.Required(ATTR_LEVEL): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=17))}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SERVICE_SCHEMA_FAN_LEVEL = AIRPURIFIER_SERVICE_SCHEMA.extend(
|
||||||
|
{vol.Required(ATTR_LEVEL): vol.All(vol.Coerce(int), vol.Clamp(min=1, max=3))}
|
||||||
|
)
|
||||||
|
|
||||||
SERVICE_SCHEMA_VOLUME = AIRPURIFIER_SERVICE_SCHEMA.extend(
|
SERVICE_SCHEMA_VOLUME = AIRPURIFIER_SERVICE_SCHEMA.extend(
|
||||||
{vol.Required(ATTR_VOLUME): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=100))}
|
{vol.Required(ATTR_VOLUME): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=100))}
|
||||||
)
|
)
|
||||||
|
@ -430,6 +480,10 @@ SERVICE_TO_METHOD = {
|
||||||
"method": "async_set_favorite_level",
|
"method": "async_set_favorite_level",
|
||||||
"schema": SERVICE_SCHEMA_FAVORITE_LEVEL,
|
"schema": SERVICE_SCHEMA_FAVORITE_LEVEL,
|
||||||
},
|
},
|
||||||
|
SERVICE_SET_FAN_LEVEL: {
|
||||||
|
"method": "async_set_fan_level",
|
||||||
|
"schema": SERVICE_SCHEMA_FAN_LEVEL,
|
||||||
|
},
|
||||||
SERVICE_SET_VOLUME: {"method": "async_set_volume", "schema": SERVICE_SCHEMA_VOLUME},
|
SERVICE_SET_VOLUME: {"method": "async_set_volume", "schema": SERVICE_SCHEMA_VOLUME},
|
||||||
SERVICE_SET_EXTRA_FEATURES: {
|
SERVICE_SET_EXTRA_FEATURES: {
|
||||||
"method": "async_set_extra_features",
|
"method": "async_set_extra_features",
|
||||||
|
@ -472,7 +526,10 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
||||||
except DeviceException:
|
except DeviceException:
|
||||||
raise PlatformNotReady
|
raise PlatformNotReady
|
||||||
|
|
||||||
if model.startswith("zhimi.airpurifier."):
|
if model in PURIFIER_MIOT:
|
||||||
|
air_purifier = AirPurifierMiot(host, token)
|
||||||
|
device = XiaomiAirPurifierMiot(name, air_purifier, model, unique_id)
|
||||||
|
elif model.startswith("zhimi.airpurifier."):
|
||||||
air_purifier = AirPurifier(host, token)
|
air_purifier = AirPurifier(host, token)
|
||||||
device = XiaomiAirPurifier(name, air_purifier, model, unique_id)
|
device = XiaomiAirPurifier(name, air_purifier, model, unique_id)
|
||||||
elif model.startswith("zhimi.humidifier."):
|
elif model.startswith("zhimi.humidifier."):
|
||||||
|
@ -690,6 +747,10 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||||
self._device_features = FEATURE_FLAGS_AIRPURIFIER_2S
|
self._device_features = FEATURE_FLAGS_AIRPURIFIER_2S
|
||||||
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_2S
|
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_2S
|
||||||
self._speed_list = OPERATION_MODES_AIRPURIFIER_2S
|
self._speed_list = OPERATION_MODES_AIRPURIFIER_2S
|
||||||
|
elif self._model == MODEL_AIRPURIFIER_3 or self._model == MODEL_AIRPURIFIER_3H:
|
||||||
|
self._device_features = FEATURE_FLAGS_AIRPURIFIER_3
|
||||||
|
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_3
|
||||||
|
self._speed_list = OPERATION_MODES_AIRPURIFIER_3
|
||||||
elif self._model == MODEL_AIRPURIFIER_V3:
|
elif self._model == MODEL_AIRPURIFIER_V3:
|
||||||
self._device_features = FEATURE_FLAGS_AIRPURIFIER_V3
|
self._device_features = FEATURE_FLAGS_AIRPURIFIER_V3
|
||||||
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_V3
|
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_V3
|
||||||
|
@ -795,6 +856,17 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||||
level,
|
level,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_set_fan_level(self, level: int = 1):
|
||||||
|
"""Set the favorite level."""
|
||||||
|
if self._device_features & FEATURE_SET_FAN_LEVEL == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
await self._try_command(
|
||||||
|
"Setting the fan level of the miio device failed.",
|
||||||
|
self._device.set_fan_level,
|
||||||
|
level,
|
||||||
|
)
|
||||||
|
|
||||||
async def async_set_auto_detect_on(self):
|
async def async_set_auto_detect_on(self):
|
||||||
"""Turn the auto detect on."""
|
"""Turn the auto detect on."""
|
||||||
if self._device_features & FEATURE_SET_AUTO_DETECT == 0:
|
if self._device_features & FEATURE_SET_AUTO_DETECT == 0:
|
||||||
|
@ -872,6 +944,42 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class XiaomiAirPurifierMiot(XiaomiAirPurifier):
|
||||||
|
"""Representation of a Xiaomi Air Purifier (MiOT protocol)."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def speed(self):
|
||||||
|
"""Return the current speed."""
|
||||||
|
if self._state:
|
||||||
|
return AirpurifierMiotOperationMode(self._state_attrs[ATTR_MODE]).name
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def async_set_speed(self, speed: str) -> None:
|
||||||
|
"""Set the speed of the fan."""
|
||||||
|
if self.supported_features & SUPPORT_SET_SPEED == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
_LOGGER.debug("Setting the operation mode to: %s", speed)
|
||||||
|
|
||||||
|
await self._try_command(
|
||||||
|
"Setting operation mode of the miio device failed.",
|
||||||
|
self._device.set_mode,
|
||||||
|
AirpurifierMiotOperationMode[speed.title()],
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_set_led_brightness(self, brightness: int = 2):
|
||||||
|
"""Set the led brightness."""
|
||||||
|
if self._device_features & FEATURE_SET_LED_BRIGHTNESS == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
await self._try_command(
|
||||||
|
"Setting the led brightness of the miio device failed.",
|
||||||
|
self._device.set_led_brightness,
|
||||||
|
AirpurifierMiotLedBrightness(brightness),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class XiaomiAirHumidifier(XiaomiGenericDevice):
|
class XiaomiAirHumidifier(XiaomiGenericDevice):
|
||||||
"""Representation of a Xiaomi Air Humidifier."""
|
"""Representation of a Xiaomi Air Humidifier."""
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,16 @@ fan_set_favorite_level:
|
||||||
description: Level, between 0 and 16.
|
description: Level, between 0 and 16.
|
||||||
example: 1
|
example: 1
|
||||||
|
|
||||||
|
fan_set_fan_level:
|
||||||
|
description: Set the fan level.
|
||||||
|
fields:
|
||||||
|
entity_id:
|
||||||
|
description: Name of the xiaomi miio entity.
|
||||||
|
example: 'fan.xiaomi_miio_device'
|
||||||
|
level:
|
||||||
|
description: Level, between 1 and 3.
|
||||||
|
example: 1
|
||||||
|
|
||||||
fan_set_led_brightness:
|
fan_set_led_brightness:
|
||||||
description: Set the led brightness.
|
description: Set the led brightness.
|
||||||
fields:
|
fields:
|
||||||
|
|
Loading…
Reference in New Issue