Make co/co2 threshold configurable via entity_config (#112978)

* make co/co2 threshold configurable via entity_config

* Split threshold into co/co2_threshold configuration
This commit is contained in:
Fabrice 2024-05-24 13:28:19 +02:00 committed by GitHub
parent e7d23d8b49
commit d4acd86819
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 92 additions and 2 deletions

View file

@ -59,6 +59,8 @@ CONF_MAX_WIDTH = "max_width"
CONF_STREAM_ADDRESS = "stream_address"
CONF_STREAM_SOURCE = "stream_source"
CONF_SUPPORT_AUDIO = "support_audio"
CONF_THRESHOLD_CO = "co_threshold"
CONF_THRESHOLD_CO2 = "co2_threshold"
CONF_VIDEO_CODEC = "video_codec"
CONF_VIDEO_PROFILE_NAMES = "video_profile_names"
CONF_VIDEO_MAP = "video_map"

View file

@ -41,6 +41,8 @@ from .const import (
CHAR_PM25_DENSITY,
CHAR_SMOKE_DETECTED,
CHAR_VOC_DENSITY,
CONF_THRESHOLD_CO,
CONF_THRESHOLD_CO2,
PROP_CELSIUS,
PROP_MAX_VALUE,
PROP_MIN_VALUE,
@ -335,6 +337,10 @@ class CarbonMonoxideSensor(HomeAccessory):
SERV_CARBON_MONOXIDE_SENSOR,
[CHAR_CARBON_MONOXIDE_LEVEL, CHAR_CARBON_MONOXIDE_PEAK_LEVEL],
)
self.threshold_co = self.config.get(CONF_THRESHOLD_CO, THRESHOLD_CO)
_LOGGER.debug("%s: Set CO threshold to %d", self.entity_id, self.threshold_co)
self.char_level = serv_co.configure_char(CHAR_CARBON_MONOXIDE_LEVEL, value=0)
self.char_peak = serv_co.configure_char(
CHAR_CARBON_MONOXIDE_PEAK_LEVEL, value=0
@ -353,7 +359,7 @@ class CarbonMonoxideSensor(HomeAccessory):
self.char_level.set_value(value)
if value > self.char_peak.value:
self.char_peak.set_value(value)
co_detected = value > THRESHOLD_CO
co_detected = value > self.threshold_co
self.char_detected.set_value(co_detected)
_LOGGER.debug("%s: Set to %d", self.entity_id, value)
@ -371,6 +377,10 @@ class CarbonDioxideSensor(HomeAccessory):
SERV_CARBON_DIOXIDE_SENSOR,
[CHAR_CARBON_DIOXIDE_LEVEL, CHAR_CARBON_DIOXIDE_PEAK_LEVEL],
)
self.threshold_co2 = self.config.get(CONF_THRESHOLD_CO2, THRESHOLD_CO2)
_LOGGER.debug("%s: Set CO2 threshold to %d", self.entity_id, self.threshold_co2)
self.char_level = serv_co2.configure_char(CHAR_CARBON_DIOXIDE_LEVEL, value=0)
self.char_peak = serv_co2.configure_char(
CHAR_CARBON_DIOXIDE_PEAK_LEVEL, value=0
@ -389,7 +399,7 @@ class CarbonDioxideSensor(HomeAccessory):
self.char_level.set_value(value)
if value > self.char_peak.value:
self.char_peak.set_value(value)
co2_detected = value > THRESHOLD_CO2
co2_detected = value > self.threshold_co2
self.char_detected.set_value(co2_detected)
_LOGGER.debug("%s: Set to %d", self.entity_id, value)

View file

@ -72,6 +72,8 @@ from .const import (
CONF_STREAM_COUNT,
CONF_STREAM_SOURCE,
CONF_SUPPORT_AUDIO,
CONF_THRESHOLD_CO,
CONF_THRESHOLD_CO2,
CONF_VIDEO_CODEC,
CONF_VIDEO_MAP,
CONF_VIDEO_PACKET_SIZE,
@ -223,6 +225,13 @@ SWITCH_TYPE_SCHEMA = BASIC_INFO_SCHEMA.extend(
}
)
SENSOR_SCHEMA = BASIC_INFO_SCHEMA.extend(
{
vol.Optional(CONF_THRESHOLD_CO): vol.Any(None, cv.positive_int),
vol.Optional(CONF_THRESHOLD_CO2): vol.Any(None, cv.positive_int),
}
)
HOMEKIT_CHAR_TRANSLATIONS = {
0: " ", # nul
@ -297,6 +306,9 @@ def validate_entity_config(values: dict) -> dict[str, dict]:
elif domain == "cover":
config = COVER_SCHEMA(config)
elif domain == "sensor":
config = SENSOR_SCHEMA(config)
else:
config = BASIC_INFO_SCHEMA(config)

View file

@ -5,6 +5,8 @@ from unittest.mock import patch
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
from homeassistant.components.homekit import get_accessory
from homeassistant.components.homekit.const import (
CONF_THRESHOLD_CO,
CONF_THRESHOLD_CO2,
PROP_CELSIUS,
THRESHOLD_CO,
THRESHOLD_CO2,
@ -375,6 +377,34 @@ async def test_co(hass: HomeAssistant, hk_driver) -> None:
assert acc.char_detected.value == 0
async def test_co_with_configured_threshold(hass: HomeAssistant, hk_driver) -> None:
"""Test if co threshold of accessory can be configured ."""
entity_id = "sensor.co"
co_threshold = 10
assert co_threshold < THRESHOLD_CO
hass.states.async_set(entity_id, None)
await hass.async_block_till_done()
acc = CarbonMonoxideSensor(
hass, hk_driver, "CO", entity_id, 2, {CONF_THRESHOLD_CO: co_threshold}
)
acc.run()
await hass.async_block_till_done()
value = 15
assert value > co_threshold
hass.states.async_set(entity_id, str(value))
await hass.async_block_till_done()
assert acc.char_detected.value == 1
value = 5
assert value < co_threshold
hass.states.async_set(entity_id, str(value))
await hass.async_block_till_done()
assert acc.char_detected.value == 0
async def test_co2(hass: HomeAssistant, hk_driver) -> None:
"""Test if accessory is updated after state change."""
entity_id = "sensor.co2"
@ -415,6 +445,34 @@ async def test_co2(hass: HomeAssistant, hk_driver) -> None:
assert acc.char_detected.value == 0
async def test_co2_with_configured_threshold(hass: HomeAssistant, hk_driver) -> None:
"""Test if co2 threshold of accessory can be configured ."""
entity_id = "sensor.co2"
co2_threshold = 500
assert co2_threshold < THRESHOLD_CO2
hass.states.async_set(entity_id, None)
await hass.async_block_till_done()
acc = CarbonDioxideSensor(
hass, hk_driver, "CO2", entity_id, 2, {CONF_THRESHOLD_CO2: co2_threshold}
)
acc.run()
await hass.async_block_till_done()
value = 800
assert value > co2_threshold
hass.states.async_set(entity_id, str(value))
await hass.async_block_till_done()
assert acc.char_detected.value == 1
value = 400
assert value < co2_threshold
hass.states.async_set(entity_id, str(value))
await hass.async_block_till_done()
assert acc.char_detected.value == 0
async def test_light(hass: HomeAssistant, hk_driver) -> None:
"""Test if accessory is updated after state change."""
entity_id = "sensor.light"

View file

@ -11,6 +11,8 @@ from homeassistant.components.homekit.const import (
CONF_FEATURE_LIST,
CONF_LINKED_BATTERY_SENSOR,
CONF_LOW_BATTERY_THRESHOLD,
CONF_THRESHOLD_CO,
CONF_THRESHOLD_CO2,
DEFAULT_CONFIG_FLOW_PORT,
DOMAIN,
FEATURE_ON_OFF,
@ -170,6 +172,12 @@ def test_validate_entity_config() -> None:
assert vec({"switch.demo": {CONF_TYPE: TYPE_VALVE}}) == {
"switch.demo": {CONF_TYPE: TYPE_VALVE, CONF_LOW_BATTERY_THRESHOLD: 20}
}
assert vec({"sensor.co": {CONF_THRESHOLD_CO: 500}}) == {
"sensor.co": {CONF_THRESHOLD_CO: 500, CONF_LOW_BATTERY_THRESHOLD: 20}
}
assert vec({"sensor.co2": {CONF_THRESHOLD_CO2: 500}}) == {
"sensor.co2": {CONF_THRESHOLD_CO2: 500, CONF_LOW_BATTERY_THRESHOLD: 20}
}
def test_validate_media_player_features() -> None: