Add support for MJJSQ humidifiers for Xiaomi MIIO integration (#53807)
This commit is contained in:
parent
d4cb819e1f
commit
938ec27a86
6 changed files with 234 additions and 105 deletions
|
@ -3,7 +3,7 @@ from datetime import timedelta
|
|||
import logging
|
||||
|
||||
import async_timeout
|
||||
from miio import AirHumidifier, AirHumidifierMiot, DeviceException
|
||||
from miio import AirHumidifier, AirHumidifierMiot, AirHumidifierMjjsq, DeviceException
|
||||
from miio.gateway.gateway import GatewayException
|
||||
|
||||
from homeassistant import config_entries, core
|
||||
|
@ -25,6 +25,7 @@ from .const import (
|
|||
MODELS_FAN,
|
||||
MODELS_HUMIDIFIER,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
MODELS_LIGHT,
|
||||
MODELS_SWITCH,
|
||||
MODELS_VACUUM,
|
||||
|
@ -107,6 +108,8 @@ async def async_create_miio_device_and_coordinator(
|
|||
|
||||
if model in MODELS_HUMIDIFIER_MIOT:
|
||||
device = AirHumidifierMiot(host, token)
|
||||
elif model in MODELS_HUMIDIFIER_MJJSQ:
|
||||
device = AirHumidifierMjjsq(host, token, model=model)
|
||||
else:
|
||||
device = AirHumidifier(host, token, model=model)
|
||||
|
||||
|
@ -123,7 +126,9 @@ async def async_create_miio_device_and_coordinator(
|
|||
"""Fetch data from the device using async_add_executor_job."""
|
||||
try:
|
||||
async with async_timeout.timeout(10):
|
||||
return await hass.async_add_executor_job(device.status)
|
||||
state = await hass.async_add_executor_job(device.status)
|
||||
_LOGGER.debug("Got new state: %s", state)
|
||||
return state
|
||||
|
||||
except DeviceException as ex:
|
||||
raise UpdateFailed(ex) from ex
|
||||
|
|
|
@ -52,6 +52,9 @@ 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_AIRHUMIDIFIER_JSQ = "deerma.humidifier.jsq"
|
||||
MODEL_AIRHUMIDIFIER_JSQ1 = "deerma.humidifier.jsq1"
|
||||
MODEL_AIRHUMIDIFIER_MJJSQ = "deerma.humidifier.mjjsq"
|
||||
|
||||
MODEL_AIRFRESH_VA2 = "zhimi.airfresh.va2"
|
||||
|
||||
|
@ -60,7 +63,6 @@ MODELS_PURIFIER_MIOT = [
|
|||
MODEL_AIRPURIFIER_3H,
|
||||
MODEL_AIRPURIFIER_PROH,
|
||||
]
|
||||
MODELS_HUMIDIFIER_MIOT = [MODEL_AIRHUMIDIFIER_CA4]
|
||||
MODELS_FAN_MIIO = [
|
||||
MODEL_AIRPURIFIER_V1,
|
||||
MODEL_AIRPURIFIER_V2,
|
||||
|
@ -83,6 +85,12 @@ MODELS_HUMIDIFIER_MIIO = [
|
|||
MODEL_AIRHUMIDIFIER_CA1,
|
||||
MODEL_AIRHUMIDIFIER_CB1,
|
||||
]
|
||||
MODELS_HUMIDIFIER_MIOT = [MODEL_AIRHUMIDIFIER_CA4]
|
||||
MODELS_HUMIDIFIER_MJJSQ = [
|
||||
MODEL_AIRHUMIDIFIER_JSQ,
|
||||
MODEL_AIRHUMIDIFIER_JSQ1,
|
||||
MODEL_AIRHUMIDIFIER_MJJSQ,
|
||||
]
|
||||
|
||||
# AirQuality Models
|
||||
MODEL_AIRQUALITYMONITOR_V1 = "zhimi.airmonitor.v1"
|
||||
|
@ -117,7 +125,9 @@ MODELS_SWITCH = [
|
|||
"chuangmi.plug.hmi206",
|
||||
]
|
||||
MODELS_FAN = MODELS_FAN_MIIO + MODELS_PURIFIER_MIOT
|
||||
MODELS_HUMIDIFIER = MODELS_HUMIDIFIER_MIOT + MODELS_HUMIDIFIER_MIIO
|
||||
MODELS_HUMIDIFIER = (
|
||||
MODELS_HUMIDIFIER_MIOT + MODELS_HUMIDIFIER_MIIO + MODELS_HUMIDIFIER_MJJSQ
|
||||
)
|
||||
MODELS_LIGHT = (
|
||||
MODELS_LIGHT_EYECARE
|
||||
+ MODELS_LIGHT_CEILING
|
||||
|
@ -146,15 +156,12 @@ MODELS_ALL = MODELS_ALL_DEVICES + MODELS_GATEWAY
|
|||
# Fan/Humidifier Services
|
||||
SERVICE_SET_BUZZER_ON = "fan_set_buzzer_on"
|
||||
SERVICE_SET_BUZZER_OFF = "fan_set_buzzer_off"
|
||||
SERVICE_SET_BUZZER = "set_buzzer"
|
||||
SERVICE_SET_CLEAN = "set_clean"
|
||||
SERVICE_SET_FAN_LED_ON = "fan_set_led_on"
|
||||
SERVICE_SET_FAN_LED_OFF = "fan_set_led_off"
|
||||
SERVICE_SET_FAN_LED = "fan_set_led"
|
||||
SERVICE_SET_LED_BRIGHTNESS = "set_led_brightness"
|
||||
SERVICE_SET_CHILD_LOCK_ON = "fan_set_child_lock_on"
|
||||
SERVICE_SET_CHILD_LOCK_OFF = "fan_set_child_lock_off"
|
||||
SERVICE_SET_CHILD_LOCK = "set_child_lock"
|
||||
SERVICE_SET_LED_BRIGHTNESS = "fan_set_led_brightness"
|
||||
SERVICE_SET_FAVORITE_LEVEL = "fan_set_favorite_level"
|
||||
SERVICE_SET_FAN_LEVEL = "fan_set_fan_level"
|
||||
|
@ -270,6 +277,10 @@ FEATURE_FLAGS_AIRHUMIDIFIER = (
|
|||
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB = FEATURE_FLAGS_AIRHUMIDIFIER | FEATURE_SET_DRY
|
||||
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_MJSSQ = (
|
||||
FEATURE_SET_BUZZER | FEATURE_SET_LED | FEATURE_SET_TARGET_HUMIDITY
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA4 = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
|
|
|
@ -5,6 +5,7 @@ import math
|
|||
|
||||
from miio.airhumidifier import OperationMode as AirhumidifierOperationMode
|
||||
from miio.airhumidifier_miot import OperationMode as AirhumidifierMiotOperationMode
|
||||
from miio.airhumidifier_mjjsq import OperationMode as AirhumidifierMjjsqOperationMode
|
||||
|
||||
from homeassistant.components.humidifier import HumidifierEntity
|
||||
from homeassistant.components.humidifier.const import (
|
||||
|
@ -28,6 +29,7 @@ from .const import (
|
|||
MODEL_AIRHUMIDIFIER_CA4,
|
||||
MODEL_AIRHUMIDIFIER_CB1,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
)
|
||||
from .device import XiaomiCoordinatedMiioEntity
|
||||
|
||||
|
@ -41,6 +43,23 @@ AVAILABLE_ATTRIBUTES = {
|
|||
ATTR_TARGET_HUMIDITY: "target_humidity",
|
||||
}
|
||||
|
||||
AVAILABLE_MODES_CA1_CB1 = [
|
||||
mode.name
|
||||
for mode in AirhumidifierOperationMode
|
||||
if mode is not AirhumidifierOperationMode.Strong
|
||||
]
|
||||
AVAILABLE_MODES_CA4 = [mode.name for mode in AirhumidifierMiotOperationMode]
|
||||
AVAILABLE_MODES_MJJSQ = [
|
||||
mode.name
|
||||
for mode in AirhumidifierMjjsqOperationMode
|
||||
if mode is not AirhumidifierMjjsqOperationMode.WetAndProtect
|
||||
]
|
||||
AVAILABLE_MODES_OTHER = [
|
||||
mode.name
|
||||
for mode in AirhumidifierOperationMode
|
||||
if mode is not AirhumidifierOperationMode.Auto
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Set up the Humidifier from a config entry."""
|
||||
|
@ -62,6 +81,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
unique_id,
|
||||
coordinator,
|
||||
)
|
||||
elif model in MODELS_HUMIDIFIER_MJJSQ:
|
||||
air_humidifier = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||
entity = XiaomiAirHumidifierMjjsq(
|
||||
name,
|
||||
air_humidifier,
|
||||
config_entry,
|
||||
unique_id,
|
||||
coordinator,
|
||||
)
|
||||
else:
|
||||
air_humidifier = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||
entity = XiaomiAirHumidifier(
|
||||
|
@ -169,28 +197,22 @@ class XiaomiAirHumidifier(XiaomiGenericHumidifier, HumidifierEntity):
|
|||
"""Initialize the plug switch."""
|
||||
super().__init__(name, device, entry, unique_id, coordinator)
|
||||
if self._model in [MODEL_AIRHUMIDIFIER_CA1, MODEL_AIRHUMIDIFIER_CB1]:
|
||||
self._available_modes = []
|
||||
self._available_modes = [
|
||||
mode.name
|
||||
for mode in AirhumidifierOperationMode
|
||||
if mode is not AirhumidifierOperationMode.Strong
|
||||
]
|
||||
self._available_modes = AVAILABLE_MODES_CA1_CB1
|
||||
self._min_humidity = 30
|
||||
self._max_humidity = 80
|
||||
self._humidity_steps = 10
|
||||
elif self._model in [MODEL_AIRHUMIDIFIER_CA4]:
|
||||
self._available_modes = [
|
||||
mode.name for mode in AirhumidifierMiotOperationMode
|
||||
]
|
||||
self._available_modes = AVAILABLE_MODES_CA4
|
||||
self._min_humidity = 30
|
||||
self._max_humidity = 80
|
||||
self._humidity_steps = 100
|
||||
elif self._model in MODELS_HUMIDIFIER_MJJSQ:
|
||||
self._available_modes = AVAILABLE_MODES_MJJSQ
|
||||
self._min_humidity = 30
|
||||
self._max_humidity = 80
|
||||
self._humidity_steps = 10
|
||||
else:
|
||||
self._available_modes = [
|
||||
mode.name
|
||||
for mode in AirhumidifierOperationMode
|
||||
if mode is not AirhumidifierOperationMode.Auto
|
||||
]
|
||||
self._available_modes = AVAILABLE_MODES_OTHER
|
||||
self._min_humidity = 30
|
||||
self._max_humidity = 80
|
||||
self._humidity_steps = 10
|
||||
|
@ -364,3 +386,75 @@ class XiaomiAirHumidifierMiot(XiaomiAirHumidifier):
|
|||
):
|
||||
self._mode = self.REVERSE_MODE_MAPPING[mode].value
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class XiaomiAirHumidifierMjjsq(XiaomiAirHumidifier):
|
||||
"""Representation of a Xiaomi Air MJJSQ Humidifier."""
|
||||
|
||||
MODE_MAPPING = {
|
||||
"Low": AirhumidifierMjjsqOperationMode.Low,
|
||||
"Medium": AirhumidifierMjjsqOperationMode.Medium,
|
||||
"High": AirhumidifierMjjsqOperationMode.High,
|
||||
"Humidity": AirhumidifierMjjsqOperationMode.Humidity,
|
||||
}
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
"""Return the current mode."""
|
||||
return AirhumidifierMjjsqOperationMode(self._mode).name
|
||||
|
||||
@property
|
||||
def target_humidity(self):
|
||||
"""Return the target humidity."""
|
||||
if self._state:
|
||||
if (
|
||||
AirhumidifierMjjsqOperationMode(self._mode)
|
||||
== AirhumidifierMjjsqOperationMode.Humidity
|
||||
):
|
||||
return self._target_humidity
|
||||
return None
|
||||
|
||||
async def async_set_humidity(self, humidity: int) -> None:
|
||||
"""Set the target humidity of the humidifier and set the mode to Humidity."""
|
||||
target_humidity = self.translate_humidity(humidity)
|
||||
if not target_humidity:
|
||||
return
|
||||
|
||||
_LOGGER.debug("Setting the humidity to: %s", target_humidity)
|
||||
if await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_target_humidity,
|
||||
target_humidity,
|
||||
):
|
||||
self._target_humidity = target_humidity
|
||||
if (
|
||||
self.supported_features & SUPPORT_MODES == 0
|
||||
or AirhumidifierMjjsqOperationMode(self._attributes[ATTR_MODE])
|
||||
== AirhumidifierMjjsqOperationMode.Humidity
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
return
|
||||
_LOGGER.debug("Setting the operation mode to: Humidity")
|
||||
if await self._try_command(
|
||||
"Setting operation mode of the miio device to MODE_HUMIDITY failed.",
|
||||
self._device.set_mode,
|
||||
AirhumidifierMjjsqOperationMode.Humidity,
|
||||
):
|
||||
self._mode = 3
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_mode(self, mode: str) -> None:
|
||||
"""Set the mode of the fan."""
|
||||
if mode not in self.MODE_MAPPING:
|
||||
_LOGGER.warning("Mode %s is not a valid operation mode", mode)
|
||||
return
|
||||
|
||||
_LOGGER.debug("Setting the operation mode to: %s", mode)
|
||||
if self._state:
|
||||
if await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_mode,
|
||||
self.MODE_MAPPING[mode],
|
||||
):
|
||||
self._mode = self.MODE_MAPPING[mode].value
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -16,10 +16,8 @@ from .const import (
|
|||
FEATURE_SET_LED_BRIGHTNESS,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRHUMIDIFIER_CA1,
|
||||
MODEL_AIRHUMIDIFIER_CA4,
|
||||
MODEL_AIRHUMIDIFIER_CB1,
|
||||
MODELS_HUMIDIFIER,
|
||||
MODELS_HUMIDIFIER_MIIO,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
SERVICE_SET_LED_BRIGHTNESS,
|
||||
)
|
||||
from .device import XiaomiCoordinatedMiioEntity
|
||||
|
@ -65,18 +63,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
entities = []
|
||||
model = config_entry.data[CONF_MODEL]
|
||||
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
|
||||
|
||||
if model in [MODEL_AIRHUMIDIFIER_CA1, MODEL_AIRHUMIDIFIER_CB1]:
|
||||
if model in MODELS_HUMIDIFIER_MIIO:
|
||||
entity_class = XiaomiAirHumidifierSelector
|
||||
elif model in [MODEL_AIRHUMIDIFIER_CA4]:
|
||||
elif model in MODELS_HUMIDIFIER_MIOT:
|
||||
entity_class = XiaomiAirHumidifierMiotSelector
|
||||
elif model in MODELS_HUMIDIFIER:
|
||||
entity_class = XiaomiAirHumidifierSelector
|
||||
else:
|
||||
return
|
||||
|
||||
for selector in SELECTOR_TYPES.values():
|
||||
selector = SELECTOR_TYPES[FEATURE_SET_LED_BRIGHTNESS]
|
||||
entities.append(
|
||||
entity_class(
|
||||
f"{config_entry.title} {selector.name}",
|
||||
|
@ -84,7 +79,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
config_entry,
|
||||
f"{selector.short_name}_{config_entry.unique_id}",
|
||||
selector,
|
||||
coordinator,
|
||||
hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ from .const import (
|
|||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
)
|
||||
from .device import XiaomiCoordinatedMiioEntity, XiaomiMiioEntity
|
||||
from .gateway import XiaomiGatewayDevice
|
||||
|
@ -135,6 +136,11 @@ HUMIDIFIER_SENSORS_MIOT = {
|
|||
ATTR_ACTUAL_MOTOR_SPEED: "actual_speed",
|
||||
}
|
||||
|
||||
HUMIDIFIER_SENSORS_MJJSQ = {
|
||||
ATTR_HUMIDITY: "humidity",
|
||||
ATTR_TEMPERATURE: "temperature",
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Import Miio configuration from YAML."""
|
||||
|
@ -191,11 +197,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
sensors = []
|
||||
if model in MODELS_HUMIDIFIER_MIOT:
|
||||
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
|
||||
sensors = HUMIDIFIER_SENSORS_MIOT
|
||||
elif model in MODELS_HUMIDIFIER_MJJSQ:
|
||||
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||
sensors = HUMIDIFIER_SENSORS_MJJSQ
|
||||
elif model.startswith("zhimi.humidifier."):
|
||||
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
|
||||
sensors = HUMIDIFIER_SENSORS
|
||||
else:
|
||||
unique_id = config_entry.unique_id
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
"""Support for Xiaomi Smart WiFi Socket and Smart Power Strip."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
|
@ -13,6 +15,7 @@ from homeassistant.components.switch import (
|
|||
DEVICE_CLASS_SWITCH,
|
||||
PLATFORM_SCHEMA,
|
||||
SwitchEntity,
|
||||
SwitchEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_IMPORT
|
||||
from homeassistant.const import (
|
||||
|
@ -35,20 +38,19 @@ from .const import (
|
|||
FEATURE_FLAGS_AIRHUMIDIFIER,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA4,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_MJSSQ,
|
||||
FEATURE_SET_BUZZER,
|
||||
FEATURE_SET_CHILD_LOCK,
|
||||
FEATURE_SET_CLEAN,
|
||||
FEATURE_SET_DRY,
|
||||
FEATURE_SET_LED,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRHUMIDIFIER_CA1,
|
||||
MODEL_AIRHUMIDIFIER_CA4,
|
||||
MODEL_AIRHUMIDIFIER_CB1,
|
||||
MODELS_HUMIDIFIER,
|
||||
SERVICE_SET_BUZZER,
|
||||
SERVICE_SET_CHILD_LOCK,
|
||||
SERVICE_SET_CLEAN,
|
||||
SERVICE_SET_DRY,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
SERVICE_SET_POWER_MODE,
|
||||
SERVICE_SET_POWER_PRICE,
|
||||
SERVICE_SET_WIFI_LED_OFF,
|
||||
|
@ -96,17 +98,18 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||
}
|
||||
)
|
||||
|
||||
ATTR_POWER = "power"
|
||||
ATTR_LOAD_POWER = "load_power"
|
||||
ATTR_MODEL = "model"
|
||||
ATTR_POWER_MODE = "power_mode"
|
||||
ATTR_WIFI_LED = "wifi_led"
|
||||
ATTR_POWER_PRICE = "power_price"
|
||||
ATTR_PRICE = "price"
|
||||
ATTR_BUZZER = "buzzer"
|
||||
ATTR_CHILD_LOCK = "child_lock"
|
||||
ATTR_DRY = "dry"
|
||||
ATTR_CLEAN = "clean_mode"
|
||||
ATTR_DRY = "dry"
|
||||
ATTR_LED = "led"
|
||||
ATTR_LOAD_POWER = "load_power"
|
||||
ATTR_MODEL = "model"
|
||||
ATTR_POWER = "power"
|
||||
ATTR_POWER_MODE = "power_mode"
|
||||
ATTR_POWER_PRICE = "power_price"
|
||||
ATTR_PRICE = "price"
|
||||
ATTR_WIFI_LED = "wifi_led"
|
||||
|
||||
FEATURE_SET_POWER_MODE = 1
|
||||
FEATURE_SET_WIFI_LED = 2
|
||||
|
@ -143,63 +146,62 @@ SERVICE_TO_METHOD = {
|
|||
"method": "async_set_power_price",
|
||||
"schema": SERVICE_SCHEMA_POWER_PRICE,
|
||||
},
|
||||
SERVICE_SET_BUZZER: {
|
||||
"method_on": "async_set_buzzer_on",
|
||||
"method_off": "async_set_buzzer_off",
|
||||
},
|
||||
SERVICE_SET_CHILD_LOCK: {
|
||||
"method_on": "async_set_child_lock_on",
|
||||
"method_off": "async_set_child_lock_off",
|
||||
},
|
||||
SERVICE_SET_DRY: {
|
||||
"method_on": "async_set_dry_on",
|
||||
"method_off": "async_set_dry_off",
|
||||
},
|
||||
SERVICE_SET_CLEAN: {
|
||||
"method_on": "async_set_clean_on",
|
||||
"method_off": "async_set_clean_off",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class SwitchType:
|
||||
"""Class that holds device specific info for a xiaomi aqara or humidifiers."""
|
||||
class XiaomiMiioSwitchDescription(SwitchEntityDescription):
|
||||
"""A class that describes switch entities."""
|
||||
|
||||
name: str = None
|
||||
short_name: str = None
|
||||
icon: str = None
|
||||
service: str = None
|
||||
feature: int | None = None
|
||||
method_on: str | None = None
|
||||
method_off: str | None = None
|
||||
available_with_device_off: bool = True
|
||||
|
||||
|
||||
SWITCH_TYPES = {
|
||||
FEATURE_SET_BUZZER: SwitchType(
|
||||
SWITCH_TYPES = (
|
||||
XiaomiMiioSwitchDescription(
|
||||
key=ATTR_BUZZER,
|
||||
feature=FEATURE_SET_BUZZER,
|
||||
name="Buzzer",
|
||||
icon="mdi:volume-high",
|
||||
short_name=ATTR_BUZZER,
|
||||
service=SERVICE_SET_BUZZER,
|
||||
method_on="async_set_buzzer_on",
|
||||
method_off="async_set_buzzer_off",
|
||||
),
|
||||
FEATURE_SET_CHILD_LOCK: SwitchType(
|
||||
XiaomiMiioSwitchDescription(
|
||||
key=ATTR_CHILD_LOCK,
|
||||
feature=FEATURE_SET_CHILD_LOCK,
|
||||
name="Child Lock",
|
||||
icon="mdi:lock",
|
||||
short_name=ATTR_CHILD_LOCK,
|
||||
service=SERVICE_SET_CHILD_LOCK,
|
||||
method_on="async_set_child_lock_on",
|
||||
method_off="async_set_child_lock_off",
|
||||
),
|
||||
FEATURE_SET_DRY: SwitchType(
|
||||
XiaomiMiioSwitchDescription(
|
||||
key=ATTR_DRY,
|
||||
feature=FEATURE_SET_DRY,
|
||||
name="Dry Mode",
|
||||
icon="mdi:hair-dryer",
|
||||
short_name=ATTR_DRY,
|
||||
service=SERVICE_SET_DRY,
|
||||
method_on="async_set_dry_on",
|
||||
method_off="async_set_dry_off",
|
||||
),
|
||||
FEATURE_SET_CLEAN: SwitchType(
|
||||
XiaomiMiioSwitchDescription(
|
||||
key=ATTR_CLEAN,
|
||||
feature=FEATURE_SET_CLEAN,
|
||||
name="Clean Mode",
|
||||
icon="mdi:sparkles",
|
||||
short_name=ATTR_CLEAN,
|
||||
service=SERVICE_SET_CLEAN,
|
||||
method_on="async_set_clean_on",
|
||||
method_off="async_set_clean_off",
|
||||
available_with_device_off=False,
|
||||
),
|
||||
}
|
||||
XiaomiMiioSwitchDescription(
|
||||
key=ATTR_LED,
|
||||
feature=FEATURE_SET_LED,
|
||||
name="Led",
|
||||
icon="mdi:led-outline",
|
||||
method_on="async_set_led_on",
|
||||
method_off="async_set_led_off",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
|
@ -241,19 +243,21 @@ async def async_setup_coordinated_entry(hass, config_entry, async_add_entities):
|
|||
device_features = FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB
|
||||
elif model in [MODEL_AIRHUMIDIFIER_CA4]:
|
||||
device_features = FEATURE_FLAGS_AIRHUMIDIFIER_CA4
|
||||
elif model in MODELS_HUMIDIFIER_MJJSQ:
|
||||
device_features = FEATURE_FLAGS_AIRHUMIDIFIER_MJSSQ
|
||||
elif model in MODELS_HUMIDIFIER:
|
||||
device_features = FEATURE_FLAGS_AIRHUMIDIFIER
|
||||
|
||||
for feature, switch in SWITCH_TYPES.items():
|
||||
if feature & device_features:
|
||||
for description in SWITCH_TYPES:
|
||||
if description.feature & device_features:
|
||||
entities.append(
|
||||
XiaomiGenericCoordinatedSwitch(
|
||||
f"{config_entry.title} {switch.name}",
|
||||
f"{config_entry.title} {description.name}",
|
||||
device,
|
||||
config_entry,
|
||||
f"{switch.short_name}_{unique_id}",
|
||||
switch,
|
||||
f"{description.key}_{unique_id}",
|
||||
coordinator,
|
||||
description,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -382,22 +386,21 @@ async def async_setup_other_entry(hass, config_entry, async_add_entities):
|
|||
class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
|
||||
"""Representation of a Xiaomi Plug Generic."""
|
||||
|
||||
def __init__(self, name, device, entry, unique_id, switch, coordinator):
|
||||
def __init__(self, name, device, entry, unique_id, coordinator, description):
|
||||
"""Initialize the plug switch."""
|
||||
super().__init__(name, device, entry, unique_id, coordinator)
|
||||
|
||||
self._attr_icon = switch.icon
|
||||
self._controller = switch
|
||||
self._attr_is_on = self._extract_value_from_attribute(
|
||||
self.coordinator.data, self._controller.short_name
|
||||
self.coordinator.data, description.key
|
||||
)
|
||||
self.entity_description = description
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self):
|
||||
"""Fetch state from the device."""
|
||||
# On state change the device doesn't provide the new state immediately.
|
||||
self._attr_is_on = self._extract_value_from_attribute(
|
||||
self.coordinator.data, self._controller.short_name
|
||||
self.coordinator.data, self.entity_description.key
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
@ -407,7 +410,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
|
|||
if (
|
||||
super().available
|
||||
and not self.coordinator.data.is_on
|
||||
and not self._controller.available_with_device_off
|
||||
and not self.entity_description.available_with_device_off
|
||||
):
|
||||
return False
|
||||
return super().available
|
||||
|
@ -422,7 +425,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
|
|||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Turn on an option of the miio device."""
|
||||
method = getattr(self, SERVICE_TO_METHOD[self._controller.service]["method_on"])
|
||||
method = getattr(self, self.entity_description.method_on)
|
||||
if await method():
|
||||
# Write state back to avoid switch flips with a slow response
|
||||
self._attr_is_on = True
|
||||
|
@ -430,9 +433,7 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
|
|||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn off an option of the miio device."""
|
||||
method = getattr(
|
||||
self, SERVICE_TO_METHOD[self._controller.service]["method_off"]
|
||||
)
|
||||
method = getattr(self, self.entity_description.method_off)
|
||||
if await method():
|
||||
# Write state back to avoid switch flips with a slow response
|
||||
self._attr_is_on = False
|
||||
|
@ -502,6 +503,22 @@ class XiaomiGenericCoordinatedSwitch(XiaomiCoordinatedMiioEntity, SwitchEntity):
|
|||
False,
|
||||
)
|
||||
|
||||
async def async_set_led_on(self) -> bool:
|
||||
"""Turn the led on."""
|
||||
return await self._try_command(
|
||||
"Turning the led of the miio device on failed.",
|
||||
self._device.set_led,
|
||||
True,
|
||||
)
|
||||
|
||||
async def async_set_led_off(self) -> bool:
|
||||
"""Turn the led off."""
|
||||
return await self._try_command(
|
||||
"Turning the led of the miio device off failed.",
|
||||
self._device.set_led,
|
||||
False,
|
||||
)
|
||||
|
||||
|
||||
class XiaomiGatewaySwitch(XiaomiGatewayDevice, SwitchEntity):
|
||||
"""Representation of a XiaomiGatewaySwitch."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue