1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 00:20:30 +01:00

Migrate netatmo to use runtime_data (#166925)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
epenet
2026-03-31 11:10:50 +02:00
committed by GitHub
parent 9499476940
commit 9bfac71bd7
15 changed files with 66 additions and 82 deletions

View File

@@ -15,7 +15,6 @@ from homeassistant.components.webhook import (
async_register as webhook_register,
async_unregister as webhook_unregister,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_WEBHOOK_ID, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import (
@@ -38,12 +37,10 @@ from homeassistant.helpers.typing import ConfigType
from . import api
from .const import (
AUTH,
CONF_CLOUDHOOK_URL,
DATA_CAMERAS,
DATA_DEVICE_IDS,
DATA_EVENTS,
DATA_HANDLER,
DATA_HOMES,
DATA_PERSONS,
DATA_SCHEDULES,
@@ -52,7 +49,7 @@ from .const import (
WEBHOOK_DEACTIVATION,
WEBHOOK_PUSH_TYPE,
)
from .data_handler import NetatmoDataHandler
from .data_handler import NetatmoConfigEntry, NetatmoDataHandler
from .webhook import async_handle_webhook
_LOGGER = logging.getLogger(__name__)
@@ -76,7 +73,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: NetatmoConfigEntry) -> bool:
"""Set up Netatmo from a config entry."""
try:
implementation = await async_get_config_entry_implementation(hass, entry)
@@ -106,14 +103,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
raise ConfigEntryAuthFailed("Token scope not valid, trigger renewal")
hass.data[DOMAIN][entry.entry_id] = {
AUTH: api.AsyncConfigEntryNetatmoAuth(
aiohttp_client.async_get_clientsession(hass), session
)
}
auth = api.AsyncConfigEntryNetatmoAuth(
aiohttp_client.async_get_clientsession(hass), session
)
data_handler = NetatmoDataHandler(hass, entry)
hass.data[DOMAIN][entry.entry_id][DATA_HANDLER] = data_handler
data_handler = NetatmoDataHandler(hass, entry, auth)
entry.runtime_data = data_handler
await data_handler.async_setup()
async def unregister_webhook(
@@ -129,7 +124,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
webhook_unregister(hass, entry.data[CONF_WEBHOOK_ID])
try:
await hass.data[DOMAIN][entry.entry_id][AUTH].async_dropwebhook()
await entry.runtime_data.auth.async_dropwebhook()
except pyatmo.ApiError:
_LOGGER.debug(
"No webhook to be dropped for %s", entry.data[CONF_WEBHOOK_ID]
@@ -165,7 +160,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
try:
await hass.data[DOMAIN][entry.entry_id][AUTH].async_addwebhook(webhook_url)
await entry.runtime_data.auth.async_addwebhook(webhook_url)
_LOGGER.debug("Register Netatmo webhook: %s", webhook_url)
except pyatmo.ApiError as err:
_LOGGER.error("Error during webhook registration - %s", err)
@@ -199,7 +194,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return True
async def async_cloudhook_generate_url(hass: HomeAssistant, entry: ConfigEntry) -> str:
async def async_cloudhook_generate_url(
hass: HomeAssistant, entry: NetatmoConfigEntry
) -> str:
"""Generate the full URL for a webhook_id."""
if CONF_CLOUDHOOK_URL not in entry.data:
webhook_url = await cloud.async_create_cloudhook(
@@ -211,32 +208,27 @@ async def async_cloudhook_generate_url(hass: HomeAssistant, entry: ConfigEntry)
return str(entry.data[CONF_CLOUDHOOK_URL])
async def async_config_entry_updated(hass: HomeAssistant, entry: ConfigEntry) -> None:
async def async_config_entry_updated(
hass: HomeAssistant, entry: NetatmoConfigEntry
) -> None:
"""Handle signals of config entry being updated."""
async_dispatcher_send(hass, f"signal-{DOMAIN}-public-update-{entry.entry_id}")
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: NetatmoConfigEntry) -> bool:
"""Unload a config entry."""
data = hass.data[DOMAIN]
if CONF_WEBHOOK_ID in entry.data:
webhook_unregister(hass, entry.data[CONF_WEBHOOK_ID])
try:
await data[entry.entry_id][AUTH].async_dropwebhook()
await entry.runtime_data.auth.async_dropwebhook()
except pyatmo.ApiError:
_LOGGER.debug("No webhook to be dropped")
_LOGGER.debug("Unregister Netatmo webhook")
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok and entry.entry_id in data:
data.pop(entry.entry_id)
return unload_ok
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
async def async_remove_entry(hass: HomeAssistant, entry: NetatmoConfigEntry) -> None:
"""Cleanup when entry is removed."""
if CONF_WEBHOOK_ID in entry.data and cloud.async_active_subscription(hass):
try:
@@ -249,10 +241,10 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
async def async_remove_config_entry_device(
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry
hass: HomeAssistant, config_entry: NetatmoConfigEntry, device_entry: DeviceEntry
) -> bool:
"""Remove a config entry from a device."""
data = hass.data[DOMAIN][config_entry.entry_id][DATA_HANDLER]
data = config_entry.runtime_data
modules = [m for h in data.account.homes.values() for m in h.modules]
rooms = [r for h in data.account.homes.values() for r in h.rooms]

View File

@@ -13,7 +13,6 @@ from homeassistant.components.binary_sensor import (
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
@@ -38,7 +37,7 @@ from .const import (
NETATMO_CREATE_OPENING_BINARY_SENSOR,
NETATMO_CREATE_WEATHER_BINARY_SENSOR,
)
from .data_handler import SIGNAL_NAME, NetatmoDevice
from .data_handler import SIGNAL_NAME, NetatmoConfigEntry, NetatmoDevice
from .entity import NetatmoModuleEntity, NetatmoWeatherModuleEntity
_LOGGER = logging.getLogger(__name__)
@@ -180,7 +179,7 @@ DEVICE_CATEGORY_BINARY_PUBLISHERS: Final[list[NetatmoDeviceCategory]] = [
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Netatmo weather binary sensors based on a config entry."""

View File

@@ -7,13 +7,12 @@ import logging
from pyatmo import modules as NaModules
from homeassistant.components.button import ButtonEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import CONF_URL_CONTROL, NETATMO_CREATE_BUTTON
from .data_handler import HOME, SIGNAL_NAME, NetatmoDevice
from .data_handler import HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoDevice
from .entity import NetatmoModuleEntity
_LOGGER = logging.getLogger(__name__)
@@ -21,7 +20,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo button platform."""

View File

@@ -11,7 +11,6 @@ from pyatmo.event import Event as NaEvent
import voluptuous as vol
from homeassistant.components.camera import Camera, CameraEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, entity_platform
@@ -41,7 +40,7 @@ from .const import (
SERVICE_SET_PERSONS_HOME,
WEBHOOK_PUSH_TYPE,
)
from .data_handler import EVENT, HOME, SIGNAL_NAME, NetatmoDevice
from .data_handler import EVENT, HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoDevice
from .entity import NetatmoModuleEntity
_LOGGER = logging.getLogger(__name__)
@@ -51,7 +50,7 @@ DEFAULT_QUALITY = "high"
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo camera platform."""

View File

@@ -20,7 +20,6 @@ from homeassistant.components.climate import (
HVACAction,
HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_TEMPERATURE,
PRECISION_HALVES,
@@ -54,7 +53,7 @@ from .const import (
SERVICE_SET_TEMPERATURE_WITH_END_DATETIME,
SERVICE_SET_TEMPERATURE_WITH_TIME_PERIOD,
)
from .data_handler import HOME, SIGNAL_NAME, NetatmoRoom
from .data_handler import HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoRoom
from .entity import NetatmoRoomEntity
_LOGGER = logging.getLogger(__name__)
@@ -120,7 +119,7 @@ NA_VALVE = DeviceType.NRV
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo energy platform."""

View File

@@ -9,12 +9,7 @@ import uuid
import voluptuous as vol
from homeassistant.config_entries import (
SOURCE_REAUTH,
ConfigEntry,
ConfigFlowResult,
OptionsFlow,
)
from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult, OptionsFlow
from homeassistant.const import CONF_SHOW_ON_MAP, CONF_UUID
from homeassistant.core import callback
from homeassistant.helpers import config_entry_oauth2_flow, config_validation as cv
@@ -31,6 +26,7 @@ from .const import (
CONF_WEATHER_AREAS,
DOMAIN,
)
from .data_handler import NetatmoConfigEntry
_LOGGER = logging.getLogger(__name__)
@@ -45,7 +41,7 @@ class NetatmoFlowHandler(
@staticmethod
@callback
def async_get_options_flow(
config_entry: ConfigEntry,
config_entry: NetatmoConfigEntry,
) -> OptionsFlow:
"""Get the options flow for this handler."""
return NetatmoOptionsFlowHandler(config_entry)
@@ -99,7 +95,7 @@ class NetatmoFlowHandler(
class NetatmoOptionsFlowHandler(OptionsFlow):
"""Handle Netatmo options."""
def __init__(self, config_entry: ConfigEntry) -> None:
def __init__(self, config_entry: NetatmoConfigEntry) -> None:
"""Initialize Netatmo options flow."""
self.options = dict(config_entry.options)
self.options.setdefault(CONF_WEATHER_AREAS, {})

View File

@@ -27,11 +27,9 @@ CONF_URL_WEATHER = "https://my.netatmo.com/app/weather"
CONF_URL_CONTROL = "https://home.netatmo.com/control"
CONF_URL_PUBLIC_WEATHER = "https://weathermap.netatmo.com/"
AUTH = "netatmo_auth"
CONF_PUBLIC = "public_sensor_config"
CAMERA_DATA = "netatmo_camera"
HOME_DATA = "netatmo_home_data"
DATA_HANDLER = "netatmo_data_handler"
SIGNAL_NAME = "signal_name"
API_SCOPES_EXCLUDED_FROM_CLOUD = [

View File

@@ -13,13 +13,12 @@ from homeassistant.components.cover import (
CoverEntity,
CoverEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import CONF_URL_CONTROL, NETATMO_CREATE_COVER
from .data_handler import HOME, SIGNAL_NAME, NetatmoDevice
from .data_handler import HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoDevice
from .entity import NetatmoModuleEntity
_LOGGER = logging.getLogger(__name__)
@@ -27,7 +26,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo cover platform."""

View File

@@ -27,7 +27,6 @@ from homeassistant.helpers.dispatcher import (
from homeassistant.helpers.event import async_track_time_interval
from .const import (
AUTH,
CAMERA_CONNECTION_WEBHOOKS,
DATA_PERSONS,
DATA_SCHEDULES,
@@ -89,6 +88,8 @@ DEFAULT_INTERVALS = {
}
SCAN_INTERVAL = 60
type NetatmoConfigEntry = ConfigEntry[NetatmoDataHandler]
@dataclass
class NetatmoDevice:
@@ -138,11 +139,16 @@ class NetatmoDataHandler:
account: pyatmo.AsyncAccount
_interval_factor: int
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
def __init__(
self,
hass: HomeAssistant,
config_entry: NetatmoConfigEntry,
auth: pyatmo.AbstractAsyncAuth,
) -> None:
"""Initialize self."""
self.hass = hass
self.config_entry = config_entry
self._auth = hass.data[DOMAIN][config_entry.entry_id][AUTH]
self.auth = auth
self.publisher: dict[str, NetatmoPublisher] = {}
self._queue: deque = deque()
self._webhook: bool = False
@@ -171,7 +177,7 @@ class NetatmoDataHandler:
)
)
self.account = pyatmo.AsyncAccount(self._auth)
self.account = pyatmo.AsyncAccount(self.auth)
await self.subscribe(ACCOUNT, ACCOUNT, None)

View File

@@ -5,11 +5,9 @@ from __future__ import annotations
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from .const import DATA_HANDLER, DOMAIN
from .data_handler import ACCOUNT, NetatmoDataHandler
from .data_handler import ACCOUNT, NetatmoConfigEntry
TO_REDACT = {
"access_token",
@@ -32,12 +30,10 @@ TO_REDACT = {
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
hass: HomeAssistant, config_entry: NetatmoConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
data_handler: NetatmoDataHandler = hass.data[DOMAIN][config_entry.entry_id][
DATA_HANDLER
]
data_handler = config_entry.runtime_data
return {
"info": async_redact_data(

View File

@@ -8,13 +8,12 @@ from typing import Final
from pyatmo import modules as NaModules
from homeassistant.components.fan import FanEntity, FanEntityFeature
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import CONF_URL_CONTROL, NETATMO_CREATE_FAN
from .data_handler import HOME, SIGNAL_NAME, NetatmoDevice
from .data_handler import HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoDevice
from .entity import NetatmoModuleEntity
_LOGGER = logging.getLogger(__name__)
@@ -27,7 +26,7 @@ PRESETS = {v: k for k, v in PRESET_MAPPING.items()}
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo fan platform."""

View File

@@ -8,7 +8,6 @@ from typing import Any
from pyatmo import modules as NaModules
from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
@@ -22,7 +21,7 @@ from .const import (
NETATMO_CREATE_CAMERA_LIGHT,
NETATMO_CREATE_LIGHT,
)
from .data_handler import HOME, SIGNAL_NAME, NetatmoDevice
from .data_handler import HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoDevice
from .entity import NetatmoModuleEntity
_LOGGER = logging.getLogger(__name__)
@@ -30,7 +29,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo camera light platform."""

View File

@@ -5,7 +5,6 @@ from __future__ import annotations
import logging
from homeassistant.components.select import SelectEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@@ -19,7 +18,7 @@ from .const import (
MANUFACTURER,
NETATMO_CREATE_SELECT,
)
from .data_handler import HOME, SIGNAL_NAME, NetatmoHome
from .data_handler import HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoHome
from .entity import NetatmoBaseEntity
_LOGGER = logging.getLogger(__name__)
@@ -27,7 +26,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo energy platform schedule selector."""

View File

@@ -16,7 +16,6 @@ from homeassistant.components.sensor import (
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_LATITUDE,
ATTR_LONGITUDE,
@@ -45,7 +44,6 @@ from .const import (
CONF_URL_ENERGY,
CONF_URL_PUBLIC_WEATHER,
CONF_WEATHER_AREAS,
DATA_HANDLER,
DOMAIN,
NETATMO_CREATE_BATTERY,
NETATMO_CREATE_ROOM_SENSOR,
@@ -53,7 +51,14 @@ from .const import (
NETATMO_CREATE_WEATHER_SENSOR,
SIGNAL_NAME,
)
from .data_handler import HOME, PUBLIC, NetatmoDataHandler, NetatmoDevice, NetatmoRoom
from .data_handler import (
HOME,
PUBLIC,
NetatmoConfigEntry,
NetatmoDataHandler,
NetatmoDevice,
NetatmoRoom,
)
from .entity import (
NetatmoBaseEntity,
NetatmoModuleEntity,
@@ -390,7 +395,7 @@ BATTERY_SENSOR_DESCRIPTION = NetatmoSensorEntityDescription(
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo sensor platform."""
@@ -456,7 +461,7 @@ async def async_setup_entry(
)
device_registry = dr.async_get(hass)
data_handler = hass.data[DOMAIN][entry.entry_id][DATA_HANDLER]
data_handler = entry.runtime_data
async def add_public_entities(update: bool = True) -> None:
"""Retrieve Netatmo public weather entities."""

View File

@@ -8,13 +8,12 @@ from typing import Any
from pyatmo import modules as NaModules
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import CONF_URL_CONTROL, NETATMO_CREATE_SWITCH
from .data_handler import HOME, SIGNAL_NAME, NetatmoDevice
from .data_handler import HOME, SIGNAL_NAME, NetatmoConfigEntry, NetatmoDevice
from .entity import NetatmoModuleEntity
_LOGGER = logging.getLogger(__name__)
@@ -22,7 +21,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
entry: NetatmoConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Netatmo switch platform."""