Initial xiaomi_miio support for dmaker.airfresh.a1/t2017 (#66331)
* Initial support for dmaker.airfresh.a1/t2017 * fix typo
This commit is contained in:
parent
cc0fb5d9db
commit
2ffb46dc93
6 changed files with 137 additions and 2 deletions
|
@ -8,6 +8,8 @@ import logging
|
|||
import async_timeout
|
||||
from miio import (
|
||||
AirFresh,
|
||||
AirFreshA1,
|
||||
AirFreshT2017,
|
||||
AirHumidifier,
|
||||
AirHumidifierMiot,
|
||||
AirHumidifierMjjsq,
|
||||
|
@ -48,6 +50,8 @@ from .const import (
|
|||
DOMAIN,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_T2017,
|
||||
MODEL_AIRPURIFIER_3C,
|
||||
MODEL_FAN_1C,
|
||||
MODEL_FAN_P5,
|
||||
|
@ -310,7 +314,7 @@ async def async_create_miio_device_and_coordinator(
|
|||
device = AirHumidifier(host, token, model=model)
|
||||
migrate = True
|
||||
# Airpurifiers and Airfresh
|
||||
elif model in MODEL_AIRPURIFIER_3C:
|
||||
elif model == MODEL_AIRPURIFIER_3C:
|
||||
device = AirPurifierMB4(host, token)
|
||||
elif model in MODELS_PURIFIER_MIOT:
|
||||
device = AirPurifierMiot(host, token)
|
||||
|
@ -318,6 +322,10 @@ async def async_create_miio_device_and_coordinator(
|
|||
device = AirPurifier(host, token)
|
||||
elif model.startswith("zhimi.airfresh."):
|
||||
device = AirFresh(host, token)
|
||||
elif model == MODEL_AIRFRESH_A1:
|
||||
device = AirFreshA1(host, token)
|
||||
elif model == MODEL_AIRFRESH_T2017:
|
||||
device = AirFreshT2017(host, token)
|
||||
elif (
|
||||
model in MODELS_VACUUM
|
||||
or model.startswith(ROBOROCK_GENERIC)
|
||||
|
|
|
@ -75,7 +75,9 @@ MODEL_AIRHUMIDIFIER_JSQ = "deerma.humidifier.jsq"
|
|||
MODEL_AIRHUMIDIFIER_JSQ1 = "deerma.humidifier.jsq1"
|
||||
MODEL_AIRHUMIDIFIER_MJJSQ = "deerma.humidifier.mjjsq"
|
||||
|
||||
MODEL_AIRFRESH_A1 = "dmaker.airfresh.a1"
|
||||
MODEL_AIRFRESH_VA2 = "zhimi.airfresh.va2"
|
||||
MODEL_AIRFRESH_T2017 = "dmaker.airfresh.t2017"
|
||||
|
||||
MODEL_FAN_1C = "dmaker.fan.1c"
|
||||
MODEL_FAN_P10 = "dmaker.fan.p10"
|
||||
|
@ -129,7 +131,9 @@ MODELS_PURIFIER_MIIO = [
|
|||
MODEL_AIRPURIFIER_SA2,
|
||||
MODEL_AIRPURIFIER_2S,
|
||||
MODEL_AIRPURIFIER_2H,
|
||||
MODEL_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_VA2,
|
||||
MODEL_AIRFRESH_T2017,
|
||||
]
|
||||
MODELS_HUMIDIFIER_MIIO = [
|
||||
MODEL_AIRHUMIDIFIER_V1,
|
||||
|
@ -383,6 +387,8 @@ FEATURE_FLAGS_AIRHUMIDIFIER_CA4 = (
|
|||
| FEATURE_SET_CLEAN
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_AIRFRESH_A1 = FEATURE_SET_BUZZER | FEATURE_SET_CHILD_LOCK
|
||||
|
||||
FEATURE_FLAGS_AIRFRESH = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
|
@ -392,6 +398,8 @@ FEATURE_FLAGS_AIRFRESH = (
|
|||
| FEATURE_SET_EXTRA_FEATURES
|
||||
)
|
||||
|
||||
FEATURE_FLAGS_AIRFRESH_T2017 = FEATURE_SET_BUZZER | FEATURE_SET_CHILD_LOCK
|
||||
|
||||
FEATURE_FLAGS_FAN_P5 = (
|
||||
FEATURE_SET_BUZZER
|
||||
| FEATURE_SET_CHILD_LOCK
|
||||
|
|
|
@ -5,6 +5,7 @@ import logging
|
|||
import math
|
||||
|
||||
from miio.airfresh import OperationMode as AirfreshOperationMode
|
||||
from miio.airfresh_t2017 import OperationMode as AirfreshOperationModeT2017
|
||||
from miio.airpurifier import OperationMode as AirpurifierOperationMode
|
||||
from miio.airpurifier_miot import OperationMode as AirpurifierMiotOperationMode
|
||||
from miio.fan import (
|
||||
|
@ -39,6 +40,8 @@ from .const import (
|
|||
CONF_FLOW_TYPE,
|
||||
DOMAIN,
|
||||
FEATURE_FLAGS_AIRFRESH,
|
||||
FEATURE_FLAGS_AIRFRESH_A1,
|
||||
FEATURE_FLAGS_AIRFRESH_T2017,
|
||||
FEATURE_FLAGS_AIRPURIFIER_2S,
|
||||
FEATURE_FLAGS_AIRPURIFIER_3C,
|
||||
FEATURE_FLAGS_AIRPURIFIER_MIIO,
|
||||
|
@ -56,6 +59,8 @@ from .const import (
|
|||
FEATURE_SET_EXTRA_FEATURES,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_T2017,
|
||||
MODEL_AIRPURIFIER_2H,
|
||||
MODEL_AIRPURIFIER_2S,
|
||||
MODEL_AIRPURIFIER_3C,
|
||||
|
@ -97,6 +102,9 @@ ATTR_SLEEP_MODE = "sleep_mode"
|
|||
ATTR_USE_TIME = "use_time"
|
||||
ATTR_BUTTON_PRESSED = "button_pressed"
|
||||
|
||||
# Air Fresh A1
|
||||
ATTR_FAVORITE_SPEED = "favorite_speed"
|
||||
|
||||
# Map attributes to properties of the state object
|
||||
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
|
||||
ATTR_EXTRA_FEATURES: "extra_features",
|
||||
|
@ -153,6 +161,7 @@ PRESET_MODES_AIRPURIFIER_V3 = [
|
|||
"Strong",
|
||||
]
|
||||
PRESET_MODES_AIRFRESH = ["Auto", "Interval"]
|
||||
PRESET_MODES_AIRFRESH_A1 = ["Auto", "Sleep", "Favorite"]
|
||||
|
||||
AIRPURIFIER_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids})
|
||||
|
||||
|
@ -213,6 +222,10 @@ async def async_setup_entry(
|
|||
entity = XiaomiAirPurifier(name, device, config_entry, unique_id, coordinator)
|
||||
elif model.startswith("zhimi.airfresh."):
|
||||
entity = XiaomiAirFresh(name, device, config_entry, unique_id, coordinator)
|
||||
elif model == MODEL_AIRFRESH_A1:
|
||||
entity = XiaomiAirFreshA1(name, device, config_entry, unique_id, coordinator)
|
||||
elif model == MODEL_AIRFRESH_T2017:
|
||||
entity = XiaomiAirFreshT2017(name, device, config_entry, unique_id, coordinator)
|
||||
elif model == MODEL_FAN_P5:
|
||||
entity = XiaomiFanP5(name, device, config_entry, unique_id, coordinator)
|
||||
elif model in MODELS_FAN_MIIO:
|
||||
|
@ -709,6 +722,89 @@ class XiaomiAirFresh(XiaomiGenericAirPurifier):
|
|||
)
|
||||
|
||||
|
||||
class XiaomiAirFreshA1(XiaomiGenericAirPurifier):
|
||||
"""Representation of a Xiaomi Air Fresh A1."""
|
||||
|
||||
def __init__(self, name, device, entry, unique_id, coordinator):
|
||||
"""Initialize the miio device."""
|
||||
super().__init__(name, device, entry, unique_id, coordinator)
|
||||
self._favorite_speed = None
|
||||
self._device_features = FEATURE_FLAGS_AIRFRESH_A1
|
||||
self._preset_modes = PRESET_MODES_AIRFRESH_A1
|
||||
self._supported_features = SUPPORT_SET_SPEED | SUPPORT_PRESET_MODE
|
||||
|
||||
self._state = self.coordinator.data.is_on
|
||||
self._mode = self.coordinator.data.mode.value
|
||||
self._speed_range = (60, 150)
|
||||
|
||||
@property
|
||||
def operation_mode_class(self):
|
||||
"""Hold operation mode class."""
|
||||
return AirfreshOperationModeT2017
|
||||
|
||||
@property
|
||||
def percentage(self):
|
||||
"""Return the current percentage based speed."""
|
||||
if self._favorite_speed is None:
|
||||
return None
|
||||
if self._state:
|
||||
return ranged_value_to_percentage(self._speed_range, self._favorite_speed)
|
||||
|
||||
return None
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the percentage of the fan. This method is a coroutine."""
|
||||
if percentage == 0:
|
||||
await self.async_turn_off()
|
||||
return
|
||||
|
||||
await self.async_set_preset_mode("Favorite")
|
||||
|
||||
favorite_speed = math.ceil(
|
||||
percentage_to_ranged_value(self._speed_range, percentage)
|
||||
)
|
||||
if not favorite_speed:
|
||||
return
|
||||
if await self._try_command(
|
||||
"Setting fan level of the miio device failed.",
|
||||
self._device.set_favorite_speed,
|
||||
favorite_speed,
|
||||
):
|
||||
self._favorite_speed = favorite_speed
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode of the fan. This method is a coroutine."""
|
||||
if preset_mode not in self.preset_modes:
|
||||
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
|
||||
return
|
||||
if await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_mode,
|
||||
self.operation_mode_class[preset_mode],
|
||||
):
|
||||
self._mode = self.operation_mode_class[preset_mode].value
|
||||
self.async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self):
|
||||
"""Fetch state from the device."""
|
||||
self._state = self.coordinator.data.is_on
|
||||
self._mode = self.coordinator.data.mode.value
|
||||
self._favorite_speed = getattr(self.coordinator.data, ATTR_FAVORITE_SPEED, None)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class XiaomiAirFreshT2017(XiaomiAirFreshA1):
|
||||
"""Representation of a Xiaomi Air Fresh T2017."""
|
||||
|
||||
def __init__(self, name, device, entry, unique_id, coordinator):
|
||||
"""Initialize the miio device."""
|
||||
super().__init__(name, device, entry, unique_id, coordinator)
|
||||
self._device_features = FEATURE_FLAGS_AIRFRESH_T2017
|
||||
self._speed_range = (60, 300)
|
||||
|
||||
|
||||
class XiaomiGenericFan(XiaomiGenericDevice):
|
||||
"""Representation of a generic Xiaomi Fan."""
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ from .const import (
|
|||
CONF_MODEL,
|
||||
DOMAIN,
|
||||
FEATURE_FLAGS_AIRFRESH,
|
||||
FEATURE_FLAGS_AIRFRESH_A1,
|
||||
FEATURE_FLAGS_AIRFRESH_T2017,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA4,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
|
||||
FEATURE_FLAGS_AIRPURIFIER_2S,
|
||||
|
@ -45,6 +47,8 @@ from .const import (
|
|||
FEATURE_SET_VOLUME,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_T2017,
|
||||
MODEL_AIRFRESH_VA2,
|
||||
MODEL_AIRHUMIDIFIER_CA1,
|
||||
MODEL_AIRHUMIDIFIER_CA4,
|
||||
|
@ -199,7 +203,9 @@ NUMBER_TYPES = {
|
|||
}
|
||||
|
||||
MODEL_TO_FEATURES_MAP = {
|
||||
MODEL_AIRFRESH_A1: FEATURE_FLAGS_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_VA2: FEATURE_FLAGS_AIRFRESH,
|
||||
MODEL_AIRFRESH_T2017: FEATURE_FLAGS_AIRFRESH_T2017,
|
||||
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,
|
||||
|
|
|
@ -52,6 +52,8 @@ from .const import (
|
|||
DOMAIN,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_T2017,
|
||||
MODEL_AIRFRESH_VA2,
|
||||
MODEL_AIRHUMIDIFIER_CA1,
|
||||
MODEL_AIRHUMIDIFIER_CB1,
|
||||
|
@ -375,6 +377,14 @@ AIRFRESH_SENSORS = (
|
|||
ATTR_TEMPERATURE,
|
||||
ATTR_USE_TIME,
|
||||
)
|
||||
AIRFRESH_SENSORS_A1 = (
|
||||
ATTR_CARBON_DIOXIDE,
|
||||
ATTR_TEMPERATURE,
|
||||
)
|
||||
AIRFRESH_SENSORS_T2017 = (
|
||||
ATTR_CARBON_DIOXIDE,
|
||||
ATTR_TEMPERATURE,
|
||||
)
|
||||
FAN_V2_V3_SENSORS = (
|
||||
ATTR_BATTERY,
|
||||
ATTR_HUMIDITY,
|
||||
|
@ -384,7 +394,9 @@ FAN_V2_V3_SENSORS = (
|
|||
FAN_ZA5_SENSORS = (ATTR_HUMIDITY, ATTR_TEMPERATURE)
|
||||
|
||||
MODEL_TO_SENSORS_MAP = {
|
||||
MODEL_AIRFRESH_A1: AIRFRESH_SENSORS_A1,
|
||||
MODEL_AIRFRESH_VA2: AIRFRESH_SENSORS,
|
||||
MODEL_AIRFRESH_T2017: AIRFRESH_SENSORS_T2017,
|
||||
MODEL_AIRHUMIDIFIER_CA1: HUMIDIFIER_CA1_CB1_SENSORS,
|
||||
MODEL_AIRHUMIDIFIER_CB1: HUMIDIFIER_CA1_CB1_SENSORS,
|
||||
MODEL_AIRPURIFIER_3C: PURIFIER_3C_SENSORS,
|
||||
|
@ -808,7 +820,6 @@ class XiaomiGatewayIlluminanceSensor(SensorEntity):
|
|||
|
||||
def __init__(self, gateway_device, gateway_name, gateway_device_id, description):
|
||||
"""Initialize the entity."""
|
||||
|
||||
self._attr_name = f"{gateway_name} {description.name}"
|
||||
self._attr_unique_id = f"{gateway_device_id}-{description.key}"
|
||||
self._attr_device_info = {"identifiers": {(DOMAIN, gateway_device_id)}}
|
||||
|
|
|
@ -35,6 +35,8 @@ from .const import (
|
|||
CONF_MODEL,
|
||||
DOMAIN,
|
||||
FEATURE_FLAGS_AIRFRESH,
|
||||
FEATURE_FLAGS_AIRFRESH_A1,
|
||||
FEATURE_FLAGS_AIRFRESH_T2017,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA4,
|
||||
FEATURE_FLAGS_AIRHUMIDIFIER_CA_AND_CB,
|
||||
|
@ -63,6 +65,8 @@ from .const import (
|
|||
FEATURE_SET_LED,
|
||||
KEY_COORDINATOR,
|
||||
KEY_DEVICE,
|
||||
MODEL_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_T2017,
|
||||
MODEL_AIRFRESH_VA2,
|
||||
MODEL_AIRHUMIDIFIER_CA1,
|
||||
MODEL_AIRHUMIDIFIER_CA4,
|
||||
|
@ -167,7 +171,9 @@ SERVICE_TO_METHOD = {
|
|||
}
|
||||
|
||||
MODEL_TO_FEATURES_MAP = {
|
||||
MODEL_AIRFRESH_A1: FEATURE_FLAGS_AIRFRESH_A1,
|
||||
MODEL_AIRFRESH_VA2: FEATURE_FLAGS_AIRFRESH,
|
||||
MODEL_AIRFRESH_T2017: FEATURE_FLAGS_AIRFRESH_T2017,
|
||||
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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue