1 """Provides device conditions for sensors."""
3 from __future__
import annotations
5 import voluptuous
as vol
8 InvalidDeviceAutomationConfig,
9 async_get_entity_registry_entry_or_raise,
22 config_validation
as cv,
23 entity_registry
as er,
28 get_unit_of_measurement,
32 from .
import ATTR_STATE_CLASS, DOMAIN, SensorDeviceClass
34 DEVICE_CLASS_NONE =
"none"
36 CONF_IS_APPARENT_POWER =
"is_apparent_power"
37 CONF_IS_AQI =
"is_aqi"
38 CONF_IS_AREA =
"is_area"
39 CONF_IS_ATMOSPHERIC_PRESSURE =
"is_atmospheric_pressure"
40 CONF_IS_BATTERY_LEVEL =
"is_battery_level"
41 CONF_IS_BLOOD_GLUCOSE_CONCENTRATION =
"is_blood_glucose_concentration"
42 CONF_IS_CO =
"is_carbon_monoxide"
43 CONF_IS_CO2 =
"is_carbon_dioxide"
44 CONF_IS_CONDUCTIVITY =
"is_conductivity"
45 CONF_IS_CURRENT =
"is_current"
46 CONF_IS_DATA_RATE =
"is_data_rate"
47 CONF_IS_DATA_SIZE =
"is_data_size"
48 CONF_IS_DISTANCE =
"is_distance"
49 CONF_IS_DURATION =
"is_duration"
50 CONF_IS_ENERGY =
"is_energy"
51 CONF_IS_FREQUENCY =
"is_frequency"
52 CONF_IS_HUMIDITY =
"is_humidity"
53 CONF_IS_GAS =
"is_gas"
54 CONF_IS_ILLUMINANCE =
"is_illuminance"
55 CONF_IS_IRRADIANCE =
"is_irradiance"
56 CONF_IS_MOISTURE =
"is_moisture"
57 CONF_IS_MONETARY =
"is_monetary"
58 CONF_IS_NITROGEN_DIOXIDE =
"is_nitrogen_dioxide"
59 CONF_IS_NITROGEN_MONOXIDE =
"is_nitrogen_monoxide"
60 CONF_IS_NITROUS_OXIDE =
"is_nitrous_oxide"
61 CONF_IS_OZONE =
"is_ozone"
63 CONF_IS_PM1 =
"is_pm1"
64 CONF_IS_PM10 =
"is_pm10"
65 CONF_IS_PM25 =
"is_pm25"
66 CONF_IS_POWER =
"is_power"
67 CONF_IS_POWER_FACTOR =
"is_power_factor"
68 CONF_IS_PRECIPITATION =
"is_precipitation"
69 CONF_IS_PRECIPITATION_INTENSITY =
"is_precipitation_intensity"
70 CONF_IS_PRESSURE =
"is_pressure"
71 CONF_IS_SPEED =
"is_speed"
72 CONF_IS_REACTIVE_POWER =
"is_reactive_power"
73 CONF_IS_SIGNAL_STRENGTH =
"is_signal_strength"
74 CONF_IS_SOUND_PRESSURE =
"is_sound_pressure"
75 CONF_IS_SULPHUR_DIOXIDE =
"is_sulphur_dioxide"
76 CONF_IS_TEMPERATURE =
"is_temperature"
77 CONF_IS_VALUE =
"is_value"
78 CONF_IS_VOLATILE_ORGANIC_COMPOUNDS =
"is_volatile_organic_compounds"
79 CONF_IS_VOLATILE_ORGANIC_COMPOUNDS_PARTS =
"is_volatile_organic_compounds_parts"
80 CONF_IS_VOLTAGE =
"is_voltage"
81 CONF_IS_VOLUME =
"is_volume"
82 CONF_IS_VOLUME_FLOW_RATE =
"is_volume_flow_rate"
83 CONF_IS_WATER =
"is_water"
84 CONF_IS_WEIGHT =
"is_weight"
85 CONF_IS_WIND_SPEED =
"is_wind_speed"
88 SensorDeviceClass.APPARENT_POWER: [{CONF_TYPE: CONF_IS_APPARENT_POWER}],
89 SensorDeviceClass.AQI: [{CONF_TYPE: CONF_IS_AQI}],
90 SensorDeviceClass.AREA: [{CONF_TYPE: CONF_IS_AREA}],
91 SensorDeviceClass.ATMOSPHERIC_PRESSURE: [{CONF_TYPE: CONF_IS_ATMOSPHERIC_PRESSURE}],
92 SensorDeviceClass.BATTERY: [{CONF_TYPE: CONF_IS_BATTERY_LEVEL}],
93 SensorDeviceClass.BLOOD_GLUCOSE_CONCENTRATION: [
94 {CONF_TYPE: CONF_IS_BLOOD_GLUCOSE_CONCENTRATION}
96 SensorDeviceClass.CO: [{CONF_TYPE: CONF_IS_CO}],
97 SensorDeviceClass.CO2: [{CONF_TYPE: CONF_IS_CO2}],
98 SensorDeviceClass.CONDUCTIVITY: [{CONF_TYPE: CONF_IS_CONDUCTIVITY}],
99 SensorDeviceClass.CURRENT: [{CONF_TYPE: CONF_IS_CURRENT}],
100 SensorDeviceClass.DATA_RATE: [{CONF_TYPE: CONF_IS_DATA_RATE}],
101 SensorDeviceClass.DATA_SIZE: [{CONF_TYPE: CONF_IS_DATA_SIZE}],
102 SensorDeviceClass.DISTANCE: [{CONF_TYPE: CONF_IS_DISTANCE}],
103 SensorDeviceClass.DURATION: [{CONF_TYPE: CONF_IS_DURATION}],
104 SensorDeviceClass.ENERGY: [{CONF_TYPE: CONF_IS_ENERGY}],
105 SensorDeviceClass.ENERGY_STORAGE: [{CONF_TYPE: CONF_IS_ENERGY}],
106 SensorDeviceClass.FREQUENCY: [{CONF_TYPE: CONF_IS_FREQUENCY}],
107 SensorDeviceClass.GAS: [{CONF_TYPE: CONF_IS_GAS}],
108 SensorDeviceClass.HUMIDITY: [{CONF_TYPE: CONF_IS_HUMIDITY}],
109 SensorDeviceClass.ILLUMINANCE: [{CONF_TYPE: CONF_IS_ILLUMINANCE}],
110 SensorDeviceClass.IRRADIANCE: [{CONF_TYPE: CONF_IS_IRRADIANCE}],
111 SensorDeviceClass.MOISTURE: [{CONF_TYPE: CONF_IS_MOISTURE}],
112 SensorDeviceClass.MONETARY: [{CONF_TYPE: CONF_IS_MONETARY}],
113 SensorDeviceClass.NITROGEN_DIOXIDE: [{CONF_TYPE: CONF_IS_NITROGEN_DIOXIDE}],
114 SensorDeviceClass.NITROGEN_MONOXIDE: [{CONF_TYPE: CONF_IS_NITROGEN_MONOXIDE}],
115 SensorDeviceClass.NITROUS_OXIDE: [{CONF_TYPE: CONF_IS_NITROUS_OXIDE}],
116 SensorDeviceClass.OZONE: [{CONF_TYPE: CONF_IS_OZONE}],
117 SensorDeviceClass.POWER: [{CONF_TYPE: CONF_IS_POWER}],
118 SensorDeviceClass.POWER_FACTOR: [{CONF_TYPE: CONF_IS_POWER_FACTOR}],
119 SensorDeviceClass.PH: [{CONF_TYPE: CONF_IS_PH}],
120 SensorDeviceClass.PM1: [{CONF_TYPE: CONF_IS_PM1}],
121 SensorDeviceClass.PM10: [{CONF_TYPE: CONF_IS_PM10}],
122 SensorDeviceClass.PM25: [{CONF_TYPE: CONF_IS_PM25}],
123 SensorDeviceClass.PRECIPITATION: [{CONF_TYPE: CONF_IS_PRECIPITATION}],
124 SensorDeviceClass.PRECIPITATION_INTENSITY: [
125 {CONF_TYPE: CONF_IS_PRECIPITATION_INTENSITY}
127 SensorDeviceClass.PRESSURE: [{CONF_TYPE: CONF_IS_PRESSURE}],
128 SensorDeviceClass.REACTIVE_POWER: [{CONF_TYPE: CONF_IS_REACTIVE_POWER}],
129 SensorDeviceClass.SIGNAL_STRENGTH: [{CONF_TYPE: CONF_IS_SIGNAL_STRENGTH}],
130 SensorDeviceClass.SOUND_PRESSURE: [{CONF_TYPE: CONF_IS_SOUND_PRESSURE}],
131 SensorDeviceClass.SPEED: [{CONF_TYPE: CONF_IS_SPEED}],
132 SensorDeviceClass.SULPHUR_DIOXIDE: [{CONF_TYPE: CONF_IS_SULPHUR_DIOXIDE}],
133 SensorDeviceClass.TEMPERATURE: [{CONF_TYPE: CONF_IS_TEMPERATURE}],
134 SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: [
135 {CONF_TYPE: CONF_IS_VOLATILE_ORGANIC_COMPOUNDS}
137 SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS: [
138 {CONF_TYPE: CONF_IS_VOLATILE_ORGANIC_COMPOUNDS_PARTS}
140 SensorDeviceClass.VOLTAGE: [{CONF_TYPE: CONF_IS_VOLTAGE}],
141 SensorDeviceClass.VOLUME: [{CONF_TYPE: CONF_IS_VOLUME}],
142 SensorDeviceClass.VOLUME_STORAGE: [{CONF_TYPE: CONF_IS_VOLUME}],
143 SensorDeviceClass.VOLUME_FLOW_RATE: [{CONF_TYPE: CONF_IS_VOLUME_FLOW_RATE}],
144 SensorDeviceClass.WATER: [{CONF_TYPE: CONF_IS_WATER}],
145 SensorDeviceClass.WEIGHT: [{CONF_TYPE: CONF_IS_WEIGHT}],
146 SensorDeviceClass.WIND_SPEED: [{CONF_TYPE: CONF_IS_WIND_SPEED}],
147 DEVICE_CLASS_NONE: [{CONF_TYPE: CONF_IS_VALUE}],
150 CONDITION_SCHEMA = vol.All(
151 cv.DEVICE_CONDITION_BASE_SCHEMA.extend(
153 vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid,
154 vol.Required(CONF_TYPE): vol.In(
156 CONF_IS_APPARENT_POWER,
159 CONF_IS_ATMOSPHERIC_PRESSURE,
160 CONF_IS_BATTERY_LEVEL,
161 CONF_IS_BLOOD_GLUCOSE_CONCENTRATION,
164 CONF_IS_CONDUCTIVITY,
178 CONF_IS_NITROGEN_DIOXIDE,
179 CONF_IS_NITROGEN_MONOXIDE,
180 CONF_IS_NITROUS_OXIDE,
183 CONF_IS_POWER_FACTOR,
188 CONF_IS_PRECIPITATION,
189 CONF_IS_PRECIPITATION_INTENSITY,
191 CONF_IS_REACTIVE_POWER,
192 CONF_IS_SIGNAL_STRENGTH,
193 CONF_IS_SOUND_PRESSURE,
195 CONF_IS_SULPHUR_DIOXIDE,
197 CONF_IS_VOLATILE_ORGANIC_COMPOUNDS,
198 CONF_IS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
201 CONF_IS_VOLUME_FLOW_RATE,
208 vol.Optional(CONF_BELOW): vol.Any(vol.Coerce(float)),
209 vol.Optional(CONF_ABOVE): vol.Any(vol.Coerce(float)),
212 cv.has_at_least_one_key(CONF_BELOW, CONF_ABOVE),
217 hass: HomeAssistant, device_id: str
218 ) -> list[dict[str, str]]:
219 """List device conditions."""
220 conditions: list[dict[str, str]] = []
221 entity_registry = er.async_get(hass)
224 for entry
in er.async_entries_for_device(entity_registry, device_id)
225 if entry.domain == DOMAIN
228 for entry
in entries:
230 state_class =
get_capability(hass, entry.entity_id, ATTR_STATE_CLASS)
233 if not unit_of_measurement
and not state_class:
236 templates = ENTITY_CONDITIONS.get(
237 device_class, ENTITY_CONDITIONS[DEVICE_CLASS_NONE]
243 "condition":
"device",
244 "device_id": device_id,
245 "entity_id": entry.id,
248 for template
in templates
256 hass: HomeAssistant, config: ConfigType
257 ) -> condition.ConditionCheckerType:
258 """Evaluate state based on configuration."""
259 numeric_state_config = {
260 CONF_CONDITION:
"numeric_state",
261 CONF_ENTITY_ID: config[CONF_ENTITY_ID],
263 if CONF_ABOVE
in config:
264 numeric_state_config[CONF_ABOVE] = config[CONF_ABOVE]
265 if CONF_BELOW
in config:
266 numeric_state_config[CONF_BELOW] = config[CONF_BELOW]
268 numeric_state_config = cv.NUMERIC_STATE_CONDITION_SCHEMA(numeric_state_config)
269 numeric_state_config = condition.numeric_state_validate_config(
270 hass, numeric_state_config
272 return condition.async_numeric_state_from_config(numeric_state_config)
276 hass: HomeAssistant, config: ConfigType
277 ) -> dict[str, vol.Schema]:
278 """List condition capabilities."""
283 except HomeAssistantError:
284 unit_of_measurement =
None
286 if not unit_of_measurement:
288 "No unit of measurement found for condition entity {config[CONF_ENTITY_ID]}"
292 "extra_fields": vol.Schema(
295 CONF_ABOVE, description={
"suffix": unit_of_measurement}
296 ): vol.Coerce(float),
298 CONF_BELOW, description={
"suffix": unit_of_measurement}
299 ): vol.Coerce(float),
er.RegistryEntry async_get_entity_registry_entry_or_raise(HomeAssistant hass, str entity_registry_id)
condition.ConditionCheckerType async_condition_from_config(HomeAssistant hass, ConfigType config)
list[dict[str, str]] async_get_conditions(HomeAssistant hass, str device_id)
dict[str, vol.Schema] async_get_condition_capabilities(HomeAssistant hass, ConfigType config)
str|None get_device_class(HomeAssistant hass, str entity_id)
Any|None get_capability(HomeAssistant hass, str entity_id, str capability)
str|None get_unit_of_measurement(HomeAssistant hass, str entity_id)