Skip to content

Commit 5927f50

Browse files
epenetclaude
andauthored
Use runtime_data in Huawei LTE (home-assistant#168876)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 66d7afa commit 5927f50

12 files changed

Lines changed: 63 additions & 85 deletions

File tree

homeassistant/components/huawei_lte/__init__.py

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""Support for Huawei LTE routers."""
2-
# pylint: disable=hass-use-runtime-data # Uses legacy hass.data[DOMAIN] pattern
32

43
from __future__ import annotations
54

@@ -9,7 +8,7 @@
98
from dataclasses import dataclass, field
109
from datetime import timedelta
1110
import logging
12-
from typing import Any, NamedTuple, cast
11+
from typing import Any, cast
1312
from xml.parsers.expat import ExpatError
1413

1514
from huawei_lte_api.Client import Client
@@ -64,6 +63,7 @@
6463
DEFAULT_MANUFACTURER,
6564
DEFAULT_NOTIFY_SERVICE_NAME,
6665
DOMAIN,
66+
HUAWEI_LTE_CONFIG,
6767
KEY_DEVICE_BASIC_INFORMATION,
6868
KEY_DEVICE_INFORMATION,
6969
KEY_DEVICE_SIGNAL,
@@ -108,7 +108,7 @@ class Router:
108108
"""Class for router state."""
109109

110110
hass: HomeAssistant
111-
config_entry: ConfigEntry
111+
config_entry: HuaweiLteConfigEntry
112112
connection: Connection
113113
url: str
114114

@@ -278,14 +278,10 @@ def cleanup(self, *_: Any) -> None:
278278
self.connection.requests_session.close()
279279

280280

281-
class HuaweiLteData(NamedTuple):
282-
"""Shared state."""
281+
type HuaweiLteConfigEntry = ConfigEntry[Router]
283282

284-
hass_config: ConfigType
285-
routers: dict[str, Router]
286283

287-
288-
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
284+
async def async_setup_entry(hass: HomeAssistant, entry: HuaweiLteConfigEntry) -> bool:
289285
"""Set up Huawei LTE component from config entry."""
290286
url = entry.data[CONF_URL]
291287

@@ -352,7 +348,7 @@ def _connect() -> Connection:
352348
return False
353349

354350
# Store reference to router
355-
hass.data[DOMAIN].routers[entry.entry_id] = router
351+
entry.runtime_data = router
356352

357353
# Clear all subscriptions, enabled entities will push back theirs
358354
router.subscriptions.clear()
@@ -417,7 +413,7 @@ def _connect() -> Connection:
417413
CONF_NAME: entry.options.get(CONF_NAME, DEFAULT_NOTIFY_SERVICE_NAME),
418414
CONF_RECIPIENT: entry.options.get(CONF_RECIPIENT),
419415
},
420-
hass.data[DOMAIN].hass_config,
416+
hass.data[HUAWEI_LTE_CONFIG],
421417
)
422418

423419
def _update_router(*_: Any) -> None:
@@ -440,46 +436,47 @@ def _update_router(*_: Any) -> None:
440436
return True
441437

442438

443-
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
439+
async def async_unload_entry(
440+
hass: HomeAssistant, config_entry: HuaweiLteConfigEntry
441+
) -> bool:
444442
"""Unload config entry."""
445443

446444
# Forward config entry unload to platforms
447445
await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)
448446

449-
# Forget about the router and invoke its cleanup
450-
router = hass.data[DOMAIN].routers.pop(config_entry.entry_id)
451-
await hass.async_add_executor_job(router.cleanup)
447+
# Invoke router cleanup
448+
await hass.async_add_executor_job(config_entry.runtime_data.cleanup)
452449

453450
return True
454451

455452

456453
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
457454
"""Set up Huawei LTE component."""
458455

459-
if DOMAIN not in hass.data:
460-
hass.data[DOMAIN] = HuaweiLteData(hass_config=config, routers={})
456+
hass.data[HUAWEI_LTE_CONFIG] = config
461457

462458
def service_handler(service: ServiceCall) -> None:
463459
"""Apply a service.
464460
465461
We key this using the router URL instead of its unique id / serial number,
466462
because the latter is not available anywhere in the UI.
467463
"""
468-
routers = hass.data[DOMAIN].routers
464+
routers = [
465+
entry.runtime_data
466+
for entry in hass.config_entries.async_loaded_entries(DOMAIN)
467+
]
469468
if url := service.data.get(CONF_URL):
470-
router = next(
471-
(router for router in routers.values() if router.url == url), None
472-
)
469+
router = next((router for router in routers if router.url == url), None)
473470
elif not routers:
474471
_LOGGER.error("%s: no routers configured", service.service)
475472
return
476473
elif len(routers) == 1:
477-
router = next(iter(routers.values()))
474+
router = routers[0]
478475
else:
479476
_LOGGER.error(
480477
"%s: more than one router configured, must specify one of URLs %s",
481478
service.service,
482-
sorted(router.url for router in routers.values()),
479+
sorted(router.url for router in routers),
483480
)
484481
return
485482
if not router:
@@ -509,7 +506,9 @@ def service_handler(service: ServiceCall) -> None:
509506
return True
510507

511508

512-
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
509+
async def async_migrate_entry(
510+
hass: HomeAssistant, config_entry: HuaweiLteConfigEntry
511+
) -> bool:
513512
"""Migrate config entry to new version."""
514513
if config_entry.version == 1:
515514
options = dict(config_entry.options)

homeassistant/components/huawei_lte/binary_sensor.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@
1212
BinarySensorDeviceClass,
1313
BinarySensorEntity,
1414
)
15-
from homeassistant.config_entries import ConfigEntry
1615
from homeassistant.core import HomeAssistant
1716
from homeassistant.helpers.entity import Entity
1817
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
1918

19+
from . import HuaweiLteConfigEntry
2020
from .const import (
21-
DOMAIN,
2221
KEY_MONITORING_CHECK_NOTIFICATIONS,
2322
KEY_MONITORING_STATUS,
2423
KEY_WLAN_WIFI_FEATURE_SWITCH,
@@ -30,13 +29,11 @@
3029

3130
async def async_setup_entry(
3231
hass: HomeAssistant,
33-
config_entry: ConfigEntry,
32+
config_entry: HuaweiLteConfigEntry,
3433
async_add_entities: AddConfigEntryEntitiesCallback,
3534
) -> None:
3635
"""Set up from config entry."""
37-
# Uses legacy hass.data[DOMAIN] pattern
38-
# pylint: disable-next=hass-use-runtime-data
39-
router = hass.data[DOMAIN].routers[config_entry.entry_id]
36+
router = config_entry.runtime_data
4037
entities: list[Entity] = []
4138

4239
if router.data.get(KEY_MONITORING_STATUS):

homeassistant/components/huawei_lte/button.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,23 @@
1111
ButtonEntity,
1212
ButtonEntityDescription,
1313
)
14-
from homeassistant.config_entries import ConfigEntry
1514
from homeassistant.const import EntityCategory
1615
from homeassistant.core import HomeAssistant
1716
from homeassistant.helpers import entity_platform
1817

19-
from .const import DOMAIN
18+
from . import HuaweiLteConfigEntry
2019
from .entity import HuaweiLteBaseEntityWithDevice
2120

2221
_LOGGER = logging.getLogger(__name__)
2322

2423

2524
async def async_setup_entry(
2625
hass: HomeAssistant,
27-
config_entry: ConfigEntry,
26+
config_entry: HuaweiLteConfigEntry,
2827
async_add_entities: entity_platform.AddConfigEntryEntitiesCallback,
2928
) -> None:
3029
"""Set up Huawei LTE buttons."""
31-
# Uses legacy hass.data[DOMAIN] pattern
32-
# pylint: disable-next=hass-use-runtime-data
33-
router = hass.data[DOMAIN].routers[config_entry.entry_id]
30+
router = config_entry.runtime_data
3431
buttons = [
3532
ClearTrafficStatisticsButton(router),
3633
RestartButton(router),

homeassistant/components/huawei_lte/config_flow.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@
2121
from url_normalize import url_normalize
2222
import voluptuous as vol
2323

24-
from homeassistant.config_entries import (
25-
ConfigEntry,
26-
ConfigFlow,
27-
ConfigFlowResult,
28-
OptionsFlow,
29-
)
24+
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult, OptionsFlow
3025
from homeassistant.const import (
3126
CONF_MAC,
3227
CONF_NAME,
@@ -47,6 +42,7 @@
4742
SsdpServiceInfo,
4843
)
4944

45+
from . import HuaweiLteConfigEntry
5046
from .const import (
5147
CONF_MANUFACTURER,
5248
CONF_TRACK_WIRED_CLIENTS,
@@ -76,7 +72,7 @@ class HuaweiLteConfigFlow(ConfigFlow, domain=DOMAIN):
7672
@staticmethod
7773
@callback
7874
def async_get_options_flow(
79-
config_entry: ConfigEntry,
75+
config_entry: HuaweiLteConfigEntry,
8076
) -> HuaweiLteOptionsFlow:
8177
"""Get options flow."""
8278
return HuaweiLteOptionsFlow()

homeassistant/components/huawei_lte/const.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
"""Huawei LTE constants."""
22

3+
from homeassistant.helpers.typing import ConfigType
4+
from homeassistant.util.hass_dict import HassKey
5+
36
DOMAIN = "huawei_lte"
47

8+
HUAWEI_LTE_CONFIG: HassKey[ConfigType] = HassKey(DOMAIN)
9+
510
CONF_MANUFACTURER = "manufacturer"
611
CONF_TRACK_WIRED_CLIENTS = "track_wired_clients"
712
CONF_UNAUTHENTICATED_MODE = "unauthenticated_mode"

homeassistant/components/huawei_lte/device_tracker.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,17 @@
99
DOMAIN as DEVICE_TRACKER_DOMAIN,
1010
ScannerEntity,
1111
)
12-
from homeassistant.config_entries import ConfigEntry
1312
from homeassistant.core import HomeAssistant, callback
1413
from homeassistant.helpers import entity_registry as er
1514
from homeassistant.helpers.dispatcher import async_dispatcher_connect
1615
from homeassistant.helpers.entity import Entity
1716
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
1817
from homeassistant.util import snakecase
1918

20-
from . import Router
19+
from . import HuaweiLteConfigEntry, Router
2120
from .const import (
2221
CONF_TRACK_WIRED_CLIENTS,
2322
DEFAULT_TRACK_WIRED_CLIENTS,
24-
DOMAIN,
2523
KEY_LAN_HOST_INFO,
2624
KEY_WLAN_HOST_LIST,
2725
UPDATE_SIGNAL,
@@ -50,17 +48,15 @@ def _get_hosts(
5048

5149
async def async_setup_entry(
5250
hass: HomeAssistant,
53-
config_entry: ConfigEntry,
51+
config_entry: HuaweiLteConfigEntry,
5452
async_add_entities: AddConfigEntryEntitiesCallback,
5553
) -> None:
5654
"""Set up from config entry."""
5755

5856
# Grab hosts list once to examine whether the initial fetch has got some data for
5957
# us, i.e. if wlan host list is supported. Only set up a subscription and proceed
6058
# with adding and tracking entities if it is.
61-
# Uses legacy hass.data[DOMAIN] pattern
62-
# pylint: disable-next=hass-use-runtime-data
63-
router = hass.data[DOMAIN].routers[config_entry.entry_id]
59+
router = config_entry.runtime_data
6460
if (hosts := _get_hosts(router, True)) is None:
6561
return
6662

homeassistant/components/huawei_lte/diagnostics.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
from typing import Any
66

77
from homeassistant.components.diagnostics import async_redact_data
8-
from homeassistant.config_entries import ConfigEntry
98
from homeassistant.core import HomeAssistant
109

11-
from .const import DOMAIN
10+
from . import HuaweiLteConfigEntry
1211

1312
ENTRY_FIELDS_DATA_TO_REDACT = {
1413
"mac",
@@ -74,13 +73,13 @@
7473

7574

7675
async def async_get_config_entry_diagnostics(
77-
hass: HomeAssistant, entry: ConfigEntry
76+
hass: HomeAssistant, entry: HuaweiLteConfigEntry
7877
) -> dict[str, Any]:
7978
"""Return diagnostics for a config entry."""
8079
return async_redact_data(
8180
{
8281
"entry": entry.data,
83-
"router": hass.data[DOMAIN].routers[entry.entry_id].data,
82+
"router": entry.runtime_data.data,
8483
},
8584
TO_REDACT,
8685
)

homeassistant/components/huawei_lte/notify.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
from homeassistant.core import HomeAssistant
1313
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
1414

15-
from . import Router
16-
from .const import DOMAIN
15+
from . import HuaweiLteConfigEntry, Router
1716

1817
_LOGGER = logging.getLogger(__name__)
1918

@@ -27,9 +26,11 @@ async def async_get_service(
2726
if discovery_info is None:
2827
return None
2928

30-
# Uses legacy hass.data[DOMAIN] pattern
31-
# pylint: disable-next=hass-use-runtime-data
32-
router = hass.data[DOMAIN].routers[discovery_info[ATTR_CONFIG_ENTRY_ID]]
29+
entry: HuaweiLteConfigEntry | None = hass.config_entries.async_get_entry(
30+
discovery_info[ATTR_CONFIG_ENTRY_ID]
31+
)
32+
assert entry is not None
33+
router = entry.runtime_data
3334
default_targets = discovery_info[CONF_RECIPIENT] or []
3435

3536
return HuaweiLteSmsNotificationService(router, default_targets)

homeassistant/components/huawei_lte/quality_scale.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ rules:
2222
entity-event-setup: done
2323
entity-unique-id: done
2424
has-entity-name: done
25-
runtime-data: todo
25+
runtime-data: done
2626
test-before-configure: done
2727
test-before-setup: done
2828
unique-config-entry: done

homeassistant/components/huawei_lte/select.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from dataclasses import dataclass
77
from functools import partial
88
import logging
9+
from typing import Any
910

1011
from huawei_lte_api.enums.net import LTEBandEnum, NetworkBandEnum, NetworkModeEnum
1112

@@ -14,14 +15,13 @@
1415
SelectEntity,
1516
SelectEntityDescription,
1617
)
17-
from homeassistant.config_entries import ConfigEntry
1818
from homeassistant.const import EntityCategory
1919
from homeassistant.core import HomeAssistant
2020
from homeassistant.helpers.entity import Entity
2121
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
2222

23-
from . import Router
24-
from .const import DOMAIN, KEY_NET_NET_MODE
23+
from . import HuaweiLteConfigEntry, Router
24+
from .const import KEY_NET_NET_MODE
2525
from .entity import HuaweiLteBaseEntityWithDevice
2626

2727
_LOGGER = logging.getLogger(__name__)
@@ -31,18 +31,16 @@
3131
class HuaweiSelectEntityDescription(SelectEntityDescription):
3232
"""Class describing Huawei LTE select entities."""
3333

34-
setter_fn: Callable[[str], None]
34+
setter_fn: Callable[[str], Any]
3535

3636

3737
async def async_setup_entry(
3838
hass: HomeAssistant,
39-
config_entry: ConfigEntry,
39+
config_entry: HuaweiLteConfigEntry,
4040
async_add_entities: AddConfigEntryEntitiesCallback,
4141
) -> None:
4242
"""Set up from config entry."""
43-
# Uses legacy hass.data[DOMAIN] pattern
44-
# pylint: disable-next=hass-use-runtime-data
45-
router = hass.data[DOMAIN].routers[config_entry.entry_id]
43+
router = config_entry.runtime_data
4644
selects: list[Entity] = []
4745

4846
desc = HuaweiSelectEntityDescription(

0 commit comments

Comments
 (0)