From 896b2c877980fd3ce49bbf614e42565c1bed43dc Mon Sep 17 00:00:00 2001 From: G Johansson Date: Wed, 3 Jan 2024 19:31:07 +0000 Subject: [PATCH 1/2] Start deprecation min_max --- homeassistant/components/group/config_flow.py | 38 ++++++++++ tests/components/group/test_config_flow.py | 75 +++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/homeassistant/components/group/config_flow.py b/homeassistant/components/group/config_flow.py index 93160b0db5b..72653512a33 100644 --- a/homeassistant/components/group/config_flow.py +++ b/homeassistant/components/group/config_flow.py @@ -1,6 +1,7 @@ """Config flow for Group integration.""" from __future__ import annotations +from collections import ChainMap from collections.abc import Callable, Coroutine, Mapping from functools import partial from typing import Any, cast @@ -15,6 +16,7 @@ from homeassistant.helpers import entity_registry as er, selector from homeassistant.helpers.schema_config_entry_flow import ( SchemaCommonFlowHandler, SchemaConfigFlowHandler, + SchemaFlowError, SchemaFlowFormStep, SchemaFlowMenuStep, SchemaOptionsFlowHandler, @@ -45,6 +47,38 @@ _STATISTIC_MEASURES = [ ] +def import_sensor() -> ( + Callable[ + [SchemaCommonFlowHandler, dict[str, Any]], Coroutine[Any, Any, dict[str, Any]] + ] +): + """Import sensor.""" + + # Missing Make sure the new group config entry adopts the existing min_max entities by changing the config entry and unique_id + # Missing Remove the min_max config entry + + async def _set_group_type( + handler: SchemaCommonFlowHandler, user_input: dict[str, Any] + ) -> dict[str, Any]: + """Add group type to user input and test not imported.""" + hass = handler.parent_handler.hass + entries = hass.config_entries.async_entries(DOMAIN) + match_dict = {"group_type": "sensor", **user_input} + for entry in entries: + if all( + item + in ChainMap( + entry.options, # type: ignore[arg-type] + entry.data, # type: ignore[arg-type] + ).items() + for item in match_dict.items() + ): + raise SchemaFlowError("already_configured") + return {"group_type": "sensor", **user_input} + + return _set_group_type + + async def basic_group_options_schema( domain: str | list[str], handler: SchemaCommonFlowHandler | None ) -> vol.Schema: @@ -263,6 +297,10 @@ OPTIONS_FLOW = { partial(light_switch_options_schema, "switch"), preview="group", ), + "import": SchemaFlowFormStep( + SENSOR_CONFIG_SCHEMA, + validate_user_input=import_sensor(), + ), } PREVIEW_OPTIONS_SCHEMA: dict[str, vol.Schema] = {} diff --git a/tests/components/group/test_config_flow.py b/tests/components/group/test_config_flow.py index 7b83ed9eb0d..398e75bc81e 100644 --- a/tests/components/group/test_config_flow.py +++ b/tests/components/group/test_config_flow.py @@ -700,3 +700,78 @@ async def test_option_flow_sensor_preview_config_entry_removed( msg = await client.receive_json() assert not msg["success"] assert msg["error"] == {"code": "home_assistant_error", "message": "Unknown error"} + + +async def test_import(hass: HomeAssistant) -> None: + """Test import config flow.""" + + members = ["sensor.one", "sensor.two"] + for member in members: + hass.states.async_set(member, "on", {}) + + with patch( + "homeassistant.components.group.async_setup_entry", wraps=async_setup_entry + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_IMPORT}, + data={ + "ignore_non_numeric": False, + "entities": ["sensor.one", "sensor.two"], + "hide_members": False, + "type": "sum", + "name": "Sensor Group sum", + }, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["title"] == "Sensor Group sum" + assert result["data"] == {} + assert result["options"] == { + "entities": members, + "group_type": "sensor", + "hide_members": False, + "name": "Sensor Group sum", + "ignore_non_numeric": False, + "type": "sum", + } + + +async def test_import_already_exist(hass: HomeAssistant) -> None: + """Test import config flow.""" + + members = ["sensor.one", "sensor.two"] + for member in members: + hass.states.async_set(member, "on", {}) + + group_config_entry = MockConfigEntry( + data={}, + domain=DOMAIN, + options={ + "entities": members, + "group_type": "sensor", + "hide_members": False, + "ignore_non_numeric": False, + "type": "sum", + "name": "Sensor Group sum", + }, + title="Sensor Group sum", + ) + group_config_entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_IMPORT}, + data={ + "ignore_non_numeric": False, + "entities": members, + "hide_members": False, + "type": "sum", + "name": "Sensor Group sum", + }, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": "already_configured"} From bfc03b633ac015cff841f11260043d7049c00b2b Mon Sep 17 00:00:00 2001 From: G Johansson Date: Wed, 3 Jan 2024 19:43:39 +0000 Subject: [PATCH 2/2] min_max config flow --- .../components/min_max/config_flow.py | 54 ++++--------------- homeassistant/components/min_max/strings.json | 3 ++ 2 files changed, 13 insertions(+), 44 deletions(-) diff --git a/homeassistant/components/min_max/config_flow.py b/homeassistant/components/min_max/config_flow.py index f449c98819e..e25a4eb58b7 100644 --- a/homeassistant/components/min_max/config_flow.py +++ b/homeassistant/components/min_max/config_flow.py @@ -6,62 +6,24 @@ from typing import Any, cast import voluptuous as vol -from homeassistant.components.input_number import DOMAIN as INPUT_NUMBER_DOMAIN -from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN -from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN -from homeassistant.const import CONF_TYPE +from homeassistant.core import callback +from homeassistant.data_entry_flow import AbortFlow from homeassistant.helpers import selector from homeassistant.helpers.schema_config_entry_flow import ( SchemaConfigFlowHandler, SchemaFlowFormStep, ) -from .const import CONF_ENTITY_IDS, CONF_ROUND_DIGITS, DOMAIN - -_STATISTIC_MEASURES = [ - "min", - "max", - "mean", - "median", - "last", - "range", - "sum", -] - - -OPTIONS_SCHEMA = vol.Schema( - { - vol.Required(CONF_ENTITY_IDS): selector.EntitySelector( - selector.EntitySelectorConfig( - domain=[SENSOR_DOMAIN, NUMBER_DOMAIN, INPUT_NUMBER_DOMAIN], - multiple=True, - ), - ), - vol.Required(CONF_TYPE): selector.SelectSelector( - selector.SelectSelectorConfig( - options=_STATISTIC_MEASURES, translation_key=CONF_TYPE - ), - ), - vol.Required(CONF_ROUND_DIGITS, default=2): selector.NumberSelector( - selector.NumberSelectorConfig( - min=0, max=6, mode=selector.NumberSelectorMode.BOX - ), - ), - } -) +from .const import DOMAIN CONFIG_SCHEMA = vol.Schema( { vol.Required("name"): selector.TextSelector(), } -).extend(OPTIONS_SCHEMA.schema) +) CONFIG_FLOW = { - "user": SchemaFlowFormStep(CONFIG_SCHEMA), -} - -OPTIONS_FLOW = { - "init": SchemaFlowFormStep(OPTIONS_SCHEMA), + "user": SchemaFlowFormStep(vol.Schema({})), } @@ -69,8 +31,12 @@ class ConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN): """Handle a config or options flow for Min/Max.""" config_flow = CONFIG_FLOW - options_flow = OPTIONS_FLOW def async_config_entry_title(self, options: Mapping[str, Any]) -> str: """Return config entry title.""" return cast(str, options["name"]) if "name" in options else "" + + @callback + def async_config_flow_finished(self, options: Mapping[str, Any]) -> None: + """Abort the flow as it should not be setup.""" + raise AbortFlow(reason="being_removed") diff --git a/homeassistant/components/min_max/strings.json b/homeassistant/components/min_max/strings.json index e73fac97bb7..700f20a5677 100644 --- a/homeassistant/components/min_max/strings.json +++ b/homeassistant/components/min_max/strings.json @@ -1,6 +1,9 @@ { "title": "Combine the state of several sensors", "config": { + "abort": { + "being_removed": "Combine the state of several sensors ss being removed. Please configure a Group Sensor instead which provides this functionality." + }, "step": { "user": { "title": "[%key:component::min_max::title%]",