Add config flow for OpenUV (#16159)
* OpenUV config flow in place * Test folder in place * Owner-requested comments * Tests * More tests * Owner-requested changes (part 1 of 2) * Updated requirements * Owner-requested changes (2 of 2) * Removed unnecessary import * Bumping Travis * Updated requirements * More requirements * Updated tests * Owner-requested changes * Hound * Updated docstringpull/16382/merge
parent
7a6facc875
commit
f96aee2832
|
@ -123,7 +123,7 @@ omit =
|
|||
homeassistant/components/hangouts/const.py
|
||||
homeassistant/components/hangouts/hangouts_bot.py
|
||||
homeassistant/components/hangouts/hangups_utils.py
|
||||
homeassistant/components/*/hangouts.py
|
||||
homeassistant/components/*/hangouts.py
|
||||
|
||||
homeassistant/components/hdmi_cec.py
|
||||
homeassistant/components/*/hdmi_cec.py
|
||||
|
@ -145,12 +145,12 @@ omit =
|
|||
|
||||
homeassistant/components/ihc/*
|
||||
homeassistant/components/*/ihc.py
|
||||
|
||||
|
||||
homeassistant/components/insteon/*
|
||||
homeassistant/components/*/insteon.py
|
||||
|
||||
homeassistant/components/insteon_local.py
|
||||
|
||||
|
||||
homeassistant/components/insteon_plm.py
|
||||
|
||||
homeassistant/components/ios.py
|
||||
|
@ -228,7 +228,7 @@ omit =
|
|||
homeassistant/components/opencv.py
|
||||
homeassistant/components/*/opencv.py
|
||||
|
||||
homeassistant/components/openuv.py
|
||||
homeassistant/components/openuv/__init__.py
|
||||
homeassistant/components/*/openuv.py
|
||||
|
||||
homeassistant/components/pilight.py
|
||||
|
|
|
@ -7,12 +7,11 @@ https://home-assistant.io/components/binary_sensor.openuv/
|
|||
import logging
|
||||
|
||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||
from homeassistant.const import CONF_MONITORED_CONDITIONS
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.components.openuv import (
|
||||
BINARY_SENSORS, DATA_PROTECTION_WINDOW, DOMAIN, TOPIC_UPDATE,
|
||||
TYPE_PROTECTION_WINDOW, OpenUvEntity)
|
||||
BINARY_SENSORS, DATA_OPENUV_CLIENT, DATA_PROTECTION_WINDOW, DOMAIN,
|
||||
TOPIC_UPDATE, TYPE_PROTECTION_WINDOW, OpenUvEntity)
|
||||
from homeassistant.util.dt import as_local, parse_datetime, utcnow
|
||||
|
||||
DEPENDENCIES = ['openuv']
|
||||
|
@ -26,17 +25,20 @@ ATTR_PROTECTION_WINDOW_ENDING_UV = 'end_uv'
|
|||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the OpenUV binary sensor platform."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
"""Set up an OpenUV sensor based on existing config."""
|
||||
pass
|
||||
|
||||
openuv = hass.data[DOMAIN]
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Set up an OpenUV sensor based on a config entry."""
|
||||
openuv = hass.data[DOMAIN][DATA_OPENUV_CLIENT][entry.entry_id]
|
||||
|
||||
binary_sensors = []
|
||||
for sensor_type in discovery_info[CONF_MONITORED_CONDITIONS]:
|
||||
for sensor_type in openuv.binary_sensor_conditions:
|
||||
name, icon = BINARY_SENSORS[sensor_type]
|
||||
binary_sensors.append(
|
||||
OpenUvBinarySensor(openuv, sensor_type, name, icon))
|
||||
OpenUvBinarySensor(
|
||||
openuv, sensor_type, name, icon, entry.entry_id))
|
||||
|
||||
async_add_entities(binary_sensors, True)
|
||||
|
||||
|
@ -44,14 +46,16 @@ async def async_setup_platform(
|
|||
class OpenUvBinarySensor(OpenUvEntity, BinarySensorDevice):
|
||||
"""Define a binary sensor for OpenUV."""
|
||||
|
||||
def __init__(self, openuv, sensor_type, name, icon):
|
||||
def __init__(self, openuv, sensor_type, name, icon, entry_id):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(openuv)
|
||||
|
||||
self._entry_id = entry_id
|
||||
self._icon = icon
|
||||
self._latitude = openuv.client.latitude
|
||||
self._longitude = openuv.client.longitude
|
||||
self._name = name
|
||||
self._dispatch_remove = None
|
||||
self._sensor_type = sensor_type
|
||||
self._state = None
|
||||
|
||||
|
@ -83,8 +87,9 @@ class OpenUvBinarySensor(OpenUvEntity, BinarySensorDevice):
|
|||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
async_dispatcher_connect(
|
||||
self._dispatch_remove = async_dispatcher_connect(
|
||||
self.hass, TOPIC_UPDATE, self._update_data)
|
||||
self.async_on_remove(self._dispatch_remove)
|
||||
|
||||
async def async_update(self):
|
||||
"""Update the state."""
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"config": {
|
||||
"error": {
|
||||
"identifier_exists": "Coordinates already registered",
|
||||
"invalid_api_key": "Invalid API key"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"api_key": "OpenUV API Key",
|
||||
"elevation": "Elevation",
|
||||
"latitude": "Latitude",
|
||||
"longitude": "Longitude"
|
||||
},
|
||||
"title": "Fill in your information"
|
||||
}
|
||||
},
|
||||
"title": "OpenUV"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Support for data from openuv.io.
|
||||
Support for UV data from openuv.io.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/openuv/
|
||||
|
@ -9,21 +9,24 @@ from datetime import timedelta
|
|||
|
||||
import voluptuous as vol
|
||||
|
||||
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)
|
||||
from homeassistant.helpers import (
|
||||
aiohttp_client, config_validation as cv, discovery)
|
||||
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
|
||||
|
||||
REQUIREMENTS = ['pyopenuv==1.0.1']
|
||||
from .config_flow import configured_instances
|
||||
from .const import DOMAIN
|
||||
|
||||
REQUIREMENTS = ['pyopenuv==1.0.4']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = 'openuv'
|
||||
|
||||
DATA_OPENUV_CLIENT = 'data_client'
|
||||
DATA_OPENUV_LISTENER = 'data_listener'
|
||||
DATA_PROTECTION_WINDOW = 'protection_window'
|
||||
DATA_UV = 'uv'
|
||||
|
||||
|
@ -82,39 +85,77 @@ SENSOR_SCHEMA = vol.Schema({
|
|||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
vol.Optional(CONF_ELEVATION): float,
|
||||
vol.Optional(CONF_LATITUDE): cv.latitude,
|
||||
vol.Optional(CONF_LONGITUDE): cv.longitude,
|
||||
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,
|
||||
})
|
||||
DOMAIN:
|
||||
vol.Schema({
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
vol.Optional(CONF_ELEVATION): float,
|
||||
vol.Optional(CONF_LATITUDE): cv.latitude,
|
||||
vol.Optional(CONF_LONGITUDE): cv.longitude,
|
||||
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)
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the OpenUV component."""
|
||||
from pyopenuv import Client
|
||||
from pyopenuv.errors import OpenUvError
|
||||
hass.data[DOMAIN] = {}
|
||||
hass.data[DOMAIN][DATA_OPENUV_CLIENT] = {}
|
||||
hass.data[DOMAIN][DATA_OPENUV_LISTENER] = {}
|
||||
|
||||
if DOMAIN not in config:
|
||||
return True
|
||||
|
||||
conf = config[DOMAIN]
|
||||
api_key = conf[CONF_API_KEY]
|
||||
elevation = conf.get(CONF_ELEVATION, hass.config.elevation)
|
||||
latitude = conf.get(CONF_LATITUDE, hass.config.latitude)
|
||||
longitude = conf.get(CONF_LONGITUDE, hass.config.longitude)
|
||||
elevation = conf.get(CONF_ELEVATION, hass.config.elevation)
|
||||
|
||||
identifier = '{0}, {1}'.format(latitude, longitude)
|
||||
|
||||
if identifier not in configured_instances(hass):
|
||||
hass.async_add_job(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={'source': SOURCE_IMPORT},
|
||||
data={
|
||||
CONF_API_KEY: conf[CONF_API_KEY],
|
||||
CONF_LATITUDE: latitude,
|
||||
CONF_LONGITUDE: longitude,
|
||||
CONF_ELEVATION: elevation,
|
||||
CONF_BINARY_SENSORS: conf[CONF_BINARY_SENSORS],
|
||||
CONF_SENSORS: conf[CONF_SENSORS],
|
||||
}))
|
||||
|
||||
hass.data[DOMAIN][CONF_SCAN_INTERVAL] = conf[CONF_SCAN_INTERVAL]
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry):
|
||||
"""Set up OpenUV as config entry."""
|
||||
from pyopenuv import Client
|
||||
from pyopenuv.errors import OpenUvError
|
||||
|
||||
try:
|
||||
websession = aiohttp_client.async_get_clientsession(hass)
|
||||
openuv = OpenUV(
|
||||
Client(
|
||||
api_key, latitude, longitude, websession, altitude=elevation),
|
||||
conf[CONF_BINARY_SENSORS][CONF_MONITORED_CONDITIONS] +
|
||||
conf[CONF_SENSORS][CONF_MONITORED_CONDITIONS])
|
||||
config_entry.data[CONF_API_KEY],
|
||||
config_entry.data.get(CONF_LATITUDE, hass.config.latitude),
|
||||
config_entry.data.get(CONF_LONGITUDE, hass.config.longitude),
|
||||
websession,
|
||||
altitude=config_entry.data.get(
|
||||
CONF_ELEVATION, hass.config.elevation)),
|
||||
config_entry.data.get(CONF_BINARY_SENSORS, {}).get(
|
||||
CONF_MONITORED_CONDITIONS, list(BINARY_SENSORS)),
|
||||
config_entry.data.get(CONF_SENSORS, {}).get(
|
||||
CONF_MONITORED_CONDITIONS, list(SENSORS)))
|
||||
await openuv.async_update()
|
||||
hass.data[DOMAIN] = openuv
|
||||
hass.data[DOMAIN][DATA_OPENUV_CLIENT][config_entry.entry_id] = openuv
|
||||
except OpenUvError as err:
|
||||
_LOGGER.error('An error occurred: %s', str(err))
|
||||
hass.components.persistent_notification.create(
|
||||
|
@ -125,13 +166,9 @@ async def async_setup(hass, config):
|
|||
notification_id=NOTIFICATION_ID)
|
||||
return False
|
||||
|
||||
for component, schema in [
|
||||
('binary_sensor', conf[CONF_BINARY_SENSORS]),
|
||||
('sensor', conf[CONF_SENSORS]),
|
||||
]:
|
||||
hass.async_create_task(
|
||||
discovery.async_load_platform(
|
||||
hass, component, DOMAIN, schema, config))
|
||||
for component in ('binary_sensor', 'sensor'):
|
||||
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
|
||||
config_entry, component))
|
||||
|
||||
async def refresh_sensors(event_time):
|
||||
"""Refresh OpenUV data."""
|
||||
|
@ -139,7 +176,25 @@ async def async_setup(hass, config):
|
|||
await openuv.async_update()
|
||||
async_dispatcher_send(hass, TOPIC_UPDATE)
|
||||
|
||||
async_track_time_interval(hass, refresh_sensors, conf[CONF_SCAN_INTERVAL])
|
||||
hass.data[DOMAIN][DATA_OPENUV_LISTENER][
|
||||
config_entry.entry_id] = async_track_time_interval(
|
||||
hass, refresh_sensors,
|
||||
hass.data[DOMAIN][CONF_SCAN_INTERVAL])
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass, config_entry):
|
||||
"""Unload an OpenUV config entry."""
|
||||
for component in ('binary_sensor', 'sensor'):
|
||||
await hass.config_entries.async_forward_entry_unload(
|
||||
config_entry, component)
|
||||
|
||||
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()
|
||||
|
||||
return True
|
||||
|
||||
|
@ -147,19 +202,20 @@ async def async_setup(hass, config):
|
|||
class OpenUV:
|
||||
"""Define a generic OpenUV object."""
|
||||
|
||||
def __init__(self, client, monitored_conditions):
|
||||
def __init__(self, client, binary_sensor_conditions, sensor_conditions):
|
||||
"""Initialize."""
|
||||
self._monitored_conditions = monitored_conditions
|
||||
self.binary_sensor_conditions = binary_sensor_conditions
|
||||
self.client = client
|
||||
self.data = {}
|
||||
self.sensor_conditions = sensor_conditions
|
||||
|
||||
async def async_update(self):
|
||||
"""Update sensor/binary sensor data."""
|
||||
if TYPE_PROTECTION_WINDOW in self._monitored_conditions:
|
||||
if TYPE_PROTECTION_WINDOW in self.binary_sensor_conditions:
|
||||
data = await self.client.uv_protection_window()
|
||||
self.data[DATA_PROTECTION_WINDOW] = data
|
||||
|
||||
if any(c in self._monitored_conditions for c in SENSORS):
|
||||
if any(c in self.sensor_conditions for c in SENSORS):
|
||||
data = await self.client.uv_index()
|
||||
self.data[DATA_UV] = data
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
"""Config flow to configure the OpenUV component."""
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY, CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE)
|
||||
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
@callback
|
||||
def configured_instances(hass):
|
||||
"""Return a set of configured OpenUV instances."""
|
||||
return set(
|
||||
'{0}, {1}'.format(
|
||||
entry.data[CONF_LATITUDE], entry.data[CONF_LONGITUDE])
|
||||
for entry in hass.config_entries.async_entries(DOMAIN))
|
||||
|
||||
|
||||
@config_entries.HANDLERS.register(DOMAIN)
|
||||
class OpenUvFlowHandler(data_entry_flow.FlowHandler):
|
||||
"""Handle an OpenUV config flow."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the config flow."""
|
||||
pass
|
||||
|
||||
async def async_step_import(self, import_config):
|
||||
"""Import a config entry from configuration.yaml."""
|
||||
return await self.async_step_user(import_config)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle the start of the config flow."""
|
||||
from pyopenuv.util import validate_api_key
|
||||
|
||||
errors = {}
|
||||
|
||||
if user_input is not None:
|
||||
identifier = '{0}, {1}'.format(
|
||||
user_input.get(CONF_LATITUDE, self.hass.config.latitude),
|
||||
user_input.get(CONF_LONGITUDE, self.hass.config.longitude))
|
||||
|
||||
if identifier in configured_instances(self.hass):
|
||||
errors['base'] = 'identifier_exists'
|
||||
else:
|
||||
websession = aiohttp_client.async_get_clientsession(self.hass)
|
||||
api_key_validation = await validate_api_key(
|
||||
user_input[CONF_API_KEY], websession)
|
||||
if api_key_validation:
|
||||
return self.async_create_entry(
|
||||
title=identifier,
|
||||
data=user_input,
|
||||
)
|
||||
errors['base'] = 'invalid_api_key'
|
||||
|
||||
data_schema = OrderedDict()
|
||||
data_schema[vol.Required(CONF_API_KEY)] = str
|
||||
data_schema[vol.Optional(CONF_LATITUDE)] = cv.latitude
|
||||
data_schema[vol.Optional(CONF_LONGITUDE)] = cv.longitude
|
||||
data_schema[vol.Optional(CONF_ELEVATION)] = vol.Coerce(float)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id='user',
|
||||
data_schema=vol.Schema(data_schema),
|
||||
errors=errors,
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
"""Define constants for the OpenUV component."""
|
||||
|
||||
DOMAIN = 'openuv'
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"config": {
|
||||
"title": "OpenUV",
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Fill in your information",
|
||||
"data": {
|
||||
"api_key": "OpenUV API Key",
|
||||
"elevation": "Elevation",
|
||||
"latitude": "Latitude",
|
||||
"longitude": "Longitude"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"identifier_exists": "Coordinates already registered",
|
||||
"invalid_api_key": "Invalid API key"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,13 +6,12 @@ https://home-assistant.io/components/sensor.openuv/
|
|||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.const import CONF_MONITORED_CONDITIONS
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.components.openuv import (
|
||||
DATA_UV, DOMAIN, SENSORS, TOPIC_UPDATE, TYPE_CURRENT_OZONE_LEVEL,
|
||||
TYPE_CURRENT_UV_INDEX, TYPE_CURRENT_UV_LEVEL, TYPE_MAX_UV_INDEX,
|
||||
TYPE_SAFE_EXPOSURE_TIME_1, TYPE_SAFE_EXPOSURE_TIME_2,
|
||||
DATA_OPENUV_CLIENT, DATA_UV, DOMAIN, SENSORS, TOPIC_UPDATE,
|
||||
TYPE_CURRENT_OZONE_LEVEL, TYPE_CURRENT_UV_INDEX, TYPE_CURRENT_UV_LEVEL,
|
||||
TYPE_MAX_UV_INDEX, TYPE_SAFE_EXPOSURE_TIME_1, TYPE_SAFE_EXPOSURE_TIME_2,
|
||||
TYPE_SAFE_EXPOSURE_TIME_3, TYPE_SAFE_EXPOSURE_TIME_4,
|
||||
TYPE_SAFE_EXPOSURE_TIME_5, TYPE_SAFE_EXPOSURE_TIME_6, OpenUvEntity)
|
||||
from homeassistant.util.dt import as_local, parse_datetime
|
||||
|
@ -40,16 +39,20 @@ UV_LEVEL_LOW = "Low"
|
|||
|
||||
async def async_setup_platform(
|
||||
hass, config, async_add_entities, discovery_info=None):
|
||||
"""Set up the OpenUV binary sensor platform."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
"""Set up an OpenUV sensor based on existing config."""
|
||||
pass
|
||||
|
||||
openuv = hass.data[DOMAIN]
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Set up a Nest sensor based on a config entry."""
|
||||
openuv = hass.data[DOMAIN][DATA_OPENUV_CLIENT][entry.entry_id]
|
||||
|
||||
sensors = []
|
||||
for sensor_type in discovery_info[CONF_MONITORED_CONDITIONS]:
|
||||
for sensor_type in openuv.sensor_conditions:
|
||||
name, icon, unit = SENSORS[sensor_type]
|
||||
sensors.append(OpenUvSensor(openuv, sensor_type, name, icon, unit))
|
||||
sensors.append(
|
||||
OpenUvSensor(
|
||||
openuv, sensor_type, name, icon, unit, entry.entry_id))
|
||||
|
||||
async_add_entities(sensors, True)
|
||||
|
||||
|
@ -57,10 +60,12 @@ async def async_setup_platform(
|
|||
class OpenUvSensor(OpenUvEntity):
|
||||
"""Define a binary sensor for OpenUV."""
|
||||
|
||||
def __init__(self, openuv, sensor_type, name, icon, unit):
|
||||
def __init__(self, openuv, sensor_type, name, icon, unit, entry_id):
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(openuv)
|
||||
|
||||
self._dispatch_remove = None
|
||||
self._entry_id = entry_id
|
||||
self._icon = icon
|
||||
self._latitude = openuv.client.latitude
|
||||
self._longitude = openuv.client.longitude
|
||||
|
@ -102,7 +107,9 @@ class OpenUvSensor(OpenUvEntity):
|
|||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register callbacks."""
|
||||
async_dispatcher_connect(self.hass, TOPIC_UPDATE, self._update_data)
|
||||
self._dispatch_remove = async_dispatcher_connect(
|
||||
self.hass, TOPIC_UPDATE, self._update_data)
|
||||
self.async_on_remove(self._dispatch_remove)
|
||||
|
||||
async def async_update(self):
|
||||
"""Update the state."""
|
||||
|
@ -125,8 +132,7 @@ class OpenUvSensor(OpenUvEntity):
|
|||
elif self._sensor_type == TYPE_MAX_UV_INDEX:
|
||||
self._state = data['uv_max']
|
||||
self._attrs.update({
|
||||
ATTR_MAX_UV_TIME: as_local(
|
||||
parse_datetime(data['uv_max_time']))
|
||||
ATTR_MAX_UV_TIME: as_local(parse_datetime(data['uv_max_time']))
|
||||
})
|
||||
elif self._sensor_type in (TYPE_SAFE_EXPOSURE_TIME_1,
|
||||
TYPE_SAFE_EXPOSURE_TIME_2,
|
||||
|
|
|
@ -141,6 +141,7 @@ FLOWS = [
|
|||
'homematicip_cloud',
|
||||
'hue',
|
||||
'nest',
|
||||
'openuv',
|
||||
'sonos',
|
||||
'zone',
|
||||
]
|
||||
|
|
|
@ -990,7 +990,7 @@ pynut2==2.1.2
|
|||
pynx584==0.4
|
||||
|
||||
# homeassistant.components.openuv
|
||||
pyopenuv==1.0.1
|
||||
pyopenuv==1.0.4
|
||||
|
||||
# homeassistant.components.iota
|
||||
pyota==2.0.5
|
||||
|
|
|
@ -154,6 +154,9 @@ pymonoprice==0.3
|
|||
# homeassistant.components.binary_sensor.nx584
|
||||
pynx584==0.4
|
||||
|
||||
# homeassistant.components.openuv
|
||||
pyopenuv==1.0.4
|
||||
|
||||
# homeassistant.auth.mfa_modules.totp
|
||||
# homeassistant.components.sensor.otp
|
||||
pyotp==2.2.6
|
||||
|
|
|
@ -78,6 +78,7 @@ TEST_REQUIREMENTS = (
|
|||
'pylitejet',
|
||||
'pymonoprice',
|
||||
'pynx584',
|
||||
'pyopenuv',
|
||||
'pyotp',
|
||||
'pyqwikswitch',
|
||||
'PyRMVtransport',
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
"""Define tests for the OpenUV component."""
|
|
@ -0,0 +1,93 @@
|
|||
"""Define tests for the OpenUV config flow."""
|
||||
from unittest.mock import patch
|
||||
|
||||
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)
|
||||
|
||||
from tests.common import MockConfigEntry, mock_coro
|
||||
|
||||
|
||||
async def test_duplicate_error(hass):
|
||||
"""Test that errors are shown when duplicates are added."""
|
||||
conf = {
|
||||
CONF_API_KEY: '12345abcde',
|
||||
CONF_ELEVATION: 59.1234,
|
||||
CONF_LATITUDE: 39.128712,
|
||||
CONF_LONGITUDE: -104.9812612,
|
||||
}
|
||||
|
||||
MockConfigEntry(domain=DOMAIN, data=conf).add_to_hass(hass)
|
||||
flow = config_flow.OpenUvFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_user(user_input=conf)
|
||||
assert result['errors'] == {'base': 'identifier_exists'}
|
||||
|
||||
|
||||
@patch('pyopenuv.util.validate_api_key', return_value=mock_coro(False))
|
||||
async def test_invalid_api_key(hass):
|
||||
"""Test that an invalid API key throws an error."""
|
||||
conf = {
|
||||
CONF_API_KEY: '12345abcde',
|
||||
CONF_ELEVATION: 59.1234,
|
||||
CONF_LATITUDE: 39.128712,
|
||||
CONF_LONGITUDE: -104.9812612,
|
||||
}
|
||||
|
||||
flow = config_flow.OpenUvFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_user(user_input=conf)
|
||||
assert result['errors'] == {'base': 'invalid_api_key'}
|
||||
|
||||
|
||||
async def test_show_form(hass):
|
||||
"""Test that the form is served with no input."""
|
||||
flow = config_flow.OpenUvFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_user(user_input=None)
|
||||
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result['step_id'] == 'user'
|
||||
|
||||
|
||||
@patch('pyopenuv.util.validate_api_key', return_value=mock_coro(True))
|
||||
async def test_step_import(hass):
|
||||
"""Test that the import step works."""
|
||||
conf = {
|
||||
CONF_API_KEY: '12345abcde',
|
||||
}
|
||||
|
||||
flow = config_flow.OpenUvFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_import(import_config=conf)
|
||||
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result['title'] == '{0}, {1}'.format(
|
||||
hass.config.latitude, hass.config.longitude)
|
||||
assert result['data'] == conf
|
||||
|
||||
|
||||
@patch('pyopenuv.util.validate_api_key', return_value=mock_coro(True))
|
||||
async def test_step_user(hass):
|
||||
"""Test that the user step works."""
|
||||
conf = {
|
||||
CONF_API_KEY: '12345abcde',
|
||||
CONF_ELEVATION: 59.1234,
|
||||
CONF_LATITUDE: 39.128712,
|
||||
CONF_LONGITUDE: -104.9812612,
|
||||
}
|
||||
|
||||
flow = config_flow.OpenUvFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_user(user_input=conf)
|
||||
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result['title'] == '{0}, {1}'.format(
|
||||
conf[CONF_LATITUDE], conf[CONF_LONGITUDE])
|
||||
assert result['data'] == conf
|
Loading…
Reference in New Issue