Add homekit pm type sensor (#46060)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Lester Lo 2022-03-08 15:37:20 +08:00 committed by GitHub
parent e1b57d83c7
commit 56abd5f2cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 220 additions and 7 deletions

View file

@ -173,9 +173,19 @@ def get_accessory(hass, driver, state, aid, config): # noqa: C901
a_type = "TemperatureSensor"
elif device_class == SensorDeviceClass.HUMIDITY and unit == PERCENTAGE:
a_type = "HumiditySensor"
elif (
device_class == SensorDeviceClass.PM10
or SensorDeviceClass.PM10 in state.entity_id
):
a_type = "PM10Sensor"
elif (
device_class == SensorDeviceClass.PM25
or SensorDeviceClass.PM25 in state.entity_id
):
a_type = "PM25Sensor"
elif (
device_class == SensorDeviceClass.GAS
or SensorDeviceClass.GAS in state.entity_id
):
a_type = "AirQualitySensor"
elif device_class == SensorDeviceClass.CO:

View file

@ -150,6 +150,8 @@ SERV_WINDOW_COVERING = "WindowCovering"
CHAR_ACTIVE = "Active"
CHAR_ACTIVE_IDENTIFIER = "ActiveIdentifier"
CHAR_AIR_PARTICULATE_DENSITY = "AirParticulateDensity"
CHAR_PM25_DENSITY = "PM2.5Density"
CHAR_PM10_DENSITY = "PM10Density"
CHAR_AIR_QUALITY = "AirQuality"
CHAR_BATTERY_LEVEL = "BatteryLevel"
CHAR_BRIGHTNESS = "Brightness"
@ -235,7 +237,6 @@ PROP_MIN_VALUE = "minValue"
PROP_MIN_STEP = "minStep"
PROP_CELSIUS = {"minValue": -273, "maxValue": 999}
PROP_VALID_VALUES = "ValidValues"
# #### Thresholds ####
THRESHOLD_CO = 25
THRESHOLD_CO2 = 1000

View file

@ -35,6 +35,8 @@ from .const import (
CHAR_LEAK_DETECTED,
CHAR_MOTION_DETECTED,
CHAR_OCCUPANCY_DETECTED,
CHAR_PM10_DENSITY,
CHAR_PM25_DENSITY,
CHAR_SMOKE_DETECTED,
PROP_CELSIUS,
SERV_AIR_QUALITY_SENSOR,
@ -51,7 +53,13 @@ from .const import (
THRESHOLD_CO,
THRESHOLD_CO2,
)
from .util import convert_to_float, density_to_air_quality, temperature_to_homekit
from .util import (
convert_to_float,
density_to_air_quality,
density_to_air_quality_pm10,
density_to_air_quality_pm25,
temperature_to_homekit,
)
_LOGGER = logging.getLogger(__name__)
@ -156,6 +164,15 @@ class AirQualitySensor(HomeAccessory):
"""Initialize a AirQualitySensor accessory object."""
super().__init__(*args, category=CATEGORY_SENSOR)
state = self.hass.states.get(self.entity_id)
self.create_services()
# Set the state so it is in sync on initial
# GET to avoid an event storm after homekit startup
self.async_update_state(state)
def create_services(self):
"""Initialize a AirQualitySensor accessory object."""
serv_air_quality = self.add_preload_service(
SERV_AIR_QUALITY_SENSOR, [CHAR_AIR_PARTICULATE_DENSITY]
)
@ -163,9 +180,6 @@ class AirQualitySensor(HomeAccessory):
self.char_density = serv_air_quality.configure_char(
CHAR_AIR_PARTICULATE_DENSITY, value=0
)
# Set the state so it is in sync on initial
# GET to avoid an event storm after homekit startup
self.async_update_state(state)
@callback
def async_update_state(self, new_state):
@ -179,6 +193,60 @@ class AirQualitySensor(HomeAccessory):
_LOGGER.debug("%s: Set air_quality to %d", self.entity_id, air_quality)
@TYPES.register("PM10Sensor")
class PM10Sensor(AirQualitySensor):
"""Generate a PM10Sensor accessory as PM 10 sensor."""
def create_services(self):
"""Override the init function for PM 10 Sensor."""
serv_air_quality = self.add_preload_service(
SERV_AIR_QUALITY_SENSOR, [CHAR_PM10_DENSITY]
)
self.char_quality = serv_air_quality.configure_char(CHAR_AIR_QUALITY, value=0)
self.char_density = serv_air_quality.configure_char(CHAR_PM10_DENSITY, value=0)
@callback
def async_update_state(self, new_state):
"""Update accessory after state change."""
density = convert_to_float(new_state.state)
if not density:
return
if self.char_density.value != density:
self.char_density.set_value(density)
_LOGGER.debug("%s: Set density to %d", self.entity_id, density)
air_quality = density_to_air_quality_pm10(density)
if self.char_quality.value != air_quality:
self.char_quality.set_value(air_quality)
_LOGGER.debug("%s: Set air_quality to %d", self.entity_id, air_quality)
@TYPES.register("PM25Sensor")
class PM25Sensor(AirQualitySensor):
"""Generate a PM25Sensor accessory as PM 2.5 sensor."""
def create_services(self):
"""Override the init function for PM 2.5 Sensor."""
serv_air_quality = self.add_preload_service(
SERV_AIR_QUALITY_SENSOR, [CHAR_PM25_DENSITY]
)
self.char_quality = serv_air_quality.configure_char(CHAR_AIR_QUALITY, value=0)
self.char_density = serv_air_quality.configure_char(CHAR_PM25_DENSITY, value=0)
@callback
def async_update_state(self, new_state):
"""Update accessory after state change."""
density = convert_to_float(new_state.state)
if not density:
return
if self.char_density.value != density:
self.char_density.set_value(density)
_LOGGER.debug("%s: Set density to %d", self.entity_id, density)
air_quality = density_to_air_quality_pm25(density)
if self.char_quality.value != air_quality:
self.char_quality.set_value(air_quality)
_LOGGER.debug("%s: Set air_quality to %d", self.entity_id, air_quality)
@TYPES.register("CarbonMonoxideSensor")
class CarbonMonoxideSensor(HomeAccessory):
"""Generate a CarbonMonoxidSensor accessory as CO sensor."""

View file

@ -407,6 +407,32 @@ def density_to_air_quality(density):
return 5
def density_to_air_quality_pm10(density):
"""Map PM10 density to HomeKit AirQuality level."""
if density <= 40:
return 1
if density <= 80:
return 2
if density <= 120:
return 3
if density <= 300:
return 4
return 5
def density_to_air_quality_pm25(density):
"""Map PM2.5 density to HomeKit AirQuality level."""
if density <= 25:
return 1
if density <= 50:
return 2
if density <= 100:
return 3
if density <= 300:
return 4
return 5
def get_persist_filename_for_entry_id(entry_id: str):
"""Determine the filename of the homekit state file."""
return f"{DOMAIN}.{entry_id}.state"