Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion homeassistant/components/acmeda/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@
DOMAIN = "acmeda"

ACMEDA_HUB_UPDATE = "acmeda_hub_update_{}"
ACMEDA_ENTITY_REMOVE = "acmeda_entity_remove_{}"
26 changes: 2 additions & 24 deletions homeassistant/components/acmeda/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
import aiopulse

from homeassistant.core import callback
from homeassistant.helpers import device_registry as dr, entity, entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers import device_registry as dr, entity

from .const import ACMEDA_ENTITY_REMOVE, DOMAIN, LOGGER
from .const import DOMAIN, LOGGER


class AcmedaEntity(entity.Entity):
Expand All @@ -21,32 +20,11 @@ def __init__(self, roller: aiopulse.Roller) -> None:
"""Initialize the roller."""
self.roller = roller

async def async_remove_and_unregister(self) -> None:
"""Unregister from registries and call entity remove function."""
LOGGER.error("Removing %s %s", self.__class__.__name__, self.unique_id)

ent_registry = er.async_get(self.hass)
if self.entity_id in ent_registry.entities:
ent_registry.async_remove(self.entity_id)

if self.device_entry:
dr.async_get(self.hass).async_remove_device(self.device_entry.id)

await self.async_remove(force_remove=True)

@override
async def async_added_to_hass(self) -> None:
"""Entity has been added to hass."""
self.roller.callback_subscribe(self.notify_update)

self.async_on_remove(
async_dispatcher_connect(
self.hass,
ACMEDA_ENTITY_REMOVE.format(self.roller.id),
self.async_remove_and_unregister,
)
)

@override
async def async_will_remove_from_hass(self) -> None:
"""Entity being removed from hass."""
Expand Down
11 changes: 1 addition & 10 deletions homeassistant/components/acmeda/hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_send

from .const import ACMEDA_ENTITY_REMOVE, ACMEDA_HUB_UPDATE, LOGGER
from .const import ACMEDA_HUB_UPDATE, LOGGER
from .helpers import update_devices


Expand All @@ -23,7 +23,6 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
self.config_entry = config_entry
self.hass = hass
self.tasks: list[asyncio.Task[None]] = []
self.current_rollers: dict[int, aiopulse.Roller] = {}
self.cleanup_callbacks: list[Callable[[], None]] = []

@property
Expand Down Expand Up @@ -79,11 +78,3 @@ async def async_notify_update(self, update_type: aiopulse.UpdateType) -> None:
async_dispatcher_send(
self.hass, ACMEDA_HUB_UPDATE.format(self.config_entry.entry_id)
)

for unique_id in list(self.current_rollers):
if unique_id not in self.api.rollers:
LOGGER.debug("Notifying remove of %s", unique_id)
self.current_rollers.pop(unique_id)
async_dispatcher_send(
self.hass, ACMEDA_ENTITY_REMOVE.format(unique_id)
)
48 changes: 48 additions & 0 deletions homeassistant/components/config/entity_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def async_setup(hass: HomeAssistant) -> bool:
websocket_api.async_register_command(hass, websocket_list_entities)
websocket_api.async_register_command(hass, websocket_remove_entity)
websocket_api.async_register_command(hass, websocket_update_entity)
websocket_api.async_register_command(hass, websocket_get_settings)
websocket_api.async_register_command(hass, websocket_update_settings)
return True


Expand Down Expand Up @@ -362,3 +364,49 @@ def websocket_get_automatic_entity_ids(
connection.send_message(
websocket_api.result_message(msg["id"], automatic_entity_ids)
)


@websocket_api.websocket_command(
{vol.Required("type"): "config/entity_registry/settings/get"}
)
@callback
def websocket_get_settings(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Handle get entity registry settings command."""
registry = er.async_get(hass)
connection.send_result(
msg["id"], {"entity_id_parts": registry.settings.entity_id_parts}
)


@require_admin
@websocket_api.websocket_command(
{
vol.Required("type"): "config/entity_registry/settings/update",
vol.Optional("entity_id_parts"): vol.Any(
None,
vol.All(
[vol.Coerce(er.EntityNamePart)],
vol.Unique(),
vol.Contains(er.EntityNamePart.ENTITY),
vol.Contains(er.EntityNamePart.DEVICE),
),
),
}
)
@callback
def websocket_update_settings(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Handle update entity registry settings command."""
registry = er.async_get(hass)
changes: dict[str, Any] = {}
if "entity_id_parts" in msg:
changes["entity_id_parts"] = msg["entity_id_parts"]
settings = registry.async_update_settings(**changes)
connection.send_result(msg["id"], {"entity_id_parts": settings.entity_id_parts})
18 changes: 15 additions & 3 deletions homeassistant/components/devolo_home_control/entity.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Base class for a device entity integrated in devolo Home Control."""

import logging
from typing import override
from typing import TYPE_CHECKING, override
from urllib.parse import urlparse

from devolo_home_control_api.devices.zwave import Zwave
Expand Down Expand Up @@ -103,8 +103,20 @@ def _generic_message(self, message: tuple) -> None:
].name,
)
self._attr_available = state
elif message[1] == "del" and self.device_entry:
dr.async_get(self.hass).async_remove_device(self.device_entry.id)
elif message[1] == "del":
# A "del" is dispatched to every entity of the device. Look the device
# up freshly instead of using the cached (possibly stale) device_entry:
# the first entity to run removes it and the rest find it already gone.
device_registry = dr.async_get(self.hass)
platform = self.platform
if TYPE_CHECKING:
# Devolo entities always belong to a config entry
assert platform.config_entry is not None
if device := device_registry.async_get_device_by_identifier(
(DOMAIN, self._device_instance.uid),
platform.config_entry.entry_id,
):
device_registry.async_remove_device(device.id)
else:
_LOGGER.debug("No valid message received: %s", message)

Expand Down
10 changes: 6 additions & 4 deletions homeassistant/components/esphome/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,15 @@ def async_static_info_updated(
# Update device assignment in registry
if info.device_id:
# Entity now belongs to a sub device
new_device = dev_reg.async_get_device(
identifiers={(DOMAIN, f"{device_info.mac_address}_{info.device_id}")}
new_device = dev_reg.async_get_device_by_identifier(
(DOMAIN, f"{device_info.mac_address}_{info.device_id}"),
entry_data.entry_id,
)
else:
# Entity now belongs to the main device
new_device = dev_reg.async_get_device(
connections={(dr.CONNECTION_NETWORK_MAC, device_info.mac_address)}
new_device = dev_reg.async_get_device_by_connection(
(dr.CONNECTION_NETWORK_MAC, device_info.mac_address),
entry_data.entry_id,
)

if new_device:
Expand Down
5 changes: 1 addition & 4 deletions homeassistant/components/matter/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,7 @@ def _on_matter_node_event(
clusters.Switch.Attributes.CurrentPosition,
clusters.Switch.Attributes.FeatureMap,
),
device_type=(
device_types.Doorbell,
device_types.GenericSwitch,
),
device_type=(device_types.GenericSwitch,),
optional_attributes=(
clusters.Switch.Attributes.NumberOfPositions,
clusters.FixedLabel.Attributes.LabelList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def get(
This call is not thread-safe and must be called from the
recorder thread.
"""
return self.get_many((event_type,), session)[event_type]
return self.get_many((event_type,), session, from_recorder)[event_type]

def get_many(
self,
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/tasmota/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ async def _remove_device(
device_registry: DeviceRegistry,
) -> None:
"""Remove a discovered Tasmota device."""
device = device_registry.async_get_device(
connections={(CONNECTION_NETWORK_MAC, mac)}
device = device_registry.async_get_device_by_connection(
(CONNECTION_NETWORK_MAC, mac), config_entry.entry_id
)

if device is None or config_entry.entry_id not in device.config_entries:
if device is None:
return

_LOGGER.debug("Removing tasmota from device %s", mac)
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/tasmota/device_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ async def discovery_update(trigger_config: TasmotaTriggerConfig) -> None:
)

device_registry = dr.async_get(hass)
device = device_registry.async_get_device(
connections={(CONNECTION_NETWORK_MAC, tasmota_trigger.cfg.mac)},
device = device_registry.async_get_device_by_connection(
(CONNECTION_NETWORK_MAC, tasmota_trigger.cfg.mac), config_entry.entry_id
)

if device is None:
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/tasmota/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ async def async_sensors_discovered(

device_registry = dr.async_get(hass)
entity_registry = er.async_get(hass)
device = device_registry.async_get_device(
connections={(dr.CONNECTION_NETWORK_MAC, mac)}
device = device_registry.async_get_device_by_connection(
(dr.CONNECTION_NETWORK_MAC, mac), config_entry.entry_id
)

if device is None:
Expand Down
4 changes: 3 additions & 1 deletion homeassistant/components/template/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ def __init__(
device_registry = dr.async_get(hass)
if (
device_id := config.get(CONF_DEVICE_ID)
) is not None and not device_registry.async_is_composite_device_id(device_id):
) is not None and device_registry.async_is_composite_device_id(
device_id
) is False:
self.device_entry = device_registry.async_get(device_id)

@property
Expand Down
7 changes: 4 additions & 3 deletions homeassistant/components/template/repairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ async def async_step_select_device(
errors: dict[str, str] = {}
if user_input is not None:
device_id = user_input.get(CONF_DEVICE_ID)
if device_id is None or not device_registry.async_is_composite_device_id(
device_id
if (
device_id is None
or device_registry.async_is_composite_device_id(device_id) is False
):
options = {**entry.options}
if device_id:
Expand All @@ -52,7 +53,7 @@ async def async_step_select_device(
self.hass.config_entries.async_update_entry(entry, options=options)
await self.hass.config_entries.async_reload(entry.entry_id)
return self.async_create_entry(data={})
# The suggested composite device id was submitted unchanged
# A composite or unknown device id was submitted
errors[CONF_DEVICE_ID] = "invalid_device"

return self.async_show_form(
Expand Down
Loading
Loading