From 380e2b602a27298894683b04b017bc8f7aff654e Mon Sep 17 00:00:00 2001 From: bj00rn Date: Wed, 30 Oct 2024 21:37:16 +0100 Subject: [PATCH] add reconfiguration flow --- custom_components/nordpool/config_flow.py | 99 ++++++++++++++----- custom_components/nordpool/strings.json | 39 ++++++++ .../nordpool/translations/en.json | 16 ++- .../nordpool/translations/sv.json | 30 ++++-- 4 files changed, 149 insertions(+), 35 deletions(-) create mode 100644 custom_components/nordpool/strings.json diff --git a/custom_components/nordpool/config_flow.py b/custom_components/nordpool/config_flow.py index 707c6b3..73b1142 100644 --- a/custom_components/nordpool/config_flow.py +++ b/custom_components/nordpool/config_flow.py @@ -1,11 +1,15 @@ """Adds config flow for nordpool.""" import logging import re +from typing import TYPE_CHECKING import voluptuous as vol from homeassistant import config_entries from homeassistant.helpers.template import Template +if TYPE_CHECKING: + from typing import Any, Mapping + from . import DOMAIN from .sensor import _PRICE_IN, _REGIONS, DEFAULT_TEMPLATE @@ -24,6 +28,7 @@ class NordpoolFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): def __init__(self): """Initialize.""" self._errors = {} + _config_entry = None async def async_step_user( self, user_input=None @@ -33,14 +38,38 @@ async def async_step_user( if user_input is not None: template_ok = False - if user_input["additional_costs"] in (None, ""): - user_input["additional_costs"] = DEFAULT_TEMPLATE + self._patch_template(user_input["additional_costs"]) + + template_ok = await self._valid_template(user_input["additional_costs"]) + if template_ok: + return self.async_create_entry(title="Nordpool", data=user_input) else: - # Lets try to remove the most common mistakes, this will still fail if the template - # was writte in notepad or something like that.. - user_input["additional_costs"] = re.sub( - r"\s{2,}", "", user_input["additional_costs"] - ) + self._errors["base"] = "invalid_template" + + return self.async_show_form( + step_id="user", + **self._get_form_data(user_input), + errors=self._errors, + ) + + async def async_step_reconfigure( + self, entry_data: "Mapping[str, Any]" + ) -> config_entries.ConfigFlowResult: + """Handle a reconfiguration flow initialized by the user.""" + config_entry = self.hass.config_entries.async_get_entry( + self.context["entry_id"] + ) + self._config_entry = config_entry + return await self.async_step_reconfigure_confirm() + + async def async_step_reconfigure_confirm( + self, user_input: "dict[str, Any] | None" = None + ) -> config_entries.ConfigFlowResult: + """Handle a reconfiguration flow initialized by the user.""" + + if user_input is not None: + template_ok = False + self._patch_template(user_input["additional_costs"]) template_ok = await self._valid_template(user_input["additional_costs"]) if template_ok: @@ -48,32 +77,50 @@ async def async_step_user( else: self._errors["base"] = "invalid_template" - data_schema = { - vol.Required("region", default=None): vol.In(regions), - vol.Optional("currency", default=""): vol.In(currencys), - vol.Optional("VAT", default=True): bool, - vol.Optional("precision", default=3): vol.Coerce(int), - vol.Optional("low_price_cutoff", default=1.0): vol.Coerce(float), - vol.Optional("price_in_cents", default=False): bool, - vol.Optional("price_type", default="kWh"): vol.In(price_types), - vol.Optional("additional_costs", default=""): str, - } + return self.async_update_reload_and_abort( + self._config_entry, + data=user_input, + reason="reconfigure_successful", + ) + + return self.async_show_form( + step_id="reconfigure_confirm", **self._get_form_data(self._config_entry.data), + errors=self._errors + ) - placeholders = { - "region": regions, - "currency": currencys, - "price_type": price_types, + def _get_form_data(self, user_input: "Mapping[str, Any] | None"): + """Populate form data from user input and default values""" + if not user_input: + user_input = dict() + + data_schema = vol.Schema({ + vol.Required("region", default=user_input.get("region", None)): vol.In(regions), + vol.Required("currency", default=user_input.get("currency", None)): vol.In(currencys), + vol.Optional("VAT", default=user_input.get("VAT", True)): bool, + vol.Required("precision", default=user_input.get("precision", 3)): vol.Coerce(int), + vol.Required("low_price_cutoff", default=user_input.get("low_price_cutoff", 1.0)): vol.Coerce(float), + vol.Optional("price_in_cents", default=user_input.get("price_in_cents", False)): bool, + vol.Required("price_type", default=user_input.get("price_type", "kWh")): vol.In(price_types), + vol.Optional("additional_costs", default=user_input.get("additional_costs", "") or DEFAULT_TEMPLATE): str, + }) + + description_placeholders = { + "price_type": price_types[0], "additional_costs": "{{0.0|float}}", } - return self.async_show_form( - step_id="user", - data_schema=vol.Schema(data_schema), - description_placeholders=placeholders, - errors=self._errors, + return dict(description_placeholders=description_placeholders, data_schema=data_schema) + + def _patch_template(self, user_template: str): + """Fix common mistakes in template""" + # Lets try to remove the most common mistakes, this will still fail if the template + # was writte in notepad or something like that.. + user_template = re.sub( + r"\s{2,}", "", user_template ) async def _valid_template(self, user_template): + """Validate template""" try: # ut = Template(user_template, self.hass).async_render( diff --git a/custom_components/nordpool/strings.json b/custom_components/nordpool/strings.json new file mode 100644 index 0000000..7a39d7e --- /dev/null +++ b/custom_components/nordpool/strings.json @@ -0,0 +1,39 @@ +{ + "config": { + "title": "Nordpool", + "step": { + "user": { + "title": "Nordpool Sensor", + "description": "Setup a Nordpool sensor", + "data": { + "region": "Region", + "currency": "Currency", + "VAT": "Include VAT", + "precision": "Decimal rounding precision", + "low_price_cutoff": "Low price percentage", + "price_in_cents": "Price in cents", + "price_type": "Energy scale", + "additional_costs": "Template for additional costs" + }, + "reconfigure_confirm": { + "title": "Nordpool Sensor", + "description": "Reconfigure Nordpool sensor", + "data": { + "region": "Region", + "currency": "Currency", + "VAT": "Include VAT", + "precision": "Decimal rounding precision", + "low_price_cutoff": "Low price percentage", + "price_in_cents": "Price in cents", + "price_type": "Energy scale", + "additional_costs": "Template for additional costs" + } + } + } + }, + "error": { + "name_exists": "Name already exists", + "invalid_template": "The template is invalid, check https://github.com/custom-components/nordpool" + } + } +} \ No newline at end of file diff --git a/custom_components/nordpool/translations/en.json b/custom_components/nordpool/translations/en.json index fbb97e9..cc7fabf 100644 --- a/custom_components/nordpool/translations/en.json +++ b/custom_components/nordpool/translations/en.json @@ -15,6 +15,20 @@ "price_type": "Energy scale", "additional_costs": "Template for additional costs" } + }, + "reconfigure_confirm": { + "title": "Nordpool Sensor", + "description": "Reconfigure a Nordpool sensor", + "data": { + "region": "Region", + "currency": "Currency", + "VAT": "Include VAT", + "precision": "Decimal rounding precision", + "low_price_cutoff": "Low price percentage", + "price_in_cents": "Price in cents", + "price_type": "Energy scale", + "additional_costs": "Template for additional costs" + } } }, "error": { @@ -22,4 +36,4 @@ "invalid_template": "The template is invalid, check https://github.com/custom-components/nordpool" } } -} +} \ No newline at end of file diff --git a/custom_components/nordpool/translations/sv.json b/custom_components/nordpool/translations/sv.json index 0387354..b0f14cd 100644 --- a/custom_components/nordpool/translations/sv.json +++ b/custom_components/nordpool/translations/sv.json @@ -3,24 +3,38 @@ "title": "Nord Pool", "step": { "user": { - "title": "Sensor", + "title": "Nordpool Sensor", "description": "Konfigurera en Nord Pool-sensor", "data": { "region": "Region", "friendly_name": "Visningsnamn", - "currency": "SEK", + "currency": "Valuta", "VAT": "Inkludera moms", "precision": "Hur många decimaler ska visas", "low_price_cutoff": "Lägsta prisnivå", "price_in_cents": "Pris i ören", "price_type": "Prisformat", "additional_costs": "Mall för ytterligare kostnader" + }, + "reconfigure_confirm": { + "title": "Nordpool Sensor", + "description": "Konfigurera en Nord Pool-sensor", + "data": { + "region": "Region", + "friendly_name": "Visningsnamn", + "currency": "Valuta", + "VAT": "Inkludera moms", + "precision": "Hur många decimaler ska visas", + "low_price_cutoff": "Lägsta prisnivå", + "price_in_cents": "Pris i ören", + "price_type": "Prisformat", + "additional_costs": "Mall för ytterligare kostnader" + } } + }, + "error": { + "name_exists": "Namnet existerar redan", + "invalid_template": "Mallen är ogiltig, se https://github.com/custom-components/nordpool" } - }, - "error": { - "name_exists": "Namnet existerar redan", - "invalid_template": "Mallen är ogiltig, se https://github.com/custom-components/nordpool" } - } -} + } \ No newline at end of file