Mobile app to update entity registry on re-register sensors (#58378)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
4e419d8c6f
commit
a122cbab61
6 changed files with 128 additions and 39 deletions
|
@ -9,6 +9,7 @@ from .const import (
|
|||
ATTR_DEVICE_NAME,
|
||||
ATTR_SENSOR_ATTRIBUTES,
|
||||
ATTR_SENSOR_DEVICE_CLASS,
|
||||
ATTR_SENSOR_ENTITY_CATEGORY,
|
||||
ATTR_SENSOR_ICON,
|
||||
ATTR_SENSOR_NAME,
|
||||
ATTR_SENSOR_STATE,
|
||||
|
@ -40,6 +41,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
ATTR_SENSOR_STATE: None,
|
||||
ATTR_SENSOR_TYPE: entry.domain,
|
||||
ATTR_SENSOR_UNIQUE_ID: entry.unique_id,
|
||||
ATTR_SENSOR_ENTITY_CATEGORY: entry.entity_category,
|
||||
}
|
||||
entities.append(MobileAppBinarySensor(config, entry.device_id, config_entry))
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ from .const import (
|
|||
ATTR_DEVICE_NAME,
|
||||
ATTR_SENSOR_ATTRIBUTES,
|
||||
ATTR_SENSOR_DEVICE_CLASS,
|
||||
ATTR_SENSOR_ENTITY_CATEGORY,
|
||||
ATTR_SENSOR_ICON,
|
||||
ATTR_SENSOR_NAME,
|
||||
ATTR_SENSOR_STATE,
|
||||
|
@ -45,6 +46,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
ATTR_SENSOR_TYPE: entry.domain,
|
||||
ATTR_SENSOR_UNIQUE_ID: entry.unique_id,
|
||||
ATTR_SENSOR_UOM: entry.unit_of_measurement,
|
||||
ATTR_SENSOR_ENTITY_CATEGORY: entry.entity_category,
|
||||
}
|
||||
entities.append(MobileAppSensor(config, entry.device_id, config_entry))
|
||||
|
||||
|
|
|
@ -446,6 +446,26 @@ async def webhook_register_sensor(hass, config_entry, data):
|
|||
"Re-register for %s of existing sensor %s", device_name, unique_id
|
||||
)
|
||||
|
||||
entry = entity_registry.async_get(existing_sensor)
|
||||
changes = {}
|
||||
|
||||
if (
|
||||
new_name := f"{device_name} {data[ATTR_SENSOR_NAME]}"
|
||||
) != entry.original_name:
|
||||
changes["original_name"] = new_name
|
||||
|
||||
for ent_reg_key, data_key in (
|
||||
("device_class", ATTR_SENSOR_DEVICE_CLASS),
|
||||
("unit_of_measurement", ATTR_SENSOR_UOM),
|
||||
("entity_category", ATTR_SENSOR_ENTITY_CATEGORY),
|
||||
("original_icon", ATTR_SENSOR_ICON),
|
||||
):
|
||||
if data_key in data and getattr(entry, ent_reg_key) != data[data_key]:
|
||||
changes[ent_reg_key] = data[data_key]
|
||||
|
||||
if changes:
|
||||
entity_registry.async_update_entity(existing_sensor, **changes)
|
||||
|
||||
async_dispatcher_send(hass, SIGNAL_SENSOR_UPDATE, data)
|
||||
else:
|
||||
register_signal = f"{DOMAIN}_{data[ATTR_SENSOR_TYPE]}_register"
|
||||
|
|
|
@ -38,7 +38,6 @@ from homeassistant.core import CALLBACK_TYPE, Context, HomeAssistant, callback
|
|||
from homeassistant.exceptions import HomeAssistantError, NoEntitySpecifiedError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import EntityPlatform
|
||||
from homeassistant.helpers.entity_registry import RegistryEntry
|
||||
from homeassistant.helpers.event import Event, async_track_entity_registry_updated_event
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.loader import bind_hass
|
||||
|
@ -227,7 +226,7 @@ class Entity(ABC):
|
|||
parallel_updates: asyncio.Semaphore | None = None
|
||||
|
||||
# Entry in the entity registry
|
||||
registry_entry: RegistryEntry | None = None
|
||||
registry_entry: er.RegistryEntry | None = None
|
||||
|
||||
# Hold list for functions to call on remove.
|
||||
_on_remove: list[CALLBACK_TYPE] | None = None
|
||||
|
@ -806,7 +805,7 @@ class Entity(ABC):
|
|||
if data["action"] != "update":
|
||||
return
|
||||
|
||||
ent_reg = await self.hass.helpers.entity_registry.async_get_registry()
|
||||
ent_reg = er.async_get(self.hass)
|
||||
old = self.registry_entry
|
||||
self.registry_entry = ent_reg.async_get(data["entity_id"])
|
||||
assert self.registry_entry is not None
|
||||
|
|
|
@ -243,21 +243,21 @@ class EntityRegistry:
|
|||
unique_id: str,
|
||||
*,
|
||||
# To influence entity ID generation
|
||||
suggested_object_id: str | None = None,
|
||||
known_object_ids: Iterable[str] | None = None,
|
||||
suggested_object_id: str | None = None,
|
||||
# To disable an entity if it gets created
|
||||
disabled_by: str | None = None,
|
||||
# Data that we want entry to have
|
||||
config_entry: ConfigEntry | None = None,
|
||||
device_id: str | None = None,
|
||||
area_id: str | None = None,
|
||||
capabilities: Mapping[str, Any] | None = None,
|
||||
supported_features: int | None = None,
|
||||
config_entry: ConfigEntry | None = None,
|
||||
device_class: str | None = None,
|
||||
unit_of_measurement: str | None = None,
|
||||
original_name: str | None = None,
|
||||
original_icon: str | None = None,
|
||||
device_id: str | None = None,
|
||||
entity_category: str | None = None,
|
||||
original_icon: str | None = None,
|
||||
original_name: str | None = None,
|
||||
supported_features: int | None = None,
|
||||
unit_of_measurement: str | None = None,
|
||||
) -> RegistryEntry:
|
||||
"""Get entity. Create if it doesn't exist."""
|
||||
config_entry_id = None
|
||||
|
@ -300,20 +300,20 @@ class EntityRegistry:
|
|||
disabled_by = DISABLED_INTEGRATION
|
||||
|
||||
entity = RegistryEntry(
|
||||
entity_id=entity_id,
|
||||
config_entry_id=config_entry_id,
|
||||
device_id=device_id,
|
||||
area_id=area_id,
|
||||
unique_id=unique_id,
|
||||
platform=platform,
|
||||
disabled_by=disabled_by,
|
||||
capabilities=capabilities,
|
||||
supported_features=supported_features or 0,
|
||||
config_entry_id=config_entry_id,
|
||||
device_class=device_class,
|
||||
unit_of_measurement=unit_of_measurement,
|
||||
original_name=original_name,
|
||||
original_icon=original_icon,
|
||||
device_id=device_id,
|
||||
disabled_by=disabled_by,
|
||||
entity_category=entity_category,
|
||||
entity_id=entity_id,
|
||||
original_icon=original_icon,
|
||||
original_name=original_name,
|
||||
platform=platform,
|
||||
supported_features=supported_features or 0,
|
||||
unique_id=unique_id,
|
||||
unit_of_measurement=unit_of_measurement,
|
||||
)
|
||||
self._register_entry(entity)
|
||||
_LOGGER.info("Registered new %s.%s entity: %s", domain, platform, entity_id)
|
||||
|
@ -383,24 +383,34 @@ class EntityRegistry:
|
|||
self,
|
||||
entity_id: str,
|
||||
*,
|
||||
name: str | None | UndefinedType = UNDEFINED,
|
||||
icon: str | None | UndefinedType = UNDEFINED,
|
||||
config_entry_id: str | None | UndefinedType = UNDEFINED,
|
||||
area_id: str | None | UndefinedType = UNDEFINED,
|
||||
config_entry_id: str | None | UndefinedType = UNDEFINED,
|
||||
device_class: str | None | UndefinedType = UNDEFINED,
|
||||
disabled_by: str | None | UndefinedType = UNDEFINED,
|
||||
entity_category: str | None | UndefinedType = UNDEFINED,
|
||||
icon: str | None | UndefinedType = UNDEFINED,
|
||||
name: str | None | UndefinedType = UNDEFINED,
|
||||
new_entity_id: str | UndefinedType = UNDEFINED,
|
||||
new_unique_id: str | UndefinedType = UNDEFINED,
|
||||
disabled_by: str | None | UndefinedType = UNDEFINED,
|
||||
original_icon: str | None | UndefinedType = UNDEFINED,
|
||||
original_name: str | None | UndefinedType = UNDEFINED,
|
||||
unit_of_measurement: str | None | UndefinedType = UNDEFINED,
|
||||
) -> RegistryEntry:
|
||||
"""Update properties of an entity."""
|
||||
return self._async_update_entity(
|
||||
entity_id,
|
||||
name=name,
|
||||
icon=icon,
|
||||
config_entry_id=config_entry_id,
|
||||
area_id=area_id,
|
||||
config_entry_id=config_entry_id,
|
||||
device_class=device_class,
|
||||
disabled_by=disabled_by,
|
||||
entity_category=entity_category,
|
||||
icon=icon,
|
||||
name=name,
|
||||
new_entity_id=new_entity_id,
|
||||
new_unique_id=new_unique_id,
|
||||
disabled_by=disabled_by,
|
||||
original_icon=original_icon,
|
||||
original_name=original_name,
|
||||
unit_of_measurement=unit_of_measurement,
|
||||
)
|
||||
|
||||
@callback
|
||||
|
@ -408,21 +418,21 @@ class EntityRegistry:
|
|||
self,
|
||||
entity_id: str,
|
||||
*,
|
||||
name: str | None | UndefinedType = UNDEFINED,
|
||||
icon: str | None | UndefinedType = UNDEFINED,
|
||||
config_entry_id: str | None | UndefinedType = UNDEFINED,
|
||||
new_entity_id: str | UndefinedType = UNDEFINED,
|
||||
device_id: str | None | UndefinedType = UNDEFINED,
|
||||
area_id: str | None | UndefinedType = UNDEFINED,
|
||||
new_unique_id: str | UndefinedType = UNDEFINED,
|
||||
disabled_by: str | None | UndefinedType = UNDEFINED,
|
||||
capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED,
|
||||
supported_features: int | UndefinedType = UNDEFINED,
|
||||
config_entry_id: str | None | UndefinedType = UNDEFINED,
|
||||
device_class: str | None | UndefinedType = UNDEFINED,
|
||||
unit_of_measurement: str | None | UndefinedType = UNDEFINED,
|
||||
original_name: str | None | UndefinedType = UNDEFINED,
|
||||
original_icon: str | None | UndefinedType = UNDEFINED,
|
||||
device_id: str | None | UndefinedType = UNDEFINED,
|
||||
disabled_by: str | None | UndefinedType = UNDEFINED,
|
||||
entity_category: str | None | UndefinedType = UNDEFINED,
|
||||
icon: str | None | UndefinedType = UNDEFINED,
|
||||
name: str | None | UndefinedType = UNDEFINED,
|
||||
new_entity_id: str | UndefinedType = UNDEFINED,
|
||||
new_unique_id: str | UndefinedType = UNDEFINED,
|
||||
original_icon: str | None | UndefinedType = UNDEFINED,
|
||||
original_name: str | None | UndefinedType = UNDEFINED,
|
||||
supported_features: int | UndefinedType = UNDEFINED,
|
||||
unit_of_measurement: str | None | UndefinedType = UNDEFINED,
|
||||
) -> RegistryEntry:
|
||||
"""Private facing update properties method."""
|
||||
old = self.entities[entity_id]
|
||||
|
|
|
@ -10,6 +10,7 @@ from homeassistant.components.zone import DOMAIN as ZONE_DOMAIN
|
|||
from homeassistant.const import CONF_WEBHOOK_ID
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .const import CALL_SERVICE, FIRE_EVENT, REGISTER_CLEARTEXT, RENDER_TEMPLATE, UPDATE
|
||||
|
||||
|
@ -515,3 +516,58 @@ async def test_register_sensor_limits_state_class(
|
|||
|
||||
# This means it was ignored.
|
||||
assert reg_resp.status == HTTPStatus.OK
|
||||
|
||||
|
||||
async def test_reregister_sensor(hass, create_registrations, webhook_client):
|
||||
"""Test that we can add more info in re-registration."""
|
||||
webhook_id = create_registrations[1]["webhook_id"]
|
||||
webhook_url = f"/api/webhook/{webhook_id}"
|
||||
|
||||
reg_resp = await webhook_client.post(
|
||||
webhook_url,
|
||||
json={
|
||||
"type": "register_sensor",
|
||||
"data": {
|
||||
"name": "Battery State",
|
||||
"state": 100,
|
||||
"type": "sensor",
|
||||
"unique_id": "abcd",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert reg_resp.status == HTTPStatus.CREATED
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
entry = ent_reg.async_get("sensor.test_1_battery_state")
|
||||
assert entry.original_name == "Test 1 Battery State"
|
||||
assert entry.device_class is None
|
||||
assert entry.unit_of_measurement is None
|
||||
assert entry.entity_category is None
|
||||
assert entry.original_icon == "mdi:cellphone"
|
||||
|
||||
reg_resp = await webhook_client.post(
|
||||
webhook_url,
|
||||
json={
|
||||
"type": "register_sensor",
|
||||
"data": {
|
||||
"name": "New Name",
|
||||
"state": 100,
|
||||
"type": "sensor",
|
||||
"unique_id": "abcd",
|
||||
"state_class": "total",
|
||||
"device_class": "battery",
|
||||
"entity_category": "diagnostic",
|
||||
"icon": "mdi:new-icon",
|
||||
"unit_of_measurement": "%",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert reg_resp.status == HTTPStatus.CREATED
|
||||
entry = ent_reg.async_get("sensor.test_1_battery_state")
|
||||
assert entry.original_name == "Test 1 New Name"
|
||||
assert entry.device_class == "battery"
|
||||
assert entry.unit_of_measurement == "%"
|
||||
assert entry.entity_category == "diagnostic"
|
||||
assert entry.original_icon == "mdi:new-icon"
|
||||
|
|
Loading…
Add table
Reference in a new issue