Revert "Add ability to ignore devices for UniFi Protect" (#77916)
This commit is contained in:
parent
5632e33426
commit
dbb556a812
12 changed files with 75 additions and 258 deletions
|
@ -26,7 +26,6 @@ from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
|||
|
||||
from .const import (
|
||||
CONF_ALL_UPDATES,
|
||||
CONF_IGNORED,
|
||||
CONF_OVERRIDE_CHOST,
|
||||
DEFAULT_SCAN_INTERVAL,
|
||||
DEVICES_FOR_SUBSCRIBE,
|
||||
|
@ -36,11 +35,11 @@ from .const import (
|
|||
OUTDATED_LOG_MESSAGE,
|
||||
PLATFORMS,
|
||||
)
|
||||
from .data import ProtectData
|
||||
from .data import ProtectData, async_ufp_instance_for_config_entry_ids
|
||||
from .discovery import async_start_discovery
|
||||
from .migrate import async_migrate_data
|
||||
from .services import async_cleanup_services, async_setup_services
|
||||
from .utils import async_unifi_mac, convert_mac_list
|
||||
from .utils import _async_unifi_mac_from_hass, async_get_devices
|
||||
from .views import ThumbnailProxyView, VideoProxyView
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -107,19 +106,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
async def _async_options_updated(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Update options."""
|
||||
|
||||
data: ProtectData = hass.data[DOMAIN][entry.entry_id]
|
||||
changed = data.async_get_changed_options(entry)
|
||||
|
||||
if len(changed) == 1 and CONF_IGNORED in changed:
|
||||
new_macs = convert_mac_list(entry.options.get(CONF_IGNORED, ""))
|
||||
added_macs = new_macs - data.ignored_macs
|
||||
removed_macs = data.ignored_macs - new_macs
|
||||
# if only ignored macs are added, we can handle without reloading
|
||||
if not removed_macs and added_macs:
|
||||
data.async_add_new_ignored_macs(added_macs)
|
||||
return
|
||||
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
|
||||
|
||||
|
@ -139,15 +125,15 @@ async def async_remove_config_entry_device(
|
|||
) -> bool:
|
||||
"""Remove ufp config entry from a device."""
|
||||
unifi_macs = {
|
||||
async_unifi_mac(connection[1])
|
||||
_async_unifi_mac_from_hass(connection[1])
|
||||
for connection in device_entry.connections
|
||||
if connection[0] == dr.CONNECTION_NETWORK_MAC
|
||||
}
|
||||
data: ProtectData = hass.data[DOMAIN][config_entry.entry_id]
|
||||
if data.api.bootstrap.nvr.mac in unifi_macs:
|
||||
api = async_ufp_instance_for_config_entry_ids(hass, {config_entry.entry_id})
|
||||
assert api is not None
|
||||
if api.bootstrap.nvr.mac in unifi_macs:
|
||||
return False
|
||||
for device in data.get_by_types(DEVICES_THAT_ADOPT):
|
||||
for device in async_get_devices(api.bootstrap, DEVICES_THAT_ADOPT):
|
||||
if device.is_adopted_by_us and device.mac in unifi_macs:
|
||||
data.async_ignore_mac(device.mac)
|
||||
break
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -35,7 +35,6 @@ from homeassistant.util.network import is_ip_address
|
|||
from .const import (
|
||||
CONF_ALL_UPDATES,
|
||||
CONF_DISABLE_RTSP,
|
||||
CONF_IGNORED,
|
||||
CONF_MAX_MEDIA,
|
||||
CONF_OVERRIDE_CHOST,
|
||||
DEFAULT_MAX_MEDIA,
|
||||
|
@ -47,7 +46,7 @@ from .const import (
|
|||
)
|
||||
from .data import async_last_update_was_successful
|
||||
from .discovery import async_start_discovery
|
||||
from .utils import _async_resolve, async_short_mac, async_unifi_mac, convert_mac_list
|
||||
from .utils import _async_resolve, _async_short_mac, _async_unifi_mac_from_hass
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -121,7 +120,7 @@ class ProtectFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
) -> FlowResult:
|
||||
"""Handle integration discovery."""
|
||||
self._discovered_device = discovery_info
|
||||
mac = async_unifi_mac(discovery_info["hw_addr"])
|
||||
mac = _async_unifi_mac_from_hass(discovery_info["hw_addr"])
|
||||
await self.async_set_unique_id(mac)
|
||||
source_ip = discovery_info["source_ip"]
|
||||
direct_connect_domain = discovery_info["direct_connect_domain"]
|
||||
|
@ -183,7 +182,7 @@ class ProtectFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
placeholders = {
|
||||
"name": discovery_info["hostname"]
|
||||
or discovery_info["platform"]
|
||||
or f"NVR {async_short_mac(discovery_info['hw_addr'])}",
|
||||
or f"NVR {_async_short_mac(discovery_info['hw_addr'])}",
|
||||
"ip_address": discovery_info["source_ip"],
|
||||
}
|
||||
self.context["title_placeholders"] = placeholders
|
||||
|
@ -225,7 +224,6 @@ class ProtectFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
CONF_ALL_UPDATES: False,
|
||||
CONF_OVERRIDE_CHOST: False,
|
||||
CONF_MAX_MEDIA: DEFAULT_MAX_MEDIA,
|
||||
CONF_IGNORED: "",
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -367,53 +365,33 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Manage the options."""
|
||||
|
||||
values = user_input or self.config_entry.options
|
||||
schema = vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_DISABLE_RTSP,
|
||||
description={
|
||||
"suggested_value": values.get(CONF_DISABLE_RTSP, False)
|
||||
},
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_ALL_UPDATES,
|
||||
description={
|
||||
"suggested_value": values.get(CONF_ALL_UPDATES, False)
|
||||
},
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_OVERRIDE_CHOST,
|
||||
description={
|
||||
"suggested_value": values.get(CONF_OVERRIDE_CHOST, False)
|
||||
},
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_MAX_MEDIA,
|
||||
description={
|
||||
"suggested_value": values.get(CONF_MAX_MEDIA, DEFAULT_MAX_MEDIA)
|
||||
},
|
||||
): vol.All(vol.Coerce(int), vol.Range(min=100, max=10000)),
|
||||
vol.Optional(
|
||||
CONF_IGNORED,
|
||||
description={"suggested_value": values.get(CONF_IGNORED, "")},
|
||||
): str,
|
||||
}
|
||||
)
|
||||
errors: dict[str, str] = {}
|
||||
|
||||
if user_input is not None:
|
||||
try:
|
||||
convert_mac_list(user_input.get(CONF_IGNORED, ""), raise_exception=True)
|
||||
except vol.Invalid:
|
||||
errors[CONF_IGNORED] = "invalid_mac_list"
|
||||
|
||||
if not errors:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init",
|
||||
data_schema=schema,
|
||||
errors=errors,
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_DISABLE_RTSP,
|
||||
default=self.config_entry.options.get(CONF_DISABLE_RTSP, False),
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_ALL_UPDATES,
|
||||
default=self.config_entry.options.get(CONF_ALL_UPDATES, False),
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_OVERRIDE_CHOST,
|
||||
default=self.config_entry.options.get(
|
||||
CONF_OVERRIDE_CHOST, False
|
||||
),
|
||||
): bool,
|
||||
vol.Optional(
|
||||
CONF_MAX_MEDIA,
|
||||
default=self.config_entry.options.get(
|
||||
CONF_MAX_MEDIA, DEFAULT_MAX_MEDIA
|
||||
),
|
||||
): vol.All(vol.Coerce(int), vol.Range(min=100, max=10000)),
|
||||
}
|
||||
),
|
||||
)
|
||||
|
|
|
@ -20,7 +20,6 @@ CONF_DISABLE_RTSP = "disable_rtsp"
|
|||
CONF_ALL_UPDATES = "all_updates"
|
||||
CONF_OVERRIDE_CHOST = "override_connection_host"
|
||||
CONF_MAX_MEDIA = "max_media"
|
||||
CONF_IGNORED = "ignored_devices"
|
||||
|
||||
CONFIG_OPTIONS = [
|
||||
CONF_ALL_UPDATES,
|
||||
|
|
|
@ -28,7 +28,6 @@ from homeassistant.helpers.event import async_track_time_interval
|
|||
|
||||
from .const import (
|
||||
CONF_DISABLE_RTSP,
|
||||
CONF_IGNORED,
|
||||
CONF_MAX_MEDIA,
|
||||
DEFAULT_MAX_MEDIA,
|
||||
DEVICES_THAT_ADOPT,
|
||||
|
@ -37,11 +36,7 @@ from .const import (
|
|||
DISPATCH_CHANNELS,
|
||||
DOMAIN,
|
||||
)
|
||||
from .utils import (
|
||||
async_dispatch_id as _ufpd,
|
||||
async_get_devices_by_type,
|
||||
convert_mac_list,
|
||||
)
|
||||
from .utils import async_dispatch_id as _ufpd, async_get_devices_by_type
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
ProtectDeviceType = Union[ProtectAdoptableDeviceModel, NVR]
|
||||
|
@ -72,7 +67,6 @@ class ProtectData:
|
|||
|
||||
self._hass = hass
|
||||
self._entry = entry
|
||||
self._existing_options = dict(entry.options)
|
||||
self._hass = hass
|
||||
self._update_interval = update_interval
|
||||
self._subscriptions: dict[str, list[Callable[[ProtectDeviceType], None]]] = {}
|
||||
|
@ -80,8 +74,6 @@ class ProtectData:
|
|||
self._unsub_interval: CALLBACK_TYPE | None = None
|
||||
self._unsub_websocket: CALLBACK_TYPE | None = None
|
||||
self._auth_failures = 0
|
||||
self._ignored_macs: set[str] | None = None
|
||||
self._ignore_update_cancel: Callable[[], None] | None = None
|
||||
|
||||
self.last_update_success = False
|
||||
self.api = protect
|
||||
|
@ -96,47 +88,6 @@ class ProtectData:
|
|||
"""Max number of events to load at once."""
|
||||
return self._entry.options.get(CONF_MAX_MEDIA, DEFAULT_MAX_MEDIA)
|
||||
|
||||
@property
|
||||
def ignored_macs(self) -> set[str]:
|
||||
"""Set of ignored MAC addresses."""
|
||||
|
||||
if self._ignored_macs is None:
|
||||
self._ignored_macs = convert_mac_list(
|
||||
self._entry.options.get(CONF_IGNORED, "")
|
||||
)
|
||||
|
||||
return self._ignored_macs
|
||||
|
||||
@callback
|
||||
def async_get_changed_options(self, entry: ConfigEntry) -> dict[str, Any]:
|
||||
"""Get changed options for when entry is updated."""
|
||||
|
||||
return dict(
|
||||
set(self._entry.options.items()) - set(self._existing_options.items())
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_ignore_mac(self, mac: str) -> None:
|
||||
"""Ignores a MAC address for a UniFi Protect device."""
|
||||
|
||||
new_macs = (self._ignored_macs or set()).copy()
|
||||
new_macs.add(mac)
|
||||
_LOGGER.debug("Updating ignored_devices option: %s", self.ignored_macs)
|
||||
options = dict(self._entry.options)
|
||||
options[CONF_IGNORED] = ",".join(new_macs)
|
||||
self._hass.config_entries.async_update_entry(self._entry, options=options)
|
||||
|
||||
@callback
|
||||
def async_add_new_ignored_macs(self, new_macs: set[str]) -> None:
|
||||
"""Add new ignored MAC addresses and ensures the devices are removed."""
|
||||
|
||||
for mac in new_macs:
|
||||
device = self.api.bootstrap.get_device_from_mac(mac)
|
||||
if device is not None:
|
||||
self._async_remove_device(device)
|
||||
self._ignored_macs = None
|
||||
self._existing_options = dict(self._entry.options)
|
||||
|
||||
def get_by_types(
|
||||
self, device_types: Iterable[ModelType], ignore_unadopted: bool = True
|
||||
) -> Generator[ProtectAdoptableDeviceModel, None, None]:
|
||||
|
@ -148,8 +99,6 @@ class ProtectData:
|
|||
for device in devices:
|
||||
if ignore_unadopted and not device.is_adopted_by_us:
|
||||
continue
|
||||
if device.mac in self.ignored_macs:
|
||||
continue
|
||||
yield device
|
||||
|
||||
async def async_setup(self) -> None:
|
||||
|
@ -159,11 +108,6 @@ class ProtectData:
|
|||
)
|
||||
await self.async_refresh()
|
||||
|
||||
for mac in self.ignored_macs:
|
||||
device = self.api.bootstrap.get_device_from_mac(mac)
|
||||
if device is not None:
|
||||
self._async_remove_device(device)
|
||||
|
||||
async def async_stop(self, *args: Any) -> None:
|
||||
"""Stop processing data."""
|
||||
if self._unsub_websocket:
|
||||
|
@ -228,7 +172,6 @@ class ProtectData:
|
|||
|
||||
@callback
|
||||
def _async_remove_device(self, device: ProtectAdoptableDeviceModel) -> None:
|
||||
|
||||
registry = dr.async_get(self._hass)
|
||||
device_entry = registry.async_get_device(
|
||||
identifiers=set(), connections={(dr.CONNECTION_NETWORK_MAC, device.mac)}
|
||||
|
@ -353,13 +296,13 @@ class ProtectData:
|
|||
|
||||
|
||||
@callback
|
||||
def async_ufp_data_for_config_entry_ids(
|
||||
def async_ufp_instance_for_config_entry_ids(
|
||||
hass: HomeAssistant, config_entry_ids: set[str]
|
||||
) -> ProtectData | None:
|
||||
) -> ProtectApiClient | None:
|
||||
"""Find the UFP instance for the config entry ids."""
|
||||
domain_data = hass.data[DOMAIN]
|
||||
for config_entry_id in config_entry_ids:
|
||||
if config_entry_id in domain_data:
|
||||
protect_data: ProtectData = domain_data[config_entry_id]
|
||||
return protect_data
|
||||
return protect_data.api
|
||||
return None
|
||||
|
|
|
@ -25,7 +25,7 @@ from homeassistant.helpers.service import async_extract_referenced_entity_ids
|
|||
from homeassistant.util.read_only_dict import ReadOnlyDict
|
||||
|
||||
from .const import ATTR_MESSAGE, DOMAIN
|
||||
from .data import async_ufp_data_for_config_entry_ids
|
||||
from .data import async_ufp_instance_for_config_entry_ids
|
||||
|
||||
SERVICE_ADD_DOORBELL_TEXT = "add_doorbell_text"
|
||||
SERVICE_REMOVE_DOORBELL_TEXT = "remove_doorbell_text"
|
||||
|
@ -70,8 +70,8 @@ def _async_get_ufp_instance(hass: HomeAssistant, device_id: str) -> ProtectApiCl
|
|||
return _async_get_ufp_instance(hass, device_entry.via_device_id)
|
||||
|
||||
config_entry_ids = device_entry.config_entries
|
||||
if ufp_data := async_ufp_data_for_config_entry_ids(hass, config_entry_ids):
|
||||
return ufp_data.api
|
||||
if ufp_instance := async_ufp_instance_for_config_entry_ids(hass, config_entry_ids):
|
||||
return ufp_instance
|
||||
|
||||
raise HomeAssistantError(f"No device found for device id: {device_id}")
|
||||
|
||||
|
|
|
@ -50,13 +50,9 @@
|
|||
"disable_rtsp": "Disable the RTSP stream",
|
||||
"all_updates": "Realtime metrics (WARNING: Greatly increases CPU usage)",
|
||||
"override_connection_host": "Override Connection Host",
|
||||
"max_media": "Max number of event to load for Media Browser (increases RAM usage)",
|
||||
"ignored_devices": "Comma separated list of MAC addresses of devices to ignore"
|
||||
"max_media": "Max number of event to load for Media Browser (increases RAM usage)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"invalid_mac_list": "Must be a list of MAC addresses seperated by commas"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,15 +42,11 @@
|
|||
}
|
||||
},
|
||||
"options": {
|
||||
"error": {
|
||||
"invalid_mac_list": "Must be a list of MAC addresses seperated by commas"
|
||||
},
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"all_updates": "Realtime metrics (WARNING: Greatly increases CPU usage)",
|
||||
"disable_rtsp": "Disable the RTSP stream",
|
||||
"ignored_devices": "Comma separated list of MAC addresses of devices to ignore",
|
||||
"max_media": "Max number of event to load for Media Browser (increases RAM usage)",
|
||||
"override_connection_host": "Override Connection Host"
|
||||
},
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""UniFi Protect Integration utils."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator, Iterable
|
||||
import contextlib
|
||||
from enum import Enum
|
||||
import re
|
||||
import socket
|
||||
from typing import Any
|
||||
|
||||
|
@ -14,16 +14,12 @@ from pyunifiprotect.data import (
|
|||
LightModeType,
|
||||
ProtectAdoptableDeviceModel,
|
||||
)
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from .const import DOMAIN, ModelType
|
||||
|
||||
MAC_RE = re.compile(r"[0-9A-F]{12}")
|
||||
|
||||
|
||||
def get_nested_attr(obj: Any, attr: str) -> Any:
|
||||
"""Fetch a nested attribute."""
|
||||
|
@ -42,16 +38,15 @@ def get_nested_attr(obj: Any, attr: str) -> Any:
|
|||
|
||||
|
||||
@callback
|
||||
def async_unifi_mac(mac: str) -> str:
|
||||
"""Convert MAC address to format from UniFi Protect."""
|
||||
def _async_unifi_mac_from_hass(mac: str) -> str:
|
||||
# MAC addresses in UFP are always caps
|
||||
return mac.replace(":", "").replace("-", "").replace("_", "").upper()
|
||||
return mac.replace(":", "").upper()
|
||||
|
||||
|
||||
@callback
|
||||
def async_short_mac(mac: str) -> str:
|
||||
def _async_short_mac(mac: str) -> str:
|
||||
"""Get the short mac address from the full mac."""
|
||||
return async_unifi_mac(mac)[-6:]
|
||||
return _async_unifi_mac_from_hass(mac)[-6:]
|
||||
|
||||
|
||||
async def _async_resolve(hass: HomeAssistant, host: str) -> str | None:
|
||||
|
@ -82,6 +77,18 @@ def async_get_devices_by_type(
|
|||
return devices
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_devices(
|
||||
bootstrap: Bootstrap, model_type: Iterable[ModelType]
|
||||
) -> Generator[ProtectAdoptableDeviceModel, None, None]:
|
||||
"""Return all device by type."""
|
||||
return (
|
||||
device
|
||||
for device_type in model_type
|
||||
for device in async_get_devices_by_type(bootstrap, device_type).values()
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def async_get_light_motion_current(obj: Light) -> str:
|
||||
"""Get light motion mode for Flood Light."""
|
||||
|
@ -99,22 +106,3 @@ def async_dispatch_id(entry: ConfigEntry, dispatch: str) -> str:
|
|||
"""Generate entry specific dispatch ID."""
|
||||
|
||||
return f"{DOMAIN}.{entry.entry_id}.{dispatch}"
|
||||
|
||||
|
||||
@callback
|
||||
def convert_mac_list(option: str, raise_exception: bool = False) -> set[str]:
|
||||
"""Convert csv list of MAC addresses."""
|
||||
|
||||
macs = set()
|
||||
values = cv.ensure_list_csv(option)
|
||||
for value in values:
|
||||
if value == "":
|
||||
continue
|
||||
value = async_unifi_mac(value)
|
||||
if not MAC_RE.match(value):
|
||||
if raise_exception:
|
||||
raise vol.Invalid("invalid_mac_list")
|
||||
continue
|
||||
macs.add(value)
|
||||
|
||||
return macs
|
||||
|
|
|
@ -68,7 +68,6 @@ def mock_ufp_config_entry():
|
|||
"port": 443,
|
||||
"verify_ssl": False,
|
||||
},
|
||||
options={"ignored_devices": "FFFFFFFFFFFF,test"},
|
||||
version=2,
|
||||
)
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ from homeassistant.components import dhcp, ssdp
|
|||
from homeassistant.components.unifiprotect.const import (
|
||||
CONF_ALL_UPDATES,
|
||||
CONF_DISABLE_RTSP,
|
||||
CONF_IGNORED,
|
||||
CONF_OVERRIDE_CHOST,
|
||||
DOMAIN,
|
||||
)
|
||||
|
@ -270,52 +269,10 @@ async def test_form_options(hass: HomeAssistant, ufp_client: ProtectApiClient) -
|
|||
"all_updates": True,
|
||||
"disable_rtsp": True,
|
||||
"override_connection_host": True,
|
||||
"max_media": 1000,
|
||||
}
|
||||
|
||||
|
||||
async def test_form_options_invalid_mac(
|
||||
hass: HomeAssistant, ufp_client: ProtectApiClient
|
||||
) -> None:
|
||||
"""Test we handle options flows."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
"host": "1.1.1.1",
|
||||
"username": "test-username",
|
||||
"password": "test-password",
|
||||
"id": "UnifiProtect",
|
||||
"port": 443,
|
||||
"verify_ssl": False,
|
||||
"max_media": 1000,
|
||||
},
|
||||
version=2,
|
||||
unique_id=dr.format_mac(MAC_ADDR),
|
||||
)
|
||||
mock_config.add_to_hass(hass)
|
||||
|
||||
with _patch_discovery(), patch(
|
||||
"homeassistant.components.unifiprotect.ProtectApiClient"
|
||||
) as mock_api:
|
||||
mock_api.return_value = ufp_client
|
||||
|
||||
await hass.config_entries.async_setup(mock_config.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert mock_config.state == config_entries.ConfigEntryState.LOADED
|
||||
|
||||
result = await hass.config_entries.options.async_init(mock_config.entry_id)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert not result["errors"]
|
||||
assert result["step_id"] == "init"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
{CONF_IGNORED: "test,test2"},
|
||||
)
|
||||
|
||||
assert result2["type"] == FlowResultType.FORM
|
||||
assert result2["errors"] == {CONF_IGNORED: "invalid_mac_list"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source, data",
|
||||
[
|
||||
|
|
|
@ -7,21 +7,20 @@ from unittest.mock import AsyncMock, patch
|
|||
|
||||
import aiohttp
|
||||
from pyunifiprotect import NotAuthorized, NvrError, ProtectApiClient
|
||||
from pyunifiprotect.data import NVR, Bootstrap, Doorlock, Light, Sensor
|
||||
from pyunifiprotect.data import NVR, Bootstrap, Light
|
||||
|
||||
from homeassistant.components.unifiprotect.const import (
|
||||
CONF_DISABLE_RTSP,
|
||||
CONF_IGNORED,
|
||||
DEFAULT_SCAN_INTERVAL,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
||||
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 homeassistant.setup import async_setup_component
|
||||
|
||||
from . import _patch_discovery
|
||||
from .utils import MockUFPFixture, get_device_from_ufp_device, init_entry, time_changed
|
||||
from .utils import MockUFPFixture, init_entry, time_changed
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
@ -212,38 +211,28 @@ async def test_device_remove_devices(
|
|||
hass: HomeAssistant,
|
||||
ufp: MockUFPFixture,
|
||||
light: Light,
|
||||
doorlock: Doorlock,
|
||||
sensor: Sensor,
|
||||
hass_ws_client: Callable[
|
||||
[HomeAssistant], Awaitable[aiohttp.ClientWebSocketResponse]
|
||||
],
|
||||
) -> None:
|
||||
"""Test we can only remove a device that no longer exists."""
|
||||
|
||||
sensor.mac = "FFFFFFFFFFFF"
|
||||
|
||||
await init_entry(hass, ufp, [light, doorlock, sensor], regenerate_ids=False)
|
||||
await init_entry(hass, ufp, [light])
|
||||
assert await async_setup_component(hass, "config", {})
|
||||
|
||||
entity_id = "light.test_light"
|
||||
entry_id = ufp.entry.entry_id
|
||||
|
||||
registry: er.EntityRegistry = er.async_get(hass)
|
||||
entity = registry.async_get(entity_id)
|
||||
assert entity is not None
|
||||
device_registry = dr.async_get(hass)
|
||||
|
||||
light_device = get_device_from_ufp_device(hass, light)
|
||||
assert light_device is not None
|
||||
live_device_entry = device_registry.async_get(entity.device_id)
|
||||
assert (
|
||||
await remove_device(await hass_ws_client(hass), light_device.id, entry_id)
|
||||
is True
|
||||
await remove_device(await hass_ws_client(hass), live_device_entry.id, entry_id)
|
||||
is False
|
||||
)
|
||||
|
||||
doorlock_device = get_device_from_ufp_device(hass, doorlock)
|
||||
assert (
|
||||
await remove_device(await hass_ws_client(hass), doorlock_device.id, entry_id)
|
||||
is True
|
||||
)
|
||||
|
||||
sensor_device = get_device_from_ufp_device(hass, sensor)
|
||||
assert sensor_device is None
|
||||
|
||||
dead_device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=entry_id,
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, "e9:88:e7:b8:b4:40")},
|
||||
|
@ -253,10 +242,6 @@ async def test_device_remove_devices(
|
|||
is True
|
||||
)
|
||||
|
||||
await time_changed(hass, 60)
|
||||
entry = hass.config_entries.async_get_entry(entry_id)
|
||||
entry.options[CONF_IGNORED] == f"{light.mac},{doorlock.mac}"
|
||||
|
||||
|
||||
async def test_device_remove_devices_nvr(
|
||||
hass: HomeAssistant,
|
||||
|
|
|
@ -23,7 +23,7 @@ from pyunifiprotect.test_util.anonymize import random_hex
|
|||
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, split_entity_id
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity import EntityDescription
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
|
@ -229,13 +229,3 @@ async def adopt_devices(
|
|||
ufp.ws_msg(mock_msg)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
def get_device_from_ufp_device(
|
||||
hass: HomeAssistant, device: ProtectAdoptableDeviceModel
|
||||
) -> dr.DeviceEntry | None:
|
||||
"""Return all device by type."""
|
||||
registry = dr.async_get(hass)
|
||||
return registry.async_get_device(
|
||||
identifiers=set(), connections={(dr.CONNECTION_NETWORK_MAC, device.mac)}
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue