Bumps version of pyunifiprotect to 4.0.4 (#73722)

This commit is contained in:
Christopher Bailey 2022-06-20 23:09:13 -04:00 committed by GitHub
parent 109d1844b3
commit 3851c7b4b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 770 additions and 155 deletions

View file

@ -7,7 +7,8 @@ import logging
from aiohttp import CookieJar
from aiohttp.client_exceptions import ServerDisconnectedError
from pyunifiprotect import NotAuthorized, NvrError, ProtectApiClient
from pyunifiprotect import ProtectApiClient
from pyunifiprotect.exceptions import ClientError, NotAuthorized
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
@ -68,7 +69,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
nvr_info = await protect.get_nvr()
except NotAuthorized as err:
raise ConfigEntryAuthFailed(err) from err
except (asyncio.TimeoutError, NvrError, ServerDisconnectedError) as err:
except (asyncio.TimeoutError, ClientError, ServerDisconnectedError) as err:
raise ConfigEntryNotReady from err
if nvr_info.version < MIN_REQUIRED_PROTECT_V:

View file

@ -6,8 +6,9 @@ import logging
from typing import Any
from aiohttp import CookieJar
from pyunifiprotect import NotAuthorized, NvrError, ProtectApiClient
from pyunifiprotect import ProtectApiClient
from pyunifiprotect.data import NVR
from pyunifiprotect.exceptions import ClientError, NotAuthorized
from unifi_discovery import async_console_is_alive
import voluptuous as vol
@ -253,7 +254,7 @@ class ProtectFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
except NotAuthorized as ex:
_LOGGER.debug(ex)
errors[CONF_PASSWORD] = "invalid_auth"
except NvrError as ex:
except ClientError as ex:
_LOGGER.debug(ex)
errors["base"] = "cannot_connect"
else:

View file

@ -6,7 +6,7 @@ from datetime import timedelta
import logging
from typing import Any
from pyunifiprotect import NotAuthorized, NvrError, ProtectApiClient
from pyunifiprotect import ProtectApiClient
from pyunifiprotect.data import (
Bootstrap,
Event,
@ -15,6 +15,7 @@ from pyunifiprotect.data import (
WSSubscriptionMessage,
)
from pyunifiprotect.data.base import ProtectAdoptableDeviceModel
from pyunifiprotect.exceptions import ClientError, NotAuthorized
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
@ -100,23 +101,27 @@ class ProtectData:
try:
updates = await self.api.update(force=force)
except NvrError:
if self.last_update_success:
_LOGGER.exception("Error while updating")
self.last_update_success = False
# manually trigger update to mark entities unavailable
self._async_process_updates(self.api.bootstrap)
except NotAuthorized:
await self.async_stop()
_LOGGER.exception("Reauthentication required")
self._entry.async_start_reauth(self._hass)
self.last_update_success = False
except ClientError:
if self.last_update_success:
_LOGGER.exception("Error while updating")
self.last_update_success = False
# manually trigger update to mark entities unavailable
self._async_process_updates(self.api.bootstrap)
else:
self.last_update_success = True
self._async_process_updates(updates)
@callback
def _async_process_ws_message(self, message: WSSubscriptionMessage) -> None:
# removed packets are not processed yet
if message.new_obj is None: # pragma: no cover
return
if message.new_obj.model in DEVICES_WITH_ENTITIES:
self.async_signal_device_id_update(message.new_obj.id)
# trigger update for all Cameras with LCD screens when NVR Doorbell settings updates

View file

@ -3,7 +3,7 @@
"name": "UniFi Protect",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/unifiprotect",
"requirements": ["pyunifiprotect==3.9.2", "unifi-discovery==1.1.4"],
"requirements": ["pyunifiprotect==4.0.4", "unifi-discovery==1.1.4"],
"dependencies": ["http"],
"codeowners": ["@briis", "@AngellusMortis", "@bdraco"],
"quality_scale": "platinum",

View file

@ -8,7 +8,7 @@ from typing import Any, cast
from pydantic import ValidationError
from pyunifiprotect.api import ProtectApiClient
from pyunifiprotect.data import Chime
from pyunifiprotect.exceptions import BadRequest
from pyunifiprotect.exceptions import ClientError
import voluptuous as vol
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
@ -100,7 +100,7 @@ async def _async_service_call_nvr(
await asyncio.gather(
*(getattr(i.bootstrap.nvr, method)(*args, **kwargs) for i in instances)
)
except (BadRequest, ValidationError) as err:
except (ClientError, ValidationError) as err:
raise HomeAssistantError(str(err)) from err

View file

@ -1990,7 +1990,7 @@ pytrafikverket==0.2.0.1
pyudev==0.22.0
# homeassistant.components.unifiprotect
pyunifiprotect==3.9.2
pyunifiprotect==4.0.4
# homeassistant.components.uptimerobot
pyuptimerobot==22.2.0

View file

@ -1325,7 +1325,7 @@ pytrafikverket==0.2.0.1
pyudev==0.22.0
# homeassistant.components.unifiprotect
pyunifiprotect==3.9.2
pyunifiprotect==4.0.4
# homeassistant.components.uptimerobot
pyuptimerobot==22.2.0

View file

@ -13,6 +13,7 @@ from unittest.mock import AsyncMock, Mock, patch
import pytest
from pyunifiprotect.data import (
NVR,
Bootstrap,
Camera,
Chime,
Doorlock,
@ -39,69 +40,6 @@ from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
MAC_ADDR = "aa:bb:cc:dd:ee:ff"
@dataclass
class MockBootstrap:
"""Mock for Bootstrap."""
nvr: NVR
cameras: dict[str, Any]
lights: dict[str, Any]
sensors: dict[str, Any]
viewers: dict[str, Any]
liveviews: dict[str, Any]
events: dict[str, Any]
doorlocks: dict[str, Any]
chimes: dict[str, Any]
def reset_objects(self) -> None:
"""Reset all devices on bootstrap for tests."""
self.cameras = {}
self.lights = {}
self.sensors = {}
self.viewers = {}
self.liveviews = {}
self.events = {}
self.doorlocks = {}
self.chimes = {}
def process_ws_packet(self, msg: WSSubscriptionMessage) -> None:
"""Fake process method for tests."""
pass
def unifi_dict(self) -> dict[str, Any]:
"""Return UniFi formatted dict representation of the NVR."""
return {
"nvr": self.nvr.unifi_dict(),
"cameras": [c.unifi_dict() for c in self.cameras.values()],
"lights": [c.unifi_dict() for c in self.lights.values()],
"sensors": [c.unifi_dict() for c in self.sensors.values()],
"viewers": [c.unifi_dict() for c in self.viewers.values()],
"liveviews": [c.unifi_dict() for c in self.liveviews.values()],
"doorlocks": [c.unifi_dict() for c in self.doorlocks.values()],
"chimes": [c.unifi_dict() for c in self.chimes.values()],
}
def get_device_from_mac(self, mac: str) -> ProtectAdoptableDeviceModel | None:
"""Return device for MAC address."""
mac = mac.lower().replace(":", "").replace("-", "").replace("_", "")
all_devices = (
self.cameras.values(),
self.lights.values(),
self.sensors.values(),
self.viewers.values(),
self.liveviews.values(),
self.doorlocks.values(),
self.chimes.values(),
)
for devices in all_devices:
for device in devices:
if device.mac.lower() == mac:
return device
return None
@dataclass
class MockEntityFixture:
"""Mock for NVR."""
@ -155,27 +93,42 @@ def mock_old_nvr_fixture():
@pytest.fixture(name="mock_bootstrap")
def mock_bootstrap_fixture(mock_nvr: NVR):
"""Mock Bootstrap fixture."""
return MockBootstrap(
nvr=mock_nvr,
cameras={},
lights={},
sensors={},
viewers={},
liveviews={},
events={},
doorlocks={},
chimes={},
)
data = json.loads(load_fixture("sample_bootstrap.json", integration=DOMAIN))
data["nvr"] = mock_nvr
data["cameras"] = []
data["lights"] = []
data["sensors"] = []
data["viewers"] = []
data["liveviews"] = []
data["events"] = []
data["doorlocks"] = []
data["chimes"] = []
return Bootstrap.from_unifi_dict(**data)
def reset_objects(bootstrap: Bootstrap):
"""Reset bootstrap objects."""
bootstrap.cameras = {}
bootstrap.lights = {}
bootstrap.sensors = {}
bootstrap.viewers = {}
bootstrap.liveviews = {}
bootstrap.events = {}
bootstrap.doorlocks = {}
bootstrap.chimes = {}
@pytest.fixture
def mock_client(mock_bootstrap: MockBootstrap):
def mock_client(mock_bootstrap: Bootstrap):
"""Mock ProtectApiClient for testing."""
client = Mock()
client.bootstrap = mock_bootstrap
nvr = mock_bootstrap.nvr
nvr = client.bootstrap.nvr
nvr._api = client
client.bootstrap._api = client
client.base_url = "https://127.0.0.1"
client.connection_host = IPv4Address("127.0.0.1")

View file

@ -0,0 +1,633 @@
{
"authUserId": "4c5f03a8c8bd48ad8e066285",
"accessKey": "8528571101220:340ff666bffb58bc404b859a:8f3f41a7b180b1ff7463fe4f7f13b528ac3d28668f25d0ecaa30c8e7888559e782b38d4335b40861030b75126eb7cea8385f3f9ab59dfa9a993e50757c277053",
"users": [
{
"permissions": [],
"lastLoginIp": null,
"lastLoginTime": null,
"isOwner": true,
"enableNotifications": false,
"settings": {
"flags": {}
},
"groups": ["b061186823695fb901973177"],
"alertRules": [],
"notificationsV2": {
"state": "custom",
"motionNotifications": {
"trigger": {
"when": "inherit",
"location": "away",
"schedules": []
},
"cameras": [
{
"inheritFromParent": true,
"motion": [],
"person": [],
"vehicle": [],
"camera": "61b3f5c7033ea703e7000424",
"trigger": {
"when": "always",
"location": "away",
"schedules": []
}
}
],
"doorbells": [],
"lights": [],
"doorlocks": [],
"sensors": []
},
"systemNotifications": {}
},
"featureFlags": {
"notificationsV2": true
},
"id": "fe4c12ae2c1348edb7854e2f",
"hasAcceptedInvite": true,
"allPermissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"nvr:write,delete:*",
"group:create,read,write,delete:*",
"user:create,read,write,delete:*",
"schedule:create,read,write,delete:*",
"legacyUFV:read,write,delete:*",
"bridge:create,read,write,delete:*",
"camera:create,read,write,delete,readmedia,deletemedia:*",
"light:create,read,write,delete:*",
"sensor:create,read,write,delete:*",
"doorlock:create,read,write,delete:*",
"viewer:create,read,write,delete:*",
"display:create,read,write,delete:*",
"chime:create,read,write,delete:*"
],
"cloudAccount": {
"firstName": "Qpvfly",
"lastName": "Ikjzilt",
"email": "QhoFvCv@example.com",
"profileImg": null,
"user": "fe4c12ae2c1348edb7854e2f",
"id": "9efc4511-4539-4402-9581-51cee8b65cf5",
"cloudId": "9efc4511-4539-4402-9581-51cee8b65cf5",
"name": "Qpvfly Ikjzilt",
"modelKey": "cloudIdentity"
},
"name": "Qpvfly Ikjzilt",
"firstName": "Qpvfly",
"lastName": "Ikjzilt",
"email": "QhoFvCv@example.com",
"localUsername": "QhoFvCv",
"modelKey": "user"
},
{
"permissions": [],
"lastLoginIp": null,
"lastLoginTime": null,
"isOwner": false,
"enableNotifications": false,
"settings": null,
"groups": ["a7f3b2eb71b4c4e56f1f45ac", "b061186823695fb901973177"],
"alertRules": [],
"notificationsV2": {
"state": "auto",
"motionNotifications": {
"trigger": {
"when": "inherit",
"location": "away",
"schedules": []
},
"cameras": [],
"doorbells": [],
"lights": [],
"doorlocks": [],
"sensors": []
},
"systemNotifications": {}
},
"featureFlags": {
"notificationsV2": true
},
"id": "dcaef9cb8aed05c7db658a46",
"hasAcceptedInvite": false,
"allPermissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"bridge:read:*",
"camera:read,readmedia:*",
"doorlock:read:*",
"light:read:*",
"sensor:read:*",
"viewer:read:*",
"display:read:*",
"chime:read:*",
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"nvr:write,delete:*",
"group:create,read,write,delete:*",
"user:create,read,write,delete:*",
"schedule:create,read,write,delete:*",
"legacyUFV:read,write,delete:*",
"bridge:create,read,write,delete:*",
"camera:create,read,write,delete,readmedia,deletemedia:*",
"light:create,read,write,delete:*",
"sensor:create,read,write,delete:*",
"doorlock:create,read,write,delete:*",
"viewer:create,read,write,delete:*",
"display:create,read,write,delete:*",
"chime:create,read,write,delete:*"
],
"cloudAccount": null,
"name": "Uxqg Wcbz",
"firstName": "Uxqg",
"lastName": "Wcbz",
"email": "epHDEhE@example.com",
"localUsername": "epHDEhE",
"modelKey": "user"
},
{
"permissions": [
"liveview:*:d65bb41c14d6aa92bfa4a6d1",
"liveview:*:49bbb5005424a0d35152671a",
"liveview:*:b28c38f1220f6b43f3930dff",
"liveview:*:b9861b533a87ea639fa4d438"
],
"lastLoginIp": null,
"lastLoginTime": null,
"isOwner": false,
"enableNotifications": false,
"settings": {
"flags": {},
"web": {
"dewarp": {
"61ddb66b018e2703e7008c19": {
"dewarp": false,
"state": {
"pan": 0,
"tilt": -1.5707963267948966,
"zoom": 1.5707963267948966,
"panning": 0,
"tilting": 0
}
}
},
"liveview.includeGlobal": true,
"elements.events_viewmode": "grid",
"elements.viewmode": "list"
}
},
"groups": ["b061186823695fb901973177"],
"location": {
"isAway": true,
"latitude": null,
"longitude": null
},
"alertRules": [],
"notificationsV2": {
"state": "custom",
"motionNotifications": {
"trigger": {
"when": "inherit",
"location": "away",
"schedules": []
},
"cameras": [
{
"inheritFromParent": true,
"motion": [],
"camera": "61b3f5c703d2a703e7000427",
"trigger": {
"when": "always",
"location": "away",
"schedules": []
}
},
{
"inheritFromParent": true,
"motion": [],
"person": [],
"vehicle": [],
"camera": "61b3f5c7033ea703e7000424",
"trigger": {
"when": "always",
"location": "away",
"schedules": []
}
}
],
"doorbells": [],
"lights": [],
"doorlocks": [],
"sensors": []
},
"systemNotifications": {}
},
"featureFlags": {
"notificationsV2": true
},
"id": "4c5f03a8c8bd48ad8e066285",
"hasAcceptedInvite": false,
"allPermissions": [
"liveview:*:d65bb41c14d6aa92bfa4a6d1",
"liveview:*:49bbb5005424a0d35152671a",
"liveview:*:b28c38f1220f6b43f3930dff",
"liveview:*:b9861b533a87ea639fa4d438",
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"nvr:write,delete:*",
"group:create,read,write,delete:*",
"user:create,read,write,delete:*",
"schedule:create,read,write,delete:*",
"legacyUFV:read,write,delete:*",
"bridge:create,read,write,delete:*",
"camera:create,read,write,delete,readmedia,deletemedia:*",
"light:create,read,write,delete:*",
"sensor:create,read,write,delete:*",
"doorlock:create,read,write,delete:*",
"viewer:create,read,write,delete:*",
"display:create,read,write,delete:*",
"chime:create,read,write,delete:*"
],
"cloudAccount": null,
"name": "Ptcmsdo Tfiyoep",
"firstName": "Ptcmsdo",
"lastName": "Tfiyoep",
"email": "EQAoXL@example.com",
"localUsername": "EQAoXL",
"modelKey": "user"
},
{
"permissions": [],
"lastLoginIp": null,
"lastLoginTime": null,
"isOwner": false,
"enableNotifications": false,
"settings": {
"flags": {},
"web": {
"dewarp": {
"61c4d1db02c82a03e700429c": {
"dewarp": false,
"state": {
"pan": 0,
"tilt": 0,
"zoom": 1.5707963267948966,
"panning": 0,
"tilting": 0
}
}
},
"liveview.includeGlobal": true
}
},
"groups": ["a7f3b2eb71b4c4e56f1f45ac"],
"alertRules": [],
"notificationsV2": {
"state": "auto",
"motionNotifications": {
"trigger": {
"when": "inherit",
"location": "away",
"schedules": []
},
"cameras": [],
"doorbells": [],
"lights": [],
"doorlocks": [],
"sensors": []
},
"systemNotifications": {}
},
"featureFlags": {
"notificationsV2": true
},
"id": "bc3dd633553907952a6fe20d",
"hasAcceptedInvite": false,
"allPermissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"bridge:read:*",
"camera:read,readmedia:*",
"doorlock:read:*",
"light:read:*",
"sensor:read:*",
"viewer:read:*",
"display:read:*",
"chime:read:*"
],
"cloudAccount": null,
"name": "Evdxou Zgyv",
"firstName": "Evdxou",
"lastName": "Zgyv",
"email": "FMZuD@example.com",
"localUsername": "FMZuD",
"modelKey": "user"
},
{
"permissions": [],
"lastLoginIp": null,
"lastLoginTime": null,
"isOwner": false,
"enableNotifications": false,
"settings": null,
"groups": ["a7f3b2eb71b4c4e56f1f45ac", "b061186823695fb901973177"],
"alertRules": [],
"notificationsV2": {
"state": "auto",
"motionNotifications": {
"trigger": {
"when": "inherit",
"location": "away",
"schedules": []
},
"cameras": [],
"doorbells": [],
"lights": [],
"doorlocks": [],
"sensors": []
},
"systemNotifications": {}
},
"featureFlags": {
"notificationsV2": true
},
"id": "adec5334b69f56f6a6c47520",
"hasAcceptedInvite": false,
"allPermissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"bridge:read:*",
"camera:read,readmedia:*",
"doorlock:read:*",
"light:read:*",
"sensor:read:*",
"viewer:read:*",
"display:read:*",
"chime:read:*",
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"nvr:write,delete:*",
"group:create,read,write,delete:*",
"user:create,read,write,delete:*",
"schedule:create,read,write,delete:*",
"legacyUFV:read,write,delete:*",
"bridge:create,read,write,delete:*",
"camera:create,read,write,delete,readmedia,deletemedia:*",
"light:create,read,write,delete:*",
"sensor:create,read,write,delete:*",
"doorlock:create,read,write,delete:*",
"viewer:create,read,write,delete:*",
"display:create,read,write,delete:*",
"chime:create,read,write,delete:*"
],
"cloudAccount": null,
"name": "Qpv Elqfgq",
"firstName": "Qpv",
"lastName": "Elqfgq",
"email": "xdr@example.com",
"localUsername": "xdr",
"modelKey": "user"
},
{
"permissions": [],
"lastLoginIp": null,
"lastLoginTime": null,
"isOwner": false,
"enableNotifications": false,
"settings": null,
"groups": ["a7f3b2eb71b4c4e56f1f45ac", "b061186823695fb901973177"],
"alertRules": [],
"notificationsV2": {
"state": "auto",
"motionNotifications": {
"trigger": {
"when": "inherit",
"location": "away",
"schedules": []
},
"cameras": [],
"doorbells": [],
"lights": [],
"doorlocks": [],
"sensors": []
},
"systemNotifications": {}
},
"featureFlags": {
"notificationsV2": true
},
"id": "8593657a25b7826a4288b6af",
"hasAcceptedInvite": false,
"allPermissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"bridge:read:*",
"camera:read,readmedia:*",
"doorlock:read:*",
"light:read:*",
"sensor:read:*",
"viewer:read:*",
"display:read:*",
"chime:read:*",
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"nvr:write,delete:*",
"group:create,read,write,delete:*",
"user:create,read,write,delete:*",
"schedule:create,read,write,delete:*",
"legacyUFV:read,write,delete:*",
"bridge:create,read,write,delete:*",
"camera:create,read,write,delete,readmedia,deletemedia:*",
"light:create,read,write,delete:*",
"sensor:create,read,write,delete:*",
"doorlock:create,read,write,delete:*",
"viewer:create,read,write,delete:*",
"display:create,read,write,delete:*",
"chime:create,read,write,delete:*"
],
"cloudAccount": null,
"name": "Sgpy Ooevsme",
"firstName": "Sgpy",
"lastName": "Ooevsme",
"email": "WQJNT@example.com",
"localUsername": "WQJNT",
"modelKey": "user"
},
{
"permissions": [],
"isOwner": false,
"enableNotifications": false,
"groups": ["a7f3b2eb71b4c4e56f1f45ac"],
"alertRules": [],
"notificationsV2": {
"state": "off",
"motionNotifications": {
"trigger": {
"when": "inherit",
"location": "away",
"schedules": []
},
"cameras": [],
"doorbells": [],
"lights": [],
"doorlocks": [],
"sensors": []
},
"systemNotifications": {}
},
"featureFlags": {
"notificationsV2": true
},
"id": "abf647aed3650a781ceba13f",
"hasAcceptedInvite": false,
"allPermissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"bridge:read:*",
"camera:read,readmedia:*",
"doorlock:read:*",
"light:read:*",
"sensor:read:*",
"viewer:read:*",
"display:read:*",
"chime:read:*"
],
"cloudAccount": null,
"name": "Yiiyq Glx",
"firstName": "Yiiyq",
"lastName": "Glx",
"email": "fBjmm@example.com",
"localUsername": "fBjmm",
"modelKey": "user"
}
],
"groups": [
{
"name": "Kubw Xnbb",
"permissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"nvr:write,delete:*",
"group:create,read,write,delete:*",
"user:create,read,write,delete:*",
"schedule:create,read,write,delete:*",
"legacyUFV:read,write,delete:*",
"bridge:create,read,write,delete:*",
"camera:create,read,write,delete,readmedia,deletemedia:*",
"light:create,read,write,delete:*",
"sensor:create,read,write,delete:*",
"doorlock:create,read,write,delete:*",
"viewer:create,read,write,delete:*",
"display:create,read,write,delete:*",
"chime:create,read,write,delete:*"
],
"type": "preset",
"isDefault": true,
"id": "b061186823695fb901973177",
"modelKey": "group"
},
{
"name": "Pmbrvp Wyzqs",
"permissions": [
"nvr:read:*",
"liveview:create",
"user:read,write,delete:$",
"bridge:read:*",
"camera:read,readmedia:*",
"doorlock:read:*",
"light:read:*",
"sensor:read:*",
"viewer:read:*",
"display:read:*",
"chime:read:*"
],
"type": "preset",
"isDefault": false,
"id": "a7f3b2eb71b4c4e56f1f45ac",
"modelKey": "group"
}
],
"schedules": [],
"legacyUFVs": [],
"lastUpdateId": "ebf25bac-d5a1-4f1d-a0ee-74c15981eb70",
"displays": [],
"bridges": [
{
"mac": "A28D0DB15AE1",
"host": "192.168.231.68",
"connectionHost": "192.168.102.63",
"type": "UFP-UAP-B",
"name": "Sffde Gxcaqe",
"upSince": 1639807977891,
"uptime": 3247782,
"lastSeen": 1643055759891,
"connectedSince": 1642374159304,
"state": "CONNECTED",
"hardwareRevision": 19,
"firmwareVersion": "0.3.1",
"latestFirmwareVersion": null,
"firmwareBuild": null,
"isUpdating": false,
"isAdopting": false,
"isAdopted": true,
"isAdoptedByOther": false,
"isProvisioned": false,
"isRebooting": false,
"isSshEnabled": false,
"canAdopt": false,
"isAttemptingToConnect": false,
"wiredConnectionState": {
"phyRate": null
},
"id": "1f5a055254fb9169d7536fb9",
"isConnected": true,
"platform": "mt7621",
"modelKey": "bridge"
},
{
"mac": "C65C557CCA95",
"host": "192.168.87.68",
"connectionHost": "192.168.102.63",
"type": "UFP-UAP-B",
"name": "Axiwj Bbd",
"upSince": 1641257260772,
"uptime": null,
"lastSeen": 1643052750862,
"connectedSince": 1643052754695,
"state": "CONNECTED",
"hardwareRevision": 19,
"firmwareVersion": "0.3.1",
"latestFirmwareVersion": null,
"firmwareBuild": null,
"isUpdating": false,
"isAdopting": false,
"isAdopted": true,
"isAdoptedByOther": false,
"isProvisioned": false,
"isRebooting": false,
"isSshEnabled": false,
"canAdopt": false,
"isAttemptingToConnect": false,
"wiredConnectionState": {
"phyRate": null
},
"id": "e6901e3665a4c0eab0d9c1a5",
"isConnected": true,
"platform": "mt7621",
"modelKey": "bridge"
}
]
}

View file

@ -36,6 +36,7 @@ from .conftest import (
MockEntityFixture,
assert_entity_counts,
ids_from_device_description,
reset_objects,
)
@ -51,7 +52,7 @@ async def camera_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -62,7 +63,7 @@ async def camera_fixture(
camera_obj.is_dark = False
camera_obj.is_motion_detected = False
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
@ -87,14 +88,14 @@ async def light_fixture(
# disable pydantic validation so mocking can happen
Light.__config__.validate_assignment = False
light_obj = mock_light.copy(deep=True)
light_obj = mock_light.copy()
light_obj._api = mock_entry.api
light_obj.name = "Test Light"
light_obj.is_dark = False
light_obj.is_pir_motion_detected = False
light_obj.last_motion = now - timedelta(hours=1)
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []
mock_entry.api.bootstrap.lights = {
light_obj.id: light_obj,
@ -119,7 +120,7 @@ async def camera_none_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -129,7 +130,7 @@ async def camera_none_fixture(
camera_obj.is_dark = False
camera_obj.is_motion_detected = False
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
@ -157,7 +158,7 @@ async def sensor_fixture(
# disable pydantic validation so mocking can happen
Sensor.__config__.validate_assignment = False
sensor_obj = mock_sensor.copy(deep=True)
sensor_obj = mock_sensor.copy()
sensor_obj._api = mock_entry.api
sensor_obj.name = "Test Sensor"
sensor_obj.mount_type = MountType.DOOR
@ -170,7 +171,7 @@ async def sensor_fixture(
sensor_obj.alarm_triggered_at = now - timedelta(hours=1)
sensor_obj.tampering_detected_at = None
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []
mock_entry.api.bootstrap.sensors = {
sensor_obj.id: sensor_obj,
@ -198,7 +199,7 @@ async def sensor_none_fixture(
# disable pydantic validation so mocking can happen
Sensor.__config__.validate_assignment = False
sensor_obj = mock_sensor.copy(deep=True)
sensor_obj = mock_sensor.copy()
sensor_obj._api = mock_entry.api
sensor_obj.name = "Test Sensor"
sensor_obj.mount_type = MountType.LEAK
@ -206,7 +207,7 @@ async def sensor_none_fixture(
sensor_obj.alarm_settings.is_enabled = False
sensor_obj.tampering_detected_at = None
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []
mock_entry.api.bootstrap.sensors = {
sensor_obj.id: sensor_obj,

View file

@ -21,7 +21,7 @@ async def chime_fixture(
):
"""Fixture for a single camera for testing the button platform."""
chime_obj = mock_chime.copy(deep=True)
chime_obj = mock_chime.copy()
chime_obj._api = mock_entry.api
chime_obj.name = "Test Chime"

View file

@ -52,7 +52,7 @@ async def camera_fixture(
# disable pydantic validation so mocking can happen
ProtectCamera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -83,7 +83,7 @@ async def camera_package_fixture(
):
"""Fixture for a single camera for testing the camera platform."""
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -95,7 +95,7 @@ async def camera_package_fixture(
camera_obj.channels[0].rtsp_alias = "test_high_alias"
camera_obj.channels[1].is_rtsp_enabled = False
camera_obj.channels[2].is_rtsp_enabled = False
package_channel = camera_obj.channels[0].copy(deep=True)
package_channel = camera_obj.channels[0].copy()
package_channel.is_rtsp_enabled = False
package_channel.name = "Package Camera"
package_channel.id = 3
@ -246,8 +246,9 @@ async def test_basic_setup(
):
"""Test working setup of unifiprotect entry."""
camera_high_only = mock_camera.copy(deep=True)
camera_high_only = mock_camera.copy()
camera_high_only._api = mock_entry.api
camera_high_only.channels = [c.copy() for c in mock_camera.channels]
camera_high_only.channels[0]._api = mock_entry.api
camera_high_only.channels[1]._api = mock_entry.api
camera_high_only.channels[2]._api = mock_entry.api
@ -259,8 +260,9 @@ async def test_basic_setup(
camera_high_only.channels[2].is_rtsp_enabled = False
regenerate_device_ids(camera_high_only)
camera_medium_only = mock_camera.copy(deep=True)
camera_medium_only = mock_camera.copy()
camera_medium_only._api = mock_entry.api
camera_medium_only.channels = [c.copy() for c in mock_camera.channels]
camera_medium_only.channels[0]._api = mock_entry.api
camera_medium_only.channels[1]._api = mock_entry.api
camera_medium_only.channels[2]._api = mock_entry.api
@ -272,8 +274,9 @@ async def test_basic_setup(
camera_medium_only.channels[2].is_rtsp_enabled = False
regenerate_device_ids(camera_medium_only)
camera_all_channels = mock_camera.copy(deep=True)
camera_all_channels = mock_camera.copy()
camera_all_channels._api = mock_entry.api
camera_all_channels.channels = [c.copy() for c in mock_camera.channels]
camera_all_channels.channels[0]._api = mock_entry.api
camera_all_channels.channels[1]._api = mock_entry.api
camera_all_channels.channels[2]._api = mock_entry.api
@ -289,8 +292,9 @@ async def test_basic_setup(
camera_all_channels.channels[2].rtsp_alias = "test_low_alias"
regenerate_device_ids(camera_all_channels)
camera_no_channels = mock_camera.copy(deep=True)
camera_no_channels = mock_camera.copy()
camera_no_channels._api = mock_entry.api
camera_no_channels.channels = [c.copy() for c in camera_no_channels.channels]
camera_no_channels.channels[0]._api = mock_entry.api
camera_no_channels.channels[1]._api = mock_entry.api
camera_no_channels.channels[2]._api = mock_entry.api
@ -301,8 +305,9 @@ async def test_basic_setup(
camera_no_channels.channels[2].is_rtsp_enabled = False
regenerate_device_ids(camera_no_channels)
camera_package = mock_camera.copy(deep=True)
camera_package = mock_camera.copy()
camera_package._api = mock_entry.api
camera_package.channels = [c.copy() for c in mock_camera.channels]
camera_package.channels[0]._api = mock_entry.api
camera_package.channels[1]._api = mock_entry.api
camera_package.channels[2]._api = mock_entry.api
@ -313,7 +318,7 @@ async def test_basic_setup(
camera_package.channels[1].is_rtsp_enabled = False
camera_package.channels[2].is_rtsp_enabled = False
regenerate_device_ids(camera_package)
package_channel = camera_package.channels[0].copy(deep=True)
package_channel = camera_package.channels[0].copy()
package_channel.is_rtsp_enabled = False
package_channel.name = "Package Camera"
package_channel.id = 3
@ -398,7 +403,7 @@ async def test_missing_channels(
):
"""Test setting up camera with no camera channels."""
camera = mock_camera.copy(deep=True)
camera = mock_camera.copy()
camera.channels = []
mock_entry.api.bootstrap.cameras = {camera.id: camera}

View file

@ -7,7 +7,7 @@ from unittest.mock import AsyncMock, patch
import aiohttp
from pyunifiprotect import NotAuthorized, NvrError
from pyunifiprotect.data import NVR, Light
from pyunifiprotect.data import NVR, Bootstrap, Light
from homeassistant.components.unifiprotect.const import CONF_DISABLE_RTSP, DOMAIN
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
@ -16,7 +16,7 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from . import _patch_discovery
from .conftest import MockBootstrap, MockEntityFixture, regenerate_device_ids
from .conftest import MockEntityFixture, regenerate_device_ids
from tests.common import MockConfigEntry
@ -52,7 +52,7 @@ async def test_setup_multiple(
hass: HomeAssistant,
mock_entry: MockEntityFixture,
mock_client,
mock_bootstrap: MockBootstrap,
mock_bootstrap: Bootstrap,
):
"""Test working setup of unifiprotect entry."""

View file

@ -32,7 +32,7 @@ async def light_fixture(
# disable pydantic validation so mocking can happen
Light.__config__.validate_assignment = False
light_obj = mock_light.copy(deep=True)
light_obj = mock_light.copy()
light_obj._api = mock_entry.api
light_obj.name = "Test Light"
light_obj.is_light_on = False

View file

@ -35,7 +35,7 @@ async def doorlock_fixture(
# disable pydantic validation so mocking can happen
Doorlock.__config__.validate_assignment = False
lock_obj = mock_doorlock.copy(deep=True)
lock_obj = mock_doorlock.copy()
lock_obj._api = mock_entry.api
lock_obj.name = "Test Lock"
lock_obj.lock_status = LockStatusType.OPEN

View file

@ -38,7 +38,7 @@ async def camera_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api

View file

@ -23,6 +23,7 @@ from .conftest import (
MockEntityFixture,
assert_entity_counts,
ids_from_device_description,
reset_objects,
)
@ -35,13 +36,13 @@ async def light_fixture(
# disable pydantic validation so mocking can happen
Light.__config__.validate_assignment = False
light_obj = mock_light.copy(deep=True)
light_obj = mock_light.copy()
light_obj._api = mock_entry.api
light_obj.name = "Test Light"
light_obj.light_device_settings.pir_sensitivity = 45
light_obj.light_device_settings.pir_duration = timedelta(seconds=45)
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.lights = {
light_obj.id: light_obj,
}
@ -65,7 +66,7 @@ async def camera_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -79,7 +80,7 @@ async def camera_fixture(
camera_obj.mic_volume = 0
camera_obj.isp_settings.zoom_position = 0
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}
@ -103,12 +104,12 @@ async def doorlock_fixture(
# disable pydantic validation so mocking can happen
Doorlock.__config__.validate_assignment = False
lock_obj = mock_doorlock.copy(deep=True)
lock_obj = mock_doorlock.copy()
lock_obj._api = mock_entry.api
lock_obj.name = "Test Lock"
lock_obj.auto_close_time = timedelta(seconds=45)
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.doorlocks = {
lock_obj.id: lock_obj,
}
@ -174,7 +175,7 @@ async def test_number_setup_camera_none(
):
"""Test number entity setup for camera devices (no features)."""
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -185,7 +186,7 @@ async def test_number_setup_camera_none(
# has_wdr is an the inverse of has HDR
camera_obj.feature_flags.has_hdr = True
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}
@ -204,7 +205,7 @@ async def test_number_setup_camera_missing_attr(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -214,7 +215,7 @@ async def test_number_setup_camera_missing_attr(
Camera.__config__.validate_assignment = True
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}

View file

@ -44,6 +44,7 @@ from .conftest import (
MockEntityFixture,
assert_entity_counts,
ids_from_device_description,
reset_objects,
)
@ -59,12 +60,12 @@ async def viewer_fixture(
# disable pydantic validation so mocking can happen
Viewer.__config__.validate_assignment = False
viewer_obj = mock_viewer.copy(deep=True)
viewer_obj = mock_viewer.copy()
viewer_obj._api = mock_entry.api
viewer_obj.name = "Test Viewer"
viewer_obj.liveview_id = mock_liveview.id
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.viewers = {
viewer_obj.id: viewer_obj,
}
@ -89,7 +90,7 @@ async def camera_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -102,7 +103,7 @@ async def camera_fixture(
camera_obj.lcd_message = None
camera_obj.chime_duration = 0
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}
@ -129,14 +130,14 @@ async def light_fixture(
# disable pydantic validation so mocking can happen
Light.__config__.validate_assignment = False
light_obj = mock_light.copy(deep=True)
light_obj = mock_light.copy()
light_obj._api = mock_entry.api
light_obj.name = "Test Light"
light_obj.camera_id = None
light_obj.light_mode_settings.mode = LightModeType.MOTION
light_obj.light_mode_settings.enable_at = LightModeEnableType.DARK
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {camera.id: camera}
mock_entry.api.bootstrap.lights = {
light_obj.id: light_obj,
@ -161,7 +162,7 @@ async def camera_none_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -172,7 +173,7 @@ async def camera_none_fixture(
camera_obj.recording_settings.mode = RecordingMode.ALWAYS
camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}

View file

@ -47,6 +47,7 @@ from .conftest import (
assert_entity_counts,
enable_entity,
ids_from_device_description,
reset_objects,
time_changed,
)
@ -63,7 +64,7 @@ async def sensor_fixture(
# disable pydantic validation so mocking can happen
Sensor.__config__.validate_assignment = False
sensor_obj = mock_sensor.copy(deep=True)
sensor_obj = mock_sensor.copy()
sensor_obj._api = mock_entry.api
sensor_obj.name = "Test Sensor"
sensor_obj.battery_status.percentage = 10.0
@ -77,7 +78,7 @@ async def sensor_fixture(
sensor_obj.up_since = now
sensor_obj.bluetooth_connection_state.signal_strength = -50.0
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.sensors = {
sensor_obj.id: sensor_obj,
}
@ -102,7 +103,7 @@ async def sensor_none_fixture(
# disable pydantic validation so mocking can happen
Sensor.__config__.validate_assignment = False
sensor_obj = mock_sensor.copy(deep=True)
sensor_obj = mock_sensor.copy()
sensor_obj._api = mock_entry.api
sensor_obj.name = "Test Sensor"
sensor_obj.battery_status.percentage = 10.0
@ -113,7 +114,7 @@ async def sensor_none_fixture(
sensor_obj.up_since = now
sensor_obj.bluetooth_connection_state.signal_strength = -50.0
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.sensors = {
sensor_obj.id: sensor_obj,
}
@ -141,7 +142,7 @@ async def camera_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -162,7 +163,7 @@ async def camera_fixture(
camera_obj.stats.storage.rate = 0.1
camera_obj.voltage = 20.0
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.nvr.system_info.storage.devices = []
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
@ -262,7 +263,7 @@ async def test_sensor_setup_nvr(
):
"""Test sensor entity setup for NVR device."""
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
nvr: NVR = mock_entry.api.bootstrap.nvr
nvr.up_since = now
nvr.system_info.cpu.average_load = 50.0
@ -339,7 +340,7 @@ async def test_sensor_nvr_missing_values(
):
"""Test NVR sensor sensors if no data available."""
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
nvr: NVR = mock_entry.api.bootstrap.nvr
nvr.system_info.memory.available = None
nvr.system_info.memory.total = None

View file

@ -5,8 +5,8 @@ from __future__ import annotations
from unittest.mock import AsyncMock, Mock
import pytest
from pyunifiprotect.data import Camera, Light, ModelType
from pyunifiprotect.data.devices import Chime
from pyunifiprotect.data import Camera, Chime, Light, ModelType
from pyunifiprotect.data.bootstrap import ProtectDeviceRef
from pyunifiprotect.exceptions import BadRequest
from homeassistant.components.unifiprotect.const import ATTR_MESSAGE, DOMAIN
@ -163,6 +163,11 @@ async def test_set_chime_paired_doorbells(
mock_entry.api.bootstrap.chimes = {
mock_chime.id: mock_chime,
}
mock_entry.api.bootstrap.mac_lookup = {
mock_chime.mac.lower(): ProtectDeviceRef(
model=mock_chime.model, id=mock_chime.id
)
}
camera1 = mock_camera.copy()
camera1.name = "Test Camera 1"
@ -186,6 +191,12 @@ async def test_set_chime_paired_doorbells(
camera1.id: camera1,
camera2.id: camera2,
}
mock_entry.api.bootstrap.mac_lookup[camera1.mac.lower()] = ProtectDeviceRef(
model=camera1.model, id=camera1.id
)
mock_entry.api.bootstrap.mac_lookup[camera2.mac.lower()] = ProtectDeviceRef(
model=camera2.model, id=camera2.id
)
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
await hass.async_block_till_done()

View file

@ -28,6 +28,7 @@ from .conftest import (
assert_entity_counts,
enable_entity,
ids_from_device_description,
reset_objects,
)
CAMERA_SWITCHES_BASIC = [
@ -51,13 +52,13 @@ async def light_fixture(
# disable pydantic validation so mocking can happen
Light.__config__.validate_assignment = False
light_obj = mock_light.copy(deep=True)
light_obj = mock_light.copy()
light_obj._api = mock_entry.api
light_obj.name = "Test Light"
light_obj.is_ssh_enabled = False
light_obj.light_device_settings.is_indicator_enabled = False
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.lights = {
light_obj.id: light_obj,
}
@ -81,7 +82,7 @@ async def camera_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -110,7 +111,7 @@ async def camera_fixture(
camera_obj.osd_settings.is_debug_enabled = False
camera_obj.smart_detect_settings.object_types = []
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}
@ -134,7 +135,7 @@ async def camera_none_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -153,7 +154,7 @@ async def camera_none_fixture(
camera_obj.osd_settings.is_logo_enabled = False
camera_obj.osd_settings.is_debug_enabled = False
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}
@ -177,7 +178,8 @@ async def camera_privacy_fixture(
# disable pydantic validation so mocking can happen
Camera.__config__.validate_assignment = False
camera_obj = mock_camera.copy(deep=True)
# mock_camera._update_lock = None
camera_obj = mock_camera.copy()
camera_obj._api = mock_entry.api
camera_obj.channels[0]._api = mock_entry.api
camera_obj.channels[1]._api = mock_entry.api
@ -197,7 +199,7 @@ async def camera_privacy_fixture(
camera_obj.osd_settings.is_logo_enabled = False
camera_obj.osd_settings.is_debug_enabled = False
mock_entry.api.bootstrap.reset_objects()
reset_objects(mock_entry.api.bootstrap)
mock_entry.api.bootstrap.cameras = {
camera_obj.id: camera_obj,
}