Track meteo_france alert departments with a HassKey (#179062)

This commit is contained in:
David Wu
2026-09-08 09:54:16 +02:00
committed by GitHub
parent 7833bb364d
commit cc7091d252
3 changed files with 97 additions and 8 deletions
@@ -1,5 +1,4 @@
"""Support for Meteo-France weather data."""
# pylint: disable=home-assistant-use-runtime-data # Uses legacy hass.data[DOMAIN] pattern
import logging
@@ -10,7 +9,7 @@ from requests import RequestException
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from .const import DOMAIN, PLATFORMS
from .const import METEO_FRANCE_DATA, PLATFORMS
from .coordinator import (
MeteoFranceAlertUpdateCoordinator,
MeteoFranceConfigEntry,
@@ -24,7 +23,8 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: MeteoFranceConfigEntry) -> bool:
"""Set up a Meteo-France account from a config entry."""
hass.data.setdefault(DOMAIN, {})
if (departments_with_alert := hass.data.get(METEO_FRANCE_DATA)) is None:
departments_with_alert = hass.data[METEO_FRANCE_DATA] = set()
client = MeteoFranceClient()
@@ -55,7 +55,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: MeteoFranceConfigEntry)
department,
)
if department is not None and is_valid_warning_department(department):
if not hass.data[DOMAIN].get(department):
if department not in departments_with_alert:
coordinator_alert = MeteoFranceAlertUpdateCoordinator(
hass,
entry,
@@ -66,7 +66,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: MeteoFranceConfigEntry)
await coordinator_alert.async_refresh()
if coordinator_alert.last_update_success:
hass.data[DOMAIN][department] = True
departments_with_alert.add(department)
else:
_LOGGER.warning(
(
@@ -108,7 +108,7 @@ async def async_unload_entry(
"""Unload a config entry."""
if entry.runtime_data.alert_coordinator:
department = entry.runtime_data.forecast_coordinator.data.position.get("dept")
hass.data[DOMAIN][department] = False
hass.data[METEO_FRANCE_DATA].discard(department)
_LOGGER.debug(
(
"Weather alert for depatment %s unloaded and released. It can be added"
@@ -119,8 +119,8 @@ async def async_unload_entry(
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
if not hass.data[DOMAIN]:
hass.data.pop(DOMAIN)
if not hass.data[METEO_FRANCE_DATA]:
hass.data.pop(METEO_FRANCE_DATA)
return unload_ok
@@ -18,9 +18,15 @@ from homeassistant.components.weather import (
ATTR_CONDITION_WINDY_VARIANT,
)
from homeassistant.const import Platform
from homeassistant.util.hass_dict import HassKey
DOMAIN = "meteo_france"
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
# Departments that already have a city providing weather alerts. Only one city
# per department may do so, so this is shared between config entries rather than
# owned by any one of them.
METEO_FRANCE_DATA: HassKey[set[str]] = HassKey(DOMAIN)
ATTRIBUTION = "Data provided by Météo-France"
MODEL = "Météo-France mobile API"
MANUFACTURER = "Météo-France"
@@ -0,0 +1,83 @@
"""Test Météo France init."""
from collections.abc import Generator
from unittest.mock import patch
import pytest
from homeassistant.components.meteo_france.const import (
CONF_CITY,
DOMAIN,
METEO_FRANCE_DATA,
)
from homeassistant.config_entries import SOURCE_USER, ConfigEntryState
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
@pytest.fixture(autouse=True)
def override_platforms() -> Generator[None]:
"""Override PLATFORMS."""
with patch("homeassistant.components.meteo_france.PLATFORMS", []):
yield
def _second_city(hass: HomeAssistant) -> MockConfigEntry:
"""Return a second entry for a different city in the same department."""
entry_data = {
CONF_CITY: "Le Grand-Bornand",
CONF_LATITUDE: 45.94179,
CONF_LONGITUDE: 6.42794,
}
config_entry = MockConfigEntry(
domain=DOMAIN,
source=SOURCE_USER,
unique_id=f"{entry_data[CONF_LATITUDE], entry_data[CONF_LONGITUDE]}",
title=entry_data[CONF_CITY],
data=entry_data,
)
config_entry.add_to_hass(hass)
return config_entry
async def test_only_one_city_per_department_provides_alerts(
hass: HomeAssistant,
config_entry: MockConfigEntry,
) -> None:
"""Test the second city in a department does not also provide alerts."""
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.runtime_data.alert_coordinator is not None
second_entry = _second_city(hass)
await hass.config_entries.async_setup(second_entry.entry_id)
await hass.async_block_till_done()
assert second_entry.state is ConfigEntryState.LOADED
assert second_entry.runtime_data.alert_coordinator is None
async def test_unload_releases_the_department(
hass: HomeAssistant,
config_entry: MockConfigEntry,
) -> None:
"""Test unloading releases the department so another city can claim it."""
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert hass.data[METEO_FRANCE_DATA]
assert await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done()
# The last entry is gone, so the shared registry is cleaned up entirely.
assert METEO_FRANCE_DATA not in hass.data
second_entry = _second_city(hass)
await hass.config_entries.async_setup(second_entry.entry_id)
await hass.async_block_till_done()
assert second_entry.runtime_data.alert_coordinator is not None