Add xiaomi miio sensors cgllc.airmonitor.s1 & cgllc.airmonitor.b1 (#30345)

* support xiaomi miio sensor: cgllc.airmonitor.s1 & cgllc.airmonitor.b1

* support xiaomi miio sensor: cgllc.airmonitor.s1 & cgllc.airmonitor.b1

* rollback sensor,  modify air_quality

* only set air_quality props

* remove set state from "zhimi.airmonitor.v1"

* unit_of_measurement return None when the pm25 isn't reported

* import libs by isort
This commit is contained in:
zhumuht 2020-01-22 00:06:17 +08:00 committed by springstan
parent 2aff913d9b
commit 27c25b6f44
2 changed files with 86 additions and 11 deletions

View File

@ -1,16 +1,22 @@
"""Support for Xiaomi Mi Air Quality Monitor (PM2.5).""" """Support for Xiaomi Mi Air Quality Monitor (PM2.5)."""
import logging
from miio import AirQualityMonitor, Device, DeviceException from miio import AirQualityMonitor, Device, DeviceException
import voluptuous as vol import voluptuous as vol
from homeassistant.components.air_quality import ( from homeassistant.components.air_quality import PLATFORM_SCHEMA, AirQualityEntity
_LOGGER,
PLATFORM_SCHEMA,
AirQualityEntity,
)
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_TOKEN from homeassistant.const import CONF_HOST, CONF_NAME, CONF_TOKEN
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import NoEntitySpecifiedError, PlatformNotReady
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from .const import (
MODEL_AIRQUALITYMONITOR_B1,
MODEL_AIRQUALITYMONITOR_S1,
MODEL_AIRQUALITYMONITOR_V1,
)
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "Xiaomi Miio Air Quality Monitor" DEFAULT_NAME = "Xiaomi Miio Air Quality Monitor"
ATTR_CO2E = "carbon_dioxide_equivalent" ATTR_CO2E = "carbon_dioxide_equivalent"
@ -54,9 +60,19 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
device_info.firmware_version, device_info.firmware_version,
device_info.hardware_version, device_info.hardware_version,
) )
device = AirMonitorB1(name, AirQualityMonitor(host, token, model=model), unique_id)
async_add_entities([device], update_before_add=True) device = AirQualityMonitor(host, token, model=model)
if model == MODEL_AIRQUALITYMONITOR_S1:
entity = AirMonitorS1(name, device, unique_id)
elif model == MODEL_AIRQUALITYMONITOR_B1:
entity = AirMonitorB1(name, device, unique_id)
elif model == MODEL_AIRQUALITYMONITOR_V1:
entity = AirMonitorV1(name, device, unique_id)
else:
raise NoEntitySpecifiedError(f"Not support for entity {unique_id}")
async_add_entities([entity], update_before_add=True)
class AirMonitorB1(AirQualityEntity): class AirMonitorB1(AirQualityEntity):
@ -69,22 +85,24 @@ class AirMonitorB1(AirQualityEntity):
self._unique_id = unique_id self._unique_id = unique_id
self._icon = "mdi:cloud" self._icon = "mdi:cloud"
self._unit_of_measurement = "μg/m3" self._unit_of_measurement = "μg/m3"
self._available = None
self._air_quality_index = None
self._carbon_dioxide = None
self._carbon_dioxide_equivalent = None self._carbon_dioxide_equivalent = None
self._particulate_matter_2_5 = None self._particulate_matter_2_5 = None
self._total_volatile_organic_compounds = None self._total_volatile_organic_compounds = None
async def async_update(self): async def async_update(self):
"""Fetch state from the miio device.""" """Fetch state from the miio device."""
try: try:
state = await self.hass.async_add_executor_job(self._device.status) state = await self.hass.async_add_executor_job(self._device.status)
_LOGGER.debug("Got new state: %s", state) _LOGGER.debug("Got new state: %s", state)
self._carbon_dioxide_equivalent = state.co2e self._carbon_dioxide_equivalent = state.co2e
self._particulate_matter_2_5 = round(state.pm25, 1) self._particulate_matter_2_5 = round(state.pm25, 1)
self._total_volatile_organic_compounds = round(state.tvoc, 3) self._total_volatile_organic_compounds = round(state.tvoc, 3)
self._available = True
except DeviceException as ex: except DeviceException as ex:
self._available = False
_LOGGER.error("Got exception while fetching the state: %s", ex) _LOGGER.error("Got exception while fetching the state: %s", ex)
@property @property
@ -97,11 +115,26 @@ class AirMonitorB1(AirQualityEntity):
"""Return the icon to use for device if any.""" """Return the icon to use for device if any."""
return self._icon return self._icon
@property
def available(self):
"""Return true when state is known."""
return self._available
@property @property
def unique_id(self): def unique_id(self):
"""Return the unique ID.""" """Return the unique ID."""
return self._unique_id return self._unique_id
@property
def air_quality_index(self):
"""Return the Air Quality Index (AQI)."""
return self._air_quality_index
@property
def carbon_dioxide(self):
"""Return the CO2 (carbon dioxide) level."""
return self._carbon_dioxide
@property @property
def carbon_dioxide_equivalent(self): def carbon_dioxide_equivalent(self):
"""Return the CO2e (carbon dioxide equivalent) level.""" """Return the CO2e (carbon dioxide equivalent) level."""
@ -133,3 +166,40 @@ class AirMonitorB1(AirQualityEntity):
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement.""" """Return the unit of measurement."""
return self._unit_of_measurement return self._unit_of_measurement
class AirMonitorS1(AirMonitorB1):
"""Air Quality class for Xiaomi cgllc.airmonitor.s1 device."""
async def async_update(self):
"""Fetch state from the miio device."""
try:
state = await self.hass.async_add_executor_job(self._device.status)
_LOGGER.debug("Got new state: %s", state)
self._carbon_dioxide = state.co2
self._particulate_matter_2_5 = state.pm25
self._total_volatile_organic_compounds = state.tvoc
self._available = True
except DeviceException as ex:
self._available = False
_LOGGER.error("Got exception while fetching the state: %s", ex)
class AirMonitorV1(AirMonitorB1):
"""Air Quality class for Xiaomi cgllc.airmonitor.s1 device."""
async def async_update(self):
"""Fetch state from the miio device."""
try:
state = await self.hass.async_add_executor_job(self._device.status)
_LOGGER.debug("Got new state: %s", state)
self._air_quality_index = state.aqi
self._available = True
except DeviceException as ex:
self._available = False
_LOGGER.error("Got exception while fetching the state: %s", ex)
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return None

View File

@ -46,3 +46,8 @@ SERVICE_MOVE_REMOTE_CONTROL_STEP = "vacuum_remote_control_move_step"
SERVICE_START_REMOTE_CONTROL = "vacuum_remote_control_start" SERVICE_START_REMOTE_CONTROL = "vacuum_remote_control_start"
SERVICE_STOP_REMOTE_CONTROL = "vacuum_remote_control_stop" SERVICE_STOP_REMOTE_CONTROL = "vacuum_remote_control_stop"
SERVICE_CLEAN_ZONE = "vacuum_clean_zone" SERVICE_CLEAN_ZONE = "vacuum_clean_zone"
# AirQuality Model
MODEL_AIRQUALITYMONITOR_V1 = "zhimi.airmonitor.v1"
MODEL_AIRQUALITYMONITOR_B1 = "cgllc.airmonitor.b1"
MODEL_AIRQUALITYMONITOR_S1 = "cgllc.airmonitor.s1"