Add Xiaomi Smartmi Fresh Air System support (#18097)

* Add Xiaomi Air Fresh VA2 support

* Add LED property again (available now)
pull/18250/head
Sebastian Muszynski 2018-11-06 00:09:15 +01:00 committed by Teemu R
parent 3366d2c1ad
commit d951ed4d68
1 changed files with 161 additions and 9 deletions

View File

@ -11,10 +11,10 @@ import logging
import voluptuous as vol
from homeassistant.components.fan import (
DOMAIN, PLATFORM_SCHEMA, SUPPORT_SET_SPEED, FanEntity)
from homeassistant.const import (
ATTR_ENTITY_ID, CONF_HOST, CONF_NAME, CONF_TOKEN)
from homeassistant.components.fan import (FanEntity, PLATFORM_SCHEMA,
SUPPORT_SET_SPEED, DOMAIN, )
from homeassistant.const import (CONF_NAME, CONF_HOST, CONF_TOKEN,
ATTR_ENTITY_ID, )
from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv
@ -30,6 +30,7 @@ MODEL_AIRPURIFIER_PRO = 'zhimi.airpurifier.v6'
MODEL_AIRPURIFIER_V3 = 'zhimi.airpurifier.v3'
MODEL_AIRHUMIDIFIER_V1 = 'zhimi.humidifier.v1'
MODEL_AIRHUMIDIFIER_CA = 'zhimi.humidifier.ca1'
MODEL_AIRFRESH_VA2 = 'zhimi.airfresh.va2'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
@ -48,7 +49,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
'zhimi.airpurifier.v5',
'zhimi.airpurifier.v6',
'zhimi.humidifier.v1',
'zhimi.humidifier.ca1']),
'zhimi.humidifier.ca1',
'zhimi.airfresh.va2']),
})
ATTR_MODEL = 'model'
@ -97,6 +99,9 @@ ATTR_SPEED = 'speed'
ATTR_DEPTH = 'depth'
ATTR_DRY = 'dry'
# Air Fresh
ATTR_CO2 = 'co2'
# Map attributes to properties of the state object
AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON = {
ATTR_TEMPERATURE: 'temperature',
@ -166,31 +171,55 @@ AVAILABLE_ATTRIBUTES_AIRPURIFIER_V3 = {
ATTR_BUTTON_PRESSED: 'button_pressed',
}
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER = {
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON = {
ATTR_TEMPERATURE: 'temperature',
ATTR_HUMIDITY: 'humidity',
ATTR_MODE: 'mode',
ATTR_BUZZER: 'buzzer',
ATTR_CHILD_LOCK: 'child_lock',
ATTR_TRANS_LEVEL: 'trans_level',
ATTR_TARGET_HUMIDITY: 'target_humidity',
ATTR_LED_BRIGHTNESS: 'led_brightness',
ATTR_BUTTON_PRESSED: 'button_pressed',
ATTR_USE_TIME: 'use_time',
ATTR_HARDWARE_VERSION: 'hardware_version',
}
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER = {
**AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON,
ATTR_TRANS_LEVEL: 'trans_level',
ATTR_BUTTON_PRESSED: 'button_pressed',
}
AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_CA = {
**AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER,
**AVAILABLE_ATTRIBUTES_AIRHUMIDIFIER_COMMON,
ATTR_SPEED: 'speed',
ATTR_DEPTH: 'depth',
ATTR_DRY: 'dry',
}
AVAILABLE_ATTRIBUTES_AIRFRESH = {
ATTR_TEMPERATURE: 'temperature',
ATTR_AIR_QUALITY_INDEX: 'aqi',
ATTR_AVERAGE_AIR_QUALITY_INDEX: 'average_aqi',
ATTR_CO2: 'co2',
ATTR_HUMIDITY: 'humidity',
ATTR_MODE: 'mode',
ATTR_LED: 'led',
ATTR_LED_BRIGHTNESS: 'led_brightness',
ATTR_BUZZER: 'buzzer',
ATTR_CHILD_LOCK: 'child_lock',
ATTR_FILTER_LIFE: 'filter_life_remaining',
ATTR_FILTER_HOURS_USED: 'filter_hours_used',
ATTR_USE_TIME: 'use_time',
ATTR_MOTOR_SPEED: 'motor_speed',
ATTR_EXTRA_FEATURES: 'extra_features',
}
OPERATION_MODES_AIRPURIFIER = ['Auto', 'Silent', 'Favorite', 'Idle']
OPERATION_MODES_AIRPURIFIER_PRO = ['Auto', 'Silent', 'Favorite']
OPERATION_MODES_AIRPURIFIER_V3 = ['Auto', 'Silent', 'Favorite', 'Idle',
'Medium', 'High', 'Strong']
OPERATION_MODES_AIRFRESH = ['Auto', 'Silent', 'Interval', 'Low',
'Middle', 'Strong']
SUCCESS = ['ok']
@ -234,6 +263,12 @@ FEATURE_FLAGS_AIRHUMIDIFIER = (FEATURE_FLAGS_GENERIC |
FEATURE_FLAGS_AIRHUMIDIFIER_CA = (FEATURE_FLAGS_AIRHUMIDIFIER |
FEATURE_SET_DRY)
FEATURE_FLAGS_AIRFRESH = (FEATURE_FLAGS_GENERIC |
FEATURE_SET_LED |
FEATURE_SET_LED_BRIGHTNESS |
FEATURE_RESET_FILTER |
FEATURE_SET_EXTRA_FEATURES)
SERVICE_SET_BUZZER_ON = 'xiaomi_miio_set_buzzer_on'
SERVICE_SET_BUZZER_OFF = 'xiaomi_miio_set_buzzer_off'
SERVICE_SET_LED_ON = 'xiaomi_miio_set_led_on'
@ -350,6 +385,10 @@ async def async_setup_platform(hass, config, async_add_entities,
from miio import AirHumidifier
air_humidifier = AirHumidifier(host, token, model=model)
device = XiaomiAirHumidifier(name, air_humidifier, model, unique_id)
elif model.startswith('zhimi.airfresh.'):
from miio import AirFresh
air_fresh = AirFresh(host, token)
device = XiaomiAirFresh(name, air_fresh, model, unique_id)
else:
_LOGGER.error(
'Unsupported device found! Please create an issue at '
@ -812,3 +851,116 @@ class XiaomiAirHumidifier(XiaomiGenericDevice):
await self._try_command(
"Turning the dry mode of the miio device off failed.",
self._device.set_dry, False)
class XiaomiAirFresh(XiaomiGenericDevice):
"""Representation of a Xiaomi Air Fresh."""
def __init__(self, name, device, model, unique_id):
"""Initialize the miio device."""
super().__init__(name, device, model, unique_id)
self._device_features = FEATURE_FLAGS_AIRFRESH
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRFRESH
self._speed_list = OPERATION_MODES_AIRFRESH
self._state_attrs.update(
{attribute: None for attribute in self._available_attributes})
async def async_update(self):
"""Fetch state from the device."""
from miio import DeviceException
# 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_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:
self._available = False
_LOGGER.error("Got exception while fetching the state: %s", ex)
@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
return self._speed_list
@property
def speed(self):
"""Return the current speed."""
if self._state:
from miio.airfresh import OperationMode
return OperationMode(self._state_attrs[ATTR_MODE]).name
return None
async def async_set_speed(self, speed: str) -> None:
"""Set the speed of the fan."""
if self.supported_features & SUPPORT_SET_SPEED == 0:
return
from miio.airfresh import OperationMode
_LOGGER.debug("Setting the operation mode to: %s", speed)
await self._try_command(
"Setting operation mode of the miio device failed.",
self._device.set_mode, OperationMode[speed.title()])
async def async_set_led_on(self):
"""Turn the led on."""
if self._device_features & FEATURE_SET_LED == 0:
return
await self._try_command(
"Turning the led of the miio device off failed.",
self._device.set_led, True)
async def async_set_led_off(self):
"""Turn the led off."""
if self._device_features & FEATURE_SET_LED == 0:
return
await self._try_command(
"Turning the led of the miio device off failed.",
self._device.set_led, False)
async def async_set_led_brightness(self, brightness: int = 2):
"""Set the led brightness."""
if self._device_features & FEATURE_SET_LED_BRIGHTNESS == 0:
return
from miio.airfresh import LedBrightness
await self._try_command(
"Setting the led brightness of the miio device failed.",
self._device.set_led_brightness, LedBrightness(brightness))
async def async_set_extra_features(self, features: int = 1):
"""Set the extra features."""
if self._device_features & FEATURE_SET_EXTRA_FEATURES == 0:
return
await self._try_command(
"Setting the extra features of the miio device failed.",
self._device.set_extra_features, features)
async def async_reset_filter(self):
"""Reset the filter lifetime and usage."""
if self._device_features & FEATURE_RESET_FILTER == 0:
return
await self._try_command(
"Resetting the filter lifetime of the miio device failed.",
self._device.reset_filter)