mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-29 21:03:40 +00:00
Refactored config_flow.py (995 lines) into focused modules within config_flow/ package to improve maintainability and code organization. Changes: - Created config_flow/ package with 6 specialized modules (1,260 lines total) - Extracted validators to validators.py (95 lines) - pure, testable functions - Extracted schemas to schemas.py (577 lines) - centralized vol.Schema definitions - Split flow handlers into separate files: * user_flow.py (274 lines) - Main config flow (setup + reauth) * subentry_flow.py (124 lines) - Subentry flow (add homes) * options_flow.py (160 lines) - Options flow (6-step configuration wizard) - Package exports via __init__.py (50 lines) for backward compatibility - Deleted config_flow_legacy.py (no longer needed) Technical improvements: - Used Mapping[str, Any] for config_entry.options compatibility - Proper TYPE_CHECKING imports for circular dependency management - All 10 inline vol.Schema definitions replaced with reusable functions - Validators are pure functions (no side effects, easily testable) - Clear separation of concerns (validation, schemas, flows) Documentation: - Updated AGENTS.md with new package structure - Updated config flow patterns and examples - Added "Add a new config flow step" guide to Common Tasks - Marked refactoring plan as COMPLETED with lessons learned Verification: - All linting checks pass (./scripts/lint-check) - All flow handlers import successfully - Home Assistant loads integration without errors - All flow types functional (user, subentry, options, reauth) - No user-facing changes (backward compatible) Impact: Improves code maintainability by organizing 995 lines into 6 focused modules (avg 210 lines/module). Enables easier testing, future modifications, and onboarding of new contributors.
135 lines
5.3 KiB
Python
135 lines
5.3 KiB
Python
"""Options flow for tibber_prices integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, ClassVar
|
|
|
|
from custom_components.tibber_prices.config_flow.schemas import (
|
|
get_best_price_schema,
|
|
get_options_init_schema,
|
|
get_peak_price_schema,
|
|
get_price_rating_schema,
|
|
get_price_trend_schema,
|
|
get_volatility_schema,
|
|
)
|
|
from custom_components.tibber_prices.const import DOMAIN
|
|
from homeassistant.config_entries import ConfigFlowResult, OptionsFlow
|
|
|
|
|
|
class TibberPricesOptionsFlowHandler(OptionsFlow):
|
|
"""Handle options for tibber_prices entries."""
|
|
|
|
# Step progress tracking
|
|
_TOTAL_STEPS: ClassVar[int] = 6
|
|
_STEP_INFO: ClassVar[dict[str, int]] = {
|
|
"init": 1,
|
|
"current_interval_price_rating": 2,
|
|
"volatility": 3,
|
|
"best_price": 4,
|
|
"peak_price": 5,
|
|
"price_trend": 6,
|
|
}
|
|
|
|
def __init__(self) -> None:
|
|
"""Initialize options flow."""
|
|
self._options: dict[str, Any] = {}
|
|
|
|
def _get_step_description_placeholders(self, step_id: str) -> dict[str, str]:
|
|
"""Get description placeholders with step progress."""
|
|
if step_id not in self._STEP_INFO:
|
|
return {}
|
|
|
|
step_num = self._STEP_INFO[step_id]
|
|
|
|
# Get translations loaded by Home Assistant
|
|
standard_translations_key = f"{DOMAIN}_standard_translations_{self.hass.config.language}"
|
|
translations = self.hass.data.get(standard_translations_key, {})
|
|
|
|
# Get step progress text from translations with placeholders
|
|
step_progress_template = translations.get("common", {}).get("step_progress", "Step {step_num} of {total_steps}")
|
|
step_progress = step_progress_template.format(step_num=step_num, total_steps=self._TOTAL_STEPS)
|
|
|
|
return {
|
|
"step_progress": step_progress,
|
|
}
|
|
|
|
async def async_step_init(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
|
|
"""Manage the options - General Settings."""
|
|
# Initialize options from config_entry on first call
|
|
if not self._options:
|
|
self._options = dict(self.config_entry.options)
|
|
|
|
if user_input is not None:
|
|
self._options.update(user_input)
|
|
return await self.async_step_current_interval_price_rating()
|
|
|
|
return self.async_show_form(
|
|
step_id="init",
|
|
data_schema=get_options_init_schema(self.config_entry.options),
|
|
description_placeholders={
|
|
**self._get_step_description_placeholders("init"),
|
|
"user_login": self.config_entry.data.get("user_login", "N/A"),
|
|
},
|
|
)
|
|
|
|
async def async_step_current_interval_price_rating(
|
|
self, user_input: dict[str, Any] | None = None
|
|
) -> ConfigFlowResult:
|
|
"""Configure price rating thresholds."""
|
|
if user_input is not None:
|
|
self._options.update(user_input)
|
|
return await self.async_step_volatility()
|
|
|
|
return self.async_show_form(
|
|
step_id="current_interval_price_rating",
|
|
data_schema=get_price_rating_schema(self.config_entry.options),
|
|
description_placeholders=self._get_step_description_placeholders("current_interval_price_rating"),
|
|
)
|
|
|
|
async def async_step_best_price(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
|
|
"""Configure best price period settings."""
|
|
if user_input is not None:
|
|
self._options.update(user_input)
|
|
return await self.async_step_peak_price()
|
|
|
|
return self.async_show_form(
|
|
step_id="best_price",
|
|
data_schema=get_best_price_schema(self.config_entry.options),
|
|
description_placeholders=self._get_step_description_placeholders("best_price"),
|
|
)
|
|
|
|
async def async_step_peak_price(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
|
|
"""Configure peak price period settings."""
|
|
if user_input is not None:
|
|
self._options.update(user_input)
|
|
return await self.async_step_price_trend()
|
|
|
|
return self.async_show_form(
|
|
step_id="peak_price",
|
|
data_schema=get_peak_price_schema(self.config_entry.options),
|
|
description_placeholders=self._get_step_description_placeholders("peak_price"),
|
|
)
|
|
|
|
async def async_step_price_trend(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
|
|
"""Configure price trend thresholds."""
|
|
if user_input is not None:
|
|
self._options.update(user_input)
|
|
return self.async_create_entry(title="", data=self._options)
|
|
|
|
return self.async_show_form(
|
|
step_id="price_trend",
|
|
data_schema=get_price_trend_schema(self.config_entry.options),
|
|
description_placeholders=self._get_step_description_placeholders("price_trend"),
|
|
)
|
|
|
|
async def async_step_volatility(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
|
|
"""Configure volatility thresholds and period filtering."""
|
|
if user_input is not None:
|
|
self._options.update(user_input)
|
|
return await self.async_step_best_price()
|
|
|
|
return self.async_show_form(
|
|
step_id="volatility",
|
|
data_schema=get_volatility_schema(self.config_entry.options),
|
|
description_placeholders=self._get_step_description_placeholders("volatility"),
|
|
)
|