mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Voip migrate entities (#136140)
* Migrate VoIP entities * Revert device name to host again
This commit is contained in:
parent
dd31c2c832
commit
22e0b0e9a7
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Callable, Iterator
|
from collections.abc import Callable, Iterator
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from voip_utils import CallInfo, VoipDatagramProtocol
|
from voip_utils import CallInfo, VoipDatagramProtocol
|
||||||
|
|
||||||
@ -144,19 +145,39 @@ class VoIPDevices:
|
|||||||
if voip_device is None:
|
if voip_device is None:
|
||||||
# If we couldn't find the device based on SIP URI, see if we can
|
# If we couldn't find the device based on SIP URI, see if we can
|
||||||
# find an old device based on just the host/IP and migrate it
|
# find an old device based on just the host/IP and migrate it
|
||||||
voip_device = self.devices.get(call_info.caller_endpoint.host)
|
old_id = call_info.caller_endpoint.host
|
||||||
|
voip_device = self.devices.get(old_id)
|
||||||
if voip_device is not None:
|
if voip_device is not None:
|
||||||
voip_device.voip_id = voip_id
|
voip_device.voip_id = voip_id
|
||||||
self.devices[voip_id] = voip_device
|
self.devices[voip_id] = voip_device
|
||||||
dev_reg.async_update_device(
|
dev_reg.async_update_device(
|
||||||
voip_device.device_id, new_identifiers={(DOMAIN, voip_id)}
|
voip_device.device_id, new_identifiers={(DOMAIN, voip_id)}
|
||||||
)
|
)
|
||||||
|
# Migrate entities
|
||||||
|
old_prefix = f"{old_id}-"
|
||||||
|
|
||||||
|
def entity_migrator(entry: er.RegistryEntry) -> dict[str, Any] | None:
|
||||||
|
"""Migrate entities."""
|
||||||
|
if not entry.unique_id.startswith(old_prefix):
|
||||||
|
return None
|
||||||
|
key = entry.unique_id[len(old_prefix) :]
|
||||||
|
return {
|
||||||
|
"new_unique_id": f"{voip_id}-{key}",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.config_entry.async_create_task(
|
||||||
|
self.hass,
|
||||||
|
er.async_migrate_entries(
|
||||||
|
self.hass, self.config_entry.entry_id, entity_migrator
|
||||||
|
),
|
||||||
|
f"voip migrating entities {voip_id}",
|
||||||
|
)
|
||||||
|
|
||||||
# Update device with latest info
|
# Update device with latest info
|
||||||
device = dev_reg.async_get_or_create(
|
device = dev_reg.async_get_or_create(
|
||||||
config_entry_id=self.config_entry.entry_id,
|
config_entry_id=self.config_entry.entry_id,
|
||||||
identifiers={(DOMAIN, voip_id)},
|
identifiers={(DOMAIN, voip_id)},
|
||||||
name=voip_id,
|
name=call_info.caller_endpoint.host,
|
||||||
manufacturer=manuf,
|
manufacturer=manuf,
|
||||||
model=model,
|
model=model,
|
||||||
sw_version=fw_version,
|
sw_version=fw_version,
|
||||||
|
@ -22,18 +22,18 @@ async def test_call_in_progress(
|
|||||||
voip_device: VoIPDevice,
|
voip_device: VoIPDevice,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test call in progress."""
|
"""Test call in progress."""
|
||||||
state = hass.states.get("binary_sensor.sip_192_168_1_210_5060_call_in_progress")
|
state = hass.states.get("binary_sensor.192_168_1_210_call_in_progress")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
|
||||||
voip_device.set_is_active(True)
|
voip_device.set_is_active(True)
|
||||||
|
|
||||||
state = hass.states.get("binary_sensor.sip_192_168_1_210_5060_call_in_progress")
|
state = hass.states.get("binary_sensor.192_168_1_210_call_in_progress")
|
||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
|
|
||||||
voip_device.set_is_active(False)
|
voip_device.set_is_active(False)
|
||||||
|
|
||||||
state = hass.states.get("binary_sensor.sip_192_168_1_210_5060_call_in_progress")
|
state = hass.states.get("binary_sensor.192_168_1_210_call_in_progress")
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
|
||||||
|
|
||||||
@ -45,9 +45,9 @@ async def test_assist_in_progress_disabled_by_default(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test assist in progress binary sensor is added disabled."""
|
"""Test assist in progress binary sensor is added disabled."""
|
||||||
|
|
||||||
assert not hass.states.get("binary_sensor.sip_192_168_1_210_5060_call_in_progress")
|
assert not hass.states.get("binary_sensor.192_168_1_210_call_in_progress")
|
||||||
entity_entry = entity_registry.async_get(
|
entity_entry = entity_registry.async_get(
|
||||||
"binary_sensor.sip_192_168_1_210_5060_call_in_progress"
|
"binary_sensor.192_168_1_210_call_in_progress"
|
||||||
)
|
)
|
||||||
assert entity_entry
|
assert entity_entry
|
||||||
assert entity_entry.disabled
|
assert entity_entry.disabled
|
||||||
@ -63,7 +63,7 @@ async def test_assist_in_progress_issue(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test assist in progress binary sensor."""
|
"""Test assist in progress binary sensor."""
|
||||||
|
|
||||||
call_in_progress_entity_id = "binary_sensor.sip_192_168_1_210_5060_call_in_progress"
|
call_in_progress_entity_id = "binary_sensor.192_168_1_210_call_in_progress"
|
||||||
|
|
||||||
state = hass.states.get(call_in_progress_entity_id)
|
state = hass.states.get(call_in_progress_entity_id)
|
||||||
assert state is not None
|
assert state is not None
|
||||||
@ -96,7 +96,7 @@ async def test_assist_in_progress_repair_flow(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test assist in progress binary sensor deprecation issue flow."""
|
"""Test assist in progress binary sensor deprecation issue flow."""
|
||||||
|
|
||||||
call_in_progress_entity_id = "binary_sensor.sip_192_168_1_210_5060_call_in_progress"
|
call_in_progress_entity_id = "binary_sensor.192_168_1_210_call_in_progress"
|
||||||
|
|
||||||
state = hass.states.get(call_in_progress_entity_id)
|
state = hass.states.get(call_in_progress_entity_id)
|
||||||
assert state is not None
|
assert state is not None
|
||||||
|
@ -8,7 +8,7 @@ from voip_utils import CallInfo
|
|||||||
from homeassistant.components.voip import DOMAIN
|
from homeassistant.components.voip import DOMAIN
|
||||||
from homeassistant.components.voip.devices import VoIPDevice, VoIPDevices
|
from homeassistant.components.voip.devices import VoIPDevice, VoIPDevices
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ async def test_device_registry_info(
|
|||||||
identifiers={(DOMAIN, call_info.caller_endpoint.uri)}
|
identifiers={(DOMAIN, call_info.caller_endpoint.uri)}
|
||||||
)
|
)
|
||||||
assert device is not None
|
assert device is not None
|
||||||
assert device.name == call_info.caller_endpoint.uri
|
assert device.name == call_info.caller_endpoint.host
|
||||||
assert device.manufacturer == "Grandstream"
|
assert device.manufacturer == "Grandstream"
|
||||||
assert device.model == "HT801"
|
assert device.model == "HT801"
|
||||||
assert device.sw_version == "1.0.17.5"
|
assert device.sw_version == "1.0.17.5"
|
||||||
@ -71,47 +71,61 @@ async def test_remove_device_registry_entry(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test removing a device registry entry."""
|
"""Test removing a device registry entry."""
|
||||||
assert voip_device.voip_id in voip_devices.devices
|
assert voip_device.voip_id in voip_devices.devices
|
||||||
assert hass.states.get("switch.sip_192_168_1_210_5060_allow_calls") is not None
|
assert hass.states.get("switch.192_168_1_210_allow_calls") is not None
|
||||||
|
|
||||||
device_registry.async_remove_device(voip_device.device_id)
|
device_registry.async_remove_device(voip_device.device_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get("switch.sip_192_168_1_210_5060_allow_calls") is None
|
assert hass.states.get("switch.192_168_1_210_allow_calls") is None
|
||||||
assert voip_device.voip_id not in voip_devices.devices
|
assert voip_device.voip_id not in voip_devices.devices
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def legacy_dev_reg_entry(
|
async def legacy_dev_reg_entry(
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
device_registry: dr.DeviceRegistry,
|
device_registry: dr.DeviceRegistry,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
call_info: CallInfo,
|
call_info: CallInfo,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Fixture to run before we set up the VoIP integration via fixture."""
|
"""Fixture to run before we set up the VoIP integration via fixture."""
|
||||||
return device_registry.async_get_or_create(
|
device = device_registry.async_get_or_create(
|
||||||
config_entry_id=config_entry.entry_id,
|
config_entry_id=config_entry.entry_id,
|
||||||
identifiers={(DOMAIN, call_info.caller_ip)},
|
identifiers={(DOMAIN, call_info.caller_ip)},
|
||||||
)
|
)
|
||||||
|
entity_registry.async_get_or_create(
|
||||||
|
"switch",
|
||||||
|
DOMAIN,
|
||||||
|
f"{call_info.caller_ip}-allow_calls",
|
||||||
|
device_id=device.id,
|
||||||
|
config_entry=config_entry,
|
||||||
|
)
|
||||||
|
return device
|
||||||
|
|
||||||
|
|
||||||
async def test_device_registry_migation(
|
async def test_device_registry_migration(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
legacy_dev_reg_entry: dr.DeviceEntry,
|
legacy_dev_reg_entry: dr.DeviceEntry,
|
||||||
voip_devices: VoIPDevices,
|
voip_devices: VoIPDevices,
|
||||||
call_info: CallInfo,
|
call_info: CallInfo,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
device_registry: dr.DeviceRegistry,
|
device_registry: dr.DeviceRegistry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test info in device registry migrates old devices."""
|
"""Test info in device registry migrates old devices."""
|
||||||
voip_device = voip_devices.async_get_or_create(call_info)
|
voip_device = voip_devices.async_get_or_create(call_info)
|
||||||
assert voip_device.voip_id == call_info.caller_endpoint.uri
|
new_id = call_info.caller_endpoint.uri
|
||||||
|
assert voip_device.voip_id == new_id
|
||||||
|
|
||||||
device = device_registry.async_get_device(
|
device = device_registry.async_get_device(identifiers={(DOMAIN, new_id)})
|
||||||
identifiers={(DOMAIN, call_info.caller_endpoint.uri)}
|
|
||||||
)
|
|
||||||
assert device is not None
|
assert device is not None
|
||||||
assert device.id == legacy_dev_reg_entry.id
|
assert device.id == legacy_dev_reg_entry.id
|
||||||
assert device.identifiers == {(DOMAIN, call_info.caller_endpoint.uri)}
|
assert device.identifiers == {(DOMAIN, new_id)}
|
||||||
assert device.name == call_info.caller_endpoint.uri
|
assert device.name == call_info.caller_endpoint.host
|
||||||
assert device.manufacturer == "Grandstream"
|
assert device.manufacturer == "Grandstream"
|
||||||
assert device.model == "HT801"
|
assert device.model == "HT801"
|
||||||
assert device.sw_version == "1.0.17.5"
|
assert device.sw_version == "1.0.17.5"
|
||||||
|
|
||||||
|
assert (
|
||||||
|
entity_registry.async_get_entity_id("switch", DOMAIN, f"{new_id}-allow_calls")
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
@ -15,7 +15,7 @@ async def test_pipeline_select(
|
|||||||
Functionality is tested in assist_pipeline/test_select.py.
|
Functionality is tested in assist_pipeline/test_select.py.
|
||||||
This test is only to ensure it is set up.
|
This test is only to ensure it is set up.
|
||||||
"""
|
"""
|
||||||
state = hass.states.get("select.sip_192_168_1_210_5060_assistant")
|
state = hass.states.get("select.192_168_1_210_assistant")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "preferred"
|
assert state.state == "preferred"
|
||||||
|
|
||||||
@ -30,6 +30,6 @@ async def test_vad_sensitivity_select(
|
|||||||
Functionality is tested in assist_pipeline/test_select.py.
|
Functionality is tested in assist_pipeline/test_select.py.
|
||||||
This test is only to ensure it is set up.
|
This test is only to ensure it is set up.
|
||||||
"""
|
"""
|
||||||
state = hass.states.get("select.sip_192_168_1_210_5060_finished_speaking_detection")
|
state = hass.states.get("select.192_168_1_210_finished_speaking_detection")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "default"
|
assert state.state == "default"
|
||||||
|
@ -13,41 +13,41 @@ async def test_allow_call(
|
|||||||
"""Test allow call."""
|
"""Test allow call."""
|
||||||
assert not voip_device.async_allow_call(hass)
|
assert not voip_device.async_allow_call(hass)
|
||||||
|
|
||||||
state = hass.states.get("switch.sip_192_168_1_210_5060_allow_calls")
|
state = hass.states.get("switch.192_168_1_210_allow_calls")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
|
||||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||||
|
|
||||||
state = hass.states.get("switch.sip_192_168_1_210_5060_allow_calls")
|
state = hass.states.get("switch.192_168_1_210_allow_calls")
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"switch",
|
"switch",
|
||||||
"turn_on",
|
"turn_on",
|
||||||
{"entity_id": "switch.sip_192_168_1_210_5060_allow_calls"},
|
{"entity_id": "switch.192_168_1_210_allow_calls"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert voip_device.async_allow_call(hass)
|
assert voip_device.async_allow_call(hass)
|
||||||
|
|
||||||
state = hass.states.get("switch.sip_192_168_1_210_5060_allow_calls")
|
state = hass.states.get("switch.192_168_1_210_allow_calls")
|
||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
|
|
||||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("switch.sip_192_168_1_210_5060_allow_calls")
|
state = hass.states.get("switch.192_168_1_210_allow_calls")
|
||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"switch",
|
"switch",
|
||||||
"turn_off",
|
"turn_off",
|
||||||
{"entity_id": "switch.sip_192_168_1_210_5060_allow_calls"},
|
{"entity_id": "switch.192_168_1_210_allow_calls"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert not voip_device.async_allow_call(hass)
|
assert not voip_device.async_allow_call(hass)
|
||||||
|
|
||||||
state = hass.states.get("switch.sip_192_168_1_210_5060_allow_calls")
|
state = hass.states.get("switch.192_168_1_210_allow_calls")
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user