mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
Change AsusWRT entities unique id (#97066)
Migrate AsusWRT entities unique id
This commit is contained in:
parent
17e757af36
commit
345df715d6
@ -20,7 +20,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
|
|||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util, slugify
|
||||||
|
|
||||||
from .bridge import AsusWrtBridge, WrtDevice
|
from .bridge import AsusWrtBridge, WrtDevice
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -39,7 +39,6 @@ from .const import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
CONF_REQ_RELOAD = [CONF_DNSMASQ, CONF_INTERFACE, CONF_REQUIRE_IP]
|
CONF_REQ_RELOAD = [CONF_DNSMASQ, CONF_INTERFACE, CONF_REQUIRE_IP]
|
||||||
DEFAULT_NAME = "Asuswrt"
|
|
||||||
|
|
||||||
SCAN_INTERVAL = timedelta(seconds=30)
|
SCAN_INTERVAL = timedelta(seconds=30)
|
||||||
|
|
||||||
@ -179,6 +178,44 @@ class AsusWrtRouter:
|
|||||||
self.hass, dict(self._entry.data), self._options
|
self.hass, dict(self._entry.data), self._options
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _migrate_entities_unique_id(self) -> None:
|
||||||
|
"""Migrate router entities to new unique id format."""
|
||||||
|
_ENTITY_MIGRATION_ID = {
|
||||||
|
"sensor_connected_device": "Devices Connected",
|
||||||
|
"sensor_rx_bytes": "Download",
|
||||||
|
"sensor_tx_bytes": "Upload",
|
||||||
|
"sensor_rx_rates": "Download Speed",
|
||||||
|
"sensor_tx_rates": "Upload Speed",
|
||||||
|
"sensor_load_avg1": "Load Avg (1m)",
|
||||||
|
"sensor_load_avg5": "Load Avg (5m)",
|
||||||
|
"sensor_load_avg15": "Load Avg (15m)",
|
||||||
|
"2.4GHz": "2.4GHz Temperature",
|
||||||
|
"5.0GHz": "5GHz Temperature",
|
||||||
|
"CPU": "CPU Temperature",
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_reg = er.async_get(self.hass)
|
||||||
|
router_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_reg, self._entry.entry_id
|
||||||
|
)
|
||||||
|
|
||||||
|
migrate_entities: dict[str, str] = {}
|
||||||
|
for entry in router_entries:
|
||||||
|
if entry.domain == TRACKER_DOMAIN:
|
||||||
|
continue
|
||||||
|
old_unique_id = entry.unique_id
|
||||||
|
if not old_unique_id.startswith(DOMAIN):
|
||||||
|
continue
|
||||||
|
for new_id, old_id in _ENTITY_MIGRATION_ID.items():
|
||||||
|
if old_unique_id.endswith(old_id):
|
||||||
|
migrate_entities[entry.entity_id] = slugify(
|
||||||
|
f"{self.unique_id}_{new_id}"
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
for entity_id, unique_id in migrate_entities.items():
|
||||||
|
entity_reg.async_update_entity(entity_id, new_unique_id=unique_id)
|
||||||
|
|
||||||
async def setup(self) -> None:
|
async def setup(self) -> None:
|
||||||
"""Set up a AsusWrt router."""
|
"""Set up a AsusWrt router."""
|
||||||
try:
|
try:
|
||||||
@ -215,6 +252,9 @@ class AsusWrtRouter:
|
|||||||
|
|
||||||
self._devices[device_mac] = AsusWrtDevInfo(device_mac, entry.original_name)
|
self._devices[device_mac] = AsusWrtDevInfo(device_mac, entry.original_name)
|
||||||
|
|
||||||
|
# Migrate entities to new unique id format
|
||||||
|
self._migrate_entities_unique_id()
|
||||||
|
|
||||||
# Update devices
|
# Update devices
|
||||||
await self.update_devices()
|
await self.update_devices()
|
||||||
|
|
||||||
@ -364,14 +404,9 @@ class AsusWrtRouter:
|
|||||||
return self._api.host
|
return self._api.host
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self) -> str | None:
|
def unique_id(self) -> str:
|
||||||
"""Return router unique id."""
|
"""Return router unique id."""
|
||||||
return self._entry.unique_id
|
return self._entry.unique_id or self._entry.entry_id
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Return router name."""
|
|
||||||
return self.host if self.unique_id else DEFAULT_NAME
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def devices(self) -> dict[str, AsusWrtDevInfo]:
|
def devices(self) -> dict[str, AsusWrtDevInfo]:
|
||||||
|
@ -22,6 +22,7 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
)
|
)
|
||||||
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DATA_ASUSWRT,
|
DATA_ASUSWRT,
|
||||||
@ -182,6 +183,9 @@ async def async_setup_entry(
|
|||||||
class AsusWrtSensor(CoordinatorEntity, SensorEntity):
|
class AsusWrtSensor(CoordinatorEntity, SensorEntity):
|
||||||
"""Representation of a AsusWrt sensor."""
|
"""Representation of a AsusWrt sensor."""
|
||||||
|
|
||||||
|
entity_description: AsusWrtSensorEntityDescription
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
coordinator: DataUpdateCoordinator,
|
coordinator: DataUpdateCoordinator,
|
||||||
@ -190,13 +194,9 @@ class AsusWrtSensor(CoordinatorEntity, SensorEntity):
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a AsusWrt sensor."""
|
"""Initialize a AsusWrt sensor."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
self.entity_description: AsusWrtSensorEntityDescription = description
|
self.entity_description = description
|
||||||
|
|
||||||
self._attr_name = f"{router.name} {description.name}"
|
self._attr_unique_id = slugify(f"{router.unique_id}_{description.key}")
|
||||||
if router.unique_id:
|
|
||||||
self._attr_unique_id = f"{DOMAIN} {router.unique_id} {description.name}"
|
|
||||||
else:
|
|
||||||
self._attr_unique_id = f"{DOMAIN} {self.name}"
|
|
||||||
self._attr_device_info = router.device_info
|
self._attr_device_info = router.device_info
|
||||||
self._attr_extra_state_attributes = {"hostname": router.host}
|
self._attr_extra_state_attributes = {"hostname": router.host}
|
||||||
|
|
||||||
|
@ -9,9 +9,13 @@ from homeassistant.components import device_tracker, sensor
|
|||||||
from homeassistant.components.asuswrt.const import (
|
from homeassistant.components.asuswrt.const import (
|
||||||
CONF_INTERFACE,
|
CONF_INTERFACE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
MODE_ROUTER,
|
||||||
PROTOCOL_TELNET,
|
PROTOCOL_TELNET,
|
||||||
|
SENSORS_BYTES,
|
||||||
|
SENSORS_LOAD_AVG,
|
||||||
|
SENSORS_RATES,
|
||||||
|
SENSORS_TEMPERATURES,
|
||||||
)
|
)
|
||||||
from homeassistant.components.asuswrt.router import DEFAULT_NAME
|
|
||||||
from homeassistant.components.device_tracker import CONF_CONSIDER_HOME
|
from homeassistant.components.device_tracker import CONF_CONSIDER_HOME
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -43,7 +47,7 @@ CONFIG_DATA = {
|
|||||||
CONF_PROTOCOL: PROTOCOL_TELNET,
|
CONF_PROTOCOL: PROTOCOL_TELNET,
|
||||||
CONF_USERNAME: "user",
|
CONF_USERNAME: "user",
|
||||||
CONF_PASSWORD: "pwd",
|
CONF_PASSWORD: "pwd",
|
||||||
CONF_MODE: "router",
|
CONF_MODE: MODE_ROUTER,
|
||||||
}
|
}
|
||||||
|
|
||||||
MAC_ADDR = "a1:b2:c3:d4:e5:f6"
|
MAC_ADDR = "a1:b2:c3:d4:e5:f6"
|
||||||
@ -57,26 +61,8 @@ MOCK_MAC_2 = "A2:B2:C2:D2:E2:F2"
|
|||||||
MOCK_MAC_3 = "A3:B3:C3:D3:E3:F3"
|
MOCK_MAC_3 = "A3:B3:C3:D3:E3:F3"
|
||||||
MOCK_MAC_4 = "A4:B4:C4:D4:E4:F4"
|
MOCK_MAC_4 = "A4:B4:C4:D4:E4:F4"
|
||||||
|
|
||||||
SENSORS_DEFAULT = [
|
SENSORS_DEFAULT = [*SENSORS_BYTES, *SENSORS_RATES]
|
||||||
"Download Speed",
|
SENSORS_ALL = [*SENSORS_DEFAULT, *SENSORS_LOAD_AVG, *SENSORS_TEMPERATURES]
|
||||||
"Download",
|
|
||||||
"Upload Speed",
|
|
||||||
"Upload",
|
|
||||||
]
|
|
||||||
|
|
||||||
SENSORS_LOADAVG = [
|
|
||||||
"Load Avg (1m)",
|
|
||||||
"Load Avg (5m)",
|
|
||||||
"Load Avg (15m)",
|
|
||||||
]
|
|
||||||
|
|
||||||
SENSORS_TEMP = [
|
|
||||||
"2.4GHz Temperature",
|
|
||||||
"5GHz Temperature",
|
|
||||||
"CPU Temperature",
|
|
||||||
]
|
|
||||||
|
|
||||||
SENSORS_ALL = [*SENSORS_DEFAULT, *SENSORS_LOADAVG, *SENSORS_TEMP]
|
|
||||||
|
|
||||||
PATCH_SETUP_ENTRY = patch(
|
PATCH_SETUP_ENTRY = patch(
|
||||||
"homeassistant.components.asuswrt.async_setup_entry",
|
"homeassistant.components.asuswrt.async_setup_entry",
|
||||||
@ -105,7 +91,7 @@ def mock_available_temps_fixture():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="create_device_registry_devices")
|
@pytest.fixture(name="create_device_registry_devices")
|
||||||
def create_device_registry_devices_fixture(hass):
|
def create_device_registry_devices_fixture(hass: HomeAssistant):
|
||||||
"""Create device registry devices so the device tracker entities are enabled when added."""
|
"""Create device registry devices so the device tracker entities are enabled when added."""
|
||||||
dev_reg = dr.async_get(hass)
|
dev_reg = dr.async_get(hass)
|
||||||
config_entry = MockConfigEntry(domain="something_else")
|
config_entry = MockConfigEntry(domain="something_else")
|
||||||
@ -182,7 +168,7 @@ def mock_controller_connect_sens_fail():
|
|||||||
yield service_mock
|
yield service_mock
|
||||||
|
|
||||||
|
|
||||||
def _setup_entry(hass, config, sensors, unique_id=None):
|
def _setup_entry(hass: HomeAssistant, config, sensors, unique_id=None):
|
||||||
"""Create mock config entry with enabled sensors."""
|
"""Create mock config entry with enabled sensors."""
|
||||||
entity_reg = er.async_get(hass)
|
entity_reg = er.async_get(hass)
|
||||||
|
|
||||||
@ -195,16 +181,17 @@ def _setup_entry(hass, config, sensors, unique_id=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# init variable
|
# init variable
|
||||||
obj_prefix = slugify(HOST if unique_id else DEFAULT_NAME)
|
obj_prefix = slugify(HOST)
|
||||||
sensor_prefix = f"{sensor.DOMAIN}.{obj_prefix}"
|
sensor_prefix = f"{sensor.DOMAIN}.{obj_prefix}"
|
||||||
|
unique_id_prefix = slugify(unique_id or config_entry.entry_id)
|
||||||
|
|
||||||
# Pre-enable the status sensor
|
# Pre-enable the status sensor
|
||||||
for sensor_name in sensors:
|
for sensor_key in sensors:
|
||||||
sensor_id = slugify(sensor_name)
|
sensor_id = slugify(sensor_key)
|
||||||
entity_reg.async_get_or_create(
|
entity_reg.async_get_or_create(
|
||||||
sensor.DOMAIN,
|
sensor.DOMAIN,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
f"{DOMAIN} {unique_id or DEFAULT_NAME} {sensor_name}",
|
f"{unique_id_prefix}_{sensor_id}",
|
||||||
suggested_object_id=f"{obj_prefix}_{sensor_id}",
|
suggested_object_id=f"{obj_prefix}_{sensor_id}",
|
||||||
config_entry=config_entry,
|
config_entry=config_entry,
|
||||||
disabled_by=None,
|
disabled_by=None,
|
||||||
@ -255,10 +242,10 @@ async def test_sensors(
|
|||||||
|
|
||||||
assert hass.states.get(f"{device_tracker.DOMAIN}.test").state == STATE_HOME
|
assert hass.states.get(f"{device_tracker.DOMAIN}.test").state == STATE_HOME
|
||||||
assert hass.states.get(f"{device_tracker.DOMAIN}.testtwo").state == STATE_HOME
|
assert hass.states.get(f"{device_tracker.DOMAIN}.testtwo").state == STATE_HOME
|
||||||
assert hass.states.get(f"{sensor_prefix}_download_speed").state == "160.0"
|
assert hass.states.get(f"{sensor_prefix}_sensor_rx_rates").state == "160.0"
|
||||||
assert hass.states.get(f"{sensor_prefix}_download").state == "60.0"
|
assert hass.states.get(f"{sensor_prefix}_sensor_rx_bytes").state == "60.0"
|
||||||
assert hass.states.get(f"{sensor_prefix}_upload_speed").state == "80.0"
|
assert hass.states.get(f"{sensor_prefix}_sensor_tx_rates").state == "80.0"
|
||||||
assert hass.states.get(f"{sensor_prefix}_upload").state == "50.0"
|
assert hass.states.get(f"{sensor_prefix}_sensor_tx_bytes").state == "50.0"
|
||||||
assert hass.states.get(f"{sensor_prefix}_devices_connected").state == "2"
|
assert hass.states.get(f"{sensor_prefix}_devices_connected").state == "2"
|
||||||
|
|
||||||
# remove first tracked device
|
# remove first tracked device
|
||||||
@ -296,7 +283,7 @@ async def test_loadavg_sensors(
|
|||||||
connect,
|
connect,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test creating an AsusWRT load average sensors."""
|
"""Test creating an AsusWRT load average sensors."""
|
||||||
config_entry, sensor_prefix = _setup_entry(hass, CONFIG_DATA, SENSORS_LOADAVG)
|
config_entry, sensor_prefix = _setup_entry(hass, CONFIG_DATA, SENSORS_LOAD_AVG)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
# initial devices setup
|
# initial devices setup
|
||||||
@ -306,9 +293,9 @@ async def test_loadavg_sensors(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# assert temperature sensor available
|
# assert temperature sensor available
|
||||||
assert hass.states.get(f"{sensor_prefix}_load_avg_1m").state == "1.1"
|
assert hass.states.get(f"{sensor_prefix}_sensor_load_avg1").state == "1.1"
|
||||||
assert hass.states.get(f"{sensor_prefix}_load_avg_5m").state == "1.2"
|
assert hass.states.get(f"{sensor_prefix}_sensor_load_avg5").state == "1.2"
|
||||||
assert hass.states.get(f"{sensor_prefix}_load_avg_15m").state == "1.3"
|
assert hass.states.get(f"{sensor_prefix}_sensor_load_avg15").state == "1.3"
|
||||||
|
|
||||||
|
|
||||||
async def test_temperature_sensors(
|
async def test_temperature_sensors(
|
||||||
@ -316,7 +303,7 @@ async def test_temperature_sensors(
|
|||||||
connect,
|
connect,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test creating a AsusWRT temperature sensors."""
|
"""Test creating a AsusWRT temperature sensors."""
|
||||||
config_entry, sensor_prefix = _setup_entry(hass, CONFIG_DATA, SENSORS_TEMP)
|
config_entry, sensor_prefix = _setup_entry(hass, CONFIG_DATA, SENSORS_TEMPERATURES)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
# initial devices setup
|
# initial devices setup
|
||||||
@ -326,9 +313,9 @@ async def test_temperature_sensors(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# assert temperature sensor available
|
# assert temperature sensor available
|
||||||
assert hass.states.get(f"{sensor_prefix}_2_4ghz_temperature").state == "40.0"
|
assert hass.states.get(f"{sensor_prefix}_2_4ghz").state == "40.0"
|
||||||
assert not hass.states.get(f"{sensor_prefix}_5ghz_temperature")
|
assert not hass.states.get(f"{sensor_prefix}_5_0ghz")
|
||||||
assert hass.states.get(f"{sensor_prefix}_cpu_temperature").state == "71.2"
|
assert hass.states.get(f"{sensor_prefix}_cpu").state == "71.2"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -396,3 +383,31 @@ async def test_options_reload(hass: HomeAssistant, connect) -> None:
|
|||||||
|
|
||||||
assert setup_entry_call.called
|
assert setup_entry_call.called
|
||||||
assert config_entry.state is ConfigEntryState.LOADED
|
assert config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
|
||||||
|
async def test_unique_id_migration(hass: HomeAssistant, connect) -> None:
|
||||||
|
"""Test AsusWRT entities unique id format migration."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data=CONFIG_DATA,
|
||||||
|
unique_id=MAC_ADDR,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
entity_reg = er.async_get(hass)
|
||||||
|
obj_entity_id = slugify(f"{HOST} Upload")
|
||||||
|
entity_reg.async_get_or_create(
|
||||||
|
sensor.DOMAIN,
|
||||||
|
DOMAIN,
|
||||||
|
f"{DOMAIN} {MAC_ADDR} Upload",
|
||||||
|
suggested_object_id=obj_entity_id,
|
||||||
|
config_entry=config_entry,
|
||||||
|
disabled_by=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
migr_entity = entity_reg.async_get(f"{sensor.DOMAIN}.{obj_entity_id}")
|
||||||
|
assert migr_entity is not None
|
||||||
|
assert migr_entity.unique_id == slugify(f"{MAC_ADDR}_sensor_tx_bytes")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user