Add new air-humidifier device CA4 with miot protocol (#39398)

* Add new air-humidifier device CA4 with miot protocol

* Update homeassistant/components/xiaomi_miio/fan.py

Co-authored-by: Teemu R. <tpr@iki.fi>

* xiomi_miio fan Standard speed for fan, removed static attributes

* xiomi_miio fan Standard speed for fan, removed static attributes

* xiomi_miio fan unnessary elif

* added mode_mapping

* Changed mode_mapping to constant also move reverse to constant

* Removerd water_level

* Return to exclude breaking changes

Co-authored-by: Teemu R. <tpr@iki.fi>
This commit is contained in:
Anton Palgunov 2020-11-19 20:56:53 +00:00 committed by GitHub
parent f693c8a9fd
commit d3f952f831
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 137 additions and 2 deletions

View file

@ -21,6 +21,7 @@ SERVICE_SET_EXTRA_FEATURES = "fan_set_extra_features"
SERVICE_SET_TARGET_HUMIDITY = "fan_set_target_humidity"
SERVICE_SET_DRY_ON = "fan_set_dry_on"
SERVICE_SET_DRY_OFF = "fan_set_dry_off"
SERVICE_SET_MOTOR_SPEED = "fan_set_motor_speed"
# Light Services
SERVICE_SET_SCENE = "light_set_scene"

View file

@ -7,6 +7,7 @@ import logging
from miio import ( # pylint: disable=import-error
AirFresh,
AirHumidifier,
AirHumidifierMiot,
AirPurifier,
AirPurifierMiot,
Device,
@ -20,6 +21,11 @@ from miio.airhumidifier import ( # pylint: disable=import-error, import-error
LedBrightness as AirhumidifierLedBrightness,
OperationMode as AirhumidifierOperationMode,
)
from miio.airhumidifier_miot import ( # pylint: disable=import-error, import-error
LedBrightness as AirhumidifierMiotLedBrightness,
OperationMode as AirhumidifierMiotOperationMode,
PressedButton as AirhumidifierPressedButton,
)
from miio.airpurifier import ( # pylint: disable=import-error, import-error
LedBrightness as AirpurifierLedBrightness,
OperationMode as AirpurifierOperationMode,
@ -30,7 +36,14 @@ from miio.airpurifier_miot import ( # pylint: disable=import-error, import-erro
)
import voluptuous as vol
from homeassistant.components.fan import PLATFORM_SCHEMA, SUPPORT_SET_SPEED, FanEntity
from homeassistant.components.fan import (
PLATFORM_SCHEMA,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SUPPORT_SET_SPEED,
FanEntity,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_MODE,
@ -60,6 +73,7 @@ from .const import (
SERVICE_SET_LEARN_MODE_OFF,
SERVICE_SET_LEARN_MODE_ON,
SERVICE_SET_LED_BRIGHTNESS,
SERVICE_SET_MOTOR_SPEED,
SERVICE_SET_TARGET_HUMIDITY,
SERVICE_SET_VOLUME,
)
@ -88,6 +102,7 @@ MODEL_AIRPURIFIER_3H = "zhimi.airpurifier.mb3"
MODEL_AIRHUMIDIFIER_V1 = "zhimi.humidifier.v1"
MODEL_AIRHUMIDIFIER_CA1 = "zhimi.humidifier.ca1"
MODEL_AIRHUMIDIFIER_CA4 = "zhimi.humidifier.ca4"
MODEL_AIRHUMIDIFIER_CB1 = "zhimi.humidifier.cb1"
MODEL_AIRFRESH_VA2 = "zhimi.airfresh.va2"
@ -116,6 +131,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
MODEL_AIRPURIFIER_3H,
MODEL_AIRHUMIDIFIER_V1,
MODEL_AIRHUMIDIFIER_CA1,
MODEL_AIRHUMIDIFIER_CA4,
MODEL_AIRHUMIDIFIER_CB1,
MODEL_AIRFRESH_VA2,
]
@ -169,10 +185,16 @@ ATTR_HARDWARE_VERSION = "hardware_version"
ATTR_DEPTH = "depth"
ATTR_DRY = "dry"
# Air Humidifier CA4
ATTR_ACTUAL_MOTOR_SPEED = "actual_speed"
ATTR_FAHRENHEIT = "fahrenheit"
ATTR_FAULT = "fault"
# Air Fresh
ATTR_CO2 = "co2"
PURIFIER_MIOT = [MODEL_AIRPURIFIER_3, MODEL_AIRPURIFIER_3H]
HUMIDIFIER_MIOT = [MODEL_AIRHUMIDIFIER_CA4]
# Map attributes to properties of the state object
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
@ -299,13 +321,13 @@ AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON = {
ATTR_TARGET_HUMIDITY: "target_humidity",
ATTR_LED_BRIGHTNESS: "led_brightness",
ATTR_USE_TIME: "use_time",
ATTR_HARDWARE_VERSION: "hardware_version",
}
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER = {
**AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON,
ATTR_TRANS_LEVEL: "trans_level",
ATTR_BUTTON_PRESSED: "button_pressed",
ATTR_HARDWARE_VERSION: "hardware_version",
}
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA_AND_CB = {
@ -313,6 +335,16 @@ AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA_AND_CB = {
ATTR_MOTOR_SPEED: "motor_speed",
ATTR_DEPTH: "depth",
ATTR_DRY: "dry",
ATTR_HARDWARE_VERSION: "hardware_version",
}
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA4 = {
**AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON,
ATTR_ACTUAL_MOTOR_SPEED: "actual_speed",
ATTR_BUTTON_PRESSED: "button_pressed",
ATTR_DRY: "dry",
ATTR_FAHRENHEIT: "fahrenheit",
ATTR_MOTOR_SPEED: "motor_speed",
}
AVAILABLE_ATTRIBUTES_AIRFRESH = {
@ -364,6 +396,7 @@ FEATURE_SET_EXTRA_FEATURES = 512
FEATURE_SET_TARGET_HUMIDITY = 1024
FEATURE_SET_DRY = 2048
FEATURE_SET_FAN_LEVEL = 4096
FEATURE_SET_MOTOR_SPEED = 8192
FEATURE_FLAGS_AIRPURIFIER = (
FEATURE_SET_BUZZER
@ -421,6 +454,15 @@ FEATURE_FLAGS_AIRHUMIDIFIER = (
FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB = FEATURE_FLAGS_AIRHUMIDIFIER | FEATURE_SET_DRY
FEATURE_FLAGS_AIRHUMIDIFIER_CA4 = (
FEATURE_SET_BUZZER
| FEATURE_SET_CHILD_LOCK
| FEATURE_SET_LED_BRIGHTNESS
| FEATURE_SET_TARGET_HUMIDITY
| FEATURE_SET_DRY
| FEATURE_SET_MOTOR_SPEED
)
FEATURE_FLAGS_AIRFRESH = (
FEATURE_SET_BUZZER
| FEATURE_SET_CHILD_LOCK
@ -460,6 +502,14 @@ SERVICE_SCHEMA_TARGET_HUMIDITY = AIRPURIFIER_SERVICE_SCHEMA.extend(
}
)
SERVICE_SCHEMA_MOTOR_SPEED = AIRPURIFIER_SERVICE_SCHEMA.extend(
{
vol.Required(ATTR_MOTOR_SPEED): vol.All(
vol.Coerce(int), vol.Clamp(min=200, max=2000)
)
}
)
SERVICE_TO_METHOD = {
SERVICE_SET_BUZZER_ON: {"method": "async_set_buzzer_on"},
SERVICE_SET_BUZZER_OFF: {"method": "async_set_buzzer_off"},
@ -495,6 +545,10 @@ SERVICE_TO_METHOD = {
},
SERVICE_SET_DRY_ON: {"method": "async_set_dry_on"},
SERVICE_SET_DRY_OFF: {"method": "async_set_dry_off"},
SERVICE_SET_MOTOR_SPEED: {
"method": "async_set_motor_speed",
"schema": SERVICE_SCHEMA_MOTOR_SPEED,
},
}
@ -532,6 +586,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
elif model.startswith("zhimi.airpurifier."):
air_purifier = AirPurifier(host, token)
device = XiaomiAirPurifier(name, air_purifier, model, unique_id)
elif model in HUMIDIFIER_MIOT:
air_humidifier = AirHumidifierMiot(host, token)
device = XiaomiAirHumidifierMiot(name, air_humidifier, model, unique_id)
elif model.startswith("zhimi.humidifier."):
air_humidifier = AirHumidifier(host, token, model=model)
device = XiaomiAirHumidifier(name, air_humidifier, model, unique_id)
@ -998,6 +1055,10 @@ class XiaomiAirHumidifier(XiaomiGenericDevice):
for mode in AirhumidifierOperationMode
if mode is not AirhumidifierOperationMode.Strong
]
elif self._model in [MODEL_AIRHUMIDIFIER_CA4]:
self._device_features = FEATURE_FLAGS_AIRHUMIDIFIER_CA4
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA4
self._speed_list = [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
else:
self._device_features = FEATURE_FLAGS_AIRHUMIDIFIER
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER
@ -1107,6 +1168,69 @@ class XiaomiAirHumidifier(XiaomiGenericDevice):
)
class XiaomiAirHumidifierMiot(XiaomiAirHumidifier):
"""Representation of a Xiaomi Air Humidifier (MiOT protocol)."""
MODE_MAPPING = {
AirhumidifierMiotOperationMode.Low: SPEED_LOW,
AirhumidifierMiotOperationMode.Mid: SPEED_MEDIUM,
AirhumidifierMiotOperationMode.High: SPEED_HIGH,
}
REVERSE_MODE_MAPPING = {v: k for k, v in MODE_MAPPING.items()}
@property
def speed(self):
"""Return the current speed."""
if self._state:
return self.MODE_MAPPING.get(
AirhumidifierMiotOperationMode(self._state_attrs[ATTR_MODE])
)
return None
@property
def button_pressed(self):
"""Return the last button pressed."""
if self._state:
return AirhumidifierPressedButton(
self._state_attrs[ATTR_BUTTON_PRESSED]
).name
return None
async def async_set_speed(self, speed: str) -> None:
"""Set the speed of the fan."""
await self._try_command(
"Setting operation mode of the miio device failed.",
self._device.set_mode,
self.REVERSE_MODE_MAPPING[speed],
)
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,
AirhumidifierMiotLedBrightness(brightness),
)
async def async_set_motor_speed(self, motor_speed: int = 400):
"""Set the target motor speed."""
if self._device_features & FEATURE_SET_MOTOR_SPEED == 0:
return
await self._try_command(
"Setting the target motor speed of the miio device failed.",
self._device.set_speed,
motor_speed,
)
class XiaomiAirFresh(XiaomiGenericDevice):
"""Representation of a Xiaomi Air Fresh."""

View file

@ -149,6 +149,16 @@ fan_set_dry_off:
description: Name of the xiaomi miio entity.
example: "fan.xiaomi_miio_device"
fan_set_motor_speed:
description: Set the target motor speed.
fields:
entity_id:
description: Name of the xiaomi miio entity.
example: 'fan.xiaomi_miio_device'
motor_speed:
description: Set RPM of motor speed, between 200 and 2000.
example: 1100
light_set_scene:
description: Set a fixed scene.
fields: