Migrate Shelly virtual component unique IDs to include roles (#153844)

This commit is contained in:
Shay Levy
2025-10-07 00:50:47 +03:00
committed by GitHub
parent f63504af01
commit 881306f6a4
16 changed files with 287 additions and 79 deletions
@@ -2,6 +2,7 @@
from __future__ import annotations
from functools import partial
from typing import Final
from aioshelly.ble.const import BLE_SCRIPT_NAME
@@ -63,6 +64,7 @@ from .repairs import (
)
from .utils import (
async_create_issue_unsupported_firmware,
async_migrate_rpc_virtual_components_unique_ids,
get_coap_context,
get_device_entry_gen,
get_http_port,
@@ -323,6 +325,12 @@ async def _async_setup_rpc_entry(hass: HomeAssistant, entry: ShellyConfigEntry)
translation_placeholders={"device": entry.title},
) from err
await er.async_migrate_entries(
hass,
entry.entry_id,
partial(async_migrate_rpc_virtual_components_unique_ids, device.config),
)
runtime_data.rpc = ShellyRpcCoordinator(hass, entry, device)
runtime_data.rpc.async_setup()
runtime_data.rpc_poll = ShellyRpcPollingCoordinator(hass, entry, device)
@@ -18,7 +18,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from .const import CONF_SLEEP_PERIOD
from .const import CONF_SLEEP_PERIOD, MODEL_FRANKEVER_WATER_VALVE
from .coordinator import ShellyConfigEntry, ShellyRpcCoordinator
from .entity import (
BlockEntityDescription,
@@ -270,12 +270,21 @@ RPC_SENSORS: Final = {
entity_registry_enabled_default=False,
entity_category=EntityCategory.DIAGNOSTIC,
),
"boolean": RpcBinarySensorDescription(
"boolean_generic": RpcBinarySensorDescription(
key="boolean",
sub_key="value",
removal_condition=lambda config, _status, key: not is_view_for_platform(
config, key, BINARY_SENSOR_PLATFORM
),
role="generic",
),
"boolean_has_power": RpcBinarySensorDescription(
key="boolean",
sub_key="value",
device_class=BinarySensorDeviceClass.POWER,
entity_category=EntityCategory.DIAGNOSTIC,
role="has_power",
models={MODEL_FRANKEVER_WATER_VALVE},
),
"calibration": RpcBinarySensorDescription(
key="blutrv",
+2
View File
@@ -308,3 +308,5 @@ MODEL_NEO_WATER_VALVE = "NeoWaterValve"
MODEL_FRANKEVER_WATER_VALVE = "WaterValve"
MODEL_LINKEDGO_ST802_THERMOSTAT = "ST-802"
MODEL_LINKEDGO_ST1820_THERMOSTAT = "ST1820"
MODEL_TOP_EV_CHARGER_EVE01 = "EVE01"
MODEL_FRANKEVER_IRRIGATION_CONTROLLER = "Irrigation"
+4 -3
View File
@@ -29,6 +29,7 @@ from .utils import (
get_rpc_device_info,
get_rpc_entity_name,
get_rpc_key_instances,
get_rpc_role_by_key,
)
@@ -189,9 +190,9 @@ def async_setup_rpc_attribute_entities(
if description.models and coordinator.model not in description.models:
continue
if description.role and description.role != coordinator.device.config[
key
].get("role", "generic"):
if description.role and description.role != get_rpc_role_by_key(
coordinator.device.config, key
):
continue
if description.sub_key not in coordinator.device.status[
+63 -2
View File
@@ -24,7 +24,16 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.entity_registry import RegistryEntry
from .const import CONF_SLEEP_PERIOD, DOMAIN, LOGGER, VIRTUAL_NUMBER_MODE_MAP
from .const import (
CONF_SLEEP_PERIOD,
DOMAIN,
LOGGER,
MODEL_FRANKEVER_WATER_VALVE,
MODEL_LINKEDGO_ST802_THERMOSTAT,
MODEL_LINKEDGO_ST1820_THERMOSTAT,
MODEL_TOP_EV_CHARGER_EVE01,
VIRTUAL_NUMBER_MODE_MAP,
)
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
from .entity import (
BlockEntityDescription,
@@ -183,7 +192,7 @@ RPC_NUMBERS: Final = {
method="blu_trv_set_external_temperature",
entity_class=RpcBluTrvExtTempNumber,
),
"number": RpcNumberDescription(
"number_generic": RpcNumberDescription(
key="number",
sub_key="value",
removal_condition=lambda config, _status, key: not is_view_for_platform(
@@ -197,6 +206,58 @@ RPC_NUMBERS: Final = {
step_fn=lambda config: config["meta"]["ui"].get("step"),
unit=get_virtual_component_unit,
method="number_set",
role="generic",
),
"number_current_limit": RpcNumberDescription(
key="number",
sub_key="value",
max_fn=lambda config: config["max"],
min_fn=lambda config: config["min"],
mode_fn=lambda config: NumberMode.SLIDER,
step_fn=lambda config: config["meta"]["ui"].get("step"),
unit=get_virtual_component_unit,
method="number_set",
role="current_limit",
models={MODEL_TOP_EV_CHARGER_EVE01},
),
"number_position": RpcNumberDescription(
key="number",
sub_key="value",
entity_registry_enabled_default=False,
max_fn=lambda config: config["max"],
min_fn=lambda config: config["min"],
mode_fn=lambda config: NumberMode.SLIDER,
step_fn=lambda config: config["meta"]["ui"].get("step"),
unit=get_virtual_component_unit,
method="number_set",
role="position",
models={MODEL_FRANKEVER_WATER_VALVE},
),
"number_target_humidity": RpcNumberDescription(
key="number",
sub_key="value",
entity_registry_enabled_default=False,
max_fn=lambda config: config["max"],
min_fn=lambda config: config["min"],
mode_fn=lambda config: NumberMode.SLIDER,
step_fn=lambda config: config["meta"]["ui"].get("step"),
unit=get_virtual_component_unit,
method="number_set",
role="target_humidity",
models={MODEL_LINKEDGO_ST802_THERMOSTAT, MODEL_LINKEDGO_ST1820_THERMOSTAT},
),
"number_target_temperature": RpcNumberDescription(
key="number",
sub_key="value",
entity_registry_enabled_default=False,
max_fn=lambda config: config["max"],
min_fn=lambda config: config["min"],
mode_fn=lambda config: NumberMode.SLIDER,
step_fn=lambda config: config["meta"]["ui"].get("step"),
unit=get_virtual_component_unit,
method="number_set",
role="target_temperature",
models={MODEL_LINKEDGO_ST802_THERMOSTAT, MODEL_LINKEDGO_ST1820_THERMOSTAT},
),
"valve_position": RpcNumberDescription(
key="blutrv",
+2 -1
View File
@@ -38,12 +38,13 @@ class RpcSelectDescription(RpcEntityDescription, SelectEntityDescription):
RPC_SELECT_ENTITIES: Final = {
"enum": RpcSelectDescription(
"enum_generic": RpcSelectDescription(
key="enum",
sub_key="value",
removal_condition=lambda config, _status, key: not is_view_for_platform(
config, key, SELECT_PLATFORM
),
role="generic",
),
}
+3 -44
View File
@@ -3,8 +3,7 @@
from __future__ import annotations
from dataclasses import dataclass
from functools import partial
from typing import Any, Final, cast
from typing import Final, cast
from aioshelly.block_device import Block
from aioshelly.const import RPC_GENERATIONS
@@ -37,13 +36,12 @@ from homeassistant.const import (
UnitOfVolume,
UnitOfVolumeFlowRate,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.entity_registry import RegistryEntry
from homeassistant.helpers.typing import StateType
from .const import CONF_SLEEP_PERIOD, LOGGER
from .const import CONF_SLEEP_PERIOD
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
from .entity import (
BlockEntityDescription,
@@ -1663,39 +1661,6 @@ RPC_SENSORS: Final = {
}
@callback
def async_migrate_unique_ids(
coordinator: ShellyRpcCoordinator,
entity_entry: er.RegistryEntry,
) -> dict[str, Any] | None:
"""Migrate sensor unique IDs to include role."""
if not entity_entry.entity_id.startswith("sensor."):
return None
for sensor_id in ("text", "number", "enum"):
old_unique_id = entity_entry.unique_id
if old_unique_id.endswith(f"-{sensor_id}"):
if entity_entry.original_device_class == SensorDeviceClass.HUMIDITY:
new_unique_id = f"{old_unique_id}_current_humidity"
elif entity_entry.original_device_class == SensorDeviceClass.TEMPERATURE:
new_unique_id = f"{old_unique_id}_current_temperature"
else:
new_unique_id = f"{old_unique_id}_generic"
LOGGER.debug(
"Migrating unique_id for %s entity from [%s] to [%s]",
entity_entry.entity_id,
old_unique_id,
new_unique_id,
)
return {
"new_unique_id": entity_entry.unique_id.replace(
old_unique_id, new_unique_id
)
}
return None
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ShellyConfigEntry,
@@ -1715,12 +1680,6 @@ async def async_setup_entry(
coordinator = config_entry.runtime_data.rpc
assert coordinator
await er.async_migrate_entries(
hass,
config_entry.entry_id,
partial(async_migrate_unique_ids, coordinator),
)
async_setup_entry_rpc(
hass, config_entry, async_add_entities, RPC_SENSORS, RpcSensor
)
+122 -1
View File
@@ -21,6 +21,13 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.entity_registry import RegistryEntry
from homeassistant.helpers.restore_state import RestoreEntity
from .const import (
MODEL_FRANKEVER_IRRIGATION_CONTROLLER,
MODEL_LINKEDGO_ST802_THERMOSTAT,
MODEL_LINKEDGO_ST1820_THERMOSTAT,
MODEL_NEO_WATER_VALVE,
MODEL_TOP_EV_CHARGER_EVE01,
)
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
from .entity import (
BlockEntityDescription,
@@ -87,7 +94,7 @@ RPC_RELAY_SWITCHES = {
}
RPC_SWITCHES = {
"boolean": RpcSwitchDescription(
"boolean_generic": RpcSwitchDescription(
key="boolean",
sub_key="value",
removal_condition=lambda config, _status, key: not is_view_for_platform(
@@ -97,6 +104,120 @@ RPC_SWITCHES = {
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="generic",
),
"boolean_anti_freeze": RpcSwitchDescription(
key="boolean",
sub_key="value",
entity_registry_enabled_default=False,
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="anti_freeze",
models={MODEL_LINKEDGO_ST802_THERMOSTAT, MODEL_LINKEDGO_ST1820_THERMOSTAT},
),
"boolean_child_lock": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="child_lock",
models={MODEL_LINKEDGO_ST1820_THERMOSTAT},
),
"boolean_enable": RpcSwitchDescription(
key="boolean",
sub_key="value",
entity_registry_enabled_default=False,
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="enable",
models={MODEL_LINKEDGO_ST802_THERMOSTAT, MODEL_LINKEDGO_ST1820_THERMOSTAT},
),
"boolean_start_charging": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="start_charging",
models={MODEL_TOP_EV_CHARGER_EVE01},
),
"boolean_state": RpcSwitchDescription(
key="boolean",
sub_key="value",
entity_registry_enabled_default=False,
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="state",
models={MODEL_NEO_WATER_VALVE},
),
"boolean_zone0": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="zone0",
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
),
"boolean_zone1": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="zone1",
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
),
"boolean_zone2": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="zone2",
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
),
"boolean_zone3": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="zone3",
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
),
"boolean_zone4": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="zone4",
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
),
"boolean_zone5": RpcSwitchDescription(
key="boolean",
sub_key="value",
is_on=lambda status: bool(status["value"]),
method_on="Boolean.Set",
method_off="Boolean.Set",
method_params_fn=lambda id, value: {"id": id, "value": value},
role="zone5",
models={MODEL_FRANKEVER_IRRIGATION_CONTROLLER},
),
"script": RpcSwitchDescription(
key="script",
+2 -1
View File
@@ -38,12 +38,13 @@ class RpcTextDescription(RpcEntityDescription, TextEntityDescription):
RPC_TEXT_ENTITIES: Final = {
"text": RpcTextDescription(
"text_generic": RpcTextDescription(
key="text",
sub_key="value",
removal_condition=lambda config, _status, key: not is_view_for_platform(
config, key, TEXT_PLATFORM
),
role="generic",
),
}
+37
View File
@@ -484,6 +484,11 @@ def get_rpc_key_by_role(keys_dict: dict[str, Any], role: str) -> str | None:
return None
def get_rpc_role_by_key(keys_dict: dict[str, Any], key: str) -> str:
"""Return role by key for RPC device from a dict."""
return cast(str, keys_dict[key].get("role", "generic"))
def id_from_key(key: str) -> int:
"""Return id from key."""
return int(key.split(":")[-1])
@@ -934,3 +939,35 @@ def remove_empty_sub_devices(hass: HomeAssistant, entry: ConfigEntry) -> None:
def format_ble_addr(ble_addr: str) -> str:
"""Format BLE address to use in unique_id."""
return ble_addr.replace(":", "").upper()
@callback
def async_migrate_rpc_virtual_components_unique_ids(
config: dict[str, Any], entity_entry: er.RegistryEntry
) -> dict[str, Any] | None:
"""Migrate RPC virtual components unique_ids to include role in the ID.
This is needed to support multiple components with the same key.
The old unique_id format is: {mac}-{key}-{component}
The new unique_id format is: {mac}-{key}-{component}_{role}
"""
for component in VIRTUAL_COMPONENTS:
if entity_entry.unique_id.endswith(f"-{component!s}"):
key = entity_entry.unique_id.split("-")[-2]
if key not in config:
continue
role = get_rpc_role_by_key(config, key)
new_unique_id = f"{entity_entry.unique_id}_{role}"
LOGGER.debug(
"Migrating unique_id for %s entity from [%s] to [%s]",
entity_entry.entity_id,
entity_entry.unique_id,
new_unique_id,
)
return {
"new_unique_id": entity_entry.unique_id.replace(
entity_entry.unique_id, new_unique_id
)
}
return None
@@ -440,7 +440,7 @@ async def test_rpc_device_virtual_binary_sensor(
assert state.state == STATE_ON
assert (entry := entity_registry.async_get(entity_id))
assert entry.unique_id == "123456789ABC-boolean:203-boolean"
assert entry.unique_id == "123456789ABC-boolean:203-boolean_generic"
monkeypatch.setitem(mock_rpc_device.status["boolean:203"], "value", False)
mock_rpc_device.mock_update()
@@ -472,7 +472,7 @@ async def test_rpc_remove_virtual_binary_sensor_when_mode_toggle(
hass,
BINARY_SENSOR_DOMAIN,
"test_name_boolean_200",
"boolean:200-boolean",
"boolean:200-boolean_generic",
config_entry,
device_id=device_entry.id,
)
@@ -498,7 +498,7 @@ async def test_rpc_remove_virtual_binary_sensor_when_orphaned(
hass,
BINARY_SENSOR_DOMAIN,
"test_name_boolean_200",
"boolean:200-boolean",
"boolean:200-boolean_generic",
config_entry,
device_id=device_entry.id,
)
@@ -507,13 +507,13 @@ async def test_rpc_remove_virtual_binary_sensor_when_orphaned(
sub_device_entry = register_sub_device(
device_registry,
config_entry,
"boolean:201-boolean",
"boolean:201-boolean_generic",
)
entity_id2 = register_entity(
hass,
BINARY_SENSOR_DOMAIN,
"boolean_201",
"boolean:201-boolean",
"boolean:201-boolean_generic",
config_entry,
device_id=sub_device_entry.id,
)
+3 -3
View File
@@ -331,7 +331,7 @@ async def test_rpc_device_virtual_number(
assert state.attributes.get(ATTR_MODE) is mode
assert (entry := entity_registry.async_get(entity_id))
assert entry.unique_id == "123456789ABC-number:203-number"
assert entry.unique_id == "123456789ABC-number:203-number_generic"
monkeypatch.setitem(mock_rpc_device.status["number:203"], "value", 78.9)
mock_rpc_device.mock_update()
@@ -380,7 +380,7 @@ async def test_rpc_remove_virtual_number_when_mode_label(
hass,
NUMBER_DOMAIN,
"test_name_number_200",
"number:200-number",
"number:200-number_generic",
config_entry,
device_id=device_entry.id,
)
@@ -404,7 +404,7 @@ async def test_rpc_remove_virtual_number_when_orphaned(
hass,
NUMBER_DOMAIN,
"test_name_number_200",
"number:200-number",
"number:200-number_generic",
config_entry,
device_id=device_entry.id,
)
+3 -3
View File
@@ -76,7 +76,7 @@ async def test_rpc_device_virtual_enum(
]
assert (entry := entity_registry.async_get(entity_id))
assert entry.unique_id == "123456789ABC-enum:203-enum"
assert entry.unique_id == "123456789ABC-enum:203-enum_generic"
monkeypatch.setitem(mock_rpc_device.status["enum:203"], "value", "option 2")
mock_rpc_device.mock_update()
@@ -128,7 +128,7 @@ async def test_rpc_remove_virtual_enum_when_mode_label(
hass,
SELECT_PLATFORM,
"test_name_enum_200",
"enum:200-enum",
"enum:200-enum_generic",
config_entry,
device_id=device_entry.id,
)
@@ -152,7 +152,7 @@ async def test_rpc_remove_virtual_enum_when_orphaned(
hass,
SELECT_PLATFORM,
"test_name_enum_200",
"enum:200-enum",
"enum:200-enum_generic",
config_entry,
device_id=device_entry.id,
)
+14 -6
View File
@@ -1080,12 +1080,12 @@ async def test_rpc_device_virtual_text_sensor(
@pytest.mark.parametrize(
("old_id", "new_id", "device_class"),
("old_id", "new_id", "role"),
[
("enum", "enum_generic", SensorDeviceClass.ENUM),
("enum", "enum_generic", None),
("number", "number_generic", None),
("number", "number_current_humidity", SensorDeviceClass.HUMIDITY),
("number", "number_current_temperature", SensorDeviceClass.TEMPERATURE),
("number", "number_current_humidity", "current_humidity"),
("number", "number_current_temperature", "current_temperature"),
("text", "text_generic", None),
],
)
@@ -1094,15 +1094,24 @@ async def test_migrate_unique_id_virtual_components_roles(
mock_rpc_device: Mock,
entity_registry: EntityRegistry,
caplog: pytest.LogCaptureFixture,
monkeypatch: pytest.MonkeyPatch,
old_id: str,
new_id: str,
device_class: SensorDeviceClass | None,
role: str | None,
) -> None:
"""Test migration of unique_id for virtual components to include role."""
entry = await init_integration(hass, 3, skip_setup=True)
unique_base = f"{MOCK_MAC}-{old_id}:200"
old_unique_id = f"{unique_base}-{old_id}"
new_unique_id = f"{unique_base}-{new_id}"
config = deepcopy(mock_rpc_device.config)
if role:
config[f"{old_id}:200"] = {
"role": role,
}
else:
config[f"{old_id}:200"] = {}
monkeypatch.setattr(mock_rpc_device, "config", config)
entity = entity_registry.async_get_or_create(
suggested_object_id="test_name_test_sensor",
@@ -1111,7 +1120,6 @@ async def test_migrate_unique_id_virtual_components_roles(
platform=DOMAIN,
unique_id=old_unique_id,
config_entry=entry,
original_device_class=device_class,
)
assert entity.unique_id == old_unique_id
+5 -5
View File
@@ -645,7 +645,7 @@ async def test_rpc_device_virtual_switch(
assert state.state == STATE_ON
assert (entry := entity_registry.async_get(entity_id))
assert entry.unique_id == "123456789ABC-boolean:200-boolean"
assert entry.unique_id == "123456789ABC-boolean:200-boolean_generic"
monkeypatch.setitem(mock_rpc_device.status["boolean:200"], "value", False)
await hass.services.async_call(
@@ -715,7 +715,7 @@ async def test_rpc_remove_virtual_switch_when_mode_label(
hass,
SWITCH_DOMAIN,
"test_name_boolean_200",
"boolean:200-boolean",
"boolean:200-boolean_generic",
config_entry,
device_id=device_entry.id,
)
@@ -741,7 +741,7 @@ async def test_rpc_remove_virtual_switch_when_orphaned(
hass,
SWITCH_DOMAIN,
"test_name_boolean_200",
"boolean:200-boolean",
"boolean:200-boolean_generic",
config_entry,
device_id=device_entry.id,
)
@@ -750,13 +750,13 @@ async def test_rpc_remove_virtual_switch_when_orphaned(
sub_device_entry = register_sub_device(
device_registry,
config_entry,
"boolean:201-boolean",
"boolean:201-boolean_generic",
)
entity_id2 = register_entity(
hass,
SWITCH_DOMAIN,
"boolean_201",
"boolean:201-boolean",
"boolean:201-boolean_generic",
config_entry,
device_id=sub_device_entry.id,
)
+3 -3
View File
@@ -62,7 +62,7 @@ async def test_rpc_device_virtual_text(
assert state.state == "lorem ipsum"
assert (entry := entity_registry.async_get(entity_id))
assert entry.unique_id == "123456789ABC-text:203-text"
assert entry.unique_id == "123456789ABC-text:203-text_generic"
monkeypatch.setitem(mock_rpc_device.status["text:203"], "value", "dolor sit amet")
mock_rpc_device.mock_update()
@@ -107,7 +107,7 @@ async def test_rpc_remove_virtual_text_when_mode_label(
hass,
TEXT_PLATFORM,
"test_name_text_200",
"text:200-text",
"text:200-text_generic",
config_entry,
device_id=device_entry.id,
)
@@ -131,7 +131,7 @@ async def test_rpc_remove_virtual_text_when_orphaned(
hass,
TEXT_PLATFORM,
"test_name_text_200",
"text:200-text",
"text:200-text_generic",
config_entry,
device_id=device_entry.id,
)