From 9e8df936ac62fe0096f85377f79c2a29239717b1 Mon Sep 17 00:00:00 2001 From: Ross Dargan Date: Tue, 6 Aug 2019 13:39:07 +0100 Subject: [PATCH] Add ring switch platform (#25612) * Add in a switch platform to ring. * Changes following code review * remove tests for now * remove the request to call update * support the new type of test * update after running black * fix comment * fixes following code review * Remove ring cache file * patch out io code * Move the patches to within a fixture * missing period --- homeassistant/components/ring/switch.py | 108 ++++++ tests/components/ring/common.py | 14 + tests/components/ring/conftest.py | 54 +++ tests/components/ring/test_switch.py | 75 ++++ tests/fixtures/ring_devices.json | 139 ++++++- tests/fixtures/ring_devices_updated.json | 355 ++++++++++++++++++ .../ring_doorbot_siren_on_response.json | 1 + 7 files changed, 745 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/ring/switch.py create mode 100644 tests/components/ring/common.py create mode 100644 tests/components/ring/conftest.py create mode 100644 tests/components/ring/test_switch.py create mode 100644 tests/fixtures/ring_devices_updated.json create mode 100644 tests/fixtures/ring_doorbot_siren_on_response.json diff --git a/homeassistant/components/ring/switch.py b/homeassistant/components/ring/switch.py new file mode 100644 index 00000000000..3b6bd4ea024 --- /dev/null +++ b/homeassistant/components/ring/switch.py @@ -0,0 +1,108 @@ +"""This component provides HA switch support for Ring Door Bell/Chimes.""" +import logging +from datetime import datetime, timedelta +from homeassistant.components.switch import SwitchDevice +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.core import callback + +from . import DATA_RING_STICKUP_CAMS, SIGNAL_UPDATE_RING + +_LOGGER = logging.getLogger(__name__) + +SIREN_ICON = "mdi:alarm-bell" + + +# It takes a few seconds for the API to correctly return an update indicating +# that the changes have been made. Once we request a change (i.e. a light +# being turned on) we simply wait for this time delta before we allow +# updates to take place. + +SKIP_UPDATES_DELAY = timedelta(seconds=5) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Create the switches for the Ring devices.""" + cameras = hass.data[DATA_RING_STICKUP_CAMS] + switches = [] + for device in cameras: + if device.has_capability("siren"): + switches.append(SirenSwitch(device)) + + add_entities(switches, True) + + +class BaseRingSwitch(SwitchDevice): + """Represents a switch for controlling an aspect of a ring device.""" + + def __init__(self, device, device_type): + """Initialize the switch.""" + self._device = device + self._device_type = device_type + self._unique_id = "{}-{}".format(self._device.id, self._device_type) + + async def async_added_to_hass(self): + """Register callbacks.""" + async_dispatcher_connect(self.hass, SIGNAL_UPDATE_RING, self._update_callback) + + @callback + def _update_callback(self): + """Call update method.""" + _LOGGER.debug("Updating Ring sensor %s (callback)", self.name) + self.async_schedule_update_ha_state(True) + + @property + def name(self): + """Name of the device.""" + return "{} {}".format(self._device.name, self._device_type) + + @property + def unique_id(self): + """Return a unique ID.""" + return self._unique_id + + @property + def should_poll(self): + """Update controlled via the hub.""" + return False + + +class SirenSwitch(BaseRingSwitch): + """Creates a switch to turn the ring cameras siren on and off.""" + + def __init__(self, device): + """Initialize the switch for a device with a siren.""" + super().__init__(device, "siren") + self._no_updates_until = datetime.now() + self._siren_on = False + + def _set_switch(self, new_state): + """Update switch state, and causes HASS to correctly update.""" + self._device.siren = new_state + self._siren_on = new_state > 0 + self._no_updates_until = datetime.now() + SKIP_UPDATES_DELAY + self.schedule_update_ha_state() + + @property + def is_on(self): + """If the switch is currently on or off.""" + return self._siren_on + + def turn_on(self, **kwargs): + """Turn the siren on for 30 seconds.""" + self._set_switch(1) + + def turn_off(self, **kwargs): + """Turn the siren off.""" + self._set_switch(0) + + @property + def icon(self): + """Return the icon.""" + return SIREN_ICON + + def update(self): + """Update state of the siren.""" + if self._no_updates_until > datetime.now(): + _LOGGER.debug("Skipping update...") + return + self._siren_on = self._device.siren > 0 diff --git a/tests/components/ring/common.py b/tests/components/ring/common.py new file mode 100644 index 00000000000..1228f998618 --- /dev/null +++ b/tests/components/ring/common.py @@ -0,0 +1,14 @@ +"""Common methods used across the tests for ring devices.""" +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, CONF_SCAN_INTERVAL +from homeassistant.components.ring import DOMAIN +from homeassistant.setup import async_setup_component + + +async def setup_platform(hass, platform): + """Set up the ring platform and prerequisites.""" + config = { + DOMAIN: {CONF_USERNAME: "foo", CONF_PASSWORD: "bar", CONF_SCAN_INTERVAL: 1000}, + platform: {"platform": DOMAIN}, + } + assert await async_setup_component(hass, platform, config) + await hass.async_block_till_done() diff --git a/tests/components/ring/conftest.py b/tests/components/ring/conftest.py new file mode 100644 index 00000000000..14a29f78aae --- /dev/null +++ b/tests/components/ring/conftest.py @@ -0,0 +1,54 @@ +"""Configuration for Ring tests.""" +import requests_mock +import pytest +from tests.common import load_fixture +from asynctest import patch + + +@pytest.fixture(name="ring_mock") +def ring_save_mock(): + """Fixture to mock a ring.""" + with patch("ring_doorbell._exists_cache", return_value=False): + with patch("ring_doorbell._save_cache", return_value=True) as save_mock: + yield save_mock + + +@pytest.fixture(name="requests_mock") +def requests_mock_fixture(ring_mock): + """Fixture to provide a requests mocker.""" + with requests_mock.mock() as mock: + # Note all devices have an id of 987652, but a different device_id. + # the device_id is used as our unique_id, but the id is what is sent + # to the APIs, which is why every mock uses that id. + + # Mocks the response for authenticating + mock.post( + "https://oauth.ring.com/oauth/token", text=load_fixture("ring_oauth.json") + ) + # Mocks the response for getting the login session + mock.post( + "https://api.ring.com/clients_api/session", + text=load_fixture("ring_session.json"), + ) + # Mocks the response for getting all the devices + mock.get( + "https://api.ring.com/clients_api/ring_devices", + text=load_fixture("ring_devices.json"), + ) + # Mocks the response for getting the history of a device + mock.get( + "https://api.ring.com/clients_api/doorbots/987652/history", + text=load_fixture("ring_doorbots.json"), + ) + # Mocks the response for getting the health of a device + mock.get( + "https://api.ring.com/clients_api/doorbots/987652/health", + text=load_fixture("ring_doorboot_health_attrs.json"), + ) + # Mocks the response for getting a chimes health + mock.get( + "https://api.ring.com/clients_api/chimes/999999/health", + text=load_fixture("ring_chime_health_attrs.json"), + ) + + yield mock diff --git a/tests/components/ring/test_switch.py b/tests/components/ring/test_switch.py new file mode 100644 index 00000000000..59f4e9061f4 --- /dev/null +++ b/tests/components/ring/test_switch.py @@ -0,0 +1,75 @@ +"""The tests for the Ring switch platform.""" +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from tests.common import load_fixture +from .common import setup_platform + + +async def test_entity_registry(hass, requests_mock): + """Tests that the devices are registed in the entity registry.""" + await setup_platform(hass, SWITCH_DOMAIN) + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + entry = entity_registry.async_get("switch.front_siren") + assert entry.unique_id == "aacdef123-siren" + + entry = entity_registry.async_get("switch.internal_siren") + assert entry.unique_id == "aacdef124-siren" + + +async def test_siren_off_reports_correctly(hass, requests_mock): + """Tests that the initial state of a device that should be off is correct.""" + await setup_platform(hass, SWITCH_DOMAIN) + + state = hass.states.get("switch.front_siren") + assert state.state == "off" + assert state.attributes.get("friendly_name") == "Front siren" + + +async def test_siren_on_reports_correctly(hass, requests_mock): + """Tests that the initial state of a device that should be on is correct.""" + await setup_platform(hass, SWITCH_DOMAIN) + + state = hass.states.get("switch.internal_siren") + assert state.state == "on" + assert state.attributes.get("friendly_name") == "Internal siren" + assert state.attributes.get("icon") == "mdi:alarm-bell" + + +async def test_siren_can_be_turned_on(hass, requests_mock): + """Tests the siren turns on correctly.""" + await setup_platform(hass, SWITCH_DOMAIN) + + # Mocks the response for turning a siren on + requests_mock.put( + "https://api.ring.com/clients_api/doorbots/987652/siren_on", + text=load_fixture("ring_doorbot_siren_on_response.json"), + ) + + state = hass.states.get("switch.front_siren") + assert state.state == "off" + + await hass.services.async_call( + "switch", "turn_on", {"entity_id": "switch.front_siren"}, blocking=True + ) + + state = hass.states.get("switch.front_siren") + assert state.state == "on" + + +async def test_updates_work(hass, requests_mock): + """Tests the update service works correctly.""" + await setup_platform(hass, SWITCH_DOMAIN) + state = hass.states.get("switch.front_siren") + assert state.state == "off" + # Changes the return to indicate that the siren is now on. + requests_mock.get( + "https://api.ring.com/clients_api/ring_devices", + text=load_fixture("ring_devices_updated.json"), + ) + + await hass.services.async_call("ring", "update", {}, blocking=True) + + await hass.async_block_till_done() + + state = hass.states.get("switch.front_siren") + assert state.state == "on" diff --git a/tests/fixtures/ring_devices.json b/tests/fixtures/ring_devices.json index 3e9171789d9..f5dd1c1f091 100644 --- a/tests/fixtures/ring_devices.json +++ b/tests/fixtures/ring_devices.json @@ -214,5 +214,142 @@ "subscribed": true, "subscribed_motions": true, "time_zone": "America/New_York" - }] + }, + { + "address": "123 Main St", + "alerts": {"connection": "online"}, + "battery_life": 80, + "description": "Internal", + "device_id": "aacdef124", + "external_connection": false, + "features": { + "advanced_motion_enabled": false, + "motion_message_enabled": false, + "motions_enabled": true, + "night_vision_enabled": false, + "people_only_enabled": false, + "shadow_correction_enabled": false, + "show_recordings": true}, + "firmware_version": "1.9.3", + "id": 987652, + "kind": "hp_cam_v1", + "latitude": 12.000000, + "led_status": "off", + "location_id": null, + "longitude": -70.12345, + "motion_snooze": {"scheduled": true}, + "night_mode_status": "false", + "owned": true, + "owner": { + "email": "foo@bar.org", + "first_name": "Foo", + "id": 999999, + "last_name": "Bar"}, + "ring_cam_light_installed": "false", + "ring_id": null, + "settings": { + "chime_settings": { + "duration": 10, + "enable": true, + "type": 0}, + "doorbell_volume": 11, + "enable_vod": true, + "floodlight_settings": { + "duration": 30, + "priority": 0}, + "light_schedule_settings": { + "end_hour": 0, + "end_minute": 0, + "start_hour": 0, + "start_minute": 0}, + "live_view_preset_profile": "highest", + "live_view_presets": [ + "low", + "middle", + "high", + "highest"], + "motion_announcement": false, + "motion_snooze_preset_profile": "low", + "motion_snooze_presets": [ + "none", + "low", + "medium", + "high"], + "motion_zones": { + "active_motion_filter": 1, + "advanced_object_settings": { + "human_detection_confidence": { + "day": 0.7, + "night": 0.7}, + "motion_zone_overlap": { + "day": 0.1, + "night": 0.2}, + "object_size_maximum": { + "day": 0.8, + "night": 0.8}, + "object_size_minimum": { + "day": 0.03, + "night": 0.05}, + "object_time_overlap": { + "day": 0.1, + "night": 0.6} + }, + "enable_audio": false, + "pir_settings": { + "sensitivity1": 1, + "sensitivity2": 1, + "sensitivity3": 1, + "zone_mask": 6}, + "sensitivity": 5, + "zone1": { + "name": "Zone 1", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}, + "zone2": { + "name": "Zone 2", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}, + "zone3": { + "name": "Zone 3", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}}, + "pir_motion_zones": [0, 1, 1], + "pir_settings": { + "sensitivity1": 1, + "sensitivity2": 1, + "sensitivity3": 1, + "zone_mask": 6}, + "stream_setting": 0, + "video_settings": { + "ae_level": 0, + "birton": null, + "brightness": 0, + "contrast": 64, + "saturation": 80}}, + "siren_status": {"seconds_remaining": 30}, + "stolen": false, + "subscribed": true, + "subscribed_motions": true, + "time_zone": "America/New_York"}] } diff --git a/tests/fixtures/ring_devices_updated.json b/tests/fixtures/ring_devices_updated.json new file mode 100644 index 00000000000..bc621f81be8 --- /dev/null +++ b/tests/fixtures/ring_devices_updated.json @@ -0,0 +1,355 @@ +{ + "authorized_doorbots": [], + "chimes": [ + { + "address": "123 Main St", + "alerts": {"connection": "online"}, + "description": "Downstairs", + "device_id": "abcdef123", + "do_not_disturb": {"seconds_left": 0}, + "features": {"ringtones_enabled": true}, + "firmware_version": "1.2.3", + "id": 999999, + "kind": "chime", + "latitude": 12.000000, + "longitude": -70.12345, + "owned": true, + "owner": { + "email": "foo@bar.org", + "first_name": "Marcelo", + "id": 999999, + "last_name": "Assistant"}, + "settings": { + "ding_audio_id": null, + "ding_audio_user_id": null, + "motion_audio_id": null, + "motion_audio_user_id": null, + "volume": 2}, + "time_zone": "America/New_York"}], + "doorbots": [ + { + "address": "123 Main St", + "alerts": {"connection": "online"}, + "battery_life": 4081, + "description": "Front Door", + "device_id": "aacdef123", + "external_connection": false, + "features": { + "advanced_motion_enabled": false, + "motion_message_enabled": false, + "motions_enabled": true, + "people_only_enabled": false, + "shadow_correction_enabled": false, + "show_recordings": true}, + "firmware_version": "1.4.26", + "id": 987652, + "kind": "lpd_v1", + "latitude": 12.000000, + "longitude": -70.12345, + "motion_snooze": null, + "owned": true, + "owner": { + "email": "foo@bar.org", + "first_name": "Home", + "id": 999999, + "last_name": "Assistant"}, + "settings": { + "chime_settings": { + "duration": 3, + "enable": true, + "type": 0}, + "doorbell_volume": 1, + "enable_vod": true, + "live_view_preset_profile": "highest", + "live_view_presets": [ + "low", + "middle", + "high", + "highest"], + "motion_announcement": false, + "motion_snooze_preset_profile": "low", + "motion_snooze_presets": [ + "null", + "low", + "medium", + "high"]}, + "subscribed": true, + "subscribed_motions": true, + "time_zone": "America/New_York"}], + "stickup_cams": [ + { + "address": "123 Main St", + "alerts": {"connection": "online"}, + "battery_life": 80, + "description": "Front", + "device_id": "aacdef123", + "external_connection": false, + "features": { + "advanced_motion_enabled": false, + "motion_message_enabled": false, + "motions_enabled": true, + "night_vision_enabled": false, + "people_only_enabled": false, + "shadow_correction_enabled": false, + "show_recordings": true}, + "firmware_version": "1.9.3", + "id": 987652, + "kind": "hp_cam_v1", + "latitude": 12.000000, + "led_status": "off", + "location_id": null, + "longitude": -70.12345, + "motion_snooze": {"scheduled": true}, + "night_mode_status": "false", + "owned": true, + "owner": { + "email": "foo@bar.org", + "first_name": "Foo", + "id": 999999, + "last_name": "Bar"}, + "ring_cam_light_installed": "false", + "ring_id": null, + "settings": { + "chime_settings": { + "duration": 10, + "enable": true, + "type": 0}, + "doorbell_volume": 11, + "enable_vod": true, + "floodlight_settings": { + "duration": 30, + "priority": 0}, + "light_schedule_settings": { + "end_hour": 0, + "end_minute": 0, + "start_hour": 0, + "start_minute": 0}, + "live_view_preset_profile": "highest", + "live_view_presets": [ + "low", + "middle", + "high", + "highest"], + "motion_announcement": false, + "motion_snooze_preset_profile": "low", + "motion_snooze_presets": [ + "none", + "low", + "medium", + "high"], + "motion_zones": { + "active_motion_filter": 1, + "advanced_object_settings": { + "human_detection_confidence": { + "day": 0.7, + "night": 0.7}, + "motion_zone_overlap": { + "day": 0.1, + "night": 0.2}, + "object_size_maximum": { + "day": 0.8, + "night": 0.8}, + "object_size_minimum": { + "day": 0.03, + "night": 0.05}, + "object_time_overlap": { + "day": 0.1, + "night": 0.6} + }, + "enable_audio": false, + "pir_settings": { + "sensitivity1": 1, + "sensitivity2": 1, + "sensitivity3": 1, + "zone_mask": 6}, + "sensitivity": 5, + "zone1": { + "name": "Zone 1", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}, + "zone2": { + "name": "Zone 2", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}, + "zone3": { + "name": "Zone 3", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}}, + "pir_motion_zones": [0, 1, 1], + "pir_settings": { + "sensitivity1": 1, + "sensitivity2": 1, + "sensitivity3": 1, + "zone_mask": 6}, + "stream_setting": 0, + "video_settings": { + "ae_level": 0, + "birton": null, + "brightness": 0, + "contrast": 64, + "saturation": 80}}, + "siren_status": {"seconds_remaining": 30}, + "stolen": false, + "subscribed": true, + "subscribed_motions": true, + "time_zone": "America/New_York" + }, + { + "address": "123 Main St", + "alerts": {"connection": "online"}, + "battery_life": 80, + "description": "Internal", + "device_id": "aacdef124", + "external_connection": false, + "features": { + "advanced_motion_enabled": false, + "motion_message_enabled": false, + "motions_enabled": true, + "night_vision_enabled": false, + "people_only_enabled": false, + "shadow_correction_enabled": false, + "show_recordings": true}, + "firmware_version": "1.9.3", + "id": 987652, + "kind": "hp_cam_v1", + "latitude": 12.000000, + "led_status": "off", + "location_id": null, + "longitude": -70.12345, + "motion_snooze": {"scheduled": true}, + "night_mode_status": "false", + "owned": true, + "owner": { + "email": "foo@bar.org", + "first_name": "Foo", + "id": 999999, + "last_name": "Bar"}, + "ring_cam_light_installed": "false", + "ring_id": null, + "settings": { + "chime_settings": { + "duration": 10, + "enable": true, + "type": 0}, + "doorbell_volume": 11, + "enable_vod": true, + "floodlight_settings": { + "duration": 30, + "priority": 0}, + "light_schedule_settings": { + "end_hour": 0, + "end_minute": 0, + "start_hour": 0, + "start_minute": 0}, + "live_view_preset_profile": "highest", + "live_view_presets": [ + "low", + "middle", + "high", + "highest"], + "motion_announcement": false, + "motion_snooze_preset_profile": "low", + "motion_snooze_presets": [ + "none", + "low", + "medium", + "high"], + "motion_zones": { + "active_motion_filter": 1, + "advanced_object_settings": { + "human_detection_confidence": { + "day": 0.7, + "night": 0.7}, + "motion_zone_overlap": { + "day": 0.1, + "night": 0.2}, + "object_size_maximum": { + "day": 0.8, + "night": 0.8}, + "object_size_minimum": { + "day": 0.03, + "night": 0.05}, + "object_time_overlap": { + "day": 0.1, + "night": 0.6} + }, + "enable_audio": false, + "pir_settings": { + "sensitivity1": 1, + "sensitivity2": 1, + "sensitivity3": 1, + "zone_mask": 6}, + "sensitivity": 5, + "zone1": { + "name": "Zone 1", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}, + "zone2": { + "name": "Zone 2", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}, + "zone3": { + "name": "Zone 3", + "state": 2, + "vertex1": {"x": 0.0, "y": 0.0}, + "vertex2": {"x": 0.0, "y": 0.0}, + "vertex3": {"x": 0.0, "y": 0.0}, + "vertex4": {"x": 0.0, "y": 0.0}, + "vertex5": {"x": 0.0, "y": 0.0}, + "vertex6": {"x": 0.0, "y": 0.0}, + "vertex7": {"x": 0.0, "y": 0.0}, + "vertex8": {"x": 0.0, "y": 0.0}}}, + "pir_motion_zones": [0, 1, 1], + "pir_settings": { + "sensitivity1": 1, + "sensitivity2": 1, + "sensitivity3": 1, + "zone_mask": 6}, + "stream_setting": 0, + "video_settings": { + "ae_level": 0, + "birton": null, + "brightness": 0, + "contrast": 64, + "saturation": 80}}, + "siren_status": {"seconds_remaining": 30}, + "stolen": false, + "subscribed": true, + "subscribed_motions": true, + "time_zone": "America/New_York"}] +} diff --git a/tests/fixtures/ring_doorbot_siren_on_response.json b/tests/fixtures/ring_doorbot_siren_on_response.json new file mode 100644 index 00000000000..6bf91f88299 --- /dev/null +++ b/tests/fixtures/ring_doorbot_siren_on_response.json @@ -0,0 +1 @@ +{"started_at":"2019-07-28T16:58:27.593+00:00","duration":30,"ends_at":"2019-07-28T16:58:57.593+00:00","seconds_remaining":30} \ No newline at end of file