Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to expose camera and doorbell data #182

Merged
merged 10 commits into from
Oct 8, 2020
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
- Scott Newman (https://github.com/greencoder)
- Scott Silence (https://github.com/ssilence5)
- William Scanlon (https://github.com/w1ll1am23)
- Niccolo Zapponi (https://github.com/nzapponi)
1 change: 1 addition & 0 deletions simplipy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ async def get_systems(self) -> Dict[str, System]:
system = system_class(
self.request, self._get_subscription_data, system_data["location"]
)

await system.update(include_system=False)
systems[system_data["sid"]] = system

Expand Down
114 changes: 114 additions & 0 deletions simplipy/camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import logging
from urllib.parse import urlencode

from simplipy.entity import Entity

_LOGGER: logging.Logger = logging.getLogger(__name__)

MEDIA_URL_BASE: str = "https://media.simplisafe.com/v1"
DEFAULT_VIDEO_WIDTH: int = 1280
DEFAULT_AUDIO_ENCODING: str = "AAC"

CAMERA_MODEL_CAMERA: str = "CAMERA"
CAMERA_MODEL_DOORBELL: str = "DOORBELL"
CAMERA_MODEL_UNKNOWN: str = "CAMERA_MODEL_UNKNOWN"

MODEL_TO_TYPE = {
"SS001": CAMERA_MODEL_CAMERA,
"SS002": CAMERA_MODEL_DOORBELL,
}


class Camera(Entity):
"""A SimpliCam."""

@property
nzapponi marked this conversation as resolved.
Show resolved Hide resolved
def camera_settings(self) -> dict:
"""Return the camera settings.

:rtype: ``dict``
"""
return self.entity_data["cameraSettings"]

@property
def camera_type(self) -> str:
"""Return the type of camera.

:rtype: ``str``
"""

try:
return MODEL_TO_TYPE[self.entity_data["model"]]
nzapponi marked this conversation as resolved.
Show resolved Hide resolved
except KeyError:
_LOGGER.error("Unknown camera type: %s", self.entity_data["model"])
return CAMERA_MODEL_UNKNOWN

@property
def name(self) -> str:
"""Return the entity name.

:rtype: ``str``
"""
return self.entity_data["cameraSettings"]["cameraName"]

@property
def serial(self) -> str:
"""Return the entity's serial number.

:rtype: ``str``
"""
return self.entity_data["uuid"]

@property
def shutter_open_when_away(self) -> bool:
"""Return whether the privacy shutter is open when alarm system is armed in away mode.

:rtype: ``bool``
"""
return self.camera_settings["shutterAway"] == "open"

@property
def shutter_open_when_home(self) -> bool:
"""Return whether the privacy shutter is open when alarm system is armed in home mode.

:rtype: ``bool``
"""
return self.camera_settings["shutterHome"] == "open"

@property
nzapponi marked this conversation as resolved.
Show resolved Hide resolved
def shutter_open_when_off(self) -> bool:
"""Return whether the privacy shutter is open when alarm system is off.

:rtype: ``bool``
"""
return self.camera_settings["shutterOff"] == "open"

@property
def status(self) -> str:
"""Return the camera status.

:rtype: ``str``
"""
return self.entity_data["status"]

@property
def subscription_enabled(self) -> bool:
"""Return the camera subscription status.

:rtype: ``bool``
"""
return self.entity_data["subscription"]["enabled"]

def video_url(
self,
width: int = DEFAULT_VIDEO_WIDTH,
audio_encoding: str = DEFAULT_AUDIO_ENCODING,
**kwargs,
) -> str:
"""Return the camera video URL.

:rtype: ``str``
"""
url_params = {"x": width, "audioEncoding": audio_encoding, **kwargs}

return f"{MEDIA_URL_BASE}/{self.serial}/flv?{urlencode(url_params)}"
20 changes: 20 additions & 0 deletions simplipy/system/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import logging
from typing import Any, Callable, Coroutine, Dict, List, Optional, Set, Type, Union

from simplipy.camera import Camera
from simplipy.entity import Entity, EntityTypes
from simplipy.errors import PinError, SimplipyError
from simplipy.lock import Lock
Expand Down Expand Up @@ -197,6 +198,25 @@ def alarm_going_off(self) -> bool:
"""
return self._location_info["system"]["isAlarming"]

@property
def cameras(self) -> Dict[str, Camera]:
"""Return list of cameras and doorbells.

:rtype: ``Dict[str, :meth:`simplipy.camera.Camera`]``
"""

cameras_doorbells = [
Camera(
self._request,
self._get_entities,
self.system_id,
EntityTypes.camera,
camera,
)
for camera in self._location_info["system"]["cameras"]
]
return {camera.serial: camera for camera in cameras_doorbells}

nzapponi marked this conversation as resolved.
Show resolved Hide resolved
@property # type: ignore
@guard_from_missing_data()
def connection_type(self) -> str:
Expand Down
3 changes: 3 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
TEST_ACCESS_TOKEN = "abcde12345"
TEST_ACCOUNT_ID = 12345
TEST_ADDRESS = "1234 Main Street"
TEST_CAMERA_ID = "1234567890"
TEST_CAMERA_ID_2 = "1234567891"
TEST_CAMERA_TYPE = "CAMERA"
TEST_CLIENT_ID = "12345DEFG"
TEST_EMAIL = "[email protected]"
TEST_LOCK_ID = "987"
Expand Down
Loading