mirror of
https://github.com/home-assistant/core.git
synced 2026-04-02 00:20:30 +01:00
Add air quality conditions (#166407)
This commit is contained in:
150
homeassistant/components/air_quality/condition.py
Normal file
150
homeassistant/components/air_quality/condition.py
Normal file
@@ -0,0 +1,150 @@
|
||||
"""Provides conditions for air quality."""
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DOMAIN as BINARY_SENSOR_DOMAIN,
|
||||
BinarySensorDeviceClass,
|
||||
)
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN, SensorDeviceClass
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.automation import DomainSpec, NumericalDomainSpec
|
||||
from homeassistant.helpers.condition import (
|
||||
Condition,
|
||||
make_entity_numerical_condition,
|
||||
make_entity_numerical_condition_with_unit,
|
||||
make_entity_state_condition,
|
||||
)
|
||||
from homeassistant.util.unit_conversion import (
|
||||
CarbonMonoxideConcentrationConverter,
|
||||
MassVolumeConcentrationConverter,
|
||||
NitrogenDioxideConcentrationConverter,
|
||||
NitrogenMonoxideConcentrationConverter,
|
||||
OzoneConcentrationConverter,
|
||||
SulphurDioxideConcentrationConverter,
|
||||
UnitlessRatioConverter,
|
||||
)
|
||||
|
||||
|
||||
def _make_detected_condition(
|
||||
device_class: BinarySensorDeviceClass,
|
||||
) -> type[Condition]:
|
||||
"""Create a detected condition for a binary sensor device class."""
|
||||
return make_entity_state_condition(
|
||||
{BINARY_SENSOR_DOMAIN: DomainSpec(device_class=device_class)}, STATE_ON
|
||||
)
|
||||
|
||||
|
||||
def _make_cleared_condition(
|
||||
device_class: BinarySensorDeviceClass,
|
||||
) -> type[Condition]:
|
||||
"""Create a cleared condition for a binary sensor device class."""
|
||||
return make_entity_state_condition(
|
||||
{BINARY_SENSOR_DOMAIN: DomainSpec(device_class=device_class)}, STATE_OFF
|
||||
)
|
||||
|
||||
|
||||
CONDITIONS: dict[str, type[Condition]] = {
|
||||
# Binary sensor conditions (detected/cleared)
|
||||
"is_gas_detected": _make_detected_condition(BinarySensorDeviceClass.GAS),
|
||||
"is_gas_cleared": _make_cleared_condition(BinarySensorDeviceClass.GAS),
|
||||
"is_co_detected": _make_detected_condition(BinarySensorDeviceClass.CO),
|
||||
"is_co_cleared": _make_cleared_condition(BinarySensorDeviceClass.CO),
|
||||
"is_smoke_detected": _make_detected_condition(BinarySensorDeviceClass.SMOKE),
|
||||
"is_smoke_cleared": _make_cleared_condition(BinarySensorDeviceClass.SMOKE),
|
||||
# Numerical sensor conditions with unit conversion
|
||||
"is_co_value": make_entity_numerical_condition_with_unit(
|
||||
{SENSOR_DOMAIN: NumericalDomainSpec(device_class=SensorDeviceClass.CO)},
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CarbonMonoxideConcentrationConverter,
|
||||
),
|
||||
"is_ozone_value": make_entity_numerical_condition_with_unit(
|
||||
{SENSOR_DOMAIN: NumericalDomainSpec(device_class=SensorDeviceClass.OZONE)},
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
OzoneConcentrationConverter,
|
||||
),
|
||||
"is_voc_value": make_entity_numerical_condition_with_unit(
|
||||
{
|
||||
SENSOR_DOMAIN: NumericalDomainSpec(
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS
|
||||
)
|
||||
},
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
MassVolumeConcentrationConverter,
|
||||
),
|
||||
"is_voc_ratio_value": make_entity_numerical_condition_with_unit(
|
||||
{
|
||||
SENSOR_DOMAIN: NumericalDomainSpec(
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS
|
||||
)
|
||||
},
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
UnitlessRatioConverter,
|
||||
),
|
||||
"is_no_value": make_entity_numerical_condition_with_unit(
|
||||
{
|
||||
SENSOR_DOMAIN: NumericalDomainSpec(
|
||||
device_class=SensorDeviceClass.NITROGEN_MONOXIDE
|
||||
)
|
||||
},
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
NitrogenMonoxideConcentrationConverter,
|
||||
),
|
||||
"is_no2_value": make_entity_numerical_condition_with_unit(
|
||||
{
|
||||
SENSOR_DOMAIN: NumericalDomainSpec(
|
||||
device_class=SensorDeviceClass.NITROGEN_DIOXIDE
|
||||
)
|
||||
},
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
NitrogenDioxideConcentrationConverter,
|
||||
),
|
||||
"is_so2_value": make_entity_numerical_condition_with_unit(
|
||||
{
|
||||
SENSOR_DOMAIN: NumericalDomainSpec(
|
||||
device_class=SensorDeviceClass.SULPHUR_DIOXIDE
|
||||
)
|
||||
},
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
SulphurDioxideConcentrationConverter,
|
||||
),
|
||||
# Numerical sensor conditions without unit conversion (single-unit device classes)
|
||||
"is_co2_value": make_entity_numerical_condition(
|
||||
{SENSOR_DOMAIN: NumericalDomainSpec(device_class=SensorDeviceClass.CO2)},
|
||||
valid_unit=CONCENTRATION_PARTS_PER_MILLION,
|
||||
),
|
||||
"is_pm1_value": make_entity_numerical_condition(
|
||||
{SENSOR_DOMAIN: NumericalDomainSpec(device_class=SensorDeviceClass.PM1)},
|
||||
valid_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
"is_pm25_value": make_entity_numerical_condition(
|
||||
{SENSOR_DOMAIN: NumericalDomainSpec(device_class=SensorDeviceClass.PM25)},
|
||||
valid_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
"is_pm4_value": make_entity_numerical_condition(
|
||||
{SENSOR_DOMAIN: NumericalDomainSpec(device_class=SensorDeviceClass.PM4)},
|
||||
valid_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
"is_pm10_value": make_entity_numerical_condition(
|
||||
{SENSOR_DOMAIN: NumericalDomainSpec(device_class=SensorDeviceClass.PM10)},
|
||||
valid_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
"is_n2o_value": make_entity_numerical_condition(
|
||||
{
|
||||
SENSOR_DOMAIN: NumericalDomainSpec(
|
||||
device_class=SensorDeviceClass.NITROUS_OXIDE
|
||||
)
|
||||
},
|
||||
valid_unit=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]:
|
||||
"""Return the air quality conditions."""
|
||||
return CONDITIONS
|
||||
588
homeassistant/components/air_quality/conditions.yaml
Normal file
588
homeassistant/components/air_quality/conditions.yaml
Normal file
@@ -0,0 +1,588 @@
|
||||
# --- Common condition fields ---
|
||||
|
||||
.condition_behavior: &condition_behavior
|
||||
required: true
|
||||
default: any
|
||||
selector:
|
||||
select:
|
||||
translation_key: condition_behavior
|
||||
options:
|
||||
- all
|
||||
- any
|
||||
|
||||
# --- Number or entity selectors ---
|
||||
|
||||
.number_or_entity_co: &number_or_entity_co
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
- "mg/m³"
|
||||
- "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: carbon_monoxide
|
||||
- domain: number
|
||||
device_class: carbon_monoxide
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_co2: &number_or_entity_co2
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
unit_of_measurement: "ppm"
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement: "ppm"
|
||||
- domain: sensor
|
||||
device_class: carbon_dioxide
|
||||
- domain: number
|
||||
device_class: carbon_dioxide
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_pm1: &number_or_entity_pm1
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
unit_of_measurement: "μg/m³"
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement: "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: pm1
|
||||
- domain: number
|
||||
device_class: pm1
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_pm25: &number_or_entity_pm25
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
unit_of_measurement: "μg/m³"
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement: "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: pm25
|
||||
- domain: number
|
||||
device_class: pm25
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_pm4: &number_or_entity_pm4
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
unit_of_measurement: "μg/m³"
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement: "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: pm4
|
||||
- domain: number
|
||||
device_class: pm4
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_pm10: &number_or_entity_pm10
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
unit_of_measurement: "μg/m³"
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement: "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: pm10
|
||||
- domain: number
|
||||
device_class: pm10
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_ozone: &number_or_entity_ozone
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
- "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: ozone
|
||||
- domain: number
|
||||
device_class: ozone
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_voc: &number_or_entity_voc
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement:
|
||||
- "μg/m³"
|
||||
- "mg/m³"
|
||||
- domain: sensor
|
||||
device_class: volatile_organic_compounds
|
||||
- domain: number
|
||||
device_class: volatile_organic_compounds
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_voc_ratio: &number_or_entity_voc_ratio
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
- domain: sensor
|
||||
device_class: volatile_organic_compounds_parts
|
||||
- domain: number
|
||||
device_class: volatile_organic_compounds_parts
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_no: &number_or_entity_no
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement:
|
||||
- "ppb"
|
||||
- "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: nitrogen_monoxide
|
||||
- domain: number
|
||||
device_class: nitrogen_monoxide
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_no2: &number_or_entity_no2
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
- "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: nitrogen_dioxide
|
||||
- domain: number
|
||||
device_class: nitrogen_dioxide
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_n2o: &number_or_entity_n2o
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
unit_of_measurement: "μg/m³"
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement: "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: nitrous_oxide
|
||||
- domain: number
|
||||
device_class: nitrous_oxide
|
||||
translation_key: number_or_entity
|
||||
|
||||
.number_or_entity_so2: &number_or_entity_so2
|
||||
required: false
|
||||
selector:
|
||||
choose:
|
||||
choices:
|
||||
number:
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
entity:
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_number
|
||||
unit_of_measurement:
|
||||
- "ppb"
|
||||
- "μg/m³"
|
||||
- domain: sensor
|
||||
device_class: sulphur_dioxide
|
||||
- domain: number
|
||||
device_class: sulphur_dioxide
|
||||
translation_key: number_or_entity
|
||||
|
||||
# --- Unit selectors ---
|
||||
|
||||
.unit_co: &unit_co
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
- "mg/m³"
|
||||
- "μg/m³"
|
||||
|
||||
.unit_ozone: &unit_ozone
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
- "μg/m³"
|
||||
|
||||
.unit_no2: &unit_no2
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
- "μg/m³"
|
||||
|
||||
.unit_no: &unit_no
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "ppb"
|
||||
- "μg/m³"
|
||||
|
||||
.unit_so2: &unit_so2
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "ppb"
|
||||
- "μg/m³"
|
||||
|
||||
.unit_voc: &unit_voc
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "μg/m³"
|
||||
- "mg/m³"
|
||||
|
||||
.unit_voc_ratio: &unit_voc_ratio
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "ppb"
|
||||
- "ppm"
|
||||
|
||||
# --- Binary sensor targets ---
|
||||
|
||||
.target_gas: &target_gas
|
||||
entity:
|
||||
- domain: binary_sensor
|
||||
device_class: gas
|
||||
|
||||
.target_co_binary: &target_co_binary
|
||||
entity:
|
||||
- domain: binary_sensor
|
||||
device_class: carbon_monoxide
|
||||
|
||||
.target_smoke: &target_smoke
|
||||
entity:
|
||||
- domain: binary_sensor
|
||||
device_class: smoke
|
||||
|
||||
# --- Sensor targets ---
|
||||
|
||||
.target_co_sensor: &target_co_sensor
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: carbon_monoxide
|
||||
|
||||
.target_co2: &target_co2
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: carbon_dioxide
|
||||
|
||||
.target_pm1: &target_pm1
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: pm1
|
||||
|
||||
.target_pm25: &target_pm25
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: pm25
|
||||
|
||||
.target_pm4: &target_pm4
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: pm4
|
||||
|
||||
.target_pm10: &target_pm10
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: pm10
|
||||
|
||||
.target_ozone: &target_ozone
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: ozone
|
||||
|
||||
.target_voc: &target_voc
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: volatile_organic_compounds
|
||||
|
||||
.target_voc_ratio: &target_voc_ratio
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: volatile_organic_compounds_parts
|
||||
|
||||
.target_no: &target_no
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: nitrogen_monoxide
|
||||
|
||||
.target_no2: &target_no2
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: nitrogen_dioxide
|
||||
|
||||
.target_n2o: &target_n2o
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: nitrous_oxide
|
||||
|
||||
.target_so2: &target_so2
|
||||
entity:
|
||||
- domain: sensor
|
||||
device_class: sulphur_dioxide
|
||||
|
||||
# --- Binary sensor conditions ---
|
||||
|
||||
.condition_binary_common: &condition_binary_common
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
|
||||
is_gas_detected:
|
||||
<<: *condition_binary_common
|
||||
target: *target_gas
|
||||
|
||||
is_gas_cleared:
|
||||
<<: *condition_binary_common
|
||||
target: *target_gas
|
||||
|
||||
is_co_detected:
|
||||
<<: *condition_binary_common
|
||||
target: *target_co_binary
|
||||
|
||||
is_co_cleared:
|
||||
<<: *condition_binary_common
|
||||
target: *target_co_binary
|
||||
|
||||
is_smoke_detected:
|
||||
<<: *condition_binary_common
|
||||
target: *target_smoke
|
||||
|
||||
is_smoke_cleared:
|
||||
<<: *condition_binary_common
|
||||
target: *target_smoke
|
||||
|
||||
# --- Numerical sensor conditions with unit conversion ---
|
||||
|
||||
is_co_value:
|
||||
target: *target_co_sensor
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_co
|
||||
below: *number_or_entity_co
|
||||
unit: *unit_co
|
||||
|
||||
is_ozone_value:
|
||||
target: *target_ozone
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_ozone
|
||||
below: *number_or_entity_ozone
|
||||
unit: *unit_ozone
|
||||
|
||||
is_voc_value:
|
||||
target: *target_voc
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_voc
|
||||
below: *number_or_entity_voc
|
||||
unit: *unit_voc
|
||||
|
||||
is_voc_ratio_value:
|
||||
target: *target_voc_ratio
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_voc_ratio
|
||||
below: *number_or_entity_voc_ratio
|
||||
unit: *unit_voc_ratio
|
||||
|
||||
is_no_value:
|
||||
target: *target_no
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_no
|
||||
below: *number_or_entity_no
|
||||
unit: *unit_no
|
||||
|
||||
is_no2_value:
|
||||
target: *target_no2
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_no2
|
||||
below: *number_or_entity_no2
|
||||
unit: *unit_no2
|
||||
|
||||
is_so2_value:
|
||||
target: *target_so2
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_so2
|
||||
below: *number_or_entity_so2
|
||||
unit: *unit_so2
|
||||
|
||||
# --- Numerical sensor conditions without unit conversion ---
|
||||
|
||||
is_co2_value:
|
||||
target: *target_co2
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_co2
|
||||
below: *number_or_entity_co2
|
||||
|
||||
is_pm1_value:
|
||||
target: *target_pm1
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_pm1
|
||||
below: *number_or_entity_pm1
|
||||
|
||||
is_pm25_value:
|
||||
target: *target_pm25
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_pm25
|
||||
below: *number_or_entity_pm25
|
||||
|
||||
is_pm4_value:
|
||||
target: *target_pm4
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_pm4
|
||||
below: *number_or_entity_pm4
|
||||
|
||||
is_pm10_value:
|
||||
target: *target_pm10
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_pm10
|
||||
below: *number_or_entity_pm10
|
||||
|
||||
is_n2o_value:
|
||||
target: *target_n2o
|
||||
fields:
|
||||
behavior: *condition_behavior
|
||||
above: *number_or_entity_n2o
|
||||
below: *number_or_entity_n2o
|
||||
@@ -1,4 +1,63 @@
|
||||
{
|
||||
"conditions": {
|
||||
"is_co2_value": {
|
||||
"condition": "mdi:molecule-co2"
|
||||
},
|
||||
"is_co_cleared": {
|
||||
"condition": "mdi:check-circle"
|
||||
},
|
||||
"is_co_detected": {
|
||||
"condition": "mdi:molecule-co"
|
||||
},
|
||||
"is_co_value": {
|
||||
"condition": "mdi:molecule-co"
|
||||
},
|
||||
"is_gas_cleared": {
|
||||
"condition": "mdi:check-circle"
|
||||
},
|
||||
"is_gas_detected": {
|
||||
"condition": "mdi:gas-cylinder"
|
||||
},
|
||||
"is_n2o_value": {
|
||||
"condition": "mdi:factory"
|
||||
},
|
||||
"is_no2_value": {
|
||||
"condition": "mdi:factory"
|
||||
},
|
||||
"is_no_value": {
|
||||
"condition": "mdi:factory"
|
||||
},
|
||||
"is_ozone_value": {
|
||||
"condition": "mdi:weather-sunny-alert"
|
||||
},
|
||||
"is_pm10_value": {
|
||||
"condition": "mdi:blur"
|
||||
},
|
||||
"is_pm1_value": {
|
||||
"condition": "mdi:blur"
|
||||
},
|
||||
"is_pm25_value": {
|
||||
"condition": "mdi:blur"
|
||||
},
|
||||
"is_pm4_value": {
|
||||
"condition": "mdi:blur"
|
||||
},
|
||||
"is_smoke_cleared": {
|
||||
"condition": "mdi:check-circle"
|
||||
},
|
||||
"is_smoke_detected": {
|
||||
"condition": "mdi:smoke-detector-variant"
|
||||
},
|
||||
"is_so2_value": {
|
||||
"condition": "mdi:factory"
|
||||
},
|
||||
"is_voc_ratio_value": {
|
||||
"condition": "mdi:air-filter"
|
||||
},
|
||||
"is_voc_value": {
|
||||
"condition": "mdi:air-filter"
|
||||
}
|
||||
},
|
||||
"entity_component": {
|
||||
"_": {
|
||||
"default": "mdi:air-filter"
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"common": {
|
||||
"condition_above_description": "Require the value to be above this value.",
|
||||
"condition_above_name": "Above",
|
||||
"condition_behavior_description": "How the value should match on the targeted entities.",
|
||||
"condition_behavior_name": "Behavior",
|
||||
"condition_below_description": "Require the value to be below this value.",
|
||||
"condition_below_name": "Below",
|
||||
"condition_unit_description": "All values will be converted to this unit when evaluating the condition.",
|
||||
"condition_unit_name": "Unit of measurement",
|
||||
"trigger_behavior_description": "The behavior of the targeted entities to trigger on.",
|
||||
"trigger_behavior_name": "Behavior",
|
||||
"trigger_changed_above_name": "Above",
|
||||
@@ -13,7 +21,337 @@
|
||||
"trigger_unit_description": "All values will be converted to this unit when evaluating the trigger.",
|
||||
"trigger_unit_name": "Unit of measurement"
|
||||
},
|
||||
"conditions": {
|
||||
"is_co2_value": {
|
||||
"description": "Tests the carbon dioxide level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Carbon dioxide value"
|
||||
},
|
||||
"is_co_cleared": {
|
||||
"description": "Tests if one or more carbon monoxide sensors are cleared.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Carbon monoxide cleared"
|
||||
},
|
||||
"is_co_detected": {
|
||||
"description": "Tests if one or more carbon monoxide sensors are detecting carbon monoxide.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Carbon monoxide detected"
|
||||
},
|
||||
"is_co_value": {
|
||||
"description": "Tests the carbon monoxide level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
},
|
||||
"unit": {
|
||||
"description": "[%key:component::air_quality::common::condition_unit_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_unit_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Carbon monoxide value"
|
||||
},
|
||||
"is_gas_cleared": {
|
||||
"description": "Tests if one or more gas sensors are cleared.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Gas cleared"
|
||||
},
|
||||
"is_gas_detected": {
|
||||
"description": "Tests if one or more gas sensors are detecting gas.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Gas detected"
|
||||
},
|
||||
"is_n2o_value": {
|
||||
"description": "Tests the nitrous oxide level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Nitrous oxide value"
|
||||
},
|
||||
"is_no2_value": {
|
||||
"description": "Tests the nitrogen dioxide level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
},
|
||||
"unit": {
|
||||
"description": "[%key:component::air_quality::common::condition_unit_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_unit_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Nitrogen dioxide value"
|
||||
},
|
||||
"is_no_value": {
|
||||
"description": "Tests the nitrogen monoxide level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
},
|
||||
"unit": {
|
||||
"description": "[%key:component::air_quality::common::condition_unit_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_unit_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Nitrogen monoxide value"
|
||||
},
|
||||
"is_ozone_value": {
|
||||
"description": "Tests the ozone level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
},
|
||||
"unit": {
|
||||
"description": "[%key:component::air_quality::common::condition_unit_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_unit_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Ozone value"
|
||||
},
|
||||
"is_pm10_value": {
|
||||
"description": "Tests the PM10 level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
}
|
||||
},
|
||||
"name": "PM10 value"
|
||||
},
|
||||
"is_pm1_value": {
|
||||
"description": "Tests the PM1 level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
}
|
||||
},
|
||||
"name": "PM1 value"
|
||||
},
|
||||
"is_pm25_value": {
|
||||
"description": "Tests the PM2.5 level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
}
|
||||
},
|
||||
"name": "PM2.5 value"
|
||||
},
|
||||
"is_pm4_value": {
|
||||
"description": "Tests the PM4 level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
}
|
||||
},
|
||||
"name": "PM4 value"
|
||||
},
|
||||
"is_smoke_cleared": {
|
||||
"description": "Tests if one or more smoke sensors are cleared.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Smoke cleared"
|
||||
},
|
||||
"is_smoke_detected": {
|
||||
"description": "Tests if one or more smoke sensors are detecting smoke.",
|
||||
"fields": {
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Smoke detected"
|
||||
},
|
||||
"is_so2_value": {
|
||||
"description": "Tests the sulphur dioxide level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
},
|
||||
"unit": {
|
||||
"description": "[%key:component::air_quality::common::condition_unit_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_unit_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Sulphur dioxide value"
|
||||
},
|
||||
"is_voc_ratio_value": {
|
||||
"description": "Tests the volatile organic compounds ratio of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
},
|
||||
"unit": {
|
||||
"description": "[%key:component::air_quality::common::condition_unit_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_unit_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Volatile organic compounds ratio value"
|
||||
},
|
||||
"is_voc_value": {
|
||||
"description": "Tests the volatile organic compounds level of one or more entities.",
|
||||
"fields": {
|
||||
"above": {
|
||||
"description": "[%key:component::air_quality::common::condition_above_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_above_name%]"
|
||||
},
|
||||
"behavior": {
|
||||
"description": "[%key:component::air_quality::common::condition_behavior_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_behavior_name%]"
|
||||
},
|
||||
"below": {
|
||||
"description": "[%key:component::air_quality::common::condition_below_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_below_name%]"
|
||||
},
|
||||
"unit": {
|
||||
"description": "[%key:component::air_quality::common::condition_unit_description%]",
|
||||
"name": "[%key:component::air_quality::common::condition_unit_name%]"
|
||||
}
|
||||
},
|
||||
"name": "Volatile organic compounds value"
|
||||
}
|
||||
},
|
||||
"selector": {
|
||||
"condition_behavior": {
|
||||
"options": {
|
||||
"all": "All",
|
||||
"any": "Any"
|
||||
}
|
||||
},
|
||||
"number_or_entity": {
|
||||
"choices": {
|
||||
"entity": "Entity",
|
||||
|
||||
@@ -118,6 +118,7 @@ SERVICE_TRIGGER = "trigger"
|
||||
NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG = "new_triggers_conditions"
|
||||
|
||||
_EXPERIMENTAL_CONDITION_PLATFORMS = {
|
||||
"air_quality",
|
||||
"alarm_control_panel",
|
||||
"assist_satellite",
|
||||
"battery",
|
||||
|
||||
577
tests/components/air_quality/test_condition.py
Normal file
577
tests/components/air_quality/test_condition.py
Normal file
@@ -0,0 +1,577 @@
|
||||
"""Test air quality conditions."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONF_ABOVE,
|
||||
CONF_BELOW,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.components.common import (
|
||||
ConditionStateDescription,
|
||||
assert_condition_behavior_all,
|
||||
assert_condition_behavior_any,
|
||||
assert_condition_gated_by_labs_flag,
|
||||
assert_numerical_condition_unit_conversion,
|
||||
parametrize_condition_states_all,
|
||||
parametrize_condition_states_any,
|
||||
parametrize_numerical_condition_above_below_all,
|
||||
parametrize_numerical_condition_above_below_any,
|
||||
parametrize_target_entities,
|
||||
target_entities,
|
||||
)
|
||||
|
||||
_UGM3_CONDITION_OPTIONS = {"unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}
|
||||
_UGM3_UNIT_ATTRIBUTES = {
|
||||
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
|
||||
}
|
||||
_PPB_CONDITION_OPTIONS = {"unit": CONCENTRATION_PARTS_PER_BILLION}
|
||||
_PPB_UNIT_ATTRIBUTES = {ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION}
|
||||
_PPM_UNIT_ATTRIBUTES = {ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_MILLION}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def target_binary_sensors(hass: HomeAssistant) -> dict[str, list[str]]:
|
||||
"""Create multiple binary sensor entities associated with different targets."""
|
||||
return await target_entities(hass, "binary_sensor")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def target_sensors(hass: HomeAssistant) -> dict[str, list[str]]:
|
||||
"""Create multiple sensor entities associated with different targets."""
|
||||
return await target_entities(hass, "sensor")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"condition",
|
||||
[
|
||||
"air_quality.is_gas_detected",
|
||||
"air_quality.is_gas_cleared",
|
||||
"air_quality.is_co_detected",
|
||||
"air_quality.is_co_cleared",
|
||||
"air_quality.is_smoke_detected",
|
||||
"air_quality.is_smoke_cleared",
|
||||
"air_quality.is_co_value",
|
||||
"air_quality.is_co2_value",
|
||||
"air_quality.is_pm1_value",
|
||||
"air_quality.is_pm25_value",
|
||||
"air_quality.is_pm4_value",
|
||||
"air_quality.is_pm10_value",
|
||||
"air_quality.is_ozone_value",
|
||||
"air_quality.is_voc_value",
|
||||
"air_quality.is_voc_ratio_value",
|
||||
"air_quality.is_no_value",
|
||||
"air_quality.is_no2_value",
|
||||
"air_quality.is_n2o_value",
|
||||
"air_quality.is_so2_value",
|
||||
],
|
||||
)
|
||||
async def test_air_quality_conditions_gated_by_labs_flag(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str
|
||||
) -> None:
|
||||
"""Test the air quality conditions are gated by the labs flag."""
|
||||
await assert_condition_gated_by_labs_flag(hass, caplog, condition)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_labs_preview_features")
|
||||
@pytest.mark.parametrize(
|
||||
("condition_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("binary_sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("condition", "condition_options", "states"),
|
||||
[
|
||||
*parametrize_condition_states_any(
|
||||
condition="air_quality.is_gas_detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.GAS},
|
||||
),
|
||||
*parametrize_condition_states_any(
|
||||
condition="air_quality.is_gas_cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.GAS},
|
||||
),
|
||||
*parametrize_condition_states_any(
|
||||
condition="air_quality.is_co_detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.CO},
|
||||
),
|
||||
*parametrize_condition_states_any(
|
||||
condition="air_quality.is_co_cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.CO},
|
||||
),
|
||||
*parametrize_condition_states_any(
|
||||
condition="air_quality.is_smoke_detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.SMOKE
|
||||
},
|
||||
),
|
||||
*parametrize_condition_states_any(
|
||||
condition="air_quality.is_smoke_cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.SMOKE
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_air_quality_binary_condition_behavior_any(
|
||||
hass: HomeAssistant,
|
||||
target_binary_sensors: dict[str, list[str]],
|
||||
condition_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
condition: str,
|
||||
condition_options: dict[str, Any],
|
||||
states: list[ConditionStateDescription],
|
||||
) -> None:
|
||||
"""Test the air quality binary sensor condition with 'any' behavior."""
|
||||
await assert_condition_behavior_any(
|
||||
hass,
|
||||
target_entities=target_binary_sensors,
|
||||
condition_target_config=condition_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
condition=condition,
|
||||
condition_options=condition_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_labs_preview_features")
|
||||
@pytest.mark.parametrize(
|
||||
("condition_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("binary_sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("condition", "condition_options", "states"),
|
||||
[
|
||||
*parametrize_condition_states_all(
|
||||
condition="air_quality.is_gas_detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.GAS},
|
||||
),
|
||||
*parametrize_condition_states_all(
|
||||
condition="air_quality.is_gas_cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.GAS},
|
||||
),
|
||||
*parametrize_condition_states_all(
|
||||
condition="air_quality.is_co_detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.CO},
|
||||
),
|
||||
*parametrize_condition_states_all(
|
||||
condition="air_quality.is_co_cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={ATTR_DEVICE_CLASS: BinarySensorDeviceClass.CO},
|
||||
),
|
||||
*parametrize_condition_states_all(
|
||||
condition="air_quality.is_smoke_detected",
|
||||
target_states=[STATE_ON],
|
||||
other_states=[STATE_OFF],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.SMOKE
|
||||
},
|
||||
),
|
||||
*parametrize_condition_states_all(
|
||||
condition="air_quality.is_smoke_cleared",
|
||||
target_states=[STATE_OFF],
|
||||
other_states=[STATE_ON],
|
||||
required_filter_attributes={
|
||||
ATTR_DEVICE_CLASS: BinarySensorDeviceClass.SMOKE
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_air_quality_binary_condition_behavior_all(
|
||||
hass: HomeAssistant,
|
||||
target_binary_sensors: dict[str, list[str]],
|
||||
condition_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
condition: str,
|
||||
condition_options: dict[str, Any],
|
||||
states: list[ConditionStateDescription],
|
||||
) -> None:
|
||||
"""Test the air quality binary sensor condition with 'all' behavior."""
|
||||
await assert_condition_behavior_all(
|
||||
hass,
|
||||
target_entities=target_binary_sensors,
|
||||
condition_target_config=condition_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
condition=condition,
|
||||
condition_options=condition_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_labs_preview_features")
|
||||
@pytest.mark.parametrize(
|
||||
("condition_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("condition", "condition_options", "states"),
|
||||
[
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_co_value",
|
||||
device_class="carbon_monoxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_ozone_value",
|
||||
device_class="ozone",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_voc_value",
|
||||
device_class="volatile_organic_compounds",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_voc_ratio_value",
|
||||
device_class="volatile_organic_compounds_parts",
|
||||
condition_options=_PPB_CONDITION_OPTIONS,
|
||||
unit_attributes=_PPB_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_no_value",
|
||||
device_class="nitrogen_monoxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_no2_value",
|
||||
device_class="nitrogen_dioxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_so2_value",
|
||||
device_class="sulphur_dioxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_air_quality_numerical_with_unit_condition_behavior_any(
|
||||
hass: HomeAssistant,
|
||||
target_sensors: dict[str, list[str]],
|
||||
condition_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
condition: str,
|
||||
condition_options: dict[str, Any],
|
||||
states: list[ConditionStateDescription],
|
||||
) -> None:
|
||||
"""Test air quality numerical conditions with unit conversion and 'any' behavior."""
|
||||
await assert_condition_behavior_any(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
condition_target_config=condition_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
condition=condition,
|
||||
condition_options=condition_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_labs_preview_features")
|
||||
@pytest.mark.parametrize(
|
||||
("condition_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("condition", "condition_options", "states"),
|
||||
[
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_co_value",
|
||||
device_class="carbon_monoxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_ozone_value",
|
||||
device_class="ozone",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_voc_value",
|
||||
device_class="volatile_organic_compounds",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_voc_ratio_value",
|
||||
device_class="volatile_organic_compounds_parts",
|
||||
condition_options=_PPB_CONDITION_OPTIONS,
|
||||
unit_attributes=_PPB_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_no_value",
|
||||
device_class="nitrogen_monoxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_no2_value",
|
||||
device_class="nitrogen_dioxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_so2_value",
|
||||
device_class="sulphur_dioxide",
|
||||
condition_options=_UGM3_CONDITION_OPTIONS,
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_air_quality_numerical_with_unit_condition_behavior_all(
|
||||
hass: HomeAssistant,
|
||||
target_sensors: dict[str, list[str]],
|
||||
condition_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
condition: str,
|
||||
condition_options: dict[str, Any],
|
||||
states: list[ConditionStateDescription],
|
||||
) -> None:
|
||||
"""Test air quality numerical conditions with unit conversion and 'all' behavior."""
|
||||
await assert_condition_behavior_all(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
condition_target_config=condition_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
condition=condition,
|
||||
condition_options=condition_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_labs_preview_features")
|
||||
@pytest.mark.parametrize(
|
||||
("condition_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("condition", "condition_options", "states"),
|
||||
[
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_co2_value",
|
||||
device_class="carbon_dioxide",
|
||||
unit_attributes=_PPM_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_pm1_value",
|
||||
device_class="pm1",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_pm25_value",
|
||||
device_class="pm25",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_pm4_value",
|
||||
device_class="pm4",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_pm10_value",
|
||||
device_class="pm10",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_any(
|
||||
"air_quality.is_n2o_value",
|
||||
device_class="nitrous_oxide",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_air_quality_numerical_no_unit_condition_behavior_any(
|
||||
hass: HomeAssistant,
|
||||
target_sensors: dict[str, list[str]],
|
||||
condition_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
condition: str,
|
||||
condition_options: dict[str, Any],
|
||||
states: list[ConditionStateDescription],
|
||||
) -> None:
|
||||
"""Test air quality numerical conditions without unit conversion and 'any' behavior."""
|
||||
await assert_condition_behavior_any(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
condition_target_config=condition_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
condition=condition,
|
||||
condition_options=condition_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_labs_preview_features")
|
||||
@pytest.mark.parametrize(
|
||||
("condition_target_config", "entity_id", "entities_in_target"),
|
||||
parametrize_target_entities("sensor"),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("condition", "condition_options", "states"),
|
||||
[
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_co2_value",
|
||||
device_class="carbon_dioxide",
|
||||
unit_attributes=_PPM_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_pm1_value",
|
||||
device_class="pm1",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_pm25_value",
|
||||
device_class="pm25",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_pm4_value",
|
||||
device_class="pm4",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_pm10_value",
|
||||
device_class="pm10",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
*parametrize_numerical_condition_above_below_all(
|
||||
"air_quality.is_n2o_value",
|
||||
device_class="nitrous_oxide",
|
||||
unit_attributes=_UGM3_UNIT_ATTRIBUTES,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_air_quality_numerical_no_unit_condition_behavior_all(
|
||||
hass: HomeAssistant,
|
||||
target_sensors: dict[str, list[str]],
|
||||
condition_target_config: dict,
|
||||
entity_id: str,
|
||||
entities_in_target: int,
|
||||
condition: str,
|
||||
condition_options: dict[str, Any],
|
||||
states: list[ConditionStateDescription],
|
||||
) -> None:
|
||||
"""Test air quality numerical conditions without unit conversion and 'all' behavior."""
|
||||
await assert_condition_behavior_all(
|
||||
hass,
|
||||
target_entities=target_sensors,
|
||||
condition_target_config=condition_target_config,
|
||||
entity_id=entity_id,
|
||||
entities_in_target=entities_in_target,
|
||||
condition=condition,
|
||||
condition_options=condition_options,
|
||||
states=states,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("enable_labs_preview_features")
|
||||
async def test_air_quality_condition_unit_conversion_co(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test that the CO condition converts units correctly."""
|
||||
_unit_ugm3 = {ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}
|
||||
_unit_ppm = {ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_MILLION}
|
||||
_unit_invalid = {ATTR_UNIT_OF_MEASUREMENT: "not_a_valid_unit"}
|
||||
|
||||
await assert_numerical_condition_unit_conversion(
|
||||
hass,
|
||||
condition="air_quality.is_co_value",
|
||||
entity_id="sensor.test",
|
||||
pass_states=[
|
||||
{
|
||||
"state": "500",
|
||||
"attributes": {
|
||||
"device_class": "carbon_monoxide",
|
||||
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
},
|
||||
}
|
||||
],
|
||||
fail_states=[
|
||||
{
|
||||
"state": "100",
|
||||
"attributes": {
|
||||
"device_class": "carbon_monoxide",
|
||||
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
},
|
||||
}
|
||||
],
|
||||
numerical_condition_options=[
|
||||
{
|
||||
CONF_ABOVE: 0.2,
|
||||
CONF_BELOW: 0.8,
|
||||
"unit": CONCENTRATION_PARTS_PER_MILLION,
|
||||
},
|
||||
{
|
||||
CONF_ABOVE: 200,
|
||||
CONF_BELOW: 800,
|
||||
"unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
},
|
||||
],
|
||||
limit_entity_condition_options={
|
||||
CONF_ABOVE: "sensor.above",
|
||||
CONF_BELOW: "sensor.below",
|
||||
},
|
||||
limit_entities=("sensor.above", "sensor.below"),
|
||||
limit_entity_states=[
|
||||
(
|
||||
{"state": "0.2", "attributes": _unit_ppm},
|
||||
{"state": "0.8", "attributes": _unit_ppm},
|
||||
),
|
||||
(
|
||||
{"state": "200", "attributes": _unit_ugm3},
|
||||
{"state": "800", "attributes": _unit_ugm3},
|
||||
),
|
||||
],
|
||||
invalid_limit_entity_states=[
|
||||
(
|
||||
{"state": "0.2", "attributes": _unit_invalid},
|
||||
{"state": "0.8", "attributes": _unit_invalid},
|
||||
),
|
||||
(
|
||||
{"state": "200", "attributes": _unit_invalid},
|
||||
{"state": "800", "attributes": _unit_invalid},
|
||||
),
|
||||
],
|
||||
)
|
||||
Reference in New Issue
Block a user