Add number platform for Xiaomi Miio fan (#54977)

This commit is contained in:
Maciej Bieniek 2021-08-21 19:09:42 +02:00 committed by GitHub
parent aa7c72a8b5
commit 4a6ca8a04e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 162 deletions

View file

@ -46,7 +46,7 @@ _LOGGER = logging.getLogger(__name__)
GATEWAY_PLATFORMS = ["alarm_control_panel", "light", "sensor", "switch"]
SWITCH_PLATFORMS = ["switch"]
FAN_PLATFORMS = ["fan", "select", "sensor", "switch"]
FAN_PLATFORMS = ["fan", "number", "select", "sensor", "switch"]
HUMIDIFIER_PLATFORMS = [
"binary_sensor",
"humidifier",

View file

@ -35,9 +35,6 @@ from .const import (
FEATURE_FLAGS_AIRPURIFIER_V3,
FEATURE_RESET_FILTER,
FEATURE_SET_EXTRA_FEATURES,
FEATURE_SET_FAN_LEVEL,
FEATURE_SET_FAVORITE_LEVEL,
FEATURE_SET_VOLUME,
KEY_COORDINATOR,
KEY_DEVICE,
MODEL_AIRPURIFIER_2H,
@ -48,9 +45,6 @@ from .const import (
MODELS_PURIFIER_MIOT,
SERVICE_RESET_FILTER,
SERVICE_SET_EXTRA_FEATURES,
SERVICE_SET_FAN_LEVEL,
SERVICE_SET_FAVORITE_LEVEL,
SERVICE_SET_VOLUME,
)
from .device import XiaomiCoordinatedMiioEntity
@ -64,9 +58,7 @@ CONF_MODEL = "model"
ATTR_MODEL = "model"
# Air Purifier
ATTR_FAVORITE_LEVEL = "favorite_level"
ATTR_BRIGHTNESS = "brightness"
ATTR_LEVEL = "level"
ATTR_FAN_LEVEL = "fan_level"
ATTR_SLEEP_TIME = "sleep_time"
ATTR_SLEEP_LEARN_COUNT = "sleep_mode_learn_count"
@ -74,14 +66,12 @@ ATTR_EXTRA_FEATURES = "extra_features"
ATTR_FEATURES = "features"
ATTR_TURBO_MODE_SUPPORTED = "turbo_mode_supported"
ATTR_SLEEP_MODE = "sleep_mode"
ATTR_VOLUME = "volume"
ATTR_USE_TIME = "use_time"
ATTR_BUTTON_PRESSED = "button_pressed"
# Map attributes to properties of the state object
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
ATTR_MODE: "mode",
ATTR_FAVORITE_LEVEL: "favorite_level",
ATTR_EXTRA_FEATURES: "extra_features",
ATTR_TURBO_MODE_SUPPORTED: "turbo_mode_supported",
ATTR_BUTTON_PRESSED: "button_pressed",
@ -98,27 +88,20 @@ AVAILABLE_ATTRIBUTES_AIRPURIFIER = {
AVAILABLE_ATTRIBUTES_AIRPURIFIER_PRO = {
**AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON,
ATTR_USE_TIME: "use_time",
ATTR_VOLUME: "volume",
ATTR_SLEEP_TIME: "sleep_time",
ATTR_SLEEP_LEARN_COUNT: "sleep_mode_learn_count",
}
AVAILABLE_ATTRIBUTES_AIRPURIFIER_MIOT = {
ATTR_MODE: "mode",
ATTR_FAVORITE_LEVEL: "favorite_level",
ATTR_USE_TIME: "use_time",
ATTR_FAN_LEVEL: "fan_level",
}
AVAILABLE_ATTRIBUTES_AIRPURIFIER_PRO_V7 = {
**AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON,
ATTR_VOLUME: "volume",
}
AVAILABLE_ATTRIBUTES_AIRPURIFIER_PRO_V7 = AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON
AVAILABLE_ATTRIBUTES_AIRPURIFIER_V3 = {
# Common set isn't used here. It's a very basic version of the device.
ATTR_MODE: "mode",
ATTR_VOLUME: "volume",
ATTR_SLEEP_TIME: "sleep_time",
ATTR_SLEEP_LEARN_COUNT: "sleep_mode_learn_count",
ATTR_EXTRA_FEATURES: "extra_features",
@ -164,33 +147,12 @@ PRESET_MODES_AIRFRESH = ["Auto", "Interval"]
AIRPURIFIER_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids})
SERVICE_SCHEMA_FAVORITE_LEVEL = AIRPURIFIER_SERVICE_SCHEMA.extend(
{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(
{vol.Required(ATTR_VOLUME): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=100))}
)
SERVICE_SCHEMA_EXTRA_FEATURES = AIRPURIFIER_SERVICE_SCHEMA.extend(
{vol.Required(ATTR_FEATURES): cv.positive_int}
)
SERVICE_TO_METHOD = {
SERVICE_RESET_FILTER: {"method": "async_reset_filter"},
SERVICE_SET_FAVORITE_LEVEL: {
"method": "async_set_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_EXTRA_FEATURES: {
"method": "async_set_extra_features",
"schema": SERVICE_SCHEMA_EXTRA_FEATURES,
@ -513,39 +475,6 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
self.PRESET_MODE_MAPPING[preset_mode],
)
async def async_set_favorite_level(self, level: int = 1):
"""Set the favorite level."""
if self._device_features & FEATURE_SET_FAVORITE_LEVEL == 0:
return
await self._try_command(
"Setting the favorite level of the miio device failed.",
self._device.set_favorite_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_volume(self, volume: int = 50):
"""Set the sound volume."""
if self._device_features & FEATURE_SET_VOLUME == 0:
return
await self._try_command(
"Setting the sound volume of the miio device failed.",
self._device.set_volume,
volume,
)
async def async_set_extra_features(self, features: int = 1):
"""Set the extra features."""
if self._device_features & FEATURE_SET_EXTRA_FEATURES == 0:

View file

@ -12,14 +12,40 @@ from .const import (
CONF_FLOW_TYPE,
CONF_MODEL,
DOMAIN,
FEATURE_FLAGS_AIRFRESH,
FEATURE_FLAGS_AIRHUMIDIFIER_CA4,
FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
FEATURE_FLAGS_AIRPURIFIER_2S,
FEATURE_FLAGS_AIRPURIFIER_MIIO,
FEATURE_FLAGS_AIRPURIFIER_MIOT,
FEATURE_FLAGS_AIRPURIFIER_PRO,
FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
FEATURE_FLAGS_AIRPURIFIER_V1,
FEATURE_FLAGS_AIRPURIFIER_V3,
FEATURE_SET_FAN_LEVEL,
FEATURE_SET_FAVORITE_LEVEL,
FEATURE_SET_MOTOR_SPEED,
FEATURE_SET_VOLUME,
KEY_COORDINATOR,
KEY_DEVICE,
MODEL_AIRFRESH_VA2,
MODEL_AIRHUMIDIFIER_CA1,
MODEL_AIRHUMIDIFIER_CA4,
MODEL_AIRHUMIDIFIER_CB1,
MODEL_AIRPURIFIER_2S,
MODEL_AIRPURIFIER_PRO,
MODEL_AIRPURIFIER_PRO_V7,
MODEL_AIRPURIFIER_V1,
MODEL_AIRPURIFIER_V3,
MODELS_PURIFIER_MIIO,
MODELS_PURIFIER_MIOT,
)
from .device import XiaomiCoordinatedMiioEntity
ATTR_FAN_LEVEL = "fan_level"
ATTR_FAVORITE_LEVEL = "favorite_level"
ATTR_MOTOR_SPEED = "motor_speed"
ATTR_VOLUME = "volume"
@dataclass
@ -30,6 +56,7 @@ class XiaomiMiioNumberDescription(NumberEntityDescription):
max_value: float | None = None
step: float | None = None
available_with_device_off: bool = True
method: str | None = None
NUMBER_TYPES = {
@ -42,7 +69,47 @@ NUMBER_TYPES = {
max_value=2000,
step=10,
available_with_device_off=False,
method="async_set_motor_speed",
),
FEATURE_SET_FAVORITE_LEVEL: XiaomiMiioNumberDescription(
key=ATTR_FAVORITE_LEVEL,
name="Favorite Level",
icon="mdi:star-cog",
min_value=0,
max_value=17,
step=1,
method="async_set_favorite_level",
),
FEATURE_SET_FAN_LEVEL: XiaomiMiioNumberDescription(
key=ATTR_FAN_LEVEL,
name="Fan Level",
icon="mdi:fan",
min_value=1,
max_value=3,
step=1,
method="async_set_fan_level",
),
FEATURE_SET_VOLUME: XiaomiMiioNumberDescription(
key=ATTR_VOLUME,
name="Volume",
icon="mdi:volume-high",
min_value=1,
max_value=100,
step=1,
method="async_set_volume",
),
}
MODEL_TO_FEATURES_MAP = {
MODEL_AIRHUMIDIFIER_CA1: FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
MODEL_AIRHUMIDIFIER_CA4: FEATURE_FLAGS_AIRHUMIDIFIER_CA4,
MODEL_AIRHUMIDIFIER_CB1: FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
MODEL_AIRPURIFIER_2S: FEATURE_FLAGS_AIRPURIFIER_2S,
MODEL_AIRPURIFIER_PRO: FEATURE_FLAGS_AIRPURIFIER_PRO,
MODEL_AIRPURIFIER_PRO_V7: FEATURE_FLAGS_AIRPURIFIER_PRO_V7,
MODEL_AIRPURIFIER_V1: FEATURE_FLAGS_AIRPURIFIER_V1,
MODEL_AIRPURIFIER_V3: FEATURE_FLAGS_AIRPURIFIER_V3,
MODEL_AIRFRESH_VA2: FEATURE_FLAGS_AIRFRESH,
}
@ -54,25 +121,32 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
model = config_entry.data[CONF_MODEL]
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
if model != MODEL_AIRHUMIDIFIER_CA4:
if model in MODEL_TO_FEATURES_MAP:
features = MODEL_TO_FEATURES_MAP[model]
elif model in MODELS_PURIFIER_MIIO:
features = FEATURE_FLAGS_AIRPURIFIER_MIIO
elif model in MODELS_PURIFIER_MIOT:
features = FEATURE_FLAGS_AIRPURIFIER_MIOT
else:
return
description = NUMBER_TYPES[FEATURE_SET_MOTOR_SPEED]
entities.append(
XiaomiAirHumidifierNumber(
f"{config_entry.title} {description.name}",
device,
config_entry,
f"{description.key}_{config_entry.unique_id}",
hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
description,
)
)
for feature, description in NUMBER_TYPES.items():
if feature & features:
entities.append(
XiaomiNumberEntity(
f"{config_entry.title} {description.name}",
device,
config_entry,
f"{description.key}_{config_entry.unique_id}",
hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
description,
)
)
async_add_entities(entities)
class XiaomiAirHumidifierNumber(XiaomiCoordinatedMiioEntity, NumberEntity):
class XiaomiNumberEntity(XiaomiCoordinatedMiioEntity, NumberEntity):
"""Representation of a generic Xiaomi attribute selector."""
def __init__(self, name, device, entry, unique_id, coordinator, description):
@ -108,7 +182,8 @@ class XiaomiAirHumidifierNumber(XiaomiCoordinatedMiioEntity, NumberEntity):
async def async_set_value(self, value):
"""Set an option of the miio device."""
if await self.async_set_motor_speed(value):
method = getattr(self, self.entity_description.method)
if await method(value):
self._attr_value = value
self.async_write_ha_state()
@ -128,3 +203,27 @@ class XiaomiAirHumidifierNumber(XiaomiCoordinatedMiioEntity, NumberEntity):
self._device.set_speed,
motor_speed,
)
async def async_set_favorite_level(self, level: int = 1):
"""Set the favorite level."""
return await self._try_command(
"Setting the favorite level of the miio device failed.",
self._device.set_favorite_level,
level,
)
async def async_set_fan_level(self, level: int = 1):
"""Set the fan level."""
return await self._try_command(
"Setting the favorite level of the miio device failed.",
self._device.set_fan_level,
level,
)
async def async_set_volume(self, volume: int = 50):
"""Set the volume."""
return await self._try_command(
"Setting the volume of the miio device failed.",
self._device.set_volume,
volume,
)

View file

@ -1,58 +1,3 @@
fan_set_favorite_level:
name: Fan set favorite level
description: Set the favorite level.
fields:
entity_id:
description: Name of the xiaomi miio entity.
selector:
entity:
integration: xiaomi_miio
domain: fan
level:
name: Level
description: Level.
required: true
selector:
number:
min: 0
max: 17
fan_set_fan_level:
name: Fan set level
description: Set the fan level.
fields:
entity_id:
description: Name of the xiaomi miio entity.
selector:
entity:
integration: xiaomi_miio
domain: fan
level:
name: Level
description: Level.
selector:
number:
min: 1
max: 3
fan_set_volume:
name: Fan set volume
description: Set the sound volume.
fields:
entity_id:
description: Name of the xiaomi miio entity.
selector:
entity:
integration: xiaomi_miio
domain: fan
volume:
description: Volume.
required: true
selector:
number:
min: 0
max: 100
fan_reset_filter:
name: Fan reset filter
description: Reset the filter lifetime and usage.
@ -83,26 +28,6 @@ fan_set_extra_features:
min: 0
max: 1
fan_set_motor_speed:
name: Fan set motor speed
description: Set the target motor speed.
fields:
entity_id:
description: Name of the xiaomi miio entity.
selector:
entity:
integration: xiaomi_miio
domain: fan
motor_speed:
name: Motor speed
description: Set motor speed.
required: true
selector:
number:
min: 200
max: 2000
unit_of_measurement: 'RPM'
light_set_scene:
name: Light set scene
description: Set a fixed scene.