bachya/simplisafe-python

View on GitHub
simplipy/device/camera.py

Summary

Maintainability
A
0 mins
Test Coverage
"""Define SimpliSafe cameras (SimpliCams)."""

from __future__ import annotations

from enum import Enum
from typing import TYPE_CHECKING, Any, cast
from urllib.parse import urlencode

from simplipy.const import LOGGER
from simplipy.device import DeviceV3

if TYPE_CHECKING:
    from simplipy.system.v3 import SystemV3

DEFAULT_AUDIO_ENCODING = "AAC"
DEFAULT_MEDIA_URL_BASE = "https://media.simplisafe.com/v1"
DEFAULT_VIDEO_WIDTH = 1280


class CameraTypes(Enum):
    """Define camera types based on internal SimpliSafe ID number."""

    CAMERA = 0
    DOORBELL = 1
    OUTDOOR_CAMERA = 2
    UNKNOWN = 99


MODEL_TO_TYPE = {
    "SS001": CameraTypes.CAMERA,
    "SS002": CameraTypes.DOORBELL,
    "SS003": CameraTypes.CAMERA,
    "SSOBCM4": CameraTypes.OUTDOOR_CAMERA,
}


class Camera(DeviceV3):
    """Define a SimpliCam."""

    _system: SystemV3

    @property
    def camera_settings(self) -> dict[str, Any]:
        """Return the camera settings.

        Returns:
            A dictionary of camera settings.
        """
        return cast(
            dict[str, Any], self._system.camera_data[self._serial]["cameraSettings"]
        )

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

        Returns:
            The camera type.
        """
        try:
            return MODEL_TO_TYPE[self._system.camera_data[self._serial]["model"]]
        except KeyError:
            LOGGER.error(
                "Unknown camera type: %s",
                self._system.camera_data[self._serial]["model"],
            )
            return CameraTypes.UNKNOWN

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

        Returns:
            The camera name.
        """
        return cast(
            str, self._system.camera_data[self._serial]["cameraSettings"]["cameraName"]
        )

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

        Returns:
            The camera serial number.
        """
        return self._serial

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

        Returns:
            The camera's "shutter open when away" status.
        """
        val = self._system.camera_data[self._serial]["cameraSettings"]["shutterAway"]
        return cast(bool, val == "open")

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

        Returns:
            The camera's "shutter open when home" status.
        """
        val = self._system.camera_data[self._serial]["cameraSettings"]["shutterHome"]
        return cast(bool, val == "open")

    @property
    def shutter_open_when_off(self) -> bool:
        """Return whether the privacy shutter is open when the alarm is disarmed.

        Returns:
            The camera's "shutter open when off" status.
        """
        val = self._system.camera_data[self._serial]["cameraSettings"]["shutterOff"]
        return cast(bool, val == "open")

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

        Returns:
            The camera status.
        """
        return cast(str, self._system.camera_data[self._serial]["status"])

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

        Returns:
            The camera subscription status.
        """
        return cast(
            bool, self._system.camera_data[self._serial]["subscription"]["enabled"]
        )

    def as_dict(self) -> dict[str, Any]:
        """Return dictionary version of this device.

        Returns:
            A dict representation of this device.
        """
        return {
            "camera_settings": self.camera_settings,
            "camera_type": self.camera_type.value,
            "name": self.name,
            "serial": self.serial,
            "shutter_open_when_away": self.shutter_open_when_away,
            "shutter_open_when_home": self.shutter_open_when_home,
            "shutter_open_when_off": self.shutter_open_when_off,
            "status": self.status,
            "subscription_enabled": self.subscription_enabled,
        }

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

        Args:
            width: The video width.
            audio_encoding: The audio encoding.
            kwargs: Additional parameters.

        Returns:
            The camera video URL.
        """
        url_params = {"x": width, "audioEncoding": audio_encoding, **kwargs}
        return f"{DEFAULT_MEDIA_URL_BASE}/{self.serial}/flv?{urlencode(url_params)}"