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:
parent
f693c8a9fd
commit
d3f952f831
3 changed files with 137 additions and 2 deletions
|
@ -21,6 +21,7 @@ SERVICE_SET_EXTRA_FEATURES = "fan_set_extra_features"
|
||||||
SERVICE_SET_TARGET_HUMIDITY = "fan_set_target_humidity"
|
SERVICE_SET_TARGET_HUMIDITY = "fan_set_target_humidity"
|
||||||
SERVICE_SET_DRY_ON = "fan_set_dry_on"
|
SERVICE_SET_DRY_ON = "fan_set_dry_on"
|
||||||
SERVICE_SET_DRY_OFF = "fan_set_dry_off"
|
SERVICE_SET_DRY_OFF = "fan_set_dry_off"
|
||||||
|
SERVICE_SET_MOTOR_SPEED = "fan_set_motor_speed"
|
||||||
|
|
||||||
# Light Services
|
# Light Services
|
||||||
SERVICE_SET_SCENE = "light_set_scene"
|
SERVICE_SET_SCENE = "light_set_scene"
|
||||||
|
|
|
@ -7,6 +7,7 @@ import logging
|
||||||
from miio import ( # pylint: disable=import-error
|
from miio import ( # pylint: disable=import-error
|
||||||
AirFresh,
|
AirFresh,
|
||||||
AirHumidifier,
|
AirHumidifier,
|
||||||
|
AirHumidifierMiot,
|
||||||
AirPurifier,
|
AirPurifier,
|
||||||
AirPurifierMiot,
|
AirPurifierMiot,
|
||||||
Device,
|
Device,
|
||||||
|
@ -20,6 +21,11 @@ from miio.airhumidifier import ( # pylint: disable=import-error, import-error
|
||||||
LedBrightness as AirhumidifierLedBrightness,
|
LedBrightness as AirhumidifierLedBrightness,
|
||||||
OperationMode as AirhumidifierOperationMode,
|
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
|
from miio.airpurifier import ( # pylint: disable=import-error, import-error
|
||||||
LedBrightness as AirpurifierLedBrightness,
|
LedBrightness as AirpurifierLedBrightness,
|
||||||
OperationMode as AirpurifierOperationMode,
|
OperationMode as AirpurifierOperationMode,
|
||||||
|
@ -30,7 +36,14 @@ from miio.airpurifier_miot import ( # pylint: disable=import-error, import-erro
|
||||||
)
|
)
|
||||||
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,
|
||||||
|
SPEED_HIGH,
|
||||||
|
SPEED_LOW,
|
||||||
|
SPEED_MEDIUM,
|
||||||
|
SUPPORT_SET_SPEED,
|
||||||
|
FanEntity,
|
||||||
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_MODE,
|
ATTR_MODE,
|
||||||
|
@ -60,6 +73,7 @@ from .const import (
|
||||||
SERVICE_SET_LEARN_MODE_OFF,
|
SERVICE_SET_LEARN_MODE_OFF,
|
||||||
SERVICE_SET_LEARN_MODE_ON,
|
SERVICE_SET_LEARN_MODE_ON,
|
||||||
SERVICE_SET_LED_BRIGHTNESS,
|
SERVICE_SET_LED_BRIGHTNESS,
|
||||||
|
SERVICE_SET_MOTOR_SPEED,
|
||||||
SERVICE_SET_TARGET_HUMIDITY,
|
SERVICE_SET_TARGET_HUMIDITY,
|
||||||
SERVICE_SET_VOLUME,
|
SERVICE_SET_VOLUME,
|
||||||
)
|
)
|
||||||
|
@ -88,6 +102,7 @@ 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"
|
||||||
|
MODEL_AIRHUMIDIFIER_CA4 = "zhimi.humidifier.ca4"
|
||||||
MODEL_AIRHUMIDIFIER_CB1 = "zhimi.humidifier.cb1"
|
MODEL_AIRHUMIDIFIER_CB1 = "zhimi.humidifier.cb1"
|
||||||
|
|
||||||
MODEL_AIRFRESH_VA2 = "zhimi.airfresh.va2"
|
MODEL_AIRFRESH_VA2 = "zhimi.airfresh.va2"
|
||||||
|
@ -116,6 +131,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
MODEL_AIRPURIFIER_3H,
|
MODEL_AIRPURIFIER_3H,
|
||||||
MODEL_AIRHUMIDIFIER_V1,
|
MODEL_AIRHUMIDIFIER_V1,
|
||||||
MODEL_AIRHUMIDIFIER_CA1,
|
MODEL_AIRHUMIDIFIER_CA1,
|
||||||
|
MODEL_AIRHUMIDIFIER_CA4,
|
||||||
MODEL_AIRHUMIDIFIER_CB1,
|
MODEL_AIRHUMIDIFIER_CB1,
|
||||||
MODEL_AIRFRESH_VA2,
|
MODEL_AIRFRESH_VA2,
|
||||||
]
|
]
|
||||||
|
@ -169,10 +185,16 @@ ATTR_HARDWARE_VERSION = "hardware_version"
|
||||||
ATTR_DEPTH = "depth"
|
ATTR_DEPTH = "depth"
|
||||||
ATTR_DRY = "dry"
|
ATTR_DRY = "dry"
|
||||||
|
|
||||||
|
# Air Humidifier CA4
|
||||||
|
ATTR_ACTUAL_MOTOR_SPEED = "actual_speed"
|
||||||
|
ATTR_FAHRENHEIT = "fahrenheit"
|
||||||
|
ATTR_FAULT = "fault"
|
||||||
|
|
||||||
# Air Fresh
|
# Air Fresh
|
||||||
ATTR_CO2 = "co2"
|
ATTR_CO2 = "co2"
|
||||||
|
|
||||||
PURIFIER_MIOT = [MODEL_AIRPURIFIER_3, MODEL_AIRPURIFIER_3H]
|
PURIFIER_MIOT = [MODEL_AIRPURIFIER_3, MODEL_AIRPURIFIER_3H]
|
||||||
|
HUMIDIFIER_MIOT = [MODEL_AIRHUMIDIFIER_CA4]
|
||||||
|
|
||||||
# Map attributes to properties of the state object
|
# Map attributes to properties of the state object
|
||||||
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
|
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
|
||||||
|
@ -299,13 +321,13 @@ AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON = {
|
||||||
ATTR_TARGET_HUMIDITY: "target_humidity",
|
ATTR_TARGET_HUMIDITY: "target_humidity",
|
||||||
ATTR_LED_BRIGHTNESS: "led_brightness",
|
ATTR_LED_BRIGHTNESS: "led_brightness",
|
||||||
ATTR_USE_TIME: "use_time",
|
ATTR_USE_TIME: "use_time",
|
||||||
ATTR_HARDWARE_VERSION: "hardware_version",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER = {
|
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER = {
|
||||||
**AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON,
|
**AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON,
|
||||||
ATTR_TRANS_LEVEL: "trans_level",
|
ATTR_TRANS_LEVEL: "trans_level",
|
||||||
ATTR_BUTTON_PRESSED: "button_pressed",
|
ATTR_BUTTON_PRESSED: "button_pressed",
|
||||||
|
ATTR_HARDWARE_VERSION: "hardware_version",
|
||||||
}
|
}
|
||||||
|
|
||||||
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA_AND_CB = {
|
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA_AND_CB = {
|
||||||
|
@ -313,6 +335,16 @@ AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA_AND_CB = {
|
||||||
ATTR_MOTOR_SPEED: "motor_speed",
|
ATTR_MOTOR_SPEED: "motor_speed",
|
||||||
ATTR_DEPTH: "depth",
|
ATTR_DEPTH: "depth",
|
||||||
ATTR_DRY: "dry",
|
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 = {
|
AVAILABLE_ATTRIBUTES_AIRFRESH = {
|
||||||
|
@ -364,6 +396,7 @@ 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_SET_FAN_LEVEL = 4096
|
||||||
|
FEATURE_SET_MOTOR_SPEED = 8192
|
||||||
|
|
||||||
FEATURE_FLAGS_AIRPURIFIER = (
|
FEATURE_FLAGS_AIRPURIFIER = (
|
||||||
FEATURE_SET_BUZZER
|
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_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_FLAGS_AIRFRESH = (
|
||||||
FEATURE_SET_BUZZER
|
FEATURE_SET_BUZZER
|
||||||
| FEATURE_SET_CHILD_LOCK
|
| 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_TO_METHOD = {
|
||||||
SERVICE_SET_BUZZER_ON: {"method": "async_set_buzzer_on"},
|
SERVICE_SET_BUZZER_ON: {"method": "async_set_buzzer_on"},
|
||||||
SERVICE_SET_BUZZER_OFF: {"method": "async_set_buzzer_off"},
|
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_ON: {"method": "async_set_dry_on"},
|
||||||
SERVICE_SET_DRY_OFF: {"method": "async_set_dry_off"},
|
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."):
|
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 in HUMIDIFIER_MIOT:
|
||||||
|
air_humidifier = AirHumidifierMiot(host, token)
|
||||||
|
device = XiaomiAirHumidifierMiot(name, air_humidifier, model, unique_id)
|
||||||
elif model.startswith("zhimi.humidifier."):
|
elif model.startswith("zhimi.humidifier."):
|
||||||
air_humidifier = AirHumidifier(host, token, model=model)
|
air_humidifier = AirHumidifier(host, token, model=model)
|
||||||
device = XiaomiAirHumidifier(name, air_humidifier, model, unique_id)
|
device = XiaomiAirHumidifier(name, air_humidifier, model, unique_id)
|
||||||
|
@ -998,6 +1055,10 @@ class XiaomiAirHumidifier(XiaomiGenericDevice):
|
||||||
for mode in AirhumidifierOperationMode
|
for mode in AirhumidifierOperationMode
|
||||||
if mode is not AirhumidifierOperationMode.Strong
|
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:
|
else:
|
||||||
self._device_features = FEATURE_FLAGS_AIRHUMIDIFIER
|
self._device_features = FEATURE_FLAGS_AIRHUMIDIFIER
|
||||||
self._available_attributes = AVAILABLE_ATTRIBUTES_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):
|
class XiaomiAirFresh(XiaomiGenericDevice):
|
||||||
"""Representation of a Xiaomi Air Fresh."""
|
"""Representation of a Xiaomi Air Fresh."""
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,16 @@ fan_set_dry_off:
|
||||||
description: Name of the xiaomi miio entity.
|
description: Name of the xiaomi miio entity.
|
||||||
example: "fan.xiaomi_miio_device"
|
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:
|
light_set_scene:
|
||||||
description: Set a fixed scene.
|
description: Set a fixed scene.
|
||||||
fields:
|
fields:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue