1 """Support for Meteo-France raining forecast sensor."""
3 from __future__
import annotations
5 from dataclasses
import dataclass
8 from meteofrance_api.helpers
import (
9 get_warning_text_status_from_indice_color,
10 readeable_phenomenoms_dict,
12 from meteofrance_api.model.forecast
import Forecast
13 from meteofrance_api.model.rain
import Rain
14 from meteofrance_api.model.warning
import CurrentPhenomenons
19 SensorEntityDescription,
26 UnitOfPrecipitationDepth,
36 DataUpdateCoordinator,
41 ATTR_NEXT_RAIN_1_HOUR_FORECAST,
42 ATTR_NEXT_RAIN_DT_REF,
53 @dataclass(frozen=True, kw_only=True)
55 """Describes Meteo-France sensor entity."""
60 SENSOR_TYPES: tuple[MeteoFranceSensorEntityDescription, ...] = (
64 native_unit_of_measurement=UnitOfPressure.HPA,
65 device_class=SensorDeviceClass.PRESSURE,
66 state_class=SensorStateClass.MEASUREMENT,
67 entity_registry_enabled_default=
False,
68 data_path=
"current_forecast:sea_level",
73 native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
74 device_class=SensorDeviceClass.WIND_SPEED,
75 state_class=SensorStateClass.MEASUREMENT,
76 icon=
"mdi:weather-windy-variant",
77 entity_registry_enabled_default=
False,
78 data_path=
"current_forecast:wind:gust",
83 native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
84 device_class=SensorDeviceClass.WIND_SPEED,
85 state_class=SensorStateClass.MEASUREMENT,
86 entity_registry_enabled_default=
False,
87 data_path=
"current_forecast:wind:speed",
92 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
93 device_class=SensorDeviceClass.TEMPERATURE,
94 state_class=SensorStateClass.MEASUREMENT,
95 entity_registry_enabled_default=
False,
96 data_path=
"current_forecast:T:value",
101 native_unit_of_measurement=UV_INDEX,
102 icon=
"mdi:sunglasses",
103 data_path=
"today_forecast:uv",
107 name=
"Daily precipitation",
108 native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
109 device_class=SensorDeviceClass.PRECIPITATION,
110 data_path=
"today_forecast:precipitation:24h",
115 native_unit_of_measurement=PERCENTAGE,
116 icon=
"mdi:weather-partly-cloudy",
117 data_path=
"current_forecast:clouds",
120 key=
"original_condition",
121 name=
"Original condition",
122 entity_registry_enabled_default=
False,
123 data_path=
"current_forecast:weather:desc",
126 key=
"daily_original_condition",
127 name=
"Daily original condition",
128 entity_registry_enabled_default=
False,
129 data_path=
"today_forecast:weather12H:desc",
134 native_unit_of_measurement=PERCENTAGE,
135 device_class=SensorDeviceClass.HUMIDITY,
136 state_class=SensorStateClass.MEASUREMENT,
137 data_path=
"current_forecast:humidity",
141 SENSOR_TYPES_RAIN: tuple[MeteoFranceSensorEntityDescription, ...] = (
145 device_class=SensorDeviceClass.TIMESTAMP,
150 SENSOR_TYPES_ALERT: tuple[MeteoFranceSensorEntityDescription, ...] = (
153 name=
"Weather alert",
154 icon=
"mdi:weather-cloudy-alert",
159 SENSOR_TYPES_PROBABILITY: tuple[MeteoFranceSensorEntityDescription, ...] = (
163 native_unit_of_measurement=PERCENTAGE,
164 icon=
"mdi:weather-rainy",
165 data_path=
"probability_forecast:rain:3h",
170 native_unit_of_measurement=PERCENTAGE,
171 icon=
"mdi:weather-snowy",
172 data_path=
"probability_forecast:snow:3h",
176 name=
"Freeze chance",
177 native_unit_of_measurement=PERCENTAGE,
178 icon=
"mdi:snowflake",
179 data_path=
"probability_forecast:freezing",
185 hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
187 """Set up the Meteo-France sensor platform."""
188 data = hass.data[DOMAIN][entry.entry_id]
189 coordinator_forecast: DataUpdateCoordinator[Forecast] = data[COORDINATOR_FORECAST]
190 coordinator_rain: DataUpdateCoordinator[Rain] |
None = data[COORDINATOR_RAIN]
191 coordinator_alert: DataUpdateCoordinator[CurrentPhenomenons] |
None = data.get(
195 entities: list[MeteoFranceSensor[Any]] = [
197 for description
in SENSOR_TYPES
204 for description
in SENSOR_TYPES_RAIN
208 if coordinator_alert:
212 for description
in SENSOR_TYPES_ALERT
216 if coordinator_forecast.data.probability_forecast:
220 for description
in SENSOR_TYPES_PROBABILITY
228 CoordinatorEntity[DataUpdateCoordinator[_DataT]], SensorEntity
230 """Representation of a Meteo-France sensor."""
232 entity_description: MeteoFranceSensorEntityDescription
233 _attr_attribution = ATTRIBUTION
237 coordinator: DataUpdateCoordinator[_DataT],
238 description: MeteoFranceSensorEntityDescription,
240 """Initialize the Meteo-France sensor."""
242 self.entity_description = description
243 if hasattr(coordinator.data,
"position"):
244 city_name = coordinator.data.position[
"name"]
245 self._attr_name = f
"{city_name} {description.name}"
246 self._attr_unique_id = f
"{coordinator.data.position['lat']},{coordinator.data.position['lon']}_{description.key}"
250 """Return the device info."""
251 assert self.platform.config_entry
and self.platform.config_entry.unique_id
253 entry_type=DeviceEntryType.SERVICE,
254 identifiers={(DOMAIN, self.platform.config_entry.unique_id)},
255 manufacturer=MANUFACTURER,
257 name=self.coordinator.name,
262 """Return the state."""
263 path = self.entity_description.data_path.split(
":")
264 data = getattr(self.coordinator.data, path[0])
267 if path[0] ==
"probability_forecast":
272 value = data[0][path[1]]
276 value = data[path[1]][path[2]]
278 value = data[path[1]]
280 if self.entity_description.key
in (
"wind_speed",
"wind_gust"):
282 value = round(value * 3.6)
287 """Representation of a Meteo-France rain sensor."""
291 """Return the state."""
294 (cadran
for cadran
in self.coordinator.data.forecast
if cadran[
"rain"] > 1),
297 return dt_util.utc_from_timestamp(next_rain[
"dt"])
if next_rain
else None
301 """Return the state attributes."""
302 reference_dt = self.coordinator.data.forecast[0][
"dt"]
304 ATTR_NEXT_RAIN_DT_REF: dt_util.utc_from_timestamp(reference_dt).isoformat(),
305 ATTR_NEXT_RAIN_1_HOUR_FORECAST: {
306 f
"{int((item['dt'] - reference_dt) / 60)} min": item[
"desc"]
307 for item
in self.coordinator.data.forecast
313 """Representation of a Meteo-France alert sensor."""
317 coordinator: DataUpdateCoordinator[CurrentPhenomenons],
318 description: MeteoFranceSensorEntityDescription,
320 """Initialize the Meteo-France sensor."""
321 super().
__init__(coordinator, description)
322 dept_code = self.coordinator.data.domain_id
323 self.
_attr_name_attr_name = f
"{dept_code} {description.name}"
328 """Return the state."""
329 return get_warning_text_status_from_indice_color(
330 self.coordinator.data.get_domain_max_color()
335 """Return the state attributes."""
337 **readeable_phenomenoms_dict(self.coordinator.data.phenomenons_max_colors),
342 probability_forecast: list, path: list
344 """Search the first not None value in the first forecast elements."""
345 for forecast
in probability_forecast[0:3]:
346 if forecast[path[1]][path[2]]
is not None:
347 return forecast[path[1]][path[2]]
None __init__(self, DataUpdateCoordinator[CurrentPhenomenons] coordinator, MeteoFranceSensorEntityDescription description)
str|None native_value(self)
def extra_state_attributes(self)
dict[str, Any] extra_state_attributes(self)
None __init__(self, DataUpdateCoordinator[_DataT] coordinator, MeteoFranceSensorEntityDescription description)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
int|None _find_first_probability_forecast_not_null(list probability_forecast, list path)
DeviceInfo device_info(self)