Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions homeassistant/components/met/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][config_entry.entry_id] = coordinator

config_entry.async_on_unload(config_entry.add_update_listener(async_update_entry))

await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)

return True
Expand All @@ -85,6 +87,11 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
return unload_ok


async def async_update_entry(hass: HomeAssistant, config_entry: ConfigEntry):
"""Reload Met component when options changed."""
await hass.config_entries.async_reload(config_entry.entry_id)


class CannotConnect(HomeAssistantError):
"""Unable to connect to the web site."""

Expand Down
98 changes: 73 additions & 25 deletions homeassistant/components/met/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,46 @@ def configured_instances(hass: HomeAssistant) -> set[str]:
return set(entries)


class MetFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
def _get_data_schema(
hass: HomeAssistant, config_entry: config_entries.ConfigEntry | None = None
) -> vol.Schema:
"""Get a schema with default values."""
# If tracking home or no config entry is passed in, default value come from Home location
if config_entry is None or config_entry.data.get(CONF_TRACK_HOME, False):
return vol.Schema(
{
vol.Required(CONF_NAME, default=HOME_LOCATION_NAME): str,
vol.Required(CONF_LATITUDE, default=hass.config.latitude): cv.latitude,
vol.Required(
CONF_LONGITUDE, default=hass.config.longitude
): cv.longitude,
vol.Required(CONF_ELEVATION, default=hass.config.elevation): int,
}
)
# Not tracking home, default values come from config entry
return vol.Schema(
{
vol.Required(CONF_NAME, default=config_entry.data.get(CONF_NAME)): str,
vol.Required(
CONF_LATITUDE, default=config_entry.data.get(CONF_LATITUDE)
): cv.latitude,
vol.Required(
CONF_LONGITUDE, default=config_entry.data.get(CONF_LONGITUDE)
): cv.longitude,
vol.Required(
CONF_ELEVATION, default=config_entry.data.get(CONF_ELEVATION)
): int,
}
)


class MetConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Config flow for Met component."""

VERSION = 1

def __init__(self) -> None:
"""Init MetFlowHandler."""
"""Init MetConfigFlowHandler."""
self._errors: dict[str, Any] = {}

async def async_step_user(
Expand All @@ -59,31 +92,9 @@ async def async_step_user(
)
self._errors[CONF_NAME] = "already_configured"

return await self._show_config_form(
name=HOME_LOCATION_NAME,
latitude=self.hass.config.latitude,
longitude=self.hass.config.longitude,
elevation=self.hass.config.elevation,
)

async def _show_config_form(
self,
name: str | None = None,
latitude: float | None = None,
longitude: float | None = None,
elevation: int | None = None,
) -> FlowResult:
"""Show the configuration form to edit location data."""
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_NAME, default=name): str,
vol.Required(CONF_LATITUDE, default=latitude): cv.latitude,
vol.Required(CONF_LONGITUDE, default=longitude): cv.longitude,
vol.Required(CONF_ELEVATION, default=elevation): int,
}
),
data_schema=_get_data_schema(self.hass),
errors=self._errors,
)

Expand All @@ -102,3 +113,40 @@ async def async_step_onboarding(
return self.async_create_entry(
title=HOME_LOCATION_NAME, data={CONF_TRACK_HOME: True}
)

@staticmethod
@callback
def async_get_options_flow(
config_entry: config_entries.ConfigEntry,
) -> config_entries.OptionsFlow:
"""Get the options flow for Met."""
return MetOptionsFlowHandler(config_entry)


class MetOptionsFlowHandler(config_entries.OptionsFlow):
Copy link
Copy Markdown
Contributor

@epenet epenet Feb 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this use a SchemaOptionsFlowHandler instead (see accuweather)?
Since this is just a single schema without any validation it seems a better fit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if SchemaOptionsFlowHandler works in this case. The OptionsFlow is calling hass.config_entries.async_update_entry to update the config entry, which SchemaOptionsFlowHandler doesn't seem to do?

"""Options flow for Met component."""

def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
"""Initialize the Met OptionsFlow."""
self._config_entry = config_entry
self._errors: dict[str, Any] = {}

async def async_step_init(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Configure options for Met."""

if user_input is not None:
# Update config entry with data from user input
self.hass.config_entries.async_update_entry(
self._config_entry, data=user_input
)
return self.async_create_entry(
title=self._config_entry.title, data=user_input
)

return self.async_show_form(
step_id="init",
data_schema=_get_data_schema(self.hass, config_entry=self._config_entry),
errors=self._errors,
)
13 changes: 13 additions & 0 deletions homeassistant/components/met/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,18 @@
"abort": {
"no_home": "No home coordinates are set in the Home Assistant configuration"
}
},
"options": {
"step": {
"init": {
"title": "[%key:common::config_flow::data::location%]",
"data": {
"name": "[%key:common::config_flow::data::name%]",
"latitude": "[%key:common::config_flow::data::latitude%]",
"longitude": "[%key:common::config_flow::data::longitude%]",
"elevation": "[%key:common::config_flow::data::elevation%]"
}
}
}
}
}
45 changes: 41 additions & 4 deletions tests/components/met/test_config_flow.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
"""Tests for Met.no config flow."""
from unittest.mock import patch
from unittest.mock import ANY, patch

import pytest

from homeassistant import config_entries
from homeassistant.components.met.const import DOMAIN, HOME_LOCATION_NAME
from homeassistant.config import async_process_ha_core_config
from homeassistant.const import CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.const import CONF_ELEVATION, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import HomeAssistant

from . import init_integration

from tests.common import MockConfigEntry


@pytest.fixture(name="met_setup", autouse=True)
def met_setup_fixture():
def met_setup_fixture(request):
"""Patch met setup entry."""
with patch("homeassistant.components.met.async_setup_entry", return_value=True):
if "disable_autouse_fixture" in request.keywords:
yield
else:
with patch("homeassistant.components.met.async_setup_entry", return_value=True):
yield


async def test_show_config_form(hass: HomeAssistant) -> None:
Expand Down Expand Up @@ -130,3 +135,35 @@ async def test_onboarding_step_abort_no_home(

assert result["type"] == "abort"
assert result["reason"] == "no_home"


@pytest.mark.disable_autouse_fixture
async def test_options_flow(hass: HomeAssistant) -> None:
"""Test show options form."""
update_data = {
CONF_NAME: "test",
CONF_LATITUDE: 12,
CONF_LONGITUDE: 23,
CONF_ELEVATION: 456,
}

entry = await init_integration(hass)
await hass.async_block_till_done()

# Test show Options form
result = await hass.config_entries.options.async_init(entry.entry_id)
assert result["type"] == "form"
assert result["step_id"] == "init"

# Test Options flow updated config entry
with patch("homeassistant.components.met.metno.MetWeatherData") as weatherdatamock:
result = await hass.config_entries.options.async_init(
entry.entry_id, data=update_data
)
await hass.async_block_till_done()
assert result["type"] == "create_entry"
assert result["title"] == "Mock Title"
assert result["data"] == update_data
weatherdatamock.assert_called_with(
{"lat": "12", "lon": "23", "msl": "456"}, ANY, api_url=ANY
)