Xiaomi miio add coordinator to fan platform (#54366)

* init coordinator for airpurifiers and airfresh

* Update fan entities with coordinator

* cache mode and fan_level at user update

* pylint define attributes in _init

* Update homeassistant/components/xiaomi_miio/fan.py

Co-authored-by: Maciej Bieniek <bieniu@users.noreply.github.com>

* Update homeassistant/components/xiaomi_miio/fan.py

Co-authored-by: Maciej Bieniek <bieniu@users.noreply.github.com>

* Update homeassistant/components/xiaomi_miio/fan.py

Co-authored-by: Maciej Bieniek <bieniu@users.noreply.github.com>

* cleanup code

* Set hass.data[DATA_KEY] to enable

* rename to filtered_entities in service handler

* Update homeassistant/components/xiaomi_miio/fan.py

Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>

* flake

Co-authored-by: Maciej Bieniek <bieniu@users.noreply.github.com>
Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
This commit is contained in:
Jan Bouwhuis 2021-08-10 14:55:11 +02:00 committed by GitHub
parent a7c08fff81
commit 5de1adacf7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 176 additions and 198 deletions

View file

@ -3,7 +3,15 @@ from datetime import timedelta
import logging import logging
import async_timeout import async_timeout
from miio import AirHumidifier, AirHumidifierMiot, AirHumidifierMjjsq, DeviceException from miio import (
AirFresh,
AirHumidifier,
AirHumidifierMiot,
AirHumidifierMjjsq,
AirPurifier,
AirPurifierMiot,
DeviceException,
)
from miio.gateway.gateway import GatewayException from miio.gateway.gateway import GatewayException
from homeassistant import config_entries, core from homeassistant import config_entries, core
@ -23,10 +31,13 @@ from .const import (
KEY_DEVICE, KEY_DEVICE,
MODELS_AIR_MONITOR, MODELS_AIR_MONITOR,
MODELS_FAN, MODELS_FAN,
MODELS_FAN_MIIO,
MODELS_HUMIDIFIER, MODELS_HUMIDIFIER,
MODELS_HUMIDIFIER_MIIO,
MODELS_HUMIDIFIER_MIOT, MODELS_HUMIDIFIER_MIOT,
MODELS_HUMIDIFIER_MJJSQ, MODELS_HUMIDIFIER_MJJSQ,
MODELS_LIGHT, MODELS_LIGHT,
MODELS_PURIFIER_MIOT,
MODELS_SWITCH, MODELS_SWITCH,
MODELS_VACUUM, MODELS_VACUUM,
) )
@ -107,27 +118,52 @@ async def async_create_miio_device_and_coordinator(
token = entry.data[CONF_TOKEN] token = entry.data[CONF_TOKEN]
name = entry.title name = entry.title
device = None device = None
migrate = False
if model not in MODELS_HUMIDIFIER: if (
model not in MODELS_HUMIDIFIER
and model not in MODELS_PURIFIER_MIOT
and model not in MODELS_FAN_MIIO
):
return return
_LOGGER.debug("Initializing with host %s (token %s...)", host, token[:5]) _LOGGER.debug("Initializing with host %s (token %s...)", host, token[:5])
# Humidifiers
if model in MODELS_HUMIDIFIER_MIOT: if model in MODELS_HUMIDIFIER_MIOT:
device = AirHumidifierMiot(host, token) device = AirHumidifierMiot(host, token)
migrate = True
elif model in MODELS_HUMIDIFIER_MJJSQ: elif model in MODELS_HUMIDIFIER_MJJSQ:
device = AirHumidifierMjjsq(host, token, model=model) device = AirHumidifierMjjsq(host, token, model=model)
else: migrate = True
elif model in MODELS_HUMIDIFIER_MIIO:
device = AirHumidifier(host, token, model=model) device = AirHumidifier(host, token, model=model)
migrate = True
# Airpurifiers and Airfresh
elif model in MODELS_PURIFIER_MIOT:
device = AirPurifierMiot(host, token)
elif model.startswith("zhimi.airpurifier."):
device = AirPurifier(host, token)
elif model.startswith("zhimi.airfresh."):
device = AirFresh(host, token)
else:
_LOGGER.error(
"Unsupported device found! Please create an issue at "
"https://github.com/syssi/xiaomi_airpurifier/issues "
"and provide the following data: %s",
model,
)
return
# Removing fan platform entity for humidifiers and migrate the name to the config entry for migration if migrate:
entity_registry = er.async_get(hass) # Removing fan platform entity for humidifiers and migrate the name to the config entry for migration
entity_id = entity_registry.async_get_entity_id("fan", DOMAIN, entry.unique_id) entity_registry = er.async_get(hass)
if entity_id: entity_id = entity_registry.async_get_entity_id("fan", DOMAIN, entry.unique_id)
# This check is entities that have a platform migration only and should be removed in the future if entity_id:
if migrate_entity_name := entity_registry.async_get(entity_id).name: # This check is entities that have a platform migration only and should be removed in the future
hass.config_entries.async_update_entry(entry, title=migrate_entity_name) if migrate_entity_name := entity_registry.async_get(entity_id).name:
entity_registry.async_remove(entity_id) hass.config_entries.async_update_entry(entry, title=migrate_entity_name)
entity_registry.async_remove(entity_id)
async def async_update_data(): async def async_update_data():
"""Fetch data from the device using async_add_executor_job.""" """Fetch data from the device using async_add_executor_job."""

View file

@ -1,11 +1,9 @@
"""Support for Xiaomi Mi Air Purifier and Xiaomi Mi Air Humidifier.""" """Support for Xiaomi Mi Air Purifier and Xiaomi Mi Air Humidifier."""
import asyncio import asyncio
from enum import Enum from enum import Enum
from functools import partial
import logging import logging
import math import math
from miio import AirFresh, AirPurifier, AirPurifierMiot, DeviceException
from miio.airfresh import ( from miio.airfresh import (
LedBrightness as AirfreshLedBrightness, LedBrightness as AirfreshLedBrightness,
OperationMode as AirfreshOperationMode, OperationMode as AirfreshOperationMode,
@ -35,6 +33,7 @@ from homeassistant.const import (
CONF_NAME, CONF_NAME,
CONF_TOKEN, CONF_TOKEN,
) )
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util.percentage import ( from homeassistant.util.percentage import (
percentage_to_ranged_value, percentage_to_ranged_value,
@ -56,6 +55,8 @@ from .const import (
FEATURE_SET_LED, FEATURE_SET_LED,
FEATURE_SET_LED_BRIGHTNESS, FEATURE_SET_LED_BRIGHTNESS,
FEATURE_SET_VOLUME, FEATURE_SET_VOLUME,
KEY_COORDINATOR,
KEY_DEVICE,
MODEL_AIRPURIFIER_2H, MODEL_AIRPURIFIER_2H,
MODEL_AIRPURIFIER_2S, MODEL_AIRPURIFIER_2S,
MODEL_AIRPURIFIER_PRO, MODEL_AIRPURIFIER_PRO,
@ -79,9 +80,8 @@ from .const import (
SERVICE_SET_LEARN_MODE_ON, SERVICE_SET_LEARN_MODE_ON,
SERVICE_SET_LED_BRIGHTNESS, SERVICE_SET_LED_BRIGHTNESS,
SERVICE_SET_VOLUME, SERVICE_SET_VOLUME,
SUCCESS,
) )
from .device import XiaomiMiioEntity from .device import XiaomiCoordinatedMiioEntity
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -430,94 +430,89 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Fan from a config entry.""" """Set up the Fan from a config entry."""
entities = [] entities = []
if config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE: if not config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE:
if DATA_KEY not in hass.data: return
hass.data[DATA_KEY] = {}
host = config_entry.data[CONF_HOST] hass.data.setdefault(DATA_KEY, {})
token = config_entry.data[CONF_TOKEN]
name = config_entry.title
model = config_entry.data[CONF_MODEL]
unique_id = config_entry.unique_id
_LOGGER.debug("Initializing with host %s (token %s...)", host, token[:5]) name = config_entry.title
model = config_entry.data[CONF_MODEL]
unique_id = config_entry.unique_id
coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
if model in MODELS_PURIFIER_MIOT: if model in MODELS_PURIFIER_MIOT:
air_purifier = AirPurifierMiot(host, token) entity = XiaomiAirPurifierMiot(
entity = XiaomiAirPurifierMiot( name,
name, air_purifier, config_entry, unique_id, allowed_failures=2 device,
) config_entry,
elif model.startswith("zhimi.airpurifier."): unique_id,
air_purifier = AirPurifier(host, token) coordinator,
entity = XiaomiAirPurifier(name, air_purifier, config_entry, unique_id) )
elif model.startswith("zhimi.airfresh."): elif model.startswith("zhimi.airpurifier."):
air_fresh = AirFresh(host, token) entity = XiaomiAirPurifier(name, device, config_entry, unique_id, coordinator)
entity = XiaomiAirFresh(name, air_fresh, config_entry, unique_id) elif model.startswith("zhimi.airfresh."):
entity = XiaomiAirFresh(name, device, config_entry, unique_id, coordinator)
else:
return
hass.data[DATA_KEY][unique_id] = entity
entities.append(entity)
async def async_service_handler(service):
"""Map services to methods on XiaomiAirPurifier."""
method = SERVICE_TO_METHOD[service.service]
params = {
key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID
}
entity_ids = service.data.get(ATTR_ENTITY_ID)
if entity_ids:
filtered_entities = [
entity
for entity in hass.data[DATA_KEY].values()
if entity.entity_id in entity_ids
]
else: else:
_LOGGER.error( filtered_entities = hass.data[DATA_KEY].values()
"Unsupported device found! Please create an issue at "
"https://github.com/syssi/xiaomi_airpurifier/issues "
"and provide the following data: %s",
model,
)
return
hass.data[DATA_KEY][host] = entity update_tasks = []
entities.append(entity)
async def async_service_handler(service): for entity in filtered_entities:
"""Map services to methods on XiaomiAirPurifier.""" entity_method = getattr(entity, method["method"], None)
method = SERVICE_TO_METHOD[service.service] if not entity_method:
params = { continue
key: value await entity_method(**params)
for key, value in service.data.items() update_tasks.append(
if key != ATTR_ENTITY_ID hass.async_create_task(entity.async_update_ha_state(True))
}
entity_ids = service.data.get(ATTR_ENTITY_ID)
if entity_ids:
entities = [
entity
for entity in hass.data[DATA_KEY].values()
if entity.entity_id in entity_ids
]
else:
entities = hass.data[DATA_KEY].values()
update_tasks = []
for entity in entities:
entity_method = getattr(entity, method["method"], None)
if not entity_method:
continue
await entity_method(**params)
update_tasks.append(
hass.async_create_task(entity.async_update_ha_state(True))
)
if update_tasks:
await asyncio.wait(update_tasks)
for air_purifier_service, method in SERVICE_TO_METHOD.items():
schema = method.get("schema", AIRPURIFIER_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, air_purifier_service, async_service_handler, schema=schema
) )
async_add_entities(entities, update_before_add=True) if update_tasks:
await asyncio.wait(update_tasks)
for air_purifier_service, method in SERVICE_TO_METHOD.items():
schema = method.get("schema", AIRPURIFIER_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, air_purifier_service, async_service_handler, schema=schema
)
async_add_entities(entities)
class XiaomiGenericDevice(XiaomiMiioEntity, FanEntity): class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity):
"""Representation of a generic Xiaomi device.""" """Representation of a generic Xiaomi device."""
def __init__(self, name, device, entry, unique_id): def __init__(self, name, device, entry, unique_id, coordinator):
"""Initialize the generic Xiaomi device.""" """Initialize the generic Xiaomi device."""
super().__init__(name, device, entry, unique_id) super().__init__(name, device, entry, unique_id, coordinator)
self._available = False self._available = False
self._available_attributes = {}
self._state = None self._state = None
self._mode = None
self._fan_level = None
self._state_attrs = {ATTR_MODEL: self._model} self._state_attrs = {ATTR_MODEL: self._model}
self._device_features = FEATURE_SET_CHILD_LOCK self._device_features = FEATURE_SET_CHILD_LOCK
self._skip_update = False
self._supported_features = 0 self._supported_features = 0
self._speed_count = 100 self._speed_count = 100
self._preset_modes = [] self._preset_modes = []
@ -583,22 +578,20 @@ class XiaomiGenericDevice(XiaomiMiioEntity, FanEntity):
return value return value
async def _try_command(self, mask_error, func, *args, **kwargs): @callback
"""Call a miio device command handling error messages.""" def _handle_coordinator_update(self):
try: """Fetch state from the device."""
result = await self.hass.async_add_executor_job( self._available = True
partial(func, *args, **kwargs) self._state = self.coordinator.data.is_on
) self._state_attrs.update(
{
_LOGGER.debug("Response received from miio device: %s", result) key: self._extract_value_from_attribute(self.coordinator.data, value)
for key, value in self._available_attributes.items()
return result == SUCCESS }
except DeviceException as exc: )
if self._available: self._mode = self._state_attrs.get(ATTR_MODE)
_LOGGER.error(mask_error, exc) self._fan_level = self._state_attrs.get(ATTR_FAN_LEVEL)
self._available = False self.async_write_ha_state()
return False
# #
# The fan entity model has changed to use percentages and preset_modes # The fan entity model has changed to use percentages and preset_modes
@ -630,7 +623,7 @@ class XiaomiGenericDevice(XiaomiMiioEntity, FanEntity):
if result: if result:
self._state = True self._state = True
self._skip_update = True self.async_write_ha_state()
async def async_turn_off(self, **kwargs) -> None: async def async_turn_off(self, **kwargs) -> None:
"""Turn the device off.""" """Turn the device off."""
@ -640,7 +633,7 @@ class XiaomiGenericDevice(XiaomiMiioEntity, FanEntity):
if result: if result:
self._state = False self._state = False
self._skip_update = True self.async_write_ha_state()
async def async_set_buzzer_on(self): async def async_set_buzzer_on(self):
"""Turn the buzzer on.""" """Turn the buzzer on."""
@ -706,11 +699,9 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
REVERSE_SPEED_MODE_MAPPING = {v: k for k, v in SPEED_MODE_MAPPING.items()} REVERSE_SPEED_MODE_MAPPING = {v: k for k, v in SPEED_MODE_MAPPING.items()}
def __init__(self, name, device, entry, unique_id, allowed_failures=0): def __init__(self, name, device, entry, unique_id, coordinator):
"""Initialize the plug switch.""" """Initialize the plug switch."""
super().__init__(name, device, entry, unique_id) super().__init__(name, device, entry, unique_id, coordinator)
self._allowed_failures = allowed_failures
self._failure = 0
if self._model == MODEL_AIRPURIFIER_PRO: if self._model == MODEL_AIRPURIFIER_PRO:
self._device_features = FEATURE_FLAGS_AIRPURIFIER_PRO self._device_features = FEATURE_FLAGS_AIRPURIFIER_PRO
@ -774,45 +765,8 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
self._state_attrs.update( self._state_attrs.update(
{attribute: None for attribute in self._available_attributes} {attribute: None for attribute in self._available_attributes}
) )
self._mode = self._state_attrs.get(ATTR_MODE)
async def async_update(self): self._fan_level = self._state_attrs.get(ATTR_FAN_LEVEL)
"""Fetch state from the device."""
# On state change the device doesn't provide the new state immediately.
if self._skip_update:
self._skip_update = False
return
try:
state = await self.hass.async_add_executor_job(self._device.status)
_LOGGER.debug("Got new state: %s", state)
self._available = True
self._state = state.is_on
self._state_attrs.update(
{
key: self._extract_value_from_attribute(state, value)
for key, value in self._available_attributes.items()
}
)
self._failure = 0
except DeviceException as ex:
self._failure += 1
if self._failure < self._allowed_failures:
_LOGGER.info(
"Got exception while fetching the state: %s, failure: %d",
ex,
self._failure,
)
else:
if self._available:
self._available = False
_LOGGER.error(
"Got exception while fetching the state: %s, failure: %d",
ex,
self._failure,
)
@property @property
def preset_mode(self): def preset_mode(self):
@ -1032,8 +986,7 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
def percentage(self): def percentage(self):
"""Return the current percentage based speed.""" """Return the current percentage based speed."""
if self._state: if self._state:
fan_level = self._state_attrs[ATTR_FAN_LEVEL] return ranged_value_to_percentage((1, 3), self._fan_level)
return ranged_value_to_percentage((1, 3), fan_level)
return None return None
@ -1041,9 +994,7 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
def preset_mode(self): def preset_mode(self):
"""Get the active preset mode.""" """Get the active preset mode."""
if self._state: if self._state:
preset_mode = AirpurifierMiotOperationMode( preset_mode = AirpurifierMiotOperationMode(self._mode).name
self._state_attrs[ATTR_MODE]
).name
return preset_mode if preset_mode in self._preset_modes else None return preset_mode if preset_mode in self._preset_modes else None
return None return None
@ -1053,7 +1004,7 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
def speed(self): def speed(self):
"""Return the current speed.""" """Return the current speed."""
if self._state: if self._state:
return AirpurifierMiotOperationMode(self._state_attrs[ATTR_MODE]).name return AirpurifierMiotOperationMode(self._mode).name
return None return None
@ -1063,12 +1014,15 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
This method is a coroutine. This method is a coroutine.
""" """
fan_level = math.ceil(percentage_to_ranged_value((1, 3), percentage)) fan_level = math.ceil(percentage_to_ranged_value((1, 3), percentage))
if fan_level: if not fan_level:
await self._try_command( return
"Setting fan level of the miio device failed.", if await self._try_command(
self._device.set_fan_level, "Setting fan level of the miio device failed.",
fan_level, self._device.set_fan_level,
) fan_level,
):
self._fan_level = fan_level
self.async_write_ha_state()
async def async_set_preset_mode(self, preset_mode: str) -> None: async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode of the fan. """Set the preset mode of the fan.
@ -1078,11 +1032,13 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
if preset_mode not in self.preset_modes: if preset_mode not in self.preset_modes:
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode) _LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
return return
await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode,
self.PRESET_MODE_MAPPING[preset_mode], self.PRESET_MODE_MAPPING[preset_mode],
) ):
self._mode = self.PRESET_MODE_MAPPING[preset_mode].value
self.async_write_ha_state()
# the async_set_speed function is deprecated, support will end with release 2021.7 # the async_set_speed function is deprecated, support will end with release 2021.7
# it is added here only for compatibility with legacy speeds # it is added here only for compatibility with legacy speeds
@ -1093,11 +1049,13 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
_LOGGER.debug("Setting the operation mode to: %s", speed) _LOGGER.debug("Setting the operation mode to: %s", speed)
await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode,
AirpurifierMiotOperationMode[speed.title()], AirpurifierMiotOperationMode[speed.title()],
) ):
self._mode = AirpurifierMiotOperationMode[speed.title()].value
self.async_write_ha_state()
async def async_set_led_brightness(self, brightness: int = 2): async def async_set_led_brightness(self, brightness: int = 2):
"""Set the led brightness.""" """Set the led brightness."""
@ -1128,9 +1086,9 @@ class XiaomiAirFresh(XiaomiGenericDevice):
"Interval": AirfreshOperationMode.Interval, "Interval": AirfreshOperationMode.Interval,
} }
def __init__(self, name, device, entry, unique_id): def __init__(self, name, device, entry, unique_id, coordinator):
"""Initialize the miio device.""" """Initialize the miio device."""
super().__init__(name, device, entry, unique_id) super().__init__(name, device, entry, unique_id, coordinator)
self._device_features = FEATURE_FLAGS_AIRFRESH self._device_features = FEATURE_FLAGS_AIRFRESH
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRFRESH self._available_attributes = AVAILABLE_ATTRIBUTES_AIRFRESH
@ -1142,37 +1100,13 @@ class XiaomiAirFresh(XiaomiGenericDevice):
self._state_attrs.update( self._state_attrs.update(
{attribute: None for attribute in self._available_attributes} {attribute: None for attribute in self._available_attributes}
) )
self._mode = self._state_attrs.get(ATTR_MODE)
async def async_update(self):
"""Fetch state from the device."""
# On state change the device doesn't provide the new state immediately.
if self._skip_update:
self._skip_update = False
return
try:
state = await self.hass.async_add_executor_job(self._device.status)
_LOGGER.debug("Got new state: %s", state)
self._available = True
self._state = state.is_on
self._state_attrs.update(
{
key: self._extract_value_from_attribute(state, value)
for key, value in self._available_attributes.items()
}
)
except DeviceException as ex:
if self._available:
self._available = False
_LOGGER.error("Got exception while fetching the state: %s", ex)
@property @property
def preset_mode(self): def preset_mode(self):
"""Get the active preset mode.""" """Get the active preset mode."""
if self._state: if self._state:
preset_mode = AirfreshOperationMode(self._state_attrs[ATTR_MODE]).name preset_mode = AirfreshOperationMode(self._mode).name
return preset_mode if preset_mode in self._preset_modes else None return preset_mode if preset_mode in self._preset_modes else None
return None return None
@ -1181,7 +1115,7 @@ class XiaomiAirFresh(XiaomiGenericDevice):
def percentage(self): def percentage(self):
"""Return the current percentage based speed.""" """Return the current percentage based speed."""
if self._state: if self._state:
mode = AirfreshOperationMode(self._state_attrs[ATTR_MODE]) mode = AirfreshOperationMode(self._mode)
if mode in self.REVERSE_SPEED_MODE_MAPPING: if mode in self.REVERSE_SPEED_MODE_MAPPING:
return ranged_value_to_percentage( return ranged_value_to_percentage(
(1, self._speed_count), self.REVERSE_SPEED_MODE_MAPPING[mode] (1, self._speed_count), self.REVERSE_SPEED_MODE_MAPPING[mode]
@ -1194,7 +1128,7 @@ class XiaomiAirFresh(XiaomiGenericDevice):
def speed(self): def speed(self):
"""Return the current speed.""" """Return the current speed."""
if self._state: if self._state:
return AirfreshOperationMode(self._state_attrs[ATTR_MODE]).name return AirfreshOperationMode(self._mode).name
return None return None
@ -1207,11 +1141,15 @@ class XiaomiAirFresh(XiaomiGenericDevice):
percentage_to_ranged_value((1, self._speed_count), percentage) percentage_to_ranged_value((1, self._speed_count), percentage)
) )
if speed_mode: if speed_mode:
await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode,
AirfreshOperationMode(self.SPEED_MODE_MAPPING[speed_mode]), AirfreshOperationMode(self.SPEED_MODE_MAPPING[speed_mode]),
) ):
self._mode = AirfreshOperationMode(
self.SPEED_MODE_MAPPING[speed_mode]
).value
self.async_write_ha_state()
async def async_set_preset_mode(self, preset_mode: str) -> None: async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode of the fan. """Set the preset mode of the fan.
@ -1221,11 +1159,13 @@ class XiaomiAirFresh(XiaomiGenericDevice):
if preset_mode not in self.preset_modes: if preset_mode not in self.preset_modes:
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode) _LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
return return
await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode,
self.PRESET_MODE_MAPPING[preset_mode], self.PRESET_MODE_MAPPING[preset_mode],
) ):
self._mode = self.PRESET_MODE_MAPPING[preset_mode].value
self.async_write_ha_state()
# the async_set_speed function is deprecated, support will end with release 2021.7 # the async_set_speed function is deprecated, support will end with release 2021.7
# it is added here only for compatibility with legacy speeds # it is added here only for compatibility with legacy speeds
@ -1236,11 +1176,13 @@ class XiaomiAirFresh(XiaomiGenericDevice):
_LOGGER.debug("Setting the operation mode to: %s", speed) _LOGGER.debug("Setting the operation mode to: %s", speed)
await self._try_command( if await self._try_command(
"Setting operation mode of the miio device failed.", "Setting operation mode of the miio device failed.",
self._device.set_mode, self._device.set_mode,
AirfreshOperationMode[speed.title()], AirfreshOperationMode[speed.title()],
) ):
self._mode = AirfreshOperationMode[speed.title()].value
self.async_write_ha_state()
async def async_set_led_on(self): async def async_set_led_on(self):
"""Turn the led on.""" """Turn the led on."""