mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 08:17:08 +00:00
Add support to remove orphan devices in AVM FRITZ!SmartHome (#100739)
This commit is contained in:
parent
82fdd8313f
commit
18fad569e0
@ -18,7 +18,7 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import Event, HomeAssistant
|
from homeassistant.core import Event, HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||||
from homeassistant.helpers.device_registry import DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceEntry, DeviceInfo
|
||||||
from homeassistant.helpers.entity import EntityDescription
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries
|
from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries
|
||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
@ -103,6 +103,24 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
return unload_ok
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
|
async def async_remove_config_entry_device(
|
||||||
|
hass: HomeAssistant, entry: ConfigEntry, device: DeviceEntry
|
||||||
|
) -> bool:
|
||||||
|
"""Remove Fritzbox config entry from a device."""
|
||||||
|
coordinator: FritzboxDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][
|
||||||
|
CONF_COORDINATOR
|
||||||
|
]
|
||||||
|
|
||||||
|
for identifier in device.identifiers:
|
||||||
|
if identifier[0] == DOMAIN and (
|
||||||
|
identifier[1] in coordinator.data.devices
|
||||||
|
or identifier[1] in coordinator.data.templates
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class FritzBoxEntity(CoordinatorEntity[FritzboxDataUpdateCoordinator], ABC):
|
class FritzBoxEntity(CoordinatorEntity[FritzboxDataUpdateCoordinator], ABC):
|
||||||
"""Basis FritzBox entity."""
|
"""Basis FritzBox entity."""
|
||||||
|
|
||||||
|
@ -21,12 +21,14 @@ from homeassistant.const import (
|
|||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from . import FritzDeviceSwitchMock, setup_config_entry
|
from . import FritzDeviceSwitchMock, setup_config_entry
|
||||||
from .const import CONF_FAKE_AIN, CONF_FAKE_NAME, MOCK_CONFIG
|
from .const import CONF_FAKE_AIN, CONF_FAKE_NAME, MOCK_CONFIG
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
from tests.typing import WebSocketGenerator
|
||||||
|
|
||||||
|
|
||||||
async def test_setup(hass: HomeAssistant, fritz: Mock) -> None:
|
async def test_setup(hass: HomeAssistant, fritz: Mock) -> None:
|
||||||
@ -250,6 +252,68 @@ async def test_unload_remove(hass: HomeAssistant, fritz: Mock) -> None:
|
|||||||
assert state is None
|
assert state is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_remove_device(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
hass_ws_client: WebSocketGenerator,
|
||||||
|
fritz: Mock,
|
||||||
|
) -> None:
|
||||||
|
"""Test removing of a device."""
|
||||||
|
assert await async_setup_component(hass, "config", {})
|
||||||
|
assert await setup_config_entry(
|
||||||
|
hass,
|
||||||
|
MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0],
|
||||||
|
f"{FB_DOMAIN}.{CONF_FAKE_NAME}",
|
||||||
|
FritzDeviceSwitchMock(),
|
||||||
|
fritz,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entries = hass.config_entries.async_entries()
|
||||||
|
assert len(entries) == 1
|
||||||
|
|
||||||
|
entry = entries[0]
|
||||||
|
assert entry.supports_remove_device
|
||||||
|
|
||||||
|
entity = entity_registry.async_get("switch.fake_name")
|
||||||
|
good_device = device_registry.async_get(entity.device_id)
|
||||||
|
|
||||||
|
orphan_device = device_registry.async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
identifiers={(FB_DOMAIN, "0000 000000")},
|
||||||
|
)
|
||||||
|
|
||||||
|
# try to delete good_device
|
||||||
|
ws_client = await hass_ws_client(hass)
|
||||||
|
await ws_client.send_json(
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "config/device_registry/remove_config_entry",
|
||||||
|
"config_entry_id": entry.entry_id,
|
||||||
|
"device_id": good_device.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
response = await ws_client.receive_json()
|
||||||
|
assert not response["success"]
|
||||||
|
assert response["error"]["code"] == "unknown_error"
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# try to delete orphan_device
|
||||||
|
ws_client = await hass_ws_client(hass)
|
||||||
|
await ws_client.send_json(
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "config/device_registry/remove_config_entry",
|
||||||
|
"config_entry_id": entry.entry_id,
|
||||||
|
"device_id": orphan_device.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
response = await ws_client.receive_json()
|
||||||
|
assert response["success"]
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
async def test_raise_config_entry_not_ready_when_offline(hass: HomeAssistant) -> None:
|
async def test_raise_config_entry_not_ready_when_offline(hass: HomeAssistant) -> None:
|
||||||
"""Config entry state is SETUP_RETRY when fritzbox is offline."""
|
"""Config entry state is SETUP_RETRY when fritzbox is offline."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user