Migrate keenetic_ndms2 to use runtime_data (#147194)

* Migrate keenetic_ndms2 to use runtime_data

* Adjust tests
This commit is contained in:
epenet 2025-06-20 12:23:59 +02:00 committed by GitHub
parent 544fd2a4a6
commit 7dfd68f8c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 32 additions and 51 deletions

View File

@ -4,7 +4,6 @@ from __future__ import annotations
import logging import logging
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_SCAN_INTERVAL, Platform from homeassistant.const import CONF_HOST, CONF_SCAN_INTERVAL, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers import device_registry as dr, entity_registry as er
@ -19,15 +18,14 @@ from .const import (
DEFAULT_INTERFACE, DEFAULT_INTERFACE,
DEFAULT_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL,
DOMAIN, DOMAIN,
ROUTER,
) )
from .router import KeeneticRouter from .router import KeeneticConfigEntry, KeeneticRouter
PLATFORMS = [Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER] PLATFORMS = [Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER]
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: KeeneticConfigEntry) -> bool:
"""Set up the component.""" """Set up the component."""
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
async_add_defaults(hass, entry) async_add_defaults(hass, entry)
@ -37,27 +35,24 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.async_on_unload(entry.add_update_listener(update_listener)) entry.async_on_unload(entry.add_update_listener(update_listener))
hass.data[DOMAIN][entry.entry_id] = { entry.runtime_data = router
ROUTER: router,
}
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: async def async_unload_entry(
hass: HomeAssistant, config_entry: KeeneticConfigEntry
) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms( unload_ok = await hass.config_entries.async_unload_platforms(
config_entry, PLATFORMS config_entry, PLATFORMS
) )
router: KeeneticRouter = hass.data[DOMAIN][config_entry.entry_id][ROUTER] router = config_entry.runtime_data
await router.async_teardown() await router.async_teardown()
hass.data[DOMAIN].pop(config_entry.entry_id)
new_tracked_interfaces: set[str] = set(config_entry.options[CONF_INTERFACES]) new_tracked_interfaces: set[str] = set(config_entry.options[CONF_INTERFACES])
if router.tracked_interfaces - new_tracked_interfaces: if router.tracked_interfaces - new_tracked_interfaces:
@ -92,12 +87,12 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
return unload_ok return unload_ok
async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: async def update_listener(hass: HomeAssistant, entry: KeeneticConfigEntry) -> None:
"""Handle options update.""" """Handle options update."""
await hass.config_entries.async_reload(entry.entry_id) await hass.config_entries.async_reload(entry.entry_id)
def async_add_defaults(hass: HomeAssistant, entry: ConfigEntry): def async_add_defaults(hass: HomeAssistant, entry: KeeneticConfigEntry):
"""Populate default options.""" """Populate default options."""
host: str = entry.data[CONF_HOST] host: str = entry.data[CONF_HOST]
imported_options: dict = hass.data[DOMAIN].get(f"imported_options_{host}", {}) imported_options: dict = hass.data[DOMAIN].get(f"imported_options_{host}", {})

View File

@ -4,24 +4,20 @@ from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass, BinarySensorDeviceClass,
BinarySensorEntity, BinarySensorEntity,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import KeeneticRouter from .router import KeeneticConfigEntry, KeeneticRouter
from .const import DOMAIN, ROUTER
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: KeeneticConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback, async_add_entities: AddConfigEntryEntitiesCallback,
) -> None: ) -> None:
"""Set up device tracker for Keenetic NDMS2 component.""" """Set up device tracker for Keenetic NDMS2 component."""
router: KeeneticRouter = hass.data[DOMAIN][config_entry.entry_id][ROUTER] async_add_entities([RouterOnlineBinarySensor(config_entry.runtime_data)])
async_add_entities([RouterOnlineBinarySensor(router)])
class RouterOnlineBinarySensor(BinarySensorEntity): class RouterOnlineBinarySensor(BinarySensorEntity):

View File

@ -8,12 +8,7 @@ from urllib.parse import urlparse
from ndms2_client import Client, ConnectionException, InterfaceInfo, TelnetConnection from ndms2_client import Client, ConnectionException, InterfaceInfo, TelnetConnection
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ( from homeassistant.config_entries import ConfigFlow, ConfigFlowResult, OptionsFlow
ConfigEntry,
ConfigFlow,
ConfigFlowResult,
OptionsFlow,
)
from homeassistant.const import ( from homeassistant.const import (
CONF_HOST, CONF_HOST,
CONF_PASSWORD, CONF_PASSWORD,
@ -41,9 +36,8 @@ from .const import (
DEFAULT_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL,
DEFAULT_TELNET_PORT, DEFAULT_TELNET_PORT,
DOMAIN, DOMAIN,
ROUTER,
) )
from .router import KeeneticRouter from .router import KeeneticConfigEntry
class KeeneticFlowHandler(ConfigFlow, domain=DOMAIN): class KeeneticFlowHandler(ConfigFlow, domain=DOMAIN):
@ -56,7 +50,7 @@ class KeeneticFlowHandler(ConfigFlow, domain=DOMAIN):
@staticmethod @staticmethod
@callback @callback
def async_get_options_flow( def async_get_options_flow(
config_entry: ConfigEntry, config_entry: KeeneticConfigEntry,
) -> KeeneticOptionsFlowHandler: ) -> KeeneticOptionsFlowHandler:
"""Get the options flow for this handler.""" """Get the options flow for this handler."""
return KeeneticOptionsFlowHandler() return KeeneticOptionsFlowHandler()
@ -142,6 +136,8 @@ class KeeneticFlowHandler(ConfigFlow, domain=DOMAIN):
class KeeneticOptionsFlowHandler(OptionsFlow): class KeeneticOptionsFlowHandler(OptionsFlow):
"""Handle options.""" """Handle options."""
config_entry: KeeneticConfigEntry
def __init__(self) -> None: def __init__(self) -> None:
"""Initialize options flow.""" """Initialize options flow."""
self._interface_options: dict[str, str] = {} self._interface_options: dict[str, str] = {}
@ -150,9 +146,7 @@ class KeeneticOptionsFlowHandler(OptionsFlow):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Manage the options.""" """Manage the options."""
router: KeeneticRouter = self.hass.data[DOMAIN][self.config_entry.entry_id][ router = self.config_entry.runtime_data
ROUTER
]
interfaces: list[InterfaceInfo] = await self.hass.async_add_executor_job( interfaces: list[InterfaceInfo] = await self.hass.async_add_executor_job(
router.client.get_interfaces router.client.get_interfaces

View File

@ -5,7 +5,6 @@ from homeassistant.components.device_tracker import (
) )
DOMAIN = "keenetic_ndms2" DOMAIN = "keenetic_ndms2"
ROUTER = "router"
DEFAULT_TELNET_PORT = 23 DEFAULT_TELNET_PORT = 23
DEFAULT_SCAN_INTERVAL = 120 DEFAULT_SCAN_INTERVAL = 120
DEFAULT_CONSIDER_HOME = _DEFAULT_CONSIDER_HOME.total_seconds() DEFAULT_CONSIDER_HOME = _DEFAULT_CONSIDER_HOME.total_seconds()

View File

@ -10,26 +10,24 @@ from homeassistant.components.device_tracker import (
DOMAIN as DEVICE_TRACKER_DOMAIN, DOMAIN as DEVICE_TRACKER_DOMAIN,
ScannerEntity, ScannerEntity,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .const import DOMAIN, ROUTER from .router import KeeneticConfigEntry, KeeneticRouter
from .router import KeeneticRouter
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config_entry: ConfigEntry, config_entry: KeeneticConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback, async_add_entities: AddConfigEntryEntitiesCallback,
) -> None: ) -> None:
"""Set up device tracker for Keenetic NDMS2 component.""" """Set up device tracker for Keenetic NDMS2 component."""
router: KeeneticRouter = hass.data[DOMAIN][config_entry.entry_id][ROUTER] router = config_entry.runtime_data
tracked: set[str] = set() tracked: set[str] = set()

View File

@ -35,11 +35,13 @@ from .const import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
type KeeneticConfigEntry = ConfigEntry[KeeneticRouter]
class KeeneticRouter: class KeeneticRouter:
"""Keenetic client Object.""" """Keenetic client Object."""
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None: def __init__(self, hass: HomeAssistant, config_entry: KeeneticConfigEntry) -> None:
"""Initialize the Client.""" """Initialize the Client."""
self.hass = hass self.hass = hass
self.config_entry = config_entry self.config_entry = config_entry

View File

@ -87,19 +87,16 @@ async def test_options(hass: HomeAssistant) -> None:
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
# fake router # fake router
hass.data.setdefault(keenetic.DOMAIN, {}) entry.runtime_data = Mock(
hass.data[keenetic.DOMAIN][entry.entry_id] = { client=Mock(
keenetic.ROUTER: Mock( get_interfaces=Mock(
client=Mock( return_value=[
get_interfaces=Mock( InterfaceInfo.from_dict({"id": name, "type": "bridge"})
return_value=[ for name in MOCK_OPTIONS[const.CONF_INTERFACES]
InterfaceInfo.from_dict({"id": name, "type": "bridge"}) ]
for name in MOCK_OPTIONS[const.CONF_INTERFACES]
]
)
) )
) )
} )
result = await hass.config_entries.options.async_init(entry.entry_id) result = await hass.config_entries.options.async_init(entry.entry_id)