mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Update meteo_france based on code review (#38789)
* Review: if not to pop * Review: async_add_job --> async_add_executor_job * Review: const * Review: start logging messages with capital letter * Review : UTC isoformated time --> fix "Invalid date"" * Fix hail forecast condition * Review: _show_setup_form is a callback * Fix update option * Review: no icon for next_rain * Review: inline cities form * Review: store places as an instance attribute * UNDO_UPDATE_LISTENER()
This commit is contained in:
parent
91ead3be50
commit
e0c0d3b53f
@ -20,6 +20,7 @@ from .const import (
|
|||||||
COORDINATOR_RAIN,
|
COORDINATOR_RAIN,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
PLATFORMS,
|
PLATFORMS,
|
||||||
|
UNDO_UPDATE_LISTENER,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -77,15 +78,17 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
|
|||||||
|
|
||||||
async def _async_update_data_forecast_forecast():
|
async def _async_update_data_forecast_forecast():
|
||||||
"""Fetch data from API endpoint."""
|
"""Fetch data from API endpoint."""
|
||||||
return await hass.async_add_job(client.get_forecast, latitude, longitude)
|
return await hass.async_add_executor_job(
|
||||||
|
client.get_forecast, latitude, longitude
|
||||||
|
)
|
||||||
|
|
||||||
async def _async_update_data_rain():
|
async def _async_update_data_rain():
|
||||||
"""Fetch data from API endpoint."""
|
"""Fetch data from API endpoint."""
|
||||||
return await hass.async_add_job(client.get_rain, latitude, longitude)
|
return await hass.async_add_executor_job(client.get_rain, latitude, longitude)
|
||||||
|
|
||||||
async def _async_update_data_alert():
|
async def _async_update_data_alert():
|
||||||
"""Fetch data from API endpoint."""
|
"""Fetch data from API endpoint."""
|
||||||
return await hass.async_add_job(
|
return await hass.async_add_executor_job(
|
||||||
client.get_warning_current_phenomenoms, department, 0, True
|
client.get_warning_current_phenomenoms, department, 0, True
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -156,10 +159,13 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
|
|||||||
entry.title,
|
entry.title,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
undo_listener = entry.add_update_listener(_async_update_listener)
|
||||||
|
|
||||||
hass.data[DOMAIN][entry.entry_id] = {
|
hass.data[DOMAIN][entry.entry_id] = {
|
||||||
COORDINATOR_FORECAST: coordinator_forecast,
|
COORDINATOR_FORECAST: coordinator_forecast,
|
||||||
COORDINATOR_RAIN: coordinator_rain,
|
COORDINATOR_RAIN: coordinator_rain,
|
||||||
COORDINATOR_ALERT: coordinator_alert,
|
COORDINATOR_ALERT: coordinator_alert,
|
||||||
|
UNDO_UPDATE_LISTENER: undo_listener,
|
||||||
}
|
}
|
||||||
|
|
||||||
for platform in PLATFORMS:
|
for platform in PLATFORMS:
|
||||||
@ -192,8 +198,14 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
if unload_ok:
|
if unload_ok:
|
||||||
|
hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENER]()
|
||||||
hass.data[DOMAIN].pop(entry.entry_id)
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
if len(hass.data[DOMAIN]) == 0:
|
if not hass.data[DOMAIN]:
|
||||||
hass.data.pop(DOMAIN)
|
hass.data.pop(DOMAIN)
|
||||||
|
|
||||||
return unload_ok
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_update_listener(hass: HomeAssistantType, entry: ConfigEntry):
|
||||||
|
"""Handle options update."""
|
||||||
|
await hass.config_entries.async_reload(entry.entry_id)
|
||||||
|
@ -21,13 +21,18 @@ class MeteoFranceFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
VERSION = 1
|
VERSION = 1
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Init MeteoFranceFlowHandler."""
|
||||||
|
self.places = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@callback
|
@callback
|
||||||
def async_get_options_flow(config_entry):
|
def async_get_options_flow(config_entry):
|
||||||
"""Get the options flow for this handler."""
|
"""Get the options flow for this handler."""
|
||||||
return MeteoFranceOptionsFlowHandler(config_entry)
|
return MeteoFranceOptionsFlowHandler(config_entry)
|
||||||
|
|
||||||
async def _show_setup_form(self, user_input=None, errors=None):
|
@callback
|
||||||
|
def _show_setup_form(self, user_input=None, errors=None):
|
||||||
"""Show the setup form to the user."""
|
"""Show the setup form to the user."""
|
||||||
|
|
||||||
if user_input is None:
|
if user_input is None:
|
||||||
@ -46,7 +51,7 @@ class MeteoFranceFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
errors = {}
|
errors = {}
|
||||||
|
|
||||||
if user_input is None:
|
if user_input is None:
|
||||||
return await self._show_setup_form(user_input, errors)
|
return self._show_setup_form(user_input, errors)
|
||||||
|
|
||||||
city = user_input[CONF_CITY] # Might be a city name or a postal code
|
city = user_input[CONF_CITY] # Might be a city name or a postal code
|
||||||
latitude = user_input.get(CONF_LATITUDE)
|
latitude = user_input.get(CONF_LATITUDE)
|
||||||
@ -54,13 +59,15 @@ class MeteoFranceFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
if not latitude:
|
if not latitude:
|
||||||
client = MeteoFranceClient()
|
client = MeteoFranceClient()
|
||||||
places = await self.hass.async_add_executor_job(client.search_places, city)
|
self.places = await self.hass.async_add_executor_job(
|
||||||
_LOGGER.debug("places search result: %s", places)
|
client.search_places, city
|
||||||
if not places:
|
)
|
||||||
|
_LOGGER.debug("Places search result: %s", self.places)
|
||||||
|
if not self.places:
|
||||||
errors[CONF_CITY] = "empty"
|
errors[CONF_CITY] = "empty"
|
||||||
return await self._show_setup_form(user_input, errors)
|
return self._show_setup_form(user_input, errors)
|
||||||
|
|
||||||
return await self.async_step_cities(places=places)
|
return await self.async_step_cities()
|
||||||
|
|
||||||
# Check if already configured
|
# Check if already configured
|
||||||
await self.async_set_unique_id(f"{latitude}, {longitude}")
|
await self.async_set_unique_id(f"{latitude}, {longitude}")
|
||||||
@ -74,19 +81,27 @@ class MeteoFranceFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
"""Import a config entry."""
|
"""Import a config entry."""
|
||||||
return await self.async_step_user(user_input)
|
return await self.async_step_user(user_input)
|
||||||
|
|
||||||
async def async_step_cities(self, user_input=None, places=None):
|
async def async_step_cities(self, user_input=None):
|
||||||
"""Step where the user choose the city from the API search results."""
|
"""Step where the user choose the city from the API search results."""
|
||||||
if places and len(places) > 1 and self.source != SOURCE_IMPORT:
|
if not user_input:
|
||||||
|
if len(self.places) > 1 and self.source != SOURCE_IMPORT:
|
||||||
places_for_form = {}
|
places_for_form = {}
|
||||||
for place in places:
|
for place in self.places:
|
||||||
places_for_form[_build_place_key(place)] = f"{place}"
|
places_for_form[_build_place_key(place)] = f"{place}"
|
||||||
|
|
||||||
return await self._show_cities_form(places_for_form)
|
return self.async_show_form(
|
||||||
# for import and only 1 city in the search result
|
step_id="cities",
|
||||||
if places and not user_input:
|
data_schema=vol.Schema(
|
||||||
user_input = {CONF_CITY: _build_place_key(places[0])}
|
{
|
||||||
|
vol.Required(CONF_CITY): vol.All(
|
||||||
|
vol.Coerce(str), vol.In(places_for_form)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
user_input = {CONF_CITY: _build_place_key(self.places[0])}
|
||||||
|
|
||||||
city_infos = user_input.get(CONF_CITY).split(";")
|
city_infos = user_input[CONF_CITY].split(";")
|
||||||
return await self.async_step_user(
|
return await self.async_step_user(
|
||||||
{
|
{
|
||||||
CONF_CITY: city_infos[0],
|
CONF_CITY: city_infos[0],
|
||||||
@ -95,15 +110,6 @@ class MeteoFranceFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _show_cities_form(self, cities):
|
|
||||||
"""Show the form to choose the city."""
|
|
||||||
return self.async_show_form(
|
|
||||||
step_id="cities",
|
|
||||||
data_schema=vol.Schema(
|
|
||||||
{vol.Required(CONF_CITY): vol.All(vol.Coerce(str), vol.In(cities))}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class MeteoFranceOptionsFlowHandler(config_entries.OptionsFlow):
|
class MeteoFranceOptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
"""Handle a option flow."""
|
"""Handle a option flow."""
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
"""Meteo-France component constants."""
|
"""Meteo-France component constants."""
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
DEVICE_CLASS_PRESSURE,
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
PRESSURE_HPA,
|
PRESSURE_HPA,
|
||||||
SPEED_KILOMETERS_PER_HOUR,
|
SPEED_KILOMETERS_PER_HOUR,
|
||||||
TEMP_CELSIUS,
|
TEMP_CELSIUS,
|
||||||
@ -12,6 +15,7 @@ PLATFORMS = ["sensor", "weather"]
|
|||||||
COORDINATOR_FORECAST = "coordinator_forecast"
|
COORDINATOR_FORECAST = "coordinator_forecast"
|
||||||
COORDINATOR_RAIN = "coordinator_rain"
|
COORDINATOR_RAIN = "coordinator_rain"
|
||||||
COORDINATOR_ALERT = "coordinator_alert"
|
COORDINATOR_ALERT = "coordinator_alert"
|
||||||
|
UNDO_UPDATE_LISTENER = "undo_update_listener"
|
||||||
ATTRIBUTION = "Data provided by Météo-France"
|
ATTRIBUTION = "Data provided by Météo-France"
|
||||||
|
|
||||||
CONF_CITY = "city"
|
CONF_CITY = "city"
|
||||||
@ -24,7 +28,7 @@ ATTR_NEXT_RAIN_1_HOUR_FORECAST = "1_hour_forecast"
|
|||||||
ENTITY_NAME = "name"
|
ENTITY_NAME = "name"
|
||||||
ENTITY_UNIT = "unit"
|
ENTITY_UNIT = "unit"
|
||||||
ENTITY_ICON = "icon"
|
ENTITY_ICON = "icon"
|
||||||
ENTITY_CLASS = "device_class"
|
ENTITY_DEVICE_CLASS = "device_class"
|
||||||
ENTITY_ENABLE = "enable"
|
ENTITY_ENABLE = "enable"
|
||||||
ENTITY_API_DATA_PATH = "data_path"
|
ENTITY_API_DATA_PATH = "data_path"
|
||||||
|
|
||||||
@ -32,8 +36,8 @@ SENSOR_TYPES = {
|
|||||||
"pressure": {
|
"pressure": {
|
||||||
ENTITY_NAME: "Pressure",
|
ENTITY_NAME: "Pressure",
|
||||||
ENTITY_UNIT: PRESSURE_HPA,
|
ENTITY_UNIT: PRESSURE_HPA,
|
||||||
ENTITY_ICON: "mdi:gauge",
|
ENTITY_ICON: None,
|
||||||
ENTITY_CLASS: "pressure",
|
ENTITY_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
|
||||||
ENTITY_ENABLE: False,
|
ENTITY_ENABLE: False,
|
||||||
ENTITY_API_DATA_PATH: "current_forecast:sea_level",
|
ENTITY_API_DATA_PATH: "current_forecast:sea_level",
|
||||||
},
|
},
|
||||||
@ -41,7 +45,7 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "Rain chance",
|
ENTITY_NAME: "Rain chance",
|
||||||
ENTITY_UNIT: UNIT_PERCENTAGE,
|
ENTITY_UNIT: UNIT_PERCENTAGE,
|
||||||
ENTITY_ICON: "mdi:weather-rainy",
|
ENTITY_ICON: "mdi:weather-rainy",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: "probability_forecast:rain:3h",
|
ENTITY_API_DATA_PATH: "probability_forecast:rain:3h",
|
||||||
},
|
},
|
||||||
@ -49,7 +53,7 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "Snow chance",
|
ENTITY_NAME: "Snow chance",
|
||||||
ENTITY_UNIT: UNIT_PERCENTAGE,
|
ENTITY_UNIT: UNIT_PERCENTAGE,
|
||||||
ENTITY_ICON: "mdi:weather-snowy",
|
ENTITY_ICON: "mdi:weather-snowy",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: "probability_forecast:snow:3h",
|
ENTITY_API_DATA_PATH: "probability_forecast:snow:3h",
|
||||||
},
|
},
|
||||||
@ -57,7 +61,7 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "Freeze chance",
|
ENTITY_NAME: "Freeze chance",
|
||||||
ENTITY_UNIT: UNIT_PERCENTAGE,
|
ENTITY_UNIT: UNIT_PERCENTAGE,
|
||||||
ENTITY_ICON: "mdi:snowflake",
|
ENTITY_ICON: "mdi:snowflake",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: "probability_forecast:freezing",
|
ENTITY_API_DATA_PATH: "probability_forecast:freezing",
|
||||||
},
|
},
|
||||||
@ -65,23 +69,23 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "Wind speed",
|
ENTITY_NAME: "Wind speed",
|
||||||
ENTITY_UNIT: SPEED_KILOMETERS_PER_HOUR,
|
ENTITY_UNIT: SPEED_KILOMETERS_PER_HOUR,
|
||||||
ENTITY_ICON: "mdi:weather-windy",
|
ENTITY_ICON: "mdi:weather-windy",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: False,
|
ENTITY_ENABLE: False,
|
||||||
ENTITY_API_DATA_PATH: "current_forecast:wind:speed",
|
ENTITY_API_DATA_PATH: "current_forecast:wind:speed",
|
||||||
},
|
},
|
||||||
"next_rain": {
|
"next_rain": {
|
||||||
ENTITY_NAME: "Next rain",
|
ENTITY_NAME: "Next rain",
|
||||||
ENTITY_UNIT: None,
|
ENTITY_UNIT: None,
|
||||||
ENTITY_ICON: "mdi:weather-pouring",
|
ENTITY_ICON: None,
|
||||||
ENTITY_CLASS: "timestamp",
|
ENTITY_DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: None,
|
ENTITY_API_DATA_PATH: None,
|
||||||
},
|
},
|
||||||
"temperature": {
|
"temperature": {
|
||||||
ENTITY_NAME: "Temperature",
|
ENTITY_NAME: "Temperature",
|
||||||
ENTITY_UNIT: TEMP_CELSIUS,
|
ENTITY_UNIT: TEMP_CELSIUS,
|
||||||
ENTITY_ICON: "mdi:thermometer",
|
ENTITY_ICON: None,
|
||||||
ENTITY_CLASS: "temperature",
|
ENTITY_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
|
||||||
ENTITY_ENABLE: False,
|
ENTITY_ENABLE: False,
|
||||||
ENTITY_API_DATA_PATH: "current_forecast:T:value",
|
ENTITY_API_DATA_PATH: "current_forecast:T:value",
|
||||||
},
|
},
|
||||||
@ -89,7 +93,7 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "UV",
|
ENTITY_NAME: "UV",
|
||||||
ENTITY_UNIT: None,
|
ENTITY_UNIT: None,
|
||||||
ENTITY_ICON: "mdi:sunglasses",
|
ENTITY_ICON: "mdi:sunglasses",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: "today_forecast:uv",
|
ENTITY_API_DATA_PATH: "today_forecast:uv",
|
||||||
},
|
},
|
||||||
@ -97,7 +101,7 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "Weather alert",
|
ENTITY_NAME: "Weather alert",
|
||||||
ENTITY_UNIT: None,
|
ENTITY_UNIT: None,
|
||||||
ENTITY_ICON: "mdi:weather-cloudy-alert",
|
ENTITY_ICON: "mdi:weather-cloudy-alert",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: None,
|
ENTITY_API_DATA_PATH: None,
|
||||||
},
|
},
|
||||||
@ -105,7 +109,7 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "Daily precipitation",
|
ENTITY_NAME: "Daily precipitation",
|
||||||
ENTITY_UNIT: "mm",
|
ENTITY_UNIT: "mm",
|
||||||
ENTITY_ICON: "mdi:cup-water",
|
ENTITY_ICON: "mdi:cup-water",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: "today_forecast:precipitation:24h",
|
ENTITY_API_DATA_PATH: "today_forecast:precipitation:24h",
|
||||||
},
|
},
|
||||||
@ -113,7 +117,7 @@ SENSOR_TYPES = {
|
|||||||
ENTITY_NAME: "Cloud cover",
|
ENTITY_NAME: "Cloud cover",
|
||||||
ENTITY_UNIT: UNIT_PERCENTAGE,
|
ENTITY_UNIT: UNIT_PERCENTAGE,
|
||||||
ENTITY_ICON: "mdi:weather-partly-cloudy",
|
ENTITY_ICON: "mdi:weather-partly-cloudy",
|
||||||
ENTITY_CLASS: None,
|
ENTITY_DEVICE_CLASS: None,
|
||||||
ENTITY_ENABLE: True,
|
ENTITY_ENABLE: True,
|
||||||
ENTITY_API_DATA_PATH: "current_forecast:clouds",
|
ENTITY_API_DATA_PATH: "current_forecast:clouds",
|
||||||
},
|
},
|
||||||
@ -128,7 +132,7 @@ CONDITION_CLASSES = {
|
|||||||
"Brouillard",
|
"Brouillard",
|
||||||
"Brouillard givrant",
|
"Brouillard givrant",
|
||||||
],
|
],
|
||||||
"hail": ["Risque de grêle"],
|
"hail": ["Risque de grêle", "Risque de grèle"],
|
||||||
"lightning": ["Risque d'orages", "Orages"],
|
"lightning": ["Risque d'orages", "Orages"],
|
||||||
"lightning-rainy": ["Pluie orageuses", "Pluies orageuses", "Averses orageuses"],
|
"lightning-rainy": ["Pluie orageuses", "Pluies orageuses", "Averses orageuses"],
|
||||||
"partlycloudy": [
|
"partlycloudy": [
|
||||||
|
@ -21,7 +21,7 @@ from .const import (
|
|||||||
COORDINATOR_RAIN,
|
COORDINATOR_RAIN,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
ENTITY_API_DATA_PATH,
|
ENTITY_API_DATA_PATH,
|
||||||
ENTITY_CLASS,
|
ENTITY_DEVICE_CLASS,
|
||||||
ENTITY_ENABLE,
|
ENTITY_ENABLE,
|
||||||
ENTITY_ICON,
|
ENTITY_ICON,
|
||||||
ENTITY_NAME,
|
ENTITY_NAME,
|
||||||
@ -128,7 +128,7 @@ class MeteoFranceSensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Return the device class."""
|
"""Return the device class."""
|
||||||
return SENSOR_TYPES[self._type][ENTITY_CLASS]
|
return SENSOR_TYPES[self._type][ENTITY_DEVICE_CLASS]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def entity_registry_enabled_default(self) -> bool:
|
def entity_registry_enabled_default(self) -> bool:
|
||||||
@ -170,9 +170,15 @@ class MeteoFranceRainSensor(MeteoFranceSensor):
|
|||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state."""
|
"""Return the state."""
|
||||||
next_rain_date_locale = self.coordinator.data.next_rain_date_locale()
|
# search first cadran with rain
|
||||||
|
next_rain = next(
|
||||||
|
(cadran for cadran in self.coordinator.data.forecast if cadran["rain"] > 1),
|
||||||
|
None,
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
dt_util.as_local(next_rain_date_locale) if next_rain_date_locale else None
|
dt_util.utc_from_timestamp(next_rain["dt"]).isoformat()
|
||||||
|
if next_rain
|
||||||
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -180,11 +186,7 @@ class MeteoFranceRainSensor(MeteoFranceSensor):
|
|||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
return {
|
return {
|
||||||
ATTR_NEXT_RAIN_1_HOUR_FORECAST: [
|
ATTR_NEXT_RAIN_1_HOUR_FORECAST: [
|
||||||
{
|
{dt_util.utc_from_timestamp(item["dt"]).isoformat(): item["desc"]}
|
||||||
dt_util.as_local(
|
|
||||||
self.coordinator.data.timestamp_to_locale_time(item["dt"])
|
|
||||||
).strftime("%H:%M"): item["desc"]
|
|
||||||
}
|
|
||||||
for item in self.coordinator.data.forecast
|
for item in self.coordinator.data.forecast
|
||||||
],
|
],
|
||||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||||
|
@ -16,6 +16,7 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import CONF_MODE, TEMP_CELSIUS
|
from homeassistant.const import CONF_MODE, TEMP_CELSIUS
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
from homeassistant.helpers.typing import HomeAssistantType
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTRIBUTION,
|
ATTRIBUTION,
|
||||||
@ -134,9 +135,9 @@ class MeteoFranceWeather(WeatherEntity):
|
|||||||
continue
|
continue
|
||||||
forecast_data.append(
|
forecast_data.append(
|
||||||
{
|
{
|
||||||
ATTR_FORECAST_TIME: self.coordinator.data.timestamp_to_locale_time(
|
ATTR_FORECAST_TIME: dt_util.utc_from_timestamp(
|
||||||
forecast["dt"]
|
forecast["dt"]
|
||||||
),
|
).isoformat(),
|
||||||
ATTR_FORECAST_CONDITION: format_condition(
|
ATTR_FORECAST_CONDITION: format_condition(
|
||||||
forecast["weather"]["desc"]
|
forecast["weather"]["desc"]
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user