diff --git a/homeassistant/components/binary_sensor/ring.py b/homeassistant/components/binary_sensor/ring.py new file mode 100644 index 00000000000..429e92afa7f --- /dev/null +++ b/homeassistant/components/binary_sensor/ring.py @@ -0,0 +1,109 @@ +""" +This component provides HA sensor support for Ring Door Bell/Chimes. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.ring/ +""" +import logging +from datetime import timedelta + +import voluptuous as vol +import homeassistant.helpers.config_validation as cv + +from homeassistant.components.ring import ( + CONF_ATTRIBUTION, DEFAULT_ENTITY_NAMESPACE) + +from homeassistant.const import ( + ATTR_ATTRIBUTION, CONF_ENTITY_NAMESPACE, CONF_MONITORED_CONDITIONS) + +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, PLATFORM_SCHEMA) + +DEPENDENCIES = ['ring'] + +_LOGGER = logging.getLogger(__name__) + +SCAN_INTERVAL = timedelta(seconds=5) + +# Sensor types: Name, category, device_class +SENSOR_TYPES = { + 'ding': ['Ding', ['doorbell'], 'occupancy'], + 'motion': ['Motion', ['doorbell'], 'motion'], +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_ENTITY_NAMESPACE, default=DEFAULT_ENTITY_NAMESPACE): + cv.string, + vol.Required(CONF_MONITORED_CONDITIONS, default=[]): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up a sensor for a Ring device.""" + ring = hass.data.get('ring') + + sensors = [] + for sensor_type in config.get(CONF_MONITORED_CONDITIONS): + for device in ring.doorbells: + if 'doorbell' in SENSOR_TYPES[sensor_type][1]: + sensors.append(RingBinarySensor(hass, + device, + sensor_type)) + add_devices(sensors, True) + return True + + +class RingBinarySensor(BinarySensorDevice): + """A binary sensor implementation for Ring device.""" + + def __init__(self, hass, data, sensor_type): + """Initialize a sensor for Ring device.""" + super(RingBinarySensor, self).__init__() + self._sensor_type = sensor_type + self._data = data + self._name = "{0} {1}".format(self._data.name, + SENSOR_TYPES.get(self._sensor_type)[0]) + self._device_class = SENSOR_TYPES.get(self._sensor_type)[2] + self._state = None + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def is_on(self): + """Return True if the binary sensor is on.""" + return self._state + + @property + def device_class(self): + """Return the class of the binary sensor.""" + return self._device_class + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attrs = {} + attrs[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION + + attrs['device_id'] = self._data.id + attrs['firmware'] = self._data.firmware + attrs['timezone'] = self._data.timezone + + if self._data.alert and self._data.alert_expires_at: + attrs['expires_at'] = self._data.alert_expires_at + attrs['state'] = self._data.alert.get('state') + + return attrs + + def update(self): + """Get the latest data and updates the state.""" + self._data.check_alerts() + + if self._data.alert: + self._state = (self._sensor_type == + self._data.alert.get('kind')) + else: + self._state = False diff --git a/homeassistant/components/ring.py b/homeassistant/components/ring.py new file mode 100644 index 00000000000..61c772eced7 --- /dev/null +++ b/homeassistant/components/ring.py @@ -0,0 +1,63 @@ +""" +Support for Ring Doorbell/Chimes. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/ring/ +""" +from datetime import timedelta +import logging +import voluptuous as vol +import homeassistant.helpers.config_validation as cv + +from homeassistant.const import CONF_USERNAME, CONF_PASSWORD +import homeassistant.loader as loader + +from requests.exceptions import HTTPError, ConnectTimeout + +REQUIREMENTS = ['ring_doorbell==0.1.3'] + +_LOGGER = logging.getLogger(__name__) + +CONF_ATTRIBUTION = "Data provided by Ring.com" + +NOTIFICATION_ID = 'ring_notification' +NOTIFICATION_TITLE = 'Ring Sensor Setup' + +DOMAIN = 'ring' +DEFAULT_CACHEDB = '.ring_cache.pickle' +DEFAULT_ENTITY_NAMESPACE = 'ring' +DEFAULT_SCAN_INTERVAL = timedelta(seconds=30) + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + }), +}, extra=vol.ALLOW_EXTRA) + + +def setup(hass, config): + """Set up Ring component.""" + conf = config[DOMAIN] + username = conf.get(CONF_USERNAME) + password = conf.get(CONF_PASSWORD) + + persistent_notification = loader.get_component('persistent_notification') + try: + from ring_doorbell import Ring + + cache = hass.config.path(DEFAULT_CACHEDB) + ring = Ring(username=username, password=password, cache_file=cache) + if not ring.is_connected: + return False + hass.data['ring'] = ring + except (ConnectTimeout, HTTPError) as ex: + _LOGGER.error("Unable to connect to Ring service: %s", str(ex)) + persistent_notification.create( + hass, 'Error: {}
' + 'You will need to restart hass after fixing.' + ''.format(ex), + title=NOTIFICATION_TITLE, + notification_id=NOTIFICATION_ID) + return False + return True diff --git a/homeassistant/components/sensor/ring.py b/homeassistant/components/sensor/ring.py index 7c342a75f13..665fb167bcc 100644 --- a/homeassistant/components/sensor/ring.py +++ b/homeassistant/components/sensor/ring.py @@ -5,43 +5,32 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.ring/ """ import logging -from datetime import timedelta import voluptuous as vol -import homeassistant.loader as loader import homeassistant.helpers.config_validation as cv +from homeassistant.components.ring import ( + CONF_ATTRIBUTION, DEFAULT_ENTITY_NAMESPACE, DEFAULT_SCAN_INTERVAL) from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( CONF_ENTITY_NAMESPACE, CONF_MONITORED_CONDITIONS, CONF_SCAN_INTERVAL, - CONF_USERNAME, CONF_PASSWORD, STATE_UNKNOWN, - ATTR_ATTRIBUTION) + STATE_UNKNOWN, ATTR_ATTRIBUTION) from homeassistant.helpers.entity import Entity -from requests.exceptions import HTTPError, ConnectTimeout - -REQUIREMENTS = ['ring_doorbell==0.1.0'] +DEPENDENCIES = ['ring'] _LOGGER = logging.getLogger(__name__) -NOTIFICATION_ID = 'ring_notification' -NOTIFICATION_TITLE = 'Ring Sensor Setup' - -DEFAULT_ENTITY_NAMESPACE = 'ring' -DEFAULT_SCAN_INTERVAL = timedelta(seconds=30) - -CONF_ATTRIBUTION = "Data provided by Ring.com" - -# Sensor types: Name, category, units, icon +# Sensor types: Name, category, units, icon, kind SENSOR_TYPES = { - 'battery': ['Battery', ['doorbell'], '%', 'battery-50'], - 'last_activity': ['Last Activity', ['doorbell'], None, 'history'], - 'volume': ['Volume', ['chime', 'doorbell'], None, 'bell-ring'], + 'battery': ['Battery', ['doorbell'], '%', 'battery-50', None], + 'last_activity': ['Last Activity', ['doorbell'], None, 'history', None], + 'last_ding': ['Last Ding', ['doorbell'], None, 'history', 'ding'], + 'last_motion': ['Last Motion', ['doorbell'], None, 'history', 'motion'], + 'volume': ['Volume', ['chime', 'doorbell'], None, 'bell-ring', None], } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, vol.Optional(CONF_ENTITY_NAMESPACE, default=DEFAULT_ENTITY_NAMESPACE): cv.string, vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): @@ -53,22 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up a sensor for a Ring device.""" - from ring_doorbell import Ring - - ring = Ring(config.get(CONF_USERNAME), config.get(CONF_PASSWORD)) - - persistent_notification = loader.get_component('persistent_notification') - try: - ring.is_connected - except (ConnectTimeout, HTTPError) as ex: - _LOGGER.error("Unable to connect to Ring service: %s", str(ex)) - persistent_notification.create( - hass, 'Error: {}
' - 'You will need to restart hass after fixing.' - ''.format(ex), - title=NOTIFICATION_TITLE, - notification_id=NOTIFICATION_ID) - return False + ring = hass.data.get('ring') sensors = [] for sensor_type in config.get(CONF_MONITORED_CONDITIONS): @@ -98,6 +72,7 @@ class RingSensor(Entity): self._data = data self._extra = None self._icon = 'mdi:{}'.format(SENSOR_TYPES.get(self._sensor_type)[3]) + self._kind = SENSOR_TYPES.get(self._sensor_type)[4] self._name = "{0} {1}".format(self._data.name, SENSOR_TYPES.get(self._sensor_type)[0]) self._state = STATE_UNKNOWN @@ -125,7 +100,7 @@ class RingSensor(Entity): attrs['timezone'] = self._data.timezone attrs['type'] = self._data.family - if self._extra and self._sensor_type == 'last_activity': + if self._extra and self._sensor_type.startswith('last_'): attrs['created_at'] = self._extra['created_at'] attrs['answered'] = self._extra['answered'] attrs['recording_status'] = self._extra['recording']['status'] @@ -153,8 +128,11 @@ class RingSensor(Entity): if self._sensor_type == 'battery': self._state = self._data.battery_life - if self._sensor_type == 'last_activity': - self._extra = self._data.history(limit=1, timezone=self._tz)[0] - created_at = self._extra['created_at'] - self._state = '{0:0>2}:{1:0>2}'.format(created_at.hour, - created_at.minute) + if self._sensor_type.startswith('last_'): + history = self._data.history(timezone=self._tz, + kind=self._kind) + if history: + self._extra = history[0] + created_at = self._extra['created_at'] + self._state = '{0:0>2}:{1:0>2}'.format(created_at.hour, + created_at.minute) diff --git a/requirements_all.txt b/requirements_all.txt index cb2f9fdff5c..ac0d6a3752f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -664,8 +664,8 @@ radiotherm==1.2 # homeassistant.components.rflink rflink==0.0.31 -# homeassistant.components.sensor.ring -ring_doorbell==0.1.0 +# homeassistant.components.ring +ring_doorbell==0.1.3 # homeassistant.components.switch.rpi_rf # rpi-rf==0.9.6 diff --git a/tests/components/binary_sensor/test_ring.py b/tests/components/binary_sensor/test_ring.py new file mode 100644 index 00000000000..75c7aced369 --- /dev/null +++ b/tests/components/binary_sensor/test_ring.py @@ -0,0 +1,63 @@ +"""The tests for the Ring binary sensor platform.""" +import unittest +import requests_mock + +from homeassistant.components.binary_sensor import ring +from homeassistant.components import ring as base_ring + +from tests.components.test_ring import ATTRIBUTION, VALID_CONFIG +from tests.common import get_test_home_assistant, load_fixture + + +class TestRingBinarySensorSetup(unittest.TestCase): + """Test the Ring Binary Sensor platform.""" + + DEVICES = [] + + def add_devices(self, devices, action): + """Mock add devices.""" + for device in devices: + self.DEVICES.append(device) + + def setUp(self): + """Initialize values for this testcase class.""" + self.hass = get_test_home_assistant() + self.config = { + 'username': 'foo', + 'password': 'bar', + 'monitored_conditions': ['ding', 'motion'], + } + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + + @requests_mock.Mocker() + def test_binary_sensor(self, mock): + """Test the Ring sensor class and methods.""" + mock.post('https://api.ring.com/clients_api/session', + text=load_fixture('ring_session.json')) + mock.get('https://api.ring.com/clients_api/ring_devices', + text=load_fixture('ring_devices.json')) + mock.get('https://api.ring.com/clients_api/dings/active', + text=load_fixture('ring_ding_active.json')) + + base_ring.setup(self.hass, VALID_CONFIG) + ring.setup_platform(self.hass, + self.config, + self.add_devices, + None) + + for device in self.DEVICES: + device.update() + if device.name == 'Front Door Ding': + self.assertEqual('on', device.state) + self.assertEqual('America/New_York', + device.device_state_attributes['timezone']) + elif device.name == 'Front Door Motion': + self.assertEqual('off', device.state) + self.assertEqual('motion', device.device_class) + + self.assertIsNone(device.entity_picture) + self.assertEqual(ATTRIBUTION, + device.device_state_attributes['attribution']) diff --git a/tests/components/sensor/test_ring.py b/tests/components/sensor/test_ring.py index c7bf966a3e9..0ee72107413 100644 --- a/tests/components/sensor/test_ring.py +++ b/tests/components/sensor/test_ring.py @@ -1,171 +1,17 @@ """The tests for the Ring sensor platform.""" import unittest -from unittest import mock +import requests_mock from homeassistant.components.sensor import ring -from tests.common import get_test_home_assistant +from homeassistant.components import ring as base_ring -VALID_CONFIG = { - "platform": "ring", - "username": "foo", - "password": "bar", - "monitored_conditions": [ - "battery", "last_activity", "volume" - ] -} - -ATTRIBUTION = 'Data provided by Ring.com' +from tests.components.test_ring import ATTRIBUTION, VALID_CONFIG +from tests.common import get_test_home_assistant, load_fixture -def mocked_requests_get(*args, **kwargs): - """Mock requests.get invocations.""" - class MockResponse: - """Class to represent a mocked response.""" - - def __init__(self, json_data, status_code): - """Initialize the mock response class.""" - self.json_data = json_data - self.status_code = status_code - - def json(self): - """Return the json of the response.""" - return self.json_data - - if str(args[0]).startswith('https://api.ring.com/clients_api/session'): - return MockResponse({ - "profile": { - "authentication_token": "12345678910", - "email": "foo@bar.org", - "features": { - "chime_dnd_enabled": False, - "chime_pro_enabled": True, - "delete_all_enabled": True, - "delete_all_settings_enabled": False, - "device_health_alerts_enabled": True, - "floodlight_cam_enabled": True, - "live_view_settings_enabled": True, - "lpd_enabled": True, - "lpd_motion_announcement_enabled": False, - "multiple_calls_enabled": True, - "multiple_delete_enabled": True, - "nw_enabled": True, - "nw_larger_area_enabled": False, - "nw_user_activated": False, - "owner_proactive_snoozing_enabled": True, - "power_cable_enabled": False, - "proactive_snoozing_enabled": False, - "reactive_snoozing_enabled": False, - "remote_logging_format_storing": False, - "remote_logging_level": 1, - "ringplus_enabled": True, - "starred_events_enabled": True, - "stickupcam_setup_enabled": True, - "subscriptions_enabled": True, - "ujet_enabled": False, - "video_search_enabled": False, - "vod_enabled": False}, - "first_name": "Home", - "id": 999999, - "last_name": "Assistant"} - }, 201) - elif str(args[0])\ - .startswith("https://api.ring.com/clients_api/ring_devices"): - return MockResponse({ - "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": None, - "ding_audio_user_id": None, - "motion_audio_id": None, - "motion_audio_user_id": None, - "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": None, - "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": [ - "none", - "low", - "medium", - "high"]}, - "subscribed": True, - "subscribed_motions": True, - "time_zone": "America/New_York"}] - }, 200) - elif str(args[0]).startswith("https://api.ring.com/clients_api/doorbots"): - return MockResponse([{ - "answered": False, - "created_at": "2017-03-05T15:03:40.000Z", - "events": [], - "favorite": False, - "id": 987654321, - "kind": "motion", - "recording": {"status": "ready"}, - "snapshot_url": "" - }], 200) - - -class TestRingSetup(unittest.TestCase): +class TestRingSensorSetup(unittest.TestCase): """Test the Ring platform.""" - # pylint: disable=invalid-name DEVICES = [] def add_devices(self, devices, action): @@ -176,25 +22,35 @@ class TestRingSetup(unittest.TestCase): def setUp(self): """Initialize values for this testcase class.""" self.hass = get_test_home_assistant() - self.config = VALID_CONFIG + self.config = { + 'username': 'foo', + 'password': 'bar', + 'monitored_conditions': [ + 'battery', + 'last_activity', + 'last_ding', + 'last_motion', + 'volume'] + } def tearDown(self): """Stop everything that was started.""" self.hass.stop() - @mock.patch('requests.Session.get', side_effect=mocked_requests_get) - @mock.patch('requests.Session.post', side_effect=mocked_requests_get) - def test_setup(self, get_mock, post_mock): - """Test if component loaded successfully.""" - self.assertTrue( - ring.setup_platform(self.hass, VALID_CONFIG, - self.add_devices, None)) - - @mock.patch('requests.Session.get', side_effect=mocked_requests_get) - @mock.patch('requests.Session.post', side_effect=mocked_requests_get) - def test_sensor(self, get_mock, post_mock): - """Test the Ring sensor class and methods.""" - ring.setup_platform(self.hass, VALID_CONFIG, self.add_devices, None) + @requests_mock.Mocker() + def test_sensor(self, mock): + """Test the Ring senskor class and methods.""" + mock.post('https://api.ring.com/clients_api/session', + text=load_fixture('ring_session.json')) + mock.get('https://api.ring.com/clients_api/ring_devices', + text=load_fixture('ring_devices.json')) + mock.get('https://api.ring.com/clients_api/doorbots/987652/history', + text=load_fixture('ring_doorbots.json')) + base_ring.setup(self.hass, VALID_CONFIG) + ring.setup_platform(self.hass, + self.config, + self.add_devices, + None) for device in self.DEVICES: device.update() diff --git a/tests/components/test_ring.py b/tests/components/test_ring.py new file mode 100644 index 00000000000..e10e5c20aea --- /dev/null +++ b/tests/components/test_ring.py @@ -0,0 +1,56 @@ +"""The tests for the Ring component.""" +import unittest +import requests_mock + +from homeassistant import setup +import homeassistant.components.ring as ring + +from tests.common import get_test_home_assistant, load_fixture + +ATTRIBUTION = 'Data provided by Ring.com' + +VALID_CONFIG = { + "ring": { + "username": "foo", + "password": "bar", + } +} + + +class TestRing(unittest.TestCase): + """Tests the Ring component.""" + + def setUp(self): + """Initialize values for this test case class.""" + self.hass = get_test_home_assistant() + self.config = VALID_CONFIG + + def tearDown(self): # pylint: disable=invalid-name + """Stop everything that was started.""" + self.hass.stop() + + @requests_mock.Mocker() + def test_setup(self, mock): + """Test the setup.""" + mock.post('https://api.ring.com/clients_api/session', + text=load_fixture('ring_session.json')) + response = ring.setup(self.hass, self.config) + self.assertTrue(response) + + @requests_mock.Mocker() + def test_setup_component_no_login(self, mock): + """Test the setup when no login is configured.""" + mock.post('https://api.ring.com/clients_api/session', + text=load_fixture('ring_session.json')) + conf = self.config.copy() + del conf['ring']['username'] + assert not setup.setup_component(self.hass, ring.DOMAIN, conf) + + @requests_mock.Mocker() + def test_setup_component_no_pwd(self, mock): + """Test the setup when no password is configured.""" + mock.post('https://api.ring.com/clients_api/session', + text=load_fixture('ring_session.json')) + conf = self.config.copy() + del conf['ring']['password'] + assert not setup.setup_component(self.hass, ring.DOMAIN, conf) diff --git a/tests/fixtures/ring_devices.json b/tests/fixtures/ring_devices.json new file mode 100644 index 00000000000..4d204ba5250 --- /dev/null +++ b/tests/fixtures/ring_devices.json @@ -0,0 +1,79 @@ +{ + "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"}] +} diff --git a/tests/fixtures/ring_ding_active.json b/tests/fixtures/ring_ding_active.json new file mode 100644 index 00000000000..6bbcc0ee3f9 --- /dev/null +++ b/tests/fixtures/ring_ding_active.json @@ -0,0 +1,26 @@ +[{ + "audio_jitter_buffer_ms": 0, + "device_kind": "lpd_v1", + "doorbot_description": "Front Door", + "doorbot_id": 12345, + "expires_in": 180, + "id": 123456789, + "id_str": "123456789", + "kind": "ding", + "motion": false, + "now": 1490949469.5498993, + "optimization_level": 1, + "protocol": "sip", + "sip_ding_id": "123456789", + "sip_endpoints": null, + "sip_from": "sip:abc123@ring.com", + "sip_server_ip": "192.168.0.1", + "sip_server_port": "15063", + "sip_server_tls": "false", + "sip_session_id": "28qdvjh-2043", + "sip_to": "sip:28qdvjh-2043@192.168.0.1:15063;transport=tcp", + "sip_token": "adecc24a428ed704b2d80adb621b5775755915529639e", + "snapshot_url": "", + "state": "ringing", + "video_jitter_buffer_ms": 0 +}] diff --git a/tests/fixtures/ring_doorbots.json b/tests/fixtures/ring_doorbots.json new file mode 100644 index 00000000000..7ec2d4fd0b7 --- /dev/null +++ b/tests/fixtures/ring_doorbots.json @@ -0,0 +1,10 @@ +[{ + "answered": false, + "created_at": "2017-03-05T15:03:40.000Z", + "events": [], + "favorite": false, + "id": 987654321, + "kind": "motion", + "recording": {"status": "ready"}, + "snapshot_url": "" +}] diff --git a/tests/fixtures/ring_session.json b/tests/fixtures/ring_session.json new file mode 100644 index 00000000000..21ae51c6bf6 --- /dev/null +++ b/tests/fixtures/ring_session.json @@ -0,0 +1,36 @@ +{ + "profile": { + "authentication_token": "12345678910", + "email": "foo@bar.org", + "features": { + "chime_dnd_enabled": false, + "chime_pro_enabled": true, + "delete_all_enabled": true, + "delete_all_settings_enabled": false, + "device_health_alerts_enabled": true, + "floodlight_cam_enabled": true, + "live_view_settings_enabled": true, + "lpd_enabled": true, + "lpd_motion_announcement_enabled": false, + "multiple_calls_enabled": true, + "multiple_delete_enabled": true, + "nw_enabled": true, + "nw_larger_area_enabled": false, + "nw_user_activated": false, + "owner_proactive_snoozing_enabled": true, + "power_cable_enabled": false, + "proactive_snoozing_enabled": false, + "reactive_snoozing_enabled": false, + "remote_logging_format_storing": false, + "remote_logging_level": 1, + "ringplus_enabled": true, + "starred_events_enabled": true, + "stickupcam_setup_enabled": true, + "subscriptions_enabled": true, + "ujet_enabled": false, + "video_search_enabled": false, + "vod_enabled": false}, + "first_name": "Home", + "id": 999999, + "last_name": "Assistant"} +}