mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 06:37:52 +00:00
Upgrade Ring to new version (#30666)
* Upgrade Ring to new version * Move legacy cleanup down * Fix test
This commit is contained in:
parent
4972b249bf
commit
7073b0eb88
@ -5,8 +5,7 @@ from functools import partial
|
|||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from requests.exceptions import ConnectTimeout, HTTPError
|
from ring_doorbell import Auth, Ring
|
||||||
from ring_doorbell import Ring
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
@ -14,6 +13,7 @@ from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
|||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.dispatcher import dispatcher_send
|
from homeassistant.helpers.dispatcher import dispatcher_send
|
||||||
from homeassistant.helpers.event import track_time_interval
|
from homeassistant.helpers.event import track_time_interval
|
||||||
|
from homeassistant.util.async_ import run_callback_threadsafe
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ DATA_RING_CHIMES = "ring_chimes"
|
|||||||
DATA_TRACK_INTERVAL = "ring_track_interval"
|
DATA_TRACK_INTERVAL = "ring_track_interval"
|
||||||
|
|
||||||
DOMAIN = "ring"
|
DOMAIN = "ring"
|
||||||
DEFAULT_CACHEDB = ".ring_cache.pickle"
|
|
||||||
DEFAULT_ENTITY_NAMESPACE = "ring"
|
DEFAULT_ENTITY_NAMESPACE = "ring"
|
||||||
SIGNAL_UPDATE_RING = "ring_update"
|
SIGNAL_UPDATE_RING = "ring_update"
|
||||||
|
|
||||||
@ -54,6 +53,14 @@ async def async_setup(hass, config):
|
|||||||
if DOMAIN not in config:
|
if DOMAIN not in config:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def legacy_cleanup():
|
||||||
|
"""Clean up old tokens."""
|
||||||
|
old_cache = Path(hass.config.path(".ring_cache.pickle"))
|
||||||
|
if old_cache.is_file():
|
||||||
|
old_cache.unlink()
|
||||||
|
|
||||||
|
await hass.async_add_executor_job(legacy_cleanup)
|
||||||
|
|
||||||
hass.async_create_task(
|
hass.async_create_task(
|
||||||
hass.config_entries.flow.async_init(
|
hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@ -69,30 +76,20 @@ async def async_setup(hass, config):
|
|||||||
|
|
||||||
async def async_setup_entry(hass, entry):
|
async def async_setup_entry(hass, entry):
|
||||||
"""Set up a config entry."""
|
"""Set up a config entry."""
|
||||||
cache = hass.config.path(DEFAULT_CACHEDB)
|
|
||||||
try:
|
|
||||||
ring = await hass.async_add_executor_job(
|
|
||||||
partial(
|
|
||||||
Ring,
|
|
||||||
username=entry.data["username"],
|
|
||||||
password="invalid-password",
|
|
||||||
cache_file=cache,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except (ConnectTimeout, HTTPError) as ex:
|
|
||||||
_LOGGER.error("Unable to connect to Ring service: %s", str(ex))
|
|
||||||
hass.components.persistent_notification.async_create(
|
|
||||||
"Error: {}<br />"
|
|
||||||
"You will need to restart hass after fixing."
|
|
||||||
"".format(ex),
|
|
||||||
title=NOTIFICATION_TITLE,
|
|
||||||
notification_id=NOTIFICATION_ID,
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not ring.is_connected:
|
def token_updater(token):
|
||||||
_LOGGER.error("Unable to connect to Ring service")
|
"""Handle from sync context when token is updated."""
|
||||||
return False
|
run_callback_threadsafe(
|
||||||
|
hass.loop,
|
||||||
|
partial(
|
||||||
|
hass.config_entries.async_update_entry,
|
||||||
|
entry,
|
||||||
|
data={**entry.data, "token": token},
|
||||||
|
),
|
||||||
|
).result()
|
||||||
|
|
||||||
|
auth = Auth(entry.data["token"], token_updater)
|
||||||
|
ring = Ring(auth)
|
||||||
|
|
||||||
await hass.async_add_executor_job(finish_setup_entry, hass, ring)
|
await hass.async_add_executor_job(finish_setup_entry, hass, ring)
|
||||||
|
|
||||||
@ -106,9 +103,10 @@ async def async_setup_entry(hass, entry):
|
|||||||
|
|
||||||
def finish_setup_entry(hass, ring):
|
def finish_setup_entry(hass, ring):
|
||||||
"""Finish setting up entry."""
|
"""Finish setting up entry."""
|
||||||
hass.data[DATA_RING_CHIMES] = chimes = ring.chimes
|
devices = ring.devices
|
||||||
hass.data[DATA_RING_DOORBELLS] = doorbells = ring.doorbells
|
hass.data[DATA_RING_CHIMES] = chimes = devices["chimes"]
|
||||||
hass.data[DATA_RING_STICKUP_CAMS] = stickup_cams = ring.stickup_cams
|
hass.data[DATA_RING_DOORBELLS] = doorbells = devices["doorbells"]
|
||||||
|
hass.data[DATA_RING_STICKUP_CAMS] = stickup_cams = devices["stickup_cams"]
|
||||||
|
|
||||||
ring_devices = chimes + doorbells + stickup_cams
|
ring_devices = chimes + doorbells + stickup_cams
|
||||||
|
|
||||||
@ -160,8 +158,3 @@ async def async_unload_entry(hass, entry):
|
|||||||
hass.data.pop(DATA_TRACK_INTERVAL)
|
hass.data.pop(DATA_TRACK_INTERVAL)
|
||||||
|
|
||||||
return unload_ok
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
async def async_remove_entry(hass, entry):
|
|
||||||
"""Act when an entry is removed."""
|
|
||||||
await hass.async_add_executor_job(Path(hass.config.path(DEFAULT_CACHEDB)).unlink)
|
|
||||||
|
@ -5,7 +5,7 @@ import logging
|
|||||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||||
from homeassistant.const import ATTR_ATTRIBUTION
|
from homeassistant.const import ATTR_ATTRIBUTION
|
||||||
|
|
||||||
from . import ATTRIBUTION, DATA_RING_DOORBELLS, DATA_RING_STICKUP_CAMS
|
from . import ATTRIBUTION, DATA_RING_DOORBELLS, DATA_RING_STICKUP_CAMS, DOMAIN
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -72,14 +72,23 @@ class RingBinarySensor(BinarySensorDevice):
|
|||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
return self._unique_id
|
return self._unique_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Return device info."""
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._data.id)},
|
||||||
|
"sw_version": self._data.firmware,
|
||||||
|
"name": self._data.name,
|
||||||
|
"model": self._data.kind,
|
||||||
|
"manufacturer": "Ring",
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
attrs = {}
|
attrs = {}
|
||||||
attrs[ATTR_ATTRIBUTION] = ATTRIBUTION
|
attrs[ATTR_ATTRIBUTION] = ATTRIBUTION
|
||||||
|
|
||||||
attrs["device_id"] = self._data.id
|
|
||||||
attrs["firmware"] = self._data.firmware
|
|
||||||
attrs["timezone"] = self._data.timezone
|
attrs["timezone"] = self._data.timezone
|
||||||
|
|
||||||
if self._data.alert and self._data.alert_expires_at:
|
if self._data.alert and self._data.alert_expires_at:
|
||||||
|
@ -18,6 +18,7 @@ from . import (
|
|||||||
ATTRIBUTION,
|
ATTRIBUTION,
|
||||||
DATA_RING_DOORBELLS,
|
DATA_RING_DOORBELLS,
|
||||||
DATA_RING_STICKUP_CAMS,
|
DATA_RING_STICKUP_CAMS,
|
||||||
|
DOMAIN,
|
||||||
SIGNAL_UPDATE_RING,
|
SIGNAL_UPDATE_RING,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -86,16 +87,23 @@ class RingCam(Camera):
|
|||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
return self._camera.id
|
return self._camera.id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Return device info."""
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._camera.id)},
|
||||||
|
"sw_version": self._camera.firmware,
|
||||||
|
"name": self._camera.name,
|
||||||
|
"model": self._camera.kind,
|
||||||
|
"manufacturer": "Ring",
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
return {
|
return {
|
||||||
ATTR_ATTRIBUTION: ATTRIBUTION,
|
ATTR_ATTRIBUTION: ATTRIBUTION,
|
||||||
"device_id": self._camera.id,
|
|
||||||
"firmware": self._camera.firmware,
|
|
||||||
"kind": self._camera.kind,
|
|
||||||
"timezone": self._camera.timezone,
|
"timezone": self._camera.timezone,
|
||||||
"type": self._camera.family,
|
|
||||||
"video_url": self._video_url,
|
"video_url": self._video_url,
|
||||||
"last_video_id": self._last_video_id,
|
"last_video_id": self._last_video_id,
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
"""Config flow for Ring integration."""
|
"""Config flow for Ring integration."""
|
||||||
from functools import partial
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from oauthlib.oauth2 import AccessDeniedError
|
from oauthlib.oauth2 import AccessDeniedError
|
||||||
from ring_doorbell import Ring
|
from ring_doorbell import Auth
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries, core, exceptions
|
from homeassistant import config_entries, core, exceptions
|
||||||
|
|
||||||
from . import DEFAULT_CACHEDB, DOMAIN # pylint: disable=unused-import
|
from . import DOMAIN # pylint: disable=unused-import
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def validate_input(hass: core.HomeAssistant, data):
|
async def validate_input(hass: core.HomeAssistant, data):
|
||||||
"""Validate the user input allows us to connect."""
|
"""Validate the user input allows us to connect."""
|
||||||
cache = hass.config.path(DEFAULT_CACHEDB)
|
|
||||||
|
|
||||||
def otp_callback():
|
def otp_callback():
|
||||||
if "2fa" in data:
|
if "2fa" in data:
|
||||||
@ -23,21 +21,16 @@ async def validate_input(hass: core.HomeAssistant, data):
|
|||||||
|
|
||||||
raise Require2FA
|
raise Require2FA
|
||||||
|
|
||||||
|
auth = Auth()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ring = await hass.async_add_executor_job(
|
token = await hass.async_add_executor_job(
|
||||||
partial(
|
auth.fetch_token, data["username"], data["password"], otp_callback,
|
||||||
Ring,
|
|
||||||
username=data["username"],
|
|
||||||
password=data["password"],
|
|
||||||
cache_file=cache,
|
|
||||||
auth_callback=otp_callback,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
except AccessDeniedError:
|
except AccessDeniedError:
|
||||||
raise InvalidAuth
|
raise InvalidAuth
|
||||||
|
|
||||||
if not ring.is_connected:
|
return token
|
||||||
raise InvalidAuth
|
|
||||||
|
|
||||||
|
|
||||||
class RingConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
class RingConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
@ -56,12 +49,12 @@ class RingConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
errors = {}
|
errors = {}
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
try:
|
try:
|
||||||
await validate_input(self.hass, user_input)
|
token = await validate_input(self.hass, user_input)
|
||||||
await self.async_set_unique_id(user_input["username"])
|
await self.async_set_unique_id(user_input["username"])
|
||||||
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=user_input["username"],
|
title=user_input["username"],
|
||||||
data={"username": user_input["username"]},
|
data={"username": user_input["username"], "token": token},
|
||||||
)
|
)
|
||||||
except Require2FA:
|
except Require2FA:
|
||||||
self.user_pass = user_input
|
self.user_pass = user_input
|
||||||
|
@ -7,7 +7,7 @@ from homeassistant.core import callback
|
|||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from . import DATA_RING_STICKUP_CAMS, SIGNAL_UPDATE_RING
|
from . import DATA_RING_STICKUP_CAMS, DOMAIN, SIGNAL_UPDATE_RING
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -84,6 +84,17 @@ class RingLight(Light):
|
|||||||
"""If the switch is currently on or off."""
|
"""If the switch is currently on or off."""
|
||||||
return self._light_on
|
return self._light_on
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Return device info."""
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._device.id)},
|
||||||
|
"sw_version": self._device.firmware,
|
||||||
|
"name": self._device.name,
|
||||||
|
"model": self._device.kind,
|
||||||
|
"manufacturer": "Ring",
|
||||||
|
}
|
||||||
|
|
||||||
def _set_light(self, new_state):
|
def _set_light(self, new_state):
|
||||||
"""Update light state, and causes Home Assistant to correctly update."""
|
"""Update light state, and causes Home Assistant to correctly update."""
|
||||||
self._device.lights = new_state
|
self._device.lights = new_state
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"domain": "ring",
|
"domain": "ring",
|
||||||
"name": "Ring",
|
"name": "Ring",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/ring",
|
"documentation": "https://www.home-assistant.io/integrations/ring",
|
||||||
"requirements": ["ring_doorbell==0.2.9"],
|
"requirements": ["ring_doorbell==0.4.0"],
|
||||||
"dependencies": ["ffmpeg"],
|
"dependencies": ["ffmpeg"],
|
||||||
"codeowners": [],
|
"codeowners": [],
|
||||||
"config_flow": true
|
"config_flow": true
|
||||||
|
@ -12,6 +12,7 @@ from . import (
|
|||||||
DATA_RING_CHIMES,
|
DATA_RING_CHIMES,
|
||||||
DATA_RING_DOORBELLS,
|
DATA_RING_DOORBELLS,
|
||||||
DATA_RING_STICKUP_CAMS,
|
DATA_RING_STICKUP_CAMS,
|
||||||
|
DOMAIN,
|
||||||
SIGNAL_UPDATE_RING,
|
SIGNAL_UPDATE_RING,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -108,6 +109,7 @@ class RingSensor(Entity):
|
|||||||
self._disp_disconnect = async_dispatcher_connect(
|
self._disp_disconnect = async_dispatcher_connect(
|
||||||
self.hass, SIGNAL_UPDATE_RING, self._update_callback
|
self.hass, SIGNAL_UPDATE_RING, self._update_callback
|
||||||
)
|
)
|
||||||
|
await self.hass.async_add_executor_job(self._data.update)
|
||||||
|
|
||||||
async def async_will_remove_from_hass(self):
|
async def async_will_remove_from_hass(self):
|
||||||
"""Disconnect callbacks."""
|
"""Disconnect callbacks."""
|
||||||
@ -140,17 +142,24 @@ class RingSensor(Entity):
|
|||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
return self._unique_id
|
return self._unique_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Return device info."""
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._data.id)},
|
||||||
|
"sw_version": self._data.firmware,
|
||||||
|
"name": self._data.name,
|
||||||
|
"model": self._data.kind,
|
||||||
|
"manufacturer": "Ring",
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
attrs = {}
|
attrs = {}
|
||||||
|
|
||||||
attrs[ATTR_ATTRIBUTION] = ATTRIBUTION
|
attrs[ATTR_ATTRIBUTION] = ATTRIBUTION
|
||||||
attrs["device_id"] = self._data.id
|
|
||||||
attrs["firmware"] = self._data.firmware
|
|
||||||
attrs["kind"] = self._data.kind
|
|
||||||
attrs["timezone"] = self._data.timezone
|
attrs["timezone"] = self._data.timezone
|
||||||
attrs["type"] = self._data.family
|
|
||||||
attrs["wifi_name"] = self._data.wifi_name
|
attrs["wifi_name"] = self._data.wifi_name
|
||||||
|
|
||||||
if self._extra and self._sensor_type.startswith("last_"):
|
if self._extra and self._sensor_type.startswith("last_"):
|
||||||
|
@ -7,7 +7,7 @@ from homeassistant.core import callback
|
|||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from . import DATA_RING_STICKUP_CAMS, SIGNAL_UPDATE_RING
|
from . import DATA_RING_STICKUP_CAMS, DOMAIN, SIGNAL_UPDATE_RING
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -76,6 +76,17 @@ class BaseRingSwitch(SwitchDevice):
|
|||||||
"""Update controlled via the hub."""
|
"""Update controlled via the hub."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Return device info."""
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._device.id)},
|
||||||
|
"sw_version": self._device.firmware,
|
||||||
|
"name": self._device.name,
|
||||||
|
"model": self._device.kind,
|
||||||
|
"manufacturer": "Ring",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class SirenSwitch(BaseRingSwitch):
|
class SirenSwitch(BaseRingSwitch):
|
||||||
"""Creates a switch to turn the ring cameras siren on and off."""
|
"""Creates a switch to turn the ring cameras siren on and off."""
|
||||||
|
@ -1753,7 +1753,7 @@ rfk101py==0.0.1
|
|||||||
rflink==0.0.50
|
rflink==0.0.50
|
||||||
|
|
||||||
# homeassistant.components.ring
|
# homeassistant.components.ring
|
||||||
ring_doorbell==0.2.9
|
ring_doorbell==0.4.0
|
||||||
|
|
||||||
# homeassistant.components.fleetgo
|
# homeassistant.components.fleetgo
|
||||||
ritassist==0.9.2
|
ritassist==0.9.2
|
||||||
|
@ -570,7 +570,7 @@ restrictedpython==5.0
|
|||||||
rflink==0.0.50
|
rflink==0.0.50
|
||||||
|
|
||||||
# homeassistant.components.ring
|
# homeassistant.components.ring
|
||||||
ring_doorbell==0.2.9
|
ring_doorbell==0.4.0
|
||||||
|
|
||||||
# homeassistant.components.yamaha
|
# homeassistant.components.yamaha
|
||||||
rxv==0.6.0
|
rxv==0.6.0
|
||||||
|
@ -9,7 +9,9 @@ from tests.common import MockConfigEntry
|
|||||||
|
|
||||||
async def setup_platform(hass, platform):
|
async def setup_platform(hass, platform):
|
||||||
"""Set up the ring platform and prerequisites."""
|
"""Set up the ring platform and prerequisites."""
|
||||||
MockConfigEntry(domain=DOMAIN, data={"username": "foo"}).add_to_hass(hass)
|
MockConfigEntry(domain=DOMAIN, data={"username": "foo", "token": {}}).add_to_hass(
|
||||||
|
hass
|
||||||
|
)
|
||||||
with patch("homeassistant.components.ring.PLATFORMS", [platform]):
|
with patch("homeassistant.components.ring.PLATFORMS", [platform]):
|
||||||
assert await async_setup_component(hass, DOMAIN, {})
|
assert await async_setup_component(hass, DOMAIN, {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -1,21 +1,12 @@
|
|||||||
"""Configuration for Ring tests."""
|
"""Configuration for Ring tests."""
|
||||||
from asynctest import patch
|
|
||||||
import pytest
|
import pytest
|
||||||
import requests_mock
|
import requests_mock
|
||||||
|
|
||||||
from tests.common import load_fixture
|
from tests.common import load_fixture
|
||||||
|
|
||||||
|
|
||||||
@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")
|
@pytest.fixture(name="requests_mock")
|
||||||
def requests_mock_fixture(ring_mock):
|
def requests_mock_fixture():
|
||||||
"""Fixture to provide a requests mocker."""
|
"""Fixture to provide a requests mocker."""
|
||||||
with requests_mock.mock() as mock:
|
with requests_mock.mock() as mock:
|
||||||
# Note all devices have an id of 987652, but a different device_id.
|
# Note all devices have an id of 987652, but a different device_id.
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""The tests for the Ring binary sensor platform."""
|
"""The tests for the Ring binary sensor platform."""
|
||||||
from asyncio import run_coroutine_threadsafe
|
from asyncio import run_coroutine_threadsafe
|
||||||
import os
|
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
@ -9,12 +8,7 @@ import requests_mock
|
|||||||
from homeassistant.components import ring as base_ring
|
from homeassistant.components import ring as base_ring
|
||||||
from homeassistant.components.ring import binary_sensor as ring
|
from homeassistant.components.ring import binary_sensor as ring
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import get_test_home_assistant, load_fixture, mock_storage
|
||||||
get_test_config_dir,
|
|
||||||
get_test_home_assistant,
|
|
||||||
load_fixture,
|
|
||||||
mock_storage,
|
|
||||||
)
|
|
||||||
from tests.components.ring.test_init import ATTRIBUTION, VALID_CONFIG
|
from tests.components.ring.test_init import ATTRIBUTION, VALID_CONFIG
|
||||||
|
|
||||||
|
|
||||||
@ -28,15 +22,9 @@ class TestRingBinarySensorSetup(unittest.TestCase):
|
|||||||
for device in devices:
|
for device in devices:
|
||||||
self.DEVICES.append(device)
|
self.DEVICES.append(device)
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
"""Cleanup any data created from the tests."""
|
|
||||||
if os.path.isfile(self.cache):
|
|
||||||
os.remove(self.cache)
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Initialize values for this testcase class."""
|
"""Initialize values for this testcase class."""
|
||||||
self.hass = get_test_home_assistant()
|
self.hass = get_test_home_assistant()
|
||||||
self.cache = get_test_config_dir(base_ring.DEFAULT_CACHEDB)
|
|
||||||
self.config = {
|
self.config = {
|
||||||
"username": "foo",
|
"username": "foo",
|
||||||
"password": "bar",
|
"password": "bar",
|
||||||
@ -46,7 +34,6 @@ class TestRingBinarySensorSetup(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
self.cleanup()
|
|
||||||
|
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_binary_sensor(self, mock):
|
def test_binary_sensor(self, mock):
|
||||||
|
@ -18,8 +18,10 @@ async def test_form(hass):
|
|||||||
assert result["errors"] == {}
|
assert result["errors"] == {}
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ring.config_flow.Ring",
|
"homeassistant.components.ring.config_flow.Auth",
|
||||||
return_value=Mock(is_connected=True),
|
return_value=Mock(
|
||||||
|
fetch_token=Mock(return_value={"access_token": "mock-token"})
|
||||||
|
),
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.ring.async_setup", return_value=mock_coro(True)
|
"homeassistant.components.ring.async_setup", return_value=mock_coro(True)
|
||||||
) as mock_setup, patch(
|
) as mock_setup, patch(
|
||||||
@ -34,6 +36,7 @@ async def test_form(hass):
|
|||||||
assert result2["title"] == "hello@home-assistant.io"
|
assert result2["title"] == "hello@home-assistant.io"
|
||||||
assert result2["data"] == {
|
assert result2["data"] == {
|
||||||
"username": "hello@home-assistant.io",
|
"username": "hello@home-assistant.io",
|
||||||
|
"token": {"access_token": "mock-token"},
|
||||||
}
|
}
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(mock_setup.mock_calls) == 1
|
assert len(mock_setup.mock_calls) == 1
|
||||||
@ -47,7 +50,8 @@ async def test_form_invalid_auth(hass):
|
|||||||
)
|
)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.ring.config_flow.Ring", side_effect=InvalidAuth,
|
"homeassistant.components.ring.config_flow.Auth.fetch_token",
|
||||||
|
side_effect=InvalidAuth,
|
||||||
):
|
):
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from asyncio import run_coroutine_threadsafe
|
from asyncio import run_coroutine_threadsafe
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import os
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import requests_mock
|
import requests_mock
|
||||||
@ -10,7 +9,7 @@ import requests_mock
|
|||||||
from homeassistant import setup
|
from homeassistant import setup
|
||||||
import homeassistant.components.ring as ring
|
import homeassistant.components.ring as ring
|
||||||
|
|
||||||
from tests.common import get_test_config_dir, get_test_home_assistant, load_fixture
|
from tests.common import get_test_home_assistant, load_fixture
|
||||||
|
|
||||||
ATTRIBUTION = "Data provided by Ring.com"
|
ATTRIBUTION = "Data provided by Ring.com"
|
||||||
|
|
||||||
@ -22,21 +21,14 @@ VALID_CONFIG = {
|
|||||||
class TestRing(unittest.TestCase):
|
class TestRing(unittest.TestCase):
|
||||||
"""Tests the Ring component."""
|
"""Tests the Ring component."""
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
"""Cleanup any data created from the tests."""
|
|
||||||
if os.path.isfile(self.cache):
|
|
||||||
os.remove(self.cache)
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Initialize values for this test case class."""
|
"""Initialize values for this test case class."""
|
||||||
self.hass = get_test_home_assistant()
|
self.hass = get_test_home_assistant()
|
||||||
self.cache = get_test_config_dir(ring.DEFAULT_CACHEDB)
|
|
||||||
self.config = VALID_CONFIG
|
self.config = VALID_CONFIG
|
||||||
|
|
||||||
def tearDown(self): # pylint: disable=invalid-name
|
def tearDown(self): # pylint: disable=invalid-name
|
||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
self.cleanup()
|
|
||||||
|
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_setup(self, mock):
|
def test_setup(self, mock):
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""The tests for the Ring sensor platform."""
|
"""The tests for the Ring sensor platform."""
|
||||||
from asyncio import run_coroutine_threadsafe
|
from asyncio import run_coroutine_threadsafe
|
||||||
import os
|
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
@ -10,12 +9,7 @@ from homeassistant.components import ring as base_ring
|
|||||||
import homeassistant.components.ring.sensor as ring
|
import homeassistant.components.ring.sensor as ring
|
||||||
from homeassistant.helpers.icon import icon_for_battery_level
|
from homeassistant.helpers.icon import icon_for_battery_level
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import get_test_home_assistant, load_fixture, mock_storage
|
||||||
get_test_config_dir,
|
|
||||||
get_test_home_assistant,
|
|
||||||
load_fixture,
|
|
||||||
mock_storage,
|
|
||||||
)
|
|
||||||
from tests.components.ring.test_init import ATTRIBUTION, VALID_CONFIG
|
from tests.components.ring.test_init import ATTRIBUTION, VALID_CONFIG
|
||||||
|
|
||||||
|
|
||||||
@ -29,15 +23,9 @@ class TestRingSensorSetup(unittest.TestCase):
|
|||||||
for device in devices:
|
for device in devices:
|
||||||
self.DEVICES.append(device)
|
self.DEVICES.append(device)
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
"""Cleanup any data created from the tests."""
|
|
||||||
if os.path.isfile(self.cache):
|
|
||||||
os.remove(self.cache)
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Initialize values for this testcase class."""
|
"""Initialize values for this testcase class."""
|
||||||
self.hass = get_test_home_assistant()
|
self.hass = get_test_home_assistant()
|
||||||
self.cache = get_test_config_dir(base_ring.DEFAULT_CACHEDB)
|
|
||||||
self.config = {
|
self.config = {
|
||||||
"username": "foo",
|
"username": "foo",
|
||||||
"password": "bar",
|
"password": "bar",
|
||||||
@ -55,7 +43,6 @@ class TestRingSensorSetup(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Stop everything that was started."""
|
"""Stop everything that was started."""
|
||||||
self.hass.stop()
|
self.hass.stop()
|
||||||
self.cleanup()
|
|
||||||
|
|
||||||
@requests_mock.Mocker()
|
@requests_mock.Mocker()
|
||||||
def test_sensor(self, mock):
|
def test_sensor(self, mock):
|
||||||
@ -97,6 +84,13 @@ class TestRingSensorSetup(unittest.TestCase):
|
|||||||
).result()
|
).result()
|
||||||
|
|
||||||
for device in self.DEVICES:
|
for device in self.DEVICES:
|
||||||
|
# Mimick add to hass
|
||||||
|
device.hass = self.hass
|
||||||
|
run_coroutine_threadsafe(
|
||||||
|
device.async_added_to_hass(), self.hass.loop,
|
||||||
|
).result()
|
||||||
|
|
||||||
|
# Entity update data from ring data
|
||||||
device.update()
|
device.update()
|
||||||
if device.name == "Front Battery":
|
if device.name == "Front Battery":
|
||||||
expected_icon = icon_for_battery_level(
|
expected_icon = icon_for_battery_level(
|
||||||
@ -104,18 +98,12 @@ class TestRingSensorSetup(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
assert device.icon == expected_icon
|
assert device.icon == expected_icon
|
||||||
assert 80 == device.state
|
assert 80 == device.state
|
||||||
assert "hp_cam_v1" == device.device_state_attributes["kind"]
|
|
||||||
assert "stickup_cams" == device.device_state_attributes["type"]
|
|
||||||
if device.name == "Front Door Battery":
|
if device.name == "Front Door Battery":
|
||||||
assert 100 == device.state
|
assert 100 == device.state
|
||||||
assert "lpd_v1" == device.device_state_attributes["kind"]
|
|
||||||
assert "chimes" != device.device_state_attributes["type"]
|
|
||||||
if device.name == "Downstairs Volume":
|
if device.name == "Downstairs Volume":
|
||||||
assert 2 == device.state
|
assert 2 == device.state
|
||||||
assert "1.2.3" == device.device_state_attributes["firmware"]
|
|
||||||
assert "ring_mock_wifi" == device.device_state_attributes["wifi_name"]
|
assert "ring_mock_wifi" == device.device_state_attributes["wifi_name"]
|
||||||
assert "mdi:bell-ring" == device.icon
|
assert "mdi:bell-ring" == device.icon
|
||||||
assert "chimes" == device.device_state_attributes["type"]
|
|
||||||
if device.name == "Front Door Last Activity":
|
if device.name == "Front Door Last Activity":
|
||||||
assert not device.device_state_attributes["answered"]
|
assert not device.device_state_attributes["answered"]
|
||||||
assert "America/New_York" == device.device_state_attributes["timezone"]
|
assert "America/New_York" == device.device_state_attributes["timezone"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user