diff --git a/homeassistant/components/met/__init__.py b/homeassistant/components/met/__init__.py index 2ccd456936d..c95c3abe05e 100644 --- a/homeassistant/components/met/__init__.py +++ b/homeassistant/components/met/__init__.py @@ -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 @@ -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.""" diff --git a/homeassistant/components/met/config_flow.py b/homeassistant/components/met/config_flow.py index baf7269a81d..453c0a9cee8 100644 --- a/homeassistant/components/met/config_flow.py +++ b/homeassistant/components/met/config_flow.py @@ -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( @@ -59,31 +92,9 @@ class MetFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): ) 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, ) @@ -102,3 +113,40 @@ class MetFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): 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): + """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, + ) diff --git a/homeassistant/components/met/strings.json b/homeassistant/components/met/strings.json index b9d251e21d8..4fa9c58e4bc 100644 --- a/homeassistant/components/met/strings.json +++ b/homeassistant/components/met/strings.json @@ -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%]" + } + } + } } } diff --git a/tests/components/met/test_config_flow.py b/tests/components/met/test_config_flow.py index 102a9a8b4ec..59ffff14f1b 100644 --- a/tests/components/met/test_config_flow.py +++ b/tests/components/met/test_config_flow.py @@ -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: @@ -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 + )