diff --git a/homeassistant/components/openuv/__init__.py b/homeassistant/components/openuv/__init__.py index bc29910a196..32c3da0d3e5 100644 --- a/homeassistant/components/openuv/__init__.py +++ b/homeassistant/components/openuv/__init__.py @@ -5,7 +5,6 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/openuv/ """ import logging -from datetime import timedelta import voluptuous as vol @@ -13,15 +12,14 @@ from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import ( ATTR_ATTRIBUTION, CONF_API_KEY, CONF_BINARY_SENSORS, CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE, CONF_MONITORED_CONDITIONS, - CONF_SCAN_INTERVAL, CONF_SENSORS) + CONF_SENSORS) from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import aiohttp_client, config_validation as cv from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity import Entity -from homeassistant.helpers.event import async_track_time_interval from .config_flow import configured_instances -from .const import DEFAULT_SCAN_INTERVAL, DOMAIN +from .const import DOMAIN REQUIREMENTS = ['pyopenuv==1.0.4'] _LOGGER = logging.getLogger(__name__) @@ -93,8 +91,6 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_BINARY_SENSORS, default={}): BINARY_SENSOR_SCHEMA, vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA, - vol.Optional(CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL): - cv.time_period, }) }, extra=vol.ALLOW_EXTRA) @@ -120,7 +116,6 @@ async def async_setup(hass, config): CONF_API_KEY: conf[CONF_API_KEY], CONF_BINARY_SENSORS: conf[CONF_BINARY_SENSORS], CONF_SENSORS: conf[CONF_SENSORS], - CONF_SCAN_INTERVAL: conf[CONF_SCAN_INTERVAL], } if CONF_LATITUDE in conf: @@ -167,17 +162,13 @@ async def async_setup_entry(hass, config_entry): hass.config_entries.async_forward_entry_setup( config_entry, component)) - async def refresh(event_time): + async def update_data(service): """Refresh OpenUV data.""" _LOGGER.debug('Refreshing OpenUV data') await openuv.async_update() async_dispatcher_send(hass, TOPIC_UPDATE) - hass.data[DOMAIN][DATA_OPENUV_LISTENER][ - config_entry.entry_id] = async_track_time_interval( - hass, - refresh, - timedelta(seconds=config_entry.data[CONF_SCAN_INTERVAL])) + hass.services.async_register(DOMAIN, 'update_data', update_data) return True @@ -186,10 +177,6 @@ async def async_unload_entry(hass, config_entry): """Unload an OpenUV config entry.""" hass.data[DOMAIN][DATA_OPENUV_CLIENT].pop(config_entry.entry_id) - remove_listener = hass.data[DOMAIN][DATA_OPENUV_LISTENER].pop( - config_entry.entry_id) - remove_listener() - for component in ('binary_sensor', 'sensor'): await hass.config_entries.async_forward_entry_unload( config_entry, component) diff --git a/homeassistant/components/openuv/config_flow.py b/homeassistant/components/openuv/config_flow.py index 11301baf5c5..0f566e5a9ef 100644 --- a/homeassistant/components/openuv/config_flow.py +++ b/homeassistant/components/openuv/config_flow.py @@ -5,11 +5,10 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.core import callback from homeassistant.const import ( - CONF_API_KEY, CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE, - CONF_SCAN_INTERVAL) + CONF_API_KEY, CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE) from homeassistant.helpers import aiohttp_client, config_validation as cv -from .const import DEFAULT_SCAN_INTERVAL, DOMAIN +from .const import DOMAIN @callback @@ -54,7 +53,8 @@ class OpenUvFlowHandler(config_entries.ConfigFlow): async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" - from pyopenuv.util import validate_api_key + from pyopenuv import Client + from pyopenuv.errors import OpenUvError if not user_input: return await self._show_form() @@ -66,14 +66,11 @@ class OpenUvFlowHandler(config_entries.ConfigFlow): return await self._show_form({CONF_LATITUDE: 'identifier_exists'}) websession = aiohttp_client.async_get_clientsession(self.hass) - api_key_validation = await validate_api_key( - user_input[CONF_API_KEY], websession) + client = Client(user_input[CONF_API_KEY], 0, 0, websession) - if not api_key_validation: + try: + await client.uv_index() + except OpenUvError: return await self._show_form({CONF_API_KEY: 'invalid_api_key'}) - scan_interval = user_input.get( - CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) - user_input[CONF_SCAN_INTERVAL] = scan_interval.seconds - return self.async_create_entry(title=identifier, data=user_input) diff --git a/homeassistant/components/openuv/const.py b/homeassistant/components/openuv/const.py index 16623e45642..a8c7fcc0ef5 100644 --- a/homeassistant/components/openuv/const.py +++ b/homeassistant/components/openuv/const.py @@ -1,6 +1,2 @@ """Define constants for the OpenUV component.""" -from datetime import timedelta - DOMAIN = 'openuv' - -DEFAULT_SCAN_INTERVAL = timedelta(minutes=30) diff --git a/homeassistant/components/openuv/services.yaml b/homeassistant/components/openuv/services.yaml new file mode 100644 index 00000000000..f353c7f4774 --- /dev/null +++ b/homeassistant/components/openuv/services.yaml @@ -0,0 +1,5 @@ +# Describes the format for available OpenUV services + +--- +update_data: + description: Request new data from OpenUV. diff --git a/tests/components/openuv/test_config_flow.py b/tests/components/openuv/test_config_flow.py index 60aa990333f..21e3db7df4f 100644 --- a/tests/components/openuv/test_config_flow.py +++ b/tests/components/openuv/test_config_flow.py @@ -1,14 +1,27 @@ """Define tests for the OpenUV config flow.""" -from datetime import timedelta -from unittest.mock import patch +import pytest +from pyopenuv.errors import OpenUvError from homeassistant import data_entry_flow from homeassistant.components.openuv import DOMAIN, config_flow from homeassistant.const import ( - CONF_API_KEY, CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE, - CONF_SCAN_INTERVAL) + CONF_API_KEY, CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE) -from tests.common import MockConfigEntry, mock_coro +from tests.common import MockConfigEntry, MockDependency, mock_coro + + +@pytest.fixture +def uv_index_response(): + """Define a fixture for a successful /uv response.""" + return mock_coro() + + +@pytest.fixture +def mock_pyopenuv(uv_index_response): + """Mock the pyopenuv library.""" + with MockDependency('pyopenuv') as mock_pyopenuv_: + mock_pyopenuv_.Client().uv_index.return_value = uv_index_response + yield mock_pyopenuv_ async def test_duplicate_error(hass): @@ -28,7 +41,9 @@ async def test_duplicate_error(hass): assert result['errors'] == {CONF_LATITUDE: 'identifier_exists'} -async def test_invalid_api_key(hass): +@pytest.mark.parametrize( + 'uv_index_response', [mock_coro(exception=OpenUvError)]) +async def test_invalid_api_key(hass, mock_pyopenuv): """Test that an invalid API key throws an error.""" conf = { CONF_API_KEY: '12345abcde', @@ -40,10 +55,8 @@ async def test_invalid_api_key(hass): flow = config_flow.OpenUvFlowHandler() flow.hass = hass - with patch('pyopenuv.util.validate_api_key', - return_value=mock_coro(False)): - result = await flow.async_step_user(user_input=conf) - assert result['errors'] == {CONF_API_KEY: 'invalid_api_key'} + result = await flow.async_step_user(user_input=conf) + assert result['errors'] == {CONF_API_KEY: 'invalid_api_key'} async def test_show_form(hass): @@ -57,7 +70,7 @@ async def test_show_form(hass): assert result['step_id'] == 'user' -async def test_step_import(hass): +async def test_step_import(hass, mock_pyopenuv): """Test that the import step works.""" conf = { CONF_API_KEY: '12345abcde', @@ -69,44 +82,35 @@ async def test_step_import(hass): flow = config_flow.OpenUvFlowHandler() flow.hass = hass - with patch('pyopenuv.util.validate_api_key', - return_value=mock_coro(True)): - result = await flow.async_step_import(import_config=conf) - - assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result['title'] == '39.128712, -104.9812612' - assert result['data'] == { - CONF_API_KEY: '12345abcde', - CONF_ELEVATION: 59.1234, - CONF_LATITUDE: 39.128712, - CONF_LONGITUDE: -104.9812612, - CONF_SCAN_INTERVAL: 1800, - } + result = await flow.async_step_import(import_config=conf) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['title'] == '39.128712, -104.9812612' + assert result['data'] == { + CONF_API_KEY: '12345abcde', + CONF_ELEVATION: 59.1234, + CONF_LATITUDE: 39.128712, + CONF_LONGITUDE: -104.9812612, + } -async def test_step_user(hass): +async def test_step_user(hass, mock_pyopenuv): """Test that the user step works.""" conf = { CONF_API_KEY: '12345abcde', CONF_ELEVATION: 59.1234, CONF_LATITUDE: 39.128712, CONF_LONGITUDE: -104.9812612, - CONF_SCAN_INTERVAL: timedelta(minutes=5) } flow = config_flow.OpenUvFlowHandler() flow.hass = hass - with patch('pyopenuv.util.validate_api_key', - return_value=mock_coro(True)): - result = await flow.async_step_user(user_input=conf) - - assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result['title'] == '39.128712, -104.9812612' - assert result['data'] == { - CONF_API_KEY: '12345abcde', - CONF_ELEVATION: 59.1234, - CONF_LATITUDE: 39.128712, - CONF_LONGITUDE: -104.9812612, - CONF_SCAN_INTERVAL: 300, - } + result = await flow.async_step_user(user_input=conf) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['title'] == '39.128712, -104.9812612' + assert result['data'] == { + CONF_API_KEY: '12345abcde', + CONF_ELEVATION: 59.1234, + CONF_LATITUDE: 39.128712, + CONF_LONGITUDE: -104.9812612, + }