Add ability to configure OpenUV "protection window" UV indices (#54562)
This commit is contained in:
parent
289734c748
commit
24d017f974
6 changed files with 126 additions and 5 deletions
|
@ -28,10 +28,14 @@ from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.service import verify_domain_control
|
from homeassistant.helpers.service import verify_domain_control
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
|
CONF_FROM_WINDOW,
|
||||||
|
CONF_TO_WINDOW,
|
||||||
DATA_CLIENT,
|
DATA_CLIENT,
|
||||||
DATA_LISTENER,
|
DATA_LISTENER,
|
||||||
DATA_PROTECTION_WINDOW,
|
DATA_PROTECTION_WINDOW,
|
||||||
DATA_UV,
|
DATA_UV,
|
||||||
|
DEFAULT_FROM_WINDOW,
|
||||||
|
DEFAULT_TO_WINDOW,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
LOGGER,
|
LOGGER,
|
||||||
)
|
)
|
||||||
|
@ -55,13 +59,14 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||||
try:
|
try:
|
||||||
websession = aiohttp_client.async_get_clientsession(hass)
|
websession = aiohttp_client.async_get_clientsession(hass)
|
||||||
openuv = OpenUV(
|
openuv = OpenUV(
|
||||||
|
config_entry,
|
||||||
Client(
|
Client(
|
||||||
config_entry.data[CONF_API_KEY],
|
config_entry.data[CONF_API_KEY],
|
||||||
config_entry.data.get(CONF_LATITUDE, hass.config.latitude),
|
config_entry.data.get(CONF_LATITUDE, hass.config.latitude),
|
||||||
config_entry.data.get(CONF_LONGITUDE, hass.config.longitude),
|
config_entry.data.get(CONF_LONGITUDE, hass.config.longitude),
|
||||||
altitude=config_entry.data.get(CONF_ELEVATION, hass.config.elevation),
|
altitude=config_entry.data.get(CONF_ELEVATION, hass.config.elevation),
|
||||||
session=websession,
|
session=websession,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
await openuv.async_update()
|
await openuv.async_update()
|
||||||
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = openuv
|
hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = openuv
|
||||||
|
@ -134,15 +139,19 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
|
||||||
class OpenUV:
|
class OpenUV:
|
||||||
"""Define a generic OpenUV object."""
|
"""Define a generic OpenUV object."""
|
||||||
|
|
||||||
def __init__(self, client: Client) -> None:
|
def __init__(self, config_entry: ConfigEntry, client: Client) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
|
self._config_entry = config_entry
|
||||||
self.client = client
|
self.client = client
|
||||||
self.data: dict[str, Any] = {}
|
self.data: dict[str, Any] = {}
|
||||||
|
|
||||||
async def async_update_protection_data(self) -> None:
|
async def async_update_protection_data(self) -> None:
|
||||||
"""Update binary sensor (protection window) data."""
|
"""Update binary sensor (protection window) data."""
|
||||||
|
low = self._config_entry.options.get(CONF_FROM_WINDOW, DEFAULT_FROM_WINDOW)
|
||||||
|
high = self._config_entry.options.get(CONF_TO_WINDOW, DEFAULT_TO_WINDOW)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp = await self.client.uv_protection_window()
|
resp = await self.client.uv_protection_window(low=low, high=high)
|
||||||
self.data[DATA_PROTECTION_WINDOW] = resp["result"]
|
self.data[DATA_PROTECTION_WINDOW] = resp["result"]
|
||||||
except OpenUvError as err:
|
except OpenUvError as err:
|
||||||
LOGGER.error("Error during protection data update: %s", err)
|
LOGGER.error("Error during protection data update: %s", err)
|
||||||
|
|
|
@ -8,16 +8,24 @@ from pyopenuv.errors import OpenUvError
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
CONF_ELEVATION,
|
CONF_ELEVATION,
|
||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
CONF_LONGITUDE,
|
CONF_LONGITUDE,
|
||||||
)
|
)
|
||||||
|
from homeassistant.core import callback
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import (
|
||||||
|
CONF_FROM_WINDOW,
|
||||||
|
CONF_TO_WINDOW,
|
||||||
|
DEFAULT_FROM_WINDOW,
|
||||||
|
DEFAULT_TO_WINDOW,
|
||||||
|
DOMAIN,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OpenUvFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
class OpenUvFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
@ -51,6 +59,12 @@ class OpenUvFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
errors=errors if errors else {},
|
errors=errors if errors else {},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@callback
|
||||||
|
def async_get_options_flow(config_entry: ConfigEntry) -> OpenUvOptionsFlowHandler:
|
||||||
|
"""Define the config flow to handle options."""
|
||||||
|
return OpenUvOptionsFlowHandler(config_entry)
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
|
@ -75,3 +89,42 @@ class OpenUvFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
return await self._show_form({CONF_API_KEY: "invalid_api_key"})
|
return await self._show_form({CONF_API_KEY: "invalid_api_key"})
|
||||||
|
|
||||||
return self.async_create_entry(title=identifier, data=user_input)
|
return self.async_create_entry(title=identifier, data=user_input)
|
||||||
|
|
||||||
|
|
||||||
|
class OpenUvOptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
|
"""Handle a OpenUV options flow."""
|
||||||
|
|
||||||
|
def __init__(self, config_entry: ConfigEntry) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
self.config_entry = config_entry
|
||||||
|
|
||||||
|
async def async_step_init(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Manage the options."""
|
||||||
|
if user_input is not None:
|
||||||
|
return self.async_create_entry(title="", data=user_input)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="init",
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Optional(
|
||||||
|
CONF_FROM_WINDOW,
|
||||||
|
description={
|
||||||
|
"suggested_value": self.config_entry.options.get(
|
||||||
|
CONF_FROM_WINDOW, DEFAULT_FROM_WINDOW
|
||||||
|
)
|
||||||
|
},
|
||||||
|
): vol.Coerce(float),
|
||||||
|
vol.Optional(
|
||||||
|
CONF_TO_WINDOW,
|
||||||
|
description={
|
||||||
|
"suggested_value": self.config_entry.options.get(
|
||||||
|
CONF_FROM_WINDOW, DEFAULT_TO_WINDOW
|
||||||
|
)
|
||||||
|
},
|
||||||
|
): vol.Coerce(float),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
|
@ -4,11 +4,17 @@ import logging
|
||||||
DOMAIN = "openuv"
|
DOMAIN = "openuv"
|
||||||
LOGGER = logging.getLogger(__package__)
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
|
CONF_FROM_WINDOW = "from_window"
|
||||||
|
CONF_TO_WINDOW = "to_window"
|
||||||
|
|
||||||
DATA_CLIENT = "data_client"
|
DATA_CLIENT = "data_client"
|
||||||
DATA_LISTENER = "data_listener"
|
DATA_LISTENER = "data_listener"
|
||||||
DATA_PROTECTION_WINDOW = "protection_window"
|
DATA_PROTECTION_WINDOW = "protection_window"
|
||||||
DATA_UV = "uv"
|
DATA_UV = "uv"
|
||||||
|
|
||||||
|
DEFAULT_FROM_WINDOW = 3.5
|
||||||
|
DEFAULT_TO_WINDOW = 3.5
|
||||||
|
|
||||||
TYPE_CURRENT_OZONE_LEVEL = "current_ozone_level"
|
TYPE_CURRENT_OZONE_LEVEL = "current_ozone_level"
|
||||||
TYPE_CURRENT_UV_INDEX = "current_uv_index"
|
TYPE_CURRENT_UV_INDEX = "current_uv_index"
|
||||||
TYPE_CURRENT_UV_LEVEL = "current_uv_level"
|
TYPE_CURRENT_UV_LEVEL = "current_uv_level"
|
||||||
|
|
|
@ -17,5 +17,16 @@
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_location%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_location%]"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"title": "Configure OpenUV",
|
||||||
|
"data": {
|
||||||
|
"from_window": "Starting UV index for the protection window",
|
||||||
|
"to_window": "Ending UV index for the protection window"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,5 +17,16 @@
|
||||||
"title": "Fill in your information"
|
"title": "Fill in your information"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"data": {
|
||||||
|
"from_window": "Starting UV index for the protection window",
|
||||||
|
"to_window": "Ending UV index for the protection window"
|
||||||
|
},
|
||||||
|
"title": "Configure OpenUV"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ from unittest.mock import patch
|
||||||
from pyopenuv.errors import InvalidApiKeyError
|
from pyopenuv.errors import InvalidApiKeyError
|
||||||
|
|
||||||
from homeassistant import data_entry_flow
|
from homeassistant import data_entry_flow
|
||||||
from homeassistant.components.openuv import DOMAIN
|
from homeassistant.components.openuv import CONF_FROM_WINDOW, CONF_TO_WINDOW, DOMAIN
|
||||||
from homeassistant.config_entries import SOURCE_USER
|
from homeassistant.config_entries import SOURCE_USER
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
|
@ -57,6 +57,37 @@ async def test_invalid_api_key(hass):
|
||||||
assert result["errors"] == {CONF_API_KEY: "invalid_api_key"}
|
assert result["errors"] == {CONF_API_KEY: "invalid_api_key"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_options_flow(hass):
|
||||||
|
"""Test config flow options."""
|
||||||
|
conf = {
|
||||||
|
CONF_API_KEY: "12345abcde",
|
||||||
|
CONF_ELEVATION: 59.1234,
|
||||||
|
CONF_LATITUDE: 39.128712,
|
||||||
|
CONF_LONGITUDE: -104.9812612,
|
||||||
|
}
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
unique_id="abcde12345",
|
||||||
|
data=conf,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
with patch("homeassistant.components.openuv.async_setup_entry", return_value=True):
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"], user_input={CONF_FROM_WINDOW: 3.5, CONF_TO_WINDOW: 2.0}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert config_entry.options == {CONF_FROM_WINDOW: 3.5, CONF_TO_WINDOW: 2.0}
|
||||||
|
|
||||||
|
|
||||||
async def test_step_user(hass):
|
async def test_step_user(hass):
|
||||||
"""Test that the user step works."""
|
"""Test that the user step works."""
|
||||||
conf = {
|
conf = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue