From aedc729d5758d710d39ebc4c0f4b57dff09e4dfe Mon Sep 17 00:00:00 2001 From: Thomas55555 <59625598+Thomas55555@users.noreply.github.com> Date: Fri, 19 Dec 2025 14:33:16 +0100 Subject: [PATCH] Only allow unique location names in google air quality (#159285) --- .../google_air_quality/config_flow.py | 22 ++++++++++- .../google_air_quality/strings.json | 4 +- .../google_air_quality/test_config_flow.py | 39 ++++++++++++++++++- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/google_air_quality/config_flow.py b/homeassistant/components/google_air_quality/config_flow.py index c7b5235f989..b0f1cd41826 100644 --- a/homeassistant/components/google_air_quality/config_flow.py +++ b/homeassistant/components/google_air_quality/config_flow.py @@ -101,6 +101,15 @@ def _is_location_already_configured( return False +def _is_location_name_already_configured(hass: HomeAssistant, new_data: str) -> bool: + """Check if the location name is already configured.""" + for entry in hass.config_entries.async_entries(DOMAIN): + for subentry in entry.subentries.values(): + if subentry.title.lower() == new_data.lower(): + return True + return False + + class GoogleAirQualityConfigFlow(ConfigFlow, domain=DOMAIN): """Handle a config flow for Google AirQuality.""" @@ -178,8 +187,19 @@ class LocationSubentryFlowHandler(ConfigSubentryFlow): description_placeholders: dict[str, str] = {} if user_input is not None: if _is_location_already_configured(self.hass, user_input[CONF_LOCATION]): - return self.async_abort(reason="already_configured") + errors["base"] = "location_already_configured" + if _is_location_name_already_configured(self.hass, user_input[CONF_NAME]): + errors["base"] = "location_name_already_configured" api: GoogleAirQualityApi = self._get_entry().runtime_data.api + if errors: + return self.async_show_form( + step_id="location", + data_schema=self.add_suggested_values_to_schema( + _get_location_schema(self.hass), user_input + ), + errors=errors, + description_placeholders=description_placeholders, + ) if await _validate_input(user_input, api, errors, description_placeholders): return self.async_create_entry( title=user_input[CONF_NAME], diff --git a/homeassistant/components/google_air_quality/strings.json b/homeassistant/components/google_air_quality/strings.json index 6ed0a11e041..8c2a7e75207 100644 --- a/homeassistant/components/google_air_quality/strings.json +++ b/homeassistant/components/google_air_quality/strings.json @@ -47,12 +47,12 @@ "config_subentries": { "location": { "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_location%]", "unable_to_fetch": "[%key:component::google_air_quality::common::unable_to_fetch%]" }, "entry_type": "Air quality location", "error": { - "no_data_for_location": "Information is unavailable for this location. Please try a different location.", + "location_already_configured": "[%key:common::config_flow::abort::already_configured_location%]", + "location_name_already_configured": "Location name already configured.", "unknown": "[%key:common::config_flow::error::unknown%]" }, "initiate_flow": { diff --git a/tests/components/google_air_quality/test_config_flow.py b/tests/components/google_air_quality/test_config_flow.py index 4ab2dc707ab..a0aabe6e407 100644 --- a/tests/components/google_air_quality/test_config_flow.py +++ b/tests/components/google_air_quality/test_config_flow.py @@ -349,8 +349,43 @@ async def test_subentry_flow_location_already_configured( }, ) - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "already_configured" + assert result["type"] is FlowResultType.FORM + assert result["errors"]["base"] == "location_already_configured" + + entry = hass.config_entries.async_get_entry(mock_config_entry.entry_id) + assert len(entry.subentries) == 1 + + +async def test_subentry_flow_location_name_already_configured( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_api: AsyncMock, +) -> None: + """Test user input for a location name that already exists.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + + result = await hass.config_entries.subentries.async_init( + (mock_config_entry.entry_id, "location"), + context={"source": "user"}, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "location" + + result = await hass.config_entries.subentries.async_configure( + result["flow_id"], + { + CONF_NAME: "Home", + CONF_LOCATION: { + CONF_LATITUDE: 30.1, + CONF_LONGITUDE: 40.1, + }, + }, + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"]["base"] == "location_name_already_configured" entry = hass.config_entries.async_get_entry(mock_config_entry.entry_id) assert len(entry.subentries) == 1