Skip to content

Commit 079e3d1

Browse files
authored
Merge pull request #133 from natekspencer/dev
Add ability to reboot camera and adjust how stream source is retrieved
2 parents d74e7e6 + da512ee commit 079e3d1

File tree

5 files changed

+67
-40
lines changed

5 files changed

+67
-40
lines changed

custom_components/vivint/button.py

+28-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
"""Support for Vivint buttons."""
2+
23
from __future__ import annotations
34

45
from vivintpy.devices.alarm_panel import AlarmPanel
6+
from vivintpy.devices.camera import Camera as VivintCamera
57
from vivintpy.entity import UPDATE
8+
from vivintpy.enums import (
9+
CapabilityCategoryType as Category,
10+
CapabilityType as Capability,
11+
)
612

713
from homeassistant.components.button import (
814
ButtonDeviceClass,
@@ -14,9 +20,9 @@
1420
from homeassistant.helpers.entity_platform import AddEntitiesCallback
1521

1622
from .const import DOMAIN
17-
from .hub import VivintBaseEntity, VivintHub
23+
from .hub import VivintBaseEntity, VivintHub, has_capability
1824

19-
HUB_REBOOT_ENTITY = ButtonEntityDescription(
25+
REBOOT_ENTITY = ButtonEntityDescription(
2026
key="reboot", device_class=ButtonDeviceClass.RESTART
2127
)
2228

@@ -30,24 +36,36 @@ async def async_setup_entry(
3036
hub: VivintHub = hass.data[DOMAIN][entry.entry_id]
3137
entities = [
3238
VivintButtonEntity(
33-
device=alarm_panel, hub=hub, entity_description=HUB_REBOOT_ENTITY
39+
device=alarm_panel, hub=hub, entity_description=REBOOT_ENTITY
3440
)
3541
for system in hub.account.systems
3642
if system.is_admin
3743
for alarm_panel in system.alarm_panels
3844
]
45+
entities.extend(
46+
VivintButtonEntity(device=device, hub=hub, entity_description=REBOOT_ENTITY)
47+
for system in hub.account.systems
48+
for alarm_panel in system.alarm_panels
49+
for device in alarm_panel.devices
50+
if isinstance(device, VivintCamera)
51+
and has_capability(device, Category.CAMERA, Capability.REBOOT_CAMERA)
52+
)
3953
async_add_entities(entities)
4054

4155

4256
class VivintButtonEntity(VivintBaseEntity, ButtonEntity):
4357
"""A class that describes device button entities."""
4458

45-
device: AlarmPanel
59+
device: AlarmPanel | VivintCamera
4660

4761
@property
4862
def available(self) -> bool:
4963
"""Return if entity is available."""
50-
return super().available and self.device._AlarmPanel__panel.data["can_reboot"]
64+
if isinstance(self.device, AlarmPanel):
65+
return (
66+
super().available and self.device._AlarmPanel__panel.data["can_reboot"]
67+
)
68+
return super().available
5169

5270
async def async_press(self) -> None:
5371
"""Handle the button press."""
@@ -56,8 +74,9 @@ async def async_press(self) -> None:
5674
async def async_added_to_hass(self) -> None:
5775
"""Set up a listener for the entity."""
5876
await super().async_added_to_hass()
59-
self.async_on_remove(
60-
self.device._AlarmPanel__panel.on(
61-
UPDATE, lambda _: self.async_write_ha_state()
77+
if isinstance(self.device, AlarmPanel):
78+
self.async_on_remove(
79+
self.device._AlarmPanel__panel.on(
80+
UPDATE, lambda _: self.async_write_ha_state()
81+
)
6282
)
63-
)

custom_components/vivint/camera.py

+8-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Support for Vivint cameras."""
2+
23
from __future__ import annotations
34

45
import logging
@@ -21,7 +22,7 @@
2122
DEFAULT_RTSP_URL_LOGGING,
2223
DOMAIN,
2324
RTSP_STREAM_DIRECT,
24-
RTSP_STREAM_EXTERNAL,
25+
RTSP_STREAM_INTERNAL,
2526
)
2627
from .hub import VivintEntity, VivintHub
2728

@@ -103,7 +104,6 @@ def __init__(
103104

104105
self.__hd_stream = hd_stream
105106
self.__rtsp_stream = rtsp_stream
106-
self.__stream_source = None
107107
self.__last_image = None
108108

109109
@property
@@ -113,15 +113,13 @@ def unique_id(self) -> str:
113113

114114
async def stream_source(self) -> str | None:
115115
"""Return the source of the stream."""
116-
if not self.__stream_source:
117-
self.__stream_source = (
118-
await self.device.get_direct_rtsp_url(hd=self.__hd_stream)
119-
if self.__rtsp_stream == RTSP_STREAM_DIRECT
120-
else None
121-
) or await self.device.get_rtsp_url(
122-
internal=self.__rtsp_stream != RTSP_STREAM_EXTERNAL, hd=self.__hd_stream
116+
await self.device.alarm_panel.get_panel_credentials()
117+
url = self.device.get_rtsp_access_url(self.__rtsp_stream, self.__hd_stream)
118+
if not url and self.__rtsp_stream == RTSP_STREAM_DIRECT:
119+
url = self.device.get_rtsp_access_url(
120+
RTSP_STREAM_INTERNAL, self.__hd_stream
123121
)
124-
return self.__stream_source
122+
return url
125123

126124
async def async_camera_image(
127125
self, width: int | None = None, height: int | None = None

custom_components/vivint/hub.py

+28-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""A wrapper 'hub' for the Vivint API and base entity for common attributes."""
2+
23
from __future__ import annotations
34

45
from collections.abc import Callable
@@ -15,6 +16,11 @@
1516
from vivintpy.devices import VivintDevice
1617
from vivintpy.devices.alarm_panel import AlarmPanel
1718
from vivintpy.entity import UPDATE
19+
from vivintpy.enums import (
20+
CapabilityCategoryType as Category,
21+
CapabilityType as Capability,
22+
FeatureType as Feature,
23+
)
1824
from vivintpy.exceptions import (
1925
VivintSkyApiAuthenticationError,
2026
VivintSkyApiError,
@@ -47,6 +53,18 @@ def get_device_id(device: VivintDevice) -> tuple[str, str]:
4753
)
4854

4955

56+
def has_capability(device: VivintDevice, category: Category, capability: Capability):
57+
"""Check if a device has a capability."""
58+
if capability in (device.capabilities or {}).get(category, []):
59+
return True
60+
return False
61+
62+
63+
def has_feature(device: VivintDevice, feature: Feature):
64+
"""Check if a device has a feature."""
65+
return feature in (device.features or [])
66+
67+
5068
class VivintHub:
5169
"""A Vivint hub wrapper class."""
5270

@@ -173,9 +191,11 @@ def __init__(
173191
manufacturer=device.manufacturer,
174192
model=device.model,
175193
sw_version=device.software_version,
176-
via_device=None
177-
if isinstance(device, AlarmPanel)
178-
else get_device_id(device.alarm_panel),
194+
via_device=(
195+
None
196+
if isinstance(device, AlarmPanel)
197+
else get_device_id(device.alarm_panel)
198+
),
179199
)
180200

181201
async def async_added_to_hass(self) -> None:
@@ -204,9 +224,11 @@ def __init__(self, device: VivintDevice, hub: VivintHub) -> None:
204224
manufacturer=device.manufacturer,
205225
model=device.model,
206226
sw_version=device.software_version,
207-
via_device=None
208-
if isinstance(device, AlarmPanel)
209-
else get_device_id(device.alarm_panel),
227+
via_device=(
228+
None
229+
if isinstance(device, AlarmPanel)
230+
else get_device_id(device.alarm_panel)
231+
),
210232
)
211233

212234
async def async_added_to_hass(self) -> None:

custom_components/vivint/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"iot_class": "cloud_push",
1010
"issue_tracker": "https://github.com/natekspencer/hacs-vivint/issues",
1111
"loggers": ["custom_components.vivint", "vivintpy"],
12-
"requirements": ["vivintpy==2023.3.8"],
12+
"requirements": ["vivintpy==2023.4.0"],
1313
"version": "0.0.0",
1414
"zeroconf": ["_vivint-ODC300._tcp.local.", "_vivint-DBC350._tcp.local."]
1515
}

custom_components/vivint/switch.py

+2-14
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
"""Support for Vivint switches."""
2+
23
from __future__ import annotations
34

45
from collections.abc import Callable
56
from dataclasses import dataclass
67
from typing import Any
78

8-
from vivintpy.devices import VivintDevice
99
from vivintpy.devices.camera import Camera
1010
from vivintpy.devices.switch import BinarySwitch
1111
from vivintpy.enums import (
@@ -21,19 +21,7 @@
2121
from homeassistant.helpers.entity_platform import AddEntitiesCallback
2222

2323
from .const import DOMAIN
24-
from .hub import VivintBaseEntity, VivintHub
25-
26-
27-
def has_capability(device: VivintDevice, category: Category, capability: Capability):
28-
"""Check if a device has a capability."""
29-
if capability in (device.capabilities or {}).get(category, []):
30-
return True
31-
return False
32-
33-
34-
def has_feature(device: VivintDevice, feature: Feature):
35-
"""Check if a device has a feature."""
36-
return feature in (device.features or [])
24+
from .hub import VivintBaseEntity, VivintHub, has_capability, has_feature
3725

3826

3927
async def async_setup_entry(

0 commit comments

Comments
 (0)