Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huawei LTE sensor unique id improvements #25609

Merged
merged 7 commits into from Aug 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 19 additions & 7 deletions homeassistant/components/huawei_lte/__init__.py
@@ -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
Expand Down Expand Up @@ -55,19 +58,14 @@ 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)
wlan_host_list = attr.ib(init=False, factory=dict)

_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.
Expand Down Expand Up @@ -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):
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/huawei_lte/manifest.json
Expand Up @@ -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": [],
Expand Down
28 changes: 22 additions & 6 deletions homeassistant/components/huawei_lte/sensor.py
Expand Up @@ -11,6 +11,7 @@
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

Expand Down Expand Up @@ -101,7 +102,7 @@
)


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 = []
Expand All @@ -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):
Expand All @@ -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)
Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions requirements_all.txt
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions requirements_test_all.txt
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions script/gen_requirements_all.py
Expand Up @@ -73,6 +73,7 @@
"georss_generic_client",
"georss_ign_sismologia_client",
"georss_qld_bushfire_alert_client",
"getmac",
"google-api-python-client",
"gTTS-token",
"ha-ffmpeg",
Expand Down
2 changes: 1 addition & 1 deletion tests/components/huawei_lte/test_init.py
Expand Up @@ -9,7 +9,7 @@
@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

Expand Down