From 9666665690968274d59a517252dc7ff808016aa6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 06:29:39 +0000 Subject: [PATCH 1/2] Initial plan From e793e7673f972135b94edbeb728de80f58dc2ca4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 06:33:46 +0000 Subject: [PATCH 2/2] Add OptionsFlow for UI-based configuration without YAML Co-authored-by: JansenDevelopment <181745188+JansenDevelopment@users.noreply.github.com> --- custom_components/smart_climate/__init__.py | 8 +++ custom_components/smart_climate/climate.py | 13 +++-- .../smart_climate/config_flow.py | 55 ++++++++++++++++++- custom_components/smart_climate/strings.json | 36 ++++++++++++ .../smart_climate/translations/en.json | 36 ++++++++++++ .../smart_climate/translations/nl.json | 36 ++++++++++++ 6 files changed, 177 insertions(+), 7 deletions(-) diff --git a/custom_components/smart_climate/__init__.py b/custom_components/smart_climate/__init__.py index 82a279d..522e78f 100644 --- a/custom_components/smart_climate/__init__.py +++ b/custom_components/smart_climate/__init__.py @@ -51,9 +51,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN][entry.entry_id] = entry.data await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + + entry.async_on_unload(entry.add_update_listener(_async_update_listener)) + return True +async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Reload entry when options are updated.""" + await hass.config_entries.async_reload(entry.entry_id) + + async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/custom_components/smart_climate/climate.py b/custom_components/smart_climate/climate.py index 052e1b4..b7f4d9b 100644 --- a/custom_components/smart_climate/climate.py +++ b/custom_components/smart_climate/climate.py @@ -56,12 +56,13 @@ async def async_setup_entry( name = entry.data.get(CONF_NAME, "Smart Climate") wrapped_climate = entry.data.get(CONF_WRAPPED_CLIMATE) zone_home = entry.data.get(CONF_ZONE_HOME) - away_temp = entry.data.get(CONF_AWAY_TEMPERATURE, 14) - auto_temp = entry.data.get(CONF_AUTO_TEMPERATURE, 21) - away_delay = entry.data.get(CONF_AWAY_DELAY_MINUTES, 5) - interruptible = entry.data.get(CONF_INTERRUPTIBLE, True) - default_override_mode = entry.data.get(CONF_DEFAULT_OVERRIDE_MODE, "timer") - default_override_duration = entry.data.get(CONF_DEFAULT_OVERRIDE_DURATION, 30) + options = {**entry.data, **entry.options} + away_temp = options.get(CONF_AWAY_TEMPERATURE, 14) + auto_temp = options.get(CONF_AUTO_TEMPERATURE, 21) + away_delay = options.get(CONF_AWAY_DELAY_MINUTES, 5) + interruptible = options.get(CONF_INTERRUPTIBLE, True) + default_override_mode = options.get(CONF_DEFAULT_OVERRIDE_MODE, "timer") + default_override_duration = options.get(CONF_DEFAULT_OVERRIDE_DURATION, 30) entity = SmartClimateEntity( hass, diff --git a/custom_components/smart_climate/config_flow.py b/custom_components/smart_climate/config_flow.py index 00e1d68..b5361b7 100644 --- a/custom_components/smart_climate/config_flow.py +++ b/custom_components/smart_climate/config_flow.py @@ -1,4 +1,4 @@ -from homeassistant.config_entries import ConfigFlow +from homeassistant.config_entries import ConfigFlow, OptionsFlow, ConfigEntry from homeassistant.const import CONF_NAME from homeassistant.helpers import config_validation as cv import voluptuous as vol @@ -24,6 +24,11 @@ def __init__(self): super().__init__() self._import_name = None + @staticmethod + def async_get_options_flow(config_entry: ConfigEntry): + """Return the options flow.""" + return SmartClimateOptionsFlow(config_entry) + async def async_step_import(self, import_data): """Handle import from YAML (only name is required).""" if isinstance(import_data, list): @@ -89,4 +94,52 @@ async def async_step_reconfigure(self, user_input=None): return self.async_show_form( step_id="reconfigure", data_schema=schema, + ) + + +class SmartClimateOptionsFlow(OptionsFlow): + """Options flow for Smart Climate — change settings after initial setup.""" + + def __init__(self, config_entry: ConfigEntry): + self._config_entry = config_entry + + async def async_step_init(self, user_input=None): + """Handle options step.""" + current = {**self._config_entry.data, **self._config_entry.options} + + if user_input is not None: + return self.async_create_entry(title="", data=user_input) + + schema = vol.Schema( + { + vol.Optional( + CONF_AUTO_TEMPERATURE, + default=current.get(CONF_AUTO_TEMPERATURE, 21), + ): vol.Coerce(float), + vol.Optional( + CONF_AWAY_TEMPERATURE, + default=current.get(CONF_AWAY_TEMPERATURE, 14), + ): vol.Coerce(float), + vol.Optional( + CONF_AWAY_DELAY_MINUTES, + default=current.get(CONF_AWAY_DELAY_MINUTES, 5), + ): vol.Coerce(int), + vol.Optional( + CONF_INTERRUPTIBLE, + default=current.get(CONF_INTERRUPTIBLE, True), + ): cv.boolean, + vol.Optional( + CONF_DEFAULT_OVERRIDE_MODE, + default=current.get(CONF_DEFAULT_OVERRIDE_MODE, "timer"), + ): vol.In(["timer", "infinity"]), + vol.Optional( + CONF_DEFAULT_OVERRIDE_DURATION, + default=current.get(CONF_DEFAULT_OVERRIDE_DURATION, 30), + ): vol.Coerce(int), + } + ) + + return self.async_show_form( + step_id="init", + data_schema=schema, ) \ No newline at end of file diff --git a/custom_components/smart_climate/strings.json b/custom_components/smart_climate/strings.json index b985e17..2f33039 100644 --- a/custom_components/smart_climate/strings.json +++ b/custom_components/smart_climate/strings.json @@ -25,11 +25,47 @@ "default_override_mode": "Override mode used when adjusting temperature (timer or infinity)", "default_override_duration": "Default duration in minutes for timer override mode" } + }, + "reconfigure": { + "title": "Reconfigure Smart Climate", + "description": "Change the linked climate entity and home zone", + "data": { + "wrapped_climate": "Wrapped Climate Entity", + "zone_home": "Home Zone" + }, + "data_description": { + "wrapped_climate": "The climate entity to wrap and control", + "zone_home": "The zone entity used for presence detection" + } } }, "error": {}, "abort": { "already_configured": "Device is already configured" } + }, + "options": { + "step": { + "init": { + "title": "Smart Climate Options", + "description": "Adjust temperature and override settings", + "data": { + "auto_temperature": "Home Temperature", + "away_temperature": "Away Temperature", + "away_delay_minutes": "Away Delay (minutes)", + "interruptible": "Override is interruptible", + "default_override_mode": "Default Override Mode", + "default_override_duration": "Default Override Duration (minutes)" + }, + "data_description": { + "auto_temperature": "Target temperature when somebody is home", + "away_temperature": "Target temperature when nobody is home", + "away_delay_minutes": "Minutes to wait before applying the away temperature", + "interruptible": "Whether a presence change can interrupt an active override", + "default_override_mode": "Override mode used when adjusting temperature (timer or infinity)", + "default_override_duration": "Default duration in minutes for timer override mode" + } + } + } } } diff --git a/custom_components/smart_climate/translations/en.json b/custom_components/smart_climate/translations/en.json index b985e17..2f33039 100644 --- a/custom_components/smart_climate/translations/en.json +++ b/custom_components/smart_climate/translations/en.json @@ -25,11 +25,47 @@ "default_override_mode": "Override mode used when adjusting temperature (timer or infinity)", "default_override_duration": "Default duration in minutes for timer override mode" } + }, + "reconfigure": { + "title": "Reconfigure Smart Climate", + "description": "Change the linked climate entity and home zone", + "data": { + "wrapped_climate": "Wrapped Climate Entity", + "zone_home": "Home Zone" + }, + "data_description": { + "wrapped_climate": "The climate entity to wrap and control", + "zone_home": "The zone entity used for presence detection" + } } }, "error": {}, "abort": { "already_configured": "Device is already configured" } + }, + "options": { + "step": { + "init": { + "title": "Smart Climate Options", + "description": "Adjust temperature and override settings", + "data": { + "auto_temperature": "Home Temperature", + "away_temperature": "Away Temperature", + "away_delay_minutes": "Away Delay (minutes)", + "interruptible": "Override is interruptible", + "default_override_mode": "Default Override Mode", + "default_override_duration": "Default Override Duration (minutes)" + }, + "data_description": { + "auto_temperature": "Target temperature when somebody is home", + "away_temperature": "Target temperature when nobody is home", + "away_delay_minutes": "Minutes to wait before applying the away temperature", + "interruptible": "Whether a presence change can interrupt an active override", + "default_override_mode": "Override mode used when adjusting temperature (timer or infinity)", + "default_override_duration": "Default duration in minutes for timer override mode" + } + } + } } } diff --git a/custom_components/smart_climate/translations/nl.json b/custom_components/smart_climate/translations/nl.json index b4c43f7..c956be9 100644 --- a/custom_components/smart_climate/translations/nl.json +++ b/custom_components/smart_climate/translations/nl.json @@ -25,11 +25,47 @@ "default_override_mode": "Overschrijfmodus bij het aanpassen van de temperatuur (timer of oneindig)", "default_override_duration": "Standaardduur in minuten voor timer-overschrijfmodus" } + }, + "reconfigure": { + "title": "Smart Climate Herconfigureren", + "description": "Wijzig het gekoppelde klimaatapparaat en de thuiszone", + "data": { + "wrapped_climate": "Gekoppeld Klimaatapparaat", + "zone_home": "Thuiszone" + }, + "data_description": { + "wrapped_climate": "Het klimaatapparaat om te beheren", + "zone_home": "De zone die gebruikt wordt voor aanwezigheidsdetectie" + } } }, "error": {}, "abort": { "already_configured": "Apparaat is al geconfigureerd" } + }, + "options": { + "step": { + "init": { + "title": "Smart Climate Opties", + "description": "Pas temperatuur- en overschrijfinstellingen aan", + "data": { + "auto_temperature": "Thuis Temperatuur", + "away_temperature": "Weg Temperatuur", + "away_delay_minutes": "Vertrekvertraging (minuten)", + "interruptible": "Overschrijving is onderbrekbaar", + "default_override_mode": "Standaard Overschrijfmodus", + "default_override_duration": "Standaard Overschrijfduur (minuten)" + }, + "data_description": { + "auto_temperature": "Doeltemperatuur wanneer iemand thuis is", + "away_temperature": "Doeltemperatuur wanneer niemand thuis is", + "away_delay_minutes": "Minuten te wachten voordat de weg-temperatuur wordt toegepast", + "interruptible": "Of een aanwezigheidswijziging een actieve overschrijving kan onderbreken", + "default_override_mode": "Overschrijfmodus bij het aanpassen van de temperatuur (timer of oneindig)", + "default_override_duration": "Standaardduur in minuten voor timer-overschrijfmodus" + } + } + } } }