Huawei LTE sensor unique id improvements (#25609)
* Convert sensor setup to async * Improve sensor unique ids * Save some indent levels, use f-string formatting * Require getmac in tests * Fix RouterData init in tests * Make discovery_info optional in async_setup_platform signaturepull/25633/head
parent
36129af447
commit
c2556d90ea
|
@ -1,12 +1,15 @@
|
|||
"""Support for Huawei LTE routers."""
|
||||
from datetime import timedelta
|
||||
from functools import reduce
|
||||
from urllib.parse import urlparse
|
||||
import ipaddress
|
||||
import logging
|
||||
import operator
|
||||
from typing import Any, Callable
|
||||
|
||||
import voluptuous as vol
|
||||
import attr
|
||||
from getmac import get_mac_address
|
||||
from huawei_lte_api.AuthorizedConnection import AuthorizedConnection
|
||||
from huawei_lte_api.Client import Client
|
||||
from huawei_lte_api.exceptions import ResponseErrorNotSupportedException
|
||||
|
@ -55,6 +58,7 @@ class RouterData:
|
|||
"""Class for router state."""
|
||||
|
||||
client = attr.ib()
|
||||
mac = attr.ib()
|
||||
device_information = attr.ib(init=False, factory=dict)
|
||||
device_signal = attr.ib(init=False, factory=dict)
|
||||
monitoring_traffic_statistics = attr.ib(init=False, factory=dict)
|
||||
|
@ -62,12 +66,6 @@ class RouterData:
|
|||
|
||||
_subscriptions = attr.ib(init=False, factory=set)
|
||||
|
||||
def __attrs_post_init__(self) -> None:
|
||||
"""Fetch device information once, for serial number in @unique_ids."""
|
||||
self.subscribe("device_information")
|
||||
self._update()
|
||||
self.unsubscribe("device_information")
|
||||
|
||||
def __getitem__(self, path: str):
|
||||
"""
|
||||
Get value corresponding to a dotted path.
|
||||
|
@ -148,10 +146,24 @@ def _setup_lte(hass, lte_config) -> None:
|
|||
username = lte_config[CONF_USERNAME]
|
||||
password = lte_config[CONF_PASSWORD]
|
||||
|
||||
# Get MAC address for use in unique ids. Being able to use something
|
||||
# from the API would be nice, but all of that seems to be available only
|
||||
# through authenticated calls (e.g. device_information.SerialNumber), and
|
||||
# we want this available and the same when unauthenticated too.
|
||||
host = urlparse(url).hostname
|
||||
try:
|
||||
if ipaddress.ip_address(host).version == 6:
|
||||
mode = "ip6"
|
||||
else:
|
||||
mode = "ip"
|
||||
except ValueError:
|
||||
mode = "hostname"
|
||||
mac = get_mac_address(**{mode: host})
|
||||
|
||||
connection = AuthorizedConnection(url, username=username, password=password)
|
||||
client = Client(connection)
|
||||
|
||||
data = RouterData(client)
|
||||
data = RouterData(client, mac)
|
||||
hass.data[DATA_KEY].data[url] = data
|
||||
|
||||
def cleanup(event):
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"name": "Huawei lte",
|
||||
"documentation": "https://www.home-assistant.io/components/huawei_lte",
|
||||
"requirements": [
|
||||
"getmac==0.8.1",
|
||||
"huawei-lte-api==1.2.0"
|
||||
],
|
||||
"dependencies": [],
|
||||
|
|
|
@ -11,6 +11,7 @@ from homeassistant.components.sensor import (
|
|||
PLATFORM_SCHEMA,
|
||||
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||
)
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.entity import Entity
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
|
@ -101,7 +102,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||
)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info):
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up Huawei LTE sensor devices."""
|
||||
data = hass.data[DATA_KEY].get_data(config)
|
||||
sensors = []
|
||||
|
@ -111,7 +112,24 @@ def setup_platform(hass, config, add_entities, discovery_info):
|
|||
data.subscribe(path)
|
||||
sensors.append(HuaweiLteSensor(data, path, SENSOR_META.get(path, {})))
|
||||
|
||||
add_entities(sensors, True)
|
||||
# Pre-0.97 unique id migration. Old ones used the device serial number
|
||||
# (see comments in HuaweiLteData._setup_lte for more info), as well as
|
||||
# had a bug that joined the path str with periods, not the path components,
|
||||
# resulting e.g. *_device_signal.sinr to end up as
|
||||
# *_d.e.v.i.c.e._.s.i.g.n.a.l...s.i.n.r
|
||||
entreg = await entity_registry.async_get_registry(hass)
|
||||
for entid, ent in entreg.entities.items():
|
||||
if ent.platform != "huawei_lte":
|
||||
continue
|
||||
for sensor in sensors:
|
||||
oldsuf = ".".join(sensor.path)
|
||||
if ent.unique_id.endswith(f"_{oldsuf}"):
|
||||
entreg.async_update_entity(entid, new_unique_id=sensor.unique_id)
|
||||
_LOGGER.debug(
|
||||
"Updated entity %s unique id to %s", entid, sensor.unique_id
|
||||
)
|
||||
|
||||
async_add_entities(sensors, True)
|
||||
|
||||
|
||||
def format_default(value):
|
||||
|
@ -134,7 +152,7 @@ class HuaweiLteSensor(Entity):
|
|||
"""Huawei LTE sensor entity."""
|
||||
|
||||
data = attr.ib(type=RouterData)
|
||||
path = attr.ib(type=list)
|
||||
path = attr.ib(type=str)
|
||||
meta = attr.ib(type=dict)
|
||||
|
||||
_state = attr.ib(init=False, default=STATE_UNKNOWN)
|
||||
|
@ -143,9 +161,7 @@ class HuaweiLteSensor(Entity):
|
|||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return unique ID for sensor."""
|
||||
return "{}_{}".format(
|
||||
self.data["device_information.SerialNumber"], ".".join(self.path)
|
||||
)
|
||||
return "{}-{}".format(self.data.mac, self.path)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
|
|
|
@ -537,6 +537,7 @@ georss_ign_sismologia_client==0.2
|
|||
georss_qld_bushfire_alert_client==0.3
|
||||
|
||||
# homeassistant.components.braviatv
|
||||
# homeassistant.components.huawei_lte
|
||||
# homeassistant.components.nmap_tracker
|
||||
getmac==0.8.1
|
||||
|
||||
|
|
|
@ -147,6 +147,11 @@ georss_ign_sismologia_client==0.2
|
|||
# homeassistant.components.qld_bushfire
|
||||
georss_qld_bushfire_alert_client==0.3
|
||||
|
||||
# homeassistant.components.braviatv
|
||||
# homeassistant.components.huawei_lte
|
||||
# homeassistant.components.nmap_tracker
|
||||
getmac==0.8.1
|
||||
|
||||
# homeassistant.components.google
|
||||
google-api-python-client==1.6.4
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ TEST_REQUIREMENTS = (
|
|||
"georss_generic_client",
|
||||
"georss_ign_sismologia_client",
|
||||
"georss_qld_bushfire_alert_client",
|
||||
"getmac",
|
||||
"google-api-python-client",
|
||||
"gTTS-token",
|
||||
"ha-ffmpeg",
|
||||
|
|
|
@ -9,7 +9,7 @@ from homeassistant.components import huawei_lte
|
|||
@pytest.fixture(autouse=True)
|
||||
def routerdata():
|
||||
"""Set up a router data for testing."""
|
||||
rd = huawei_lte.RouterData(Mock())
|
||||
rd = huawei_lte.RouterData(Mock(), "de:ad:be:ef:00:00")
|
||||
rd.device_information = {"SoftwareVersion": "1.0", "nested": {"foo": "bar"}}
|
||||
return rd
|
||||
|
||||
|
|
Loading…
Reference in New Issue