1 """Support for the Environment Canada weather service."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
12 SensorEntityDescription,
30 from .
import device_info
31 from .const
import ATTR_STATION, DOMAIN
33 ATTR_TIME =
"alert time"
36 @dataclass(frozen=True, kw_only=True)
38 """Describes Environment Canada sensor entity."""
40 value_fn: Callable[[Any], Any]
41 transform: Callable[[Any], Any] |
None =
None
44 SENSOR_TYPES: tuple[ECSensorEntityDescription, ...] = (
47 translation_key=
"condition",
48 value_fn=
lambda data: data.conditions.get(
"condition", {}).
get(
"value"),
52 translation_key=
"dewpoint",
53 device_class=SensorDeviceClass.TEMPERATURE,
54 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
55 state_class=SensorStateClass.MEASUREMENT,
56 value_fn=
lambda data: data.conditions.get(
"dewpoint", {}).
get(
"value"),
60 translation_key=
"high_temp",
61 device_class=SensorDeviceClass.TEMPERATURE,
62 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
63 state_class=SensorStateClass.MEASUREMENT,
64 value_fn=
lambda data: data.conditions.get(
"high_temp", {}).
get(
"value"),
68 translation_key=
"humidex",
69 device_class=SensorDeviceClass.TEMPERATURE,
70 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
71 state_class=SensorStateClass.MEASUREMENT,
72 value_fn=
lambda data: data.conditions.get(
"humidex", {}).
get(
"value"),
76 device_class=SensorDeviceClass.HUMIDITY,
77 native_unit_of_measurement=PERCENTAGE,
78 state_class=SensorStateClass.MEASUREMENT,
79 value_fn=
lambda data: data.conditions.get(
"humidity", {}).
get(
"value"),
83 translation_key=
"icon_code",
85 value_fn=
lambda data: data.conditions.get(
"icon_code", {}).
get(
"value"),
89 translation_key=
"low_temp",
90 name=
"Low temperature",
91 device_class=SensorDeviceClass.TEMPERATURE,
92 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
93 state_class=SensorStateClass.MEASUREMENT,
94 value_fn=
lambda data: data.conditions.get(
"low_temp", {}).
get(
"value"),
98 translation_key=
"normal_high",
99 device_class=SensorDeviceClass.TEMPERATURE,
100 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
101 value_fn=
lambda data: data.conditions.get(
"normal_high", {}).
get(
"value"),
105 translation_key=
"normal_low",
106 device_class=SensorDeviceClass.TEMPERATURE,
107 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
108 value_fn=
lambda data: data.conditions.get(
"normal_low", {}).
get(
"value"),
112 translation_key=
"pop",
113 native_unit_of_measurement=PERCENTAGE,
114 value_fn=
lambda data: data.conditions.get(
"pop", {}).
get(
"value"),
118 translation_key=
"pressure",
119 device_class=SensorDeviceClass.PRESSURE,
120 native_unit_of_measurement=UnitOfPressure.KPA,
121 state_class=SensorStateClass.MEASUREMENT,
122 value_fn=
lambda data: data.conditions.get(
"pressure", {}).
get(
"value"),
126 device_class=SensorDeviceClass.TEMPERATURE,
127 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
128 state_class=SensorStateClass.MEASUREMENT,
129 value_fn=
lambda data: data.conditions.get(
"temperature", {}).
get(
"value"),
133 translation_key=
"tendency",
134 value_fn=
lambda data: data.conditions.get(
"tendency", {}).
get(
"value"),
135 transform=
lambda val:
str(val).capitalize(),
139 translation_key=
"text_summary",
140 value_fn=
lambda data: data.conditions.get(
"text_summary", {}).
get(
"value"),
141 transform=
lambda val: val[:255],
145 translation_key=
"timestamp",
146 device_class=SensorDeviceClass.TIMESTAMP,
147 value_fn=
lambda data: data.metadata.get(
"timestamp"),
151 translation_key=
"uv_index",
152 native_unit_of_measurement=UV_INDEX,
153 state_class=SensorStateClass.MEASUREMENT,
154 value_fn=
lambda data: data.conditions.get(
"uv_index", {}).
get(
"value"),
158 translation_key=
"visibility",
159 native_unit_of_measurement=UnitOfLength.KILOMETERS,
160 device_class=SensorDeviceClass.DISTANCE,
161 state_class=SensorStateClass.MEASUREMENT,
162 value_fn=
lambda data: data.conditions.get(
"visibility", {}).
get(
"value"),
166 translation_key=
"wind_bearing",
167 native_unit_of_measurement=DEGREE,
168 value_fn=
lambda data: data.conditions.get(
"wind_bearing", {}).
get(
"value"),
172 translation_key=
"wind_chill",
173 device_class=SensorDeviceClass.TEMPERATURE,
174 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
175 state_class=SensorStateClass.MEASUREMENT,
176 value_fn=
lambda data: data.conditions.get(
"wind_chill", {}).
get(
"value"),
180 translation_key=
"wind_dir",
181 value_fn=
lambda data: data.conditions.get(
"wind_dir", {}).
get(
"value"),
185 translation_key=
"wind_gust",
186 native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
187 device_class=SensorDeviceClass.WIND_SPEED,
188 state_class=SensorStateClass.MEASUREMENT,
189 value_fn=
lambda data: data.conditions.get(
"wind_gust", {}).
get(
"value"),
193 native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
194 device_class=SensorDeviceClass.WIND_SPEED,
195 state_class=SensorStateClass.MEASUREMENT,
196 value_fn=
lambda data: data.conditions.get(
"wind_speed", {}).
get(
"value"),
202 if (aqhi := data.current)
is not None:
204 if data.forecasts
and (hourly := data.forecasts.get(
"hourly"))
is not None:
205 if values :=
list(hourly.values()):
212 translation_key=
"aqhi",
213 device_class=SensorDeviceClass.AQI,
214 state_class=SensorStateClass.MEASUREMENT,
215 value_fn=_get_aqhi_value,
218 ALERT_TYPES: tuple[ECSensorEntityDescription, ...] = (
221 translation_key=
"advisories",
222 value_fn=
lambda data: data.alerts.get(
"advisories", {}).
get(
"value"),
227 translation_key=
"endings",
228 value_fn=
lambda data: data.alerts.get(
"endings", {}).
get(
"value"),
233 translation_key=
"statements",
234 value_fn=
lambda data: data.alerts.get(
"statements", {}).
get(
"value"),
239 translation_key=
"warnings",
240 value_fn=
lambda data: data.alerts.get(
"warnings", {}).
get(
"value"),
245 translation_key=
"watches",
246 value_fn=
lambda data: data.alerts.get(
"watches", {}).
get(
"value"),
254 config_entry: ConfigEntry,
255 async_add_entities: AddEntitiesCallback,
257 """Add a weather entity from a config_entry."""
258 coordinator = hass.data[DOMAIN][config_entry.entry_id][
"weather_coordinator"]
259 sensors: list[ECBaseSensor] = [
ECSensor(coordinator, desc)
for desc
in SENSOR_TYPES]
260 sensors.extend([
ECAlertSensor(coordinator, desc)
for desc
in ALERT_TYPES])
261 aqhi_coordinator = hass.data[DOMAIN][config_entry.entry_id][
"aqhi_coordinator"]
262 sensors.append(
ECSensor(aqhi_coordinator, AQHI_SENSOR))
267 """Environment Canada sensor base."""
269 entity_description: ECSensorEntityDescription
270 _attr_has_entity_name =
True
273 """Initialize the base sensor."""
278 self.
_attr_unique_id_attr_unique_id = f
"{coordinator.config_entry.title}-{description.key}"
283 """Return the native value of the sensor."""
291 """Environment Canada sensor for conditions."""
294 """Initialize the sensor."""
295 super().
__init__(coordinator, description)
297 ATTR_LOCATION: self.
_ec_data_ec_data.metadata.get(
"location"),
298 ATTR_STATION: self.
_ec_data_ec_data.metadata.get(
"station"),
303 """Environment Canada sensor for alerts."""
307 """Return the extra state attributes."""
312 extra_state_attrs = {
313 ATTR_LOCATION: self.
_ec_data_ec_data.metadata.get(
"location"),
314 ATTR_STATION: self.
_ec_data_ec_data.metadata.get(
"station"),
316 for index, alert
in enumerate(value, start=1):
317 extra_state_attrs[f
"alert_{index}"] = alert.get(
"title")
318 extra_state_attrs[f
"alert_time_{index}"] = alert.get(
"date")
320 return extra_state_attrs
def extra_state_attributes(self)
def __init__(self, coordinator, description)
_attr_extra_state_attributes
def __init__(self, coordinator, description)
DeviceInfo|None device_info(self)
web.Response get(self, web.Request request, str config_key)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
def _get_aqhi_value(data)