Commit graph

10 commits

Author SHA1 Message Date
Julian Pawlowski
a1ab98d666 refactor(config_flow): reorganize options flow steps with section structure
Restructured 5 options flow steps (current_interval_price_rating, best_price,
peak_price, price_trend, volatility) to use Home Assistant's sections feature
for better UI organization and logical grouping.

Changes:
- current_interval_price_rating: Single section "price_rating_thresholds"
- best_price: Three sections (period_settings, flexibility_settings,
  relaxation_and_target_periods)
- peak_price: Three sections (period_settings, flexibility_settings,
  relaxation_and_target_periods)
- price_trend: Single section "price_trend_thresholds"
- volatility: Single section "volatility_thresholds"

Each section includes name, description, data fields, and data_description
fields following HA translation schema requirements.

Updated all 5 language files (de, en, nb, nl, sv) with new section structure
while preserving existing field descriptions and translations.

Impact: Options flow now displays configuration fields in collapsible,
logically grouped sections with clear section headers, improving UX for
complex multi-parameter configuration steps. No functional changes to
configuration logic or validation.
2025-12-02 20:23:31 +00:00
Julian Pawlowski
b6f5f1678f feat(services): add fetch_price_info_range service and update schema
Added new service for fetching historical/future price data:
- fetch_price_info_range: Query prices for arbitrary date ranges
- Supports start_time and end_time parameters
- Returns structured price data via service response
- Uses interval pool for efficient data retrieval

Service definition:
- services.yaml: Added fetch_price_info_range with date selectors
- services/__init__.py: Implemented handler with validation
- Response format: {"priceInfo": [...], "currency": "..."}

Schema updates:
- config_flow_handlers/schemas.py: Convert days slider to IntSelector
  (was NumberSelector with float, caused "2.0 Tage" display issue)

Impact: Users can fetch price data for custom date ranges programmatically.
Config flow displays clean integer values for day offsets.
2025-11-25 20:44:39 +00:00
Julian Pawlowski
9a6eb44382 refactor(config): use negative values for Best Price min_distance
Best Price min_distance now uses negative values (-50 to 0) to match
semantic meaning "below average". Peak Price continues using positive
values (0 to 50) for "above average".

Uniform formula: avg * (1 + distance/100) works for both period types.
Sign indicates direction: negative = toward MIN (cheap), positive = toward MAX (expensive).

Changes:
- const.py: DEFAULT_BEST_PRICE_MIN_DISTANCE_FROM_AVG = -5 (was 5)
- schemas.py: Best Price range -50 to 0, Peak Price range 0 to 50
- validators.py: Separate validate_best_price_distance_percentage()
- level_filtering.py: Simplified to uniform formula (removed conditionals)
- translations: Separate error messages for Best/Peak distance validation
- tests: 37 comprehensive validator tests (100% coverage)

Impact: Configuration UI now visually represents direction relative to average.
Users see intuitive negative values for "below average" pricing.
2025-11-22 04:44:57 +00:00
Julian Pawlowski
14b68a504b refactor(config): optimize volatility thresholds with separate ranges and improved UX
Volatility Threshold Optimization:
- Replaced global MIN/MAX_VOLATILITY_THRESHOLD (0-100%) with six separate
  constants for overlapping ranges per threshold level
- MODERATE: 5.0-25.0% (was: 0-100%)
- HIGH: 20.0-40.0% (was: 0-100%)
- VERY_HIGH: 35.0-80.0% (was: 0-100%)
- Added detailed comments explaining ranges and cascading requirements

Validators:
- Added three specific validation functions (one per threshold level)
- Added cross-validation ensuring MODERATE < HIGH < VERY_HIGH
- Added fallback to existing option values for completeness check
- Updated error keys to specific messages per threshold level

UI Improvements:
- Changed NumberSelector mode: BOX → SLIDER (consistency with other config steps)
- Changed step size: 0.1% → 1.0% (better UX, sufficient precision)
- Updated min/max ranges to match new validation constants

Translations:
- Removed: "invalid_volatility_threshold" (generic)
- Added: "invalid_volatility_threshold_moderate/high/very_high" (specific ranges)
- Added: "invalid_volatility_thresholds" (cross-validation error)
- Updated all 5 languages (de, en, nb, nl, sv)

Files modified:
- config_flow_handlers/options_flow.py: Updated validation logic
- config_flow_handlers/schemas.py: Updated NumberSelector configs
- config_flow_handlers/validators.py: Added specific validators + cross-validation
- const.py: Replaced global constants with six specific constants
- translations/*.json: Updated error messages (5 languages)

Impact: Users get clearer validation errors with specific ranges shown,
better UX with sliders and appropriate step size, and guaranteed
threshold ordering (MODERATE < HIGH < VERY_HIGH).
2025-11-21 17:31:07 +00:00
Julian Pawlowski
ebd1b8ddbf chore: Enhance validation logic and constants for options configuration flow
- Added new validation functions for various parameters including flexibility percentage, distance percentage, minimum periods, gap count, relaxation attempts, price rating thresholds, volatility threshold, and price trend thresholds.
- Updated constants in `const.py` to define maximum and minimum limits for the new validation criteria.
- Improved error messages in translations for invalid parameters to provide clearer guidance to users.
- Adjusted existing validation functions to ensure they align with the new constants and validation logic.
2025-11-21 13:57:35 +00:00
Julian Pawlowski
e950737478 feat(chart_export): migrate sensor config from UI to configuration.yaml
Moved Chart Data Export sensor configuration from config flow textarea
to configuration.yaml for better maintainability and consistency with
Home Assistant standards.

Changes:
- __init__.py: Added async_setup() with CONFIG_SCHEMA for tibber_prices.chart_export
- const.py: Added DATA_CHART_CONFIG constant for hass.data storage
- options_flow.py: Simplified chart_data_export step to info-only page
- schemas.py: get_chart_data_export_schema() returns empty schema (no input fields)
- sensor/chart_data.py: Reads config from hass.data instead of config_entry.options
- All 5 translation files: Updated chart_data_export description with:
  - Clear heading: "📊 Chart Data Export Sensor"
  - Intro line explaining sensor purpose
  - Legacy warning (⚠️) recommending service use
  - Two valid use cases (): attribute-only tools, auto-updating data
  - One discouraged use case (): automations should use service directly
  - 3-step activation instructions
  - YAML configuration example with all parameters
  - Correct default behavior: today+tomorrow, 15-minute intervals, prices only

Impact: Users configure chart export in configuration.yaml instead of UI.
Sensor remains disabled by default (diagnostic sensor). Config flow shows
prominent info page guiding users toward service usage while keeping
sensor available for legacy dashboard tools that only read attributes.
2025-11-20 13:41:26 +00:00
Julian Pawlowski
b8a502672b refactor(config_flow): unify translation structure across all languages
Standardized config flow translations (nb, nl, sv) to match German/English
format with minimal field labels and comprehensive data_descriptions.

Changes across Norwegian, Dutch, and Swedish translations:
- Updated step_progress format: **{step_progress}** → _{step_progress}_
- Made all step descriptions bold with **text** formatting
- Simplified field labels (removed verbose explanations)
- Added data_description for price_rating (low/high thresholds)
- Added data_description for price_trend (rising/falling thresholds)
- Added data_description for volatility (moderate/high/very high thresholds)
- Ensured all steps have: emojis, italic step_progress, separator (---)
- Added missing emoji to Swedish price_rating step (📊)

Impact: All 5 languages now have consistent UX with minimal, scannable
field labels and detailed optional descriptions accessible via ⓘ icon.
Users get cleaner config flow with better clarity.
2025-11-20 12:59:12 +00:00
Julian Pawlowski
457fa7c03f refactor(periods): merge adjacent periods and remove is_extension logic
BREAKING CHANGE: Period overlap resolution now merges adjacent/overlapping periods
instead of marking them as extensions. This simplifies automation logic and provides
clearer period boundaries for users.

Previous Behavior:
- Adjacent periods created by relaxation were marked with is_extension=true
- Multiple short periods instead of one continuous period
- Complex logic needed to determine actual period length in automations

New Behavior:
- Adjacent/overlapping periods are merged into single continuous periods
- Newer period's relaxation attributes override older period's
- Simpler automation: one period = one continuous time window

Changes:
- Period Overlap Resolution (new file: period_overlap.py):
  * Added merge_adjacent_periods() to combine periods and preserve attributes
  * Rewrote resolve_period_overlaps() with simplified merge logic
  * Removed split_period_by_overlaps() (no longer needed)
  * Removed is_extension marking logic
  * Removed unused parameters: min_period_length, baseline_periods

- Relaxation Strategy (relaxation.py):
  * Removed all is_extension filtering from period counting
  * Simplified standalone counting to just len(periods)
  * Changed from period_merging import to period_overlap import
  * Added MAX_FLEX_HARD_LIMIT constant (0.50)
  * Improved debug logging for merged periods

- Code Quality:
  * Fixed all remaining linter errors (N806, PLR2004, PLR0912)
  * Extracted magic values to module-level constants:
    - FLEX_SCALING_THRESHOLD = 0.20
    - SCALE_FACTOR_WARNING_THRESHOLD = 0.8
    - MAX_FLEX_HARD_LIMIT = 0.50
  * Added appropriate noqa comments for unavoidable patterns

- Configuration (from previous work in this session):
  * Removed CONF_RELAXATION_STEP_BEST, CONF_RELAXATION_STEP_PEAK
  * Hard-coded 3% relaxation increment for reliability
  * Optimized defaults: RELAXATION_ATTEMPTS 8→11, ENABLE_MIN_PERIODS False→True,
    MIN_PERIODS undefined→2
  * Removed relaxation_step UI fields from config flow
  * Updated all 5 translation files

- Documentation:
  * Updated period_handlers/__init__.py: period_merging → period_overlap
  * No user-facing docs changes needed (already described continuous periods)

Rationale - Period Merging:
User experience was complicated by fragmented periods:
- Automations had to check multiple adjacent periods
- Binary sensors showed ON/OFF transitions within same cheap time
- No clear way to determine actual continuous period length

With merging:
- One continuous cheap time = one period
- Binary sensor clearly ON during entire period
- Attributes show merge history via merged_from dict
- Relaxation info preserved from newest/highest flex period

Rationale - Hard-Coded Relaxation Increment:
The configurable relaxation_step parameter proved problematic:
- High base flex + high step → rapid explosion (40% base + 10% step → 100% in 6 steps)
- Users don't understand the multiplicative nature
- 3% increment provides optimal balance: 11 attempts to reach 50% hard cap

Impact:
- Existing installations: Periods may appear longer (merged instead of split)
- Automations benefit from simpler logic (no is_extension checks needed)
- Custom relaxation_step values will use new 3% increment
- Users may need to adjust relaxation_attempts if they relied on high step sizes
2025-11-19 20:16:58 +00:00
Julian Pawlowski
38ce1c4c50 feat(chart_export): add Chart Data Export diagnostic sensor
Added optional diagnostic binary sensor that exposes get_chartdata
service results as entity attributes for legacy dashboard tools.

Key features:
- Entity: binary_sensor.tibber_home_NAME_chart_data_export
- Configurable via Options Flow Step 7 (YAML parameters)
- Calls get_chartdata service with user configuration
- Exposes response as attributes for chart cards
- Disabled by default (opt-in)
- Auto-refreshes on coordinator updates
- Manual refresh via homeassistant.update_entity

Implementation details:
- Added chart_data_export entity description to definitions.py
- Implemented state/attribute logic in binary_sensor/core.py
- Added YAML configuration schema in schemas.py
- Added validation in options_flow.py (Step 7)
- Service call validation with detailed error messages
- Attribute ordering: metadata first, descriptions next, service data last
- Dynamic icon mapping (database-export/database-alert)

Translations:
- Added chart_data_export_config to all 5 languages
- Added Step 7 descriptions with legacy warning
- Added invalid_yaml_syntax/invalid_yaml_structure error messages
- Added custom_translations for sensor descriptions

Documentation:
- Added Chart Data Export section to sensors.md
- Added comprehensive service guide to services.md
- Migration path from sensor to service
- Configuration instructions via Options Flow

Impact: Provides backward compatibility for dashboard tools that can
only read entity attributes (e.g., older ApexCharts versions). New
integrations should use tibber_prices.get_chartdata service directly.
2025-11-17 03:14:02 +00:00
Julian Pawlowski
503075c443 refactor(config_flow): restructure package to satisfy hassfest validation
Home Assistant's hassfest validation requires config flows to be defined
in a file named config_flow.py (not a package directory).

Changes:
- Renamed custom_components/tibber_prices/config_flow/ → config_flow_handlers/
- Created config_flow.py as bridge file re-exporting from config_flow_handlers/
- Updated all import paths across 5 files (user_flow, options_flow, subentry_flow, etc.)
- Added ./scripts/hassfest for local validation (JSON/Python syntax, required files)
- Added ./scripts/clean with three modes (--minimal, normal, --deep)
- Refactored develop/lint/lint-check to use centralized cleanup (DRY principle)
- Updated documentation in AGENTS.md and docs/development/

Technical details:
- Bridge file uses __all__ exports to maintain clean public API
- hassfest script uses ast.parse() for syntax validation (no disk artifacts)
- clean --minimal removes .egg-info only (silent, for automated scripts)
- Dual pip/uv pip compatibility for package uninstallation

Impact: Integration now passes hassfest validation. Local validation available
via ./scripts/hassfest before pushing to GitHub. Cleanup logic centralized and
DRY across all development scripts.
2025-11-15 17:40:53 +00:00
Renamed from custom_components/tibber_prices/config_flow/schemas.py (Browse further)