Completely rewrote period-calculation.md based on user feedback and
live development understanding.
Changes:
- Replaced outdated 3-phase relaxation description with correct 4×4
matrix approach (4 flex levels × 4 filter combinations)
- Added per-day independence explanation (each day relaxes independently)
- Documented replacement logic (larger periods replace smaller ones)
- Added extension logic (baseline periods get expanded, not replaced)
- Updated metadata format examples (price_diff_27.3%+level_any)
- Restructured for clarity: Quick Start → How It Works → Config →
Relaxation → Scenarios → Troubleshooting
- Added 4 real-world scenarios with automation examples (dishwasher,
heat pump, EV charging, peak avoidance)
- Added visual timeline examples
- Reduced technical complexity, focused on user understanding
- Added practical troubleshooting with specific solutions
Impact: Users can now understand how period calculation actually works,
with correct information matching the implemented 4×4 relaxation
strategy. Documentation evolved from cold code reading to live
development insights with user feedback.
Implemented configurable gap tolerance (0-8 intervals) for best price and peak price
level filters to prevent periods from being split by occasional level deviations.
Key features:
- Gap tolerance only applies to periods ≥ MIN_INTERVALS_FOR_GAP_TOLERANCE (1.5h)
- Short periods (< 1.5h) use strict filtering (zero tolerance)
- Dynamic minimum distance between gaps: max(2, (interval_count // max_gap_count) // 2)
- 25% maximum cap on total gaps to prevent excessive outliers in long periods
- Intelligent period splitting at gap clusters (2+ consecutive non-qualifying intervals)
- Each sub-period independently validated with same gap tolerance rules
Technical implementation:
- Added CONF_BEST_PRICE_MAX_LEVEL_GAP_COUNT and CONF_PEAK_PRICE_MAX_LEVEL_GAP_COUNT constants
- Added MIN_INTERVALS_FOR_GAP_TOLERANCE = 6 (1.5h minimum for gap tolerance)
- Implemented _split_at_gap_clusters() for period recovery
- Implemented _check_short_period_strict() for strict short-period filtering
- Implemented _check_level_filter_with_gaps() with fallback splitting logic
- Extracted _check_sequence_with_gap_tolerance() for reusable core validation
- Enhanced _check_level_filter() to use gap-tolerant validation
Configuration UI:
- Added NumberSelector (0-8, slider mode) for gap count in config flow
- Added translations for all 5 languages (de, en, nb, nl, sv)
- Default: 0 (strict filtering, backwards compatible)
Impact: Users can now configure how many occasional level deviations are acceptable
within qualifying price periods. This reduces period fragmentation while maintaining
meaningful price-based filtering. Long periods are protected by the 25% cap, and
gap clusters trigger intelligent splitting to recover usable sub-periods.
Implemented multi-phase filter relaxation system to ensure minimum number
of best-price and peak-price periods are found, even on days with unusual
price patterns.
New configuration options per period type (best/peak):
- enable_min_periods_{best|peak}: Toggle feature on/off
- min_periods_{best|peak}: Target number of periods (default: 2)
- relaxation_step_{best|peak}: Step size for threshold increase (default: 25%)
Relaxation phases (applied sequentially until target reached):
1. Flex threshold increase (up to 4 steps, e.g., 15% → 18.75% → 22.5% → ...)
2. Volatility filter bypass + continued flex increase
3. All filters off + continued flex increase
Changes to period calculation:
- New calculate_periods_with_relaxation() wrapper function
- filter_periods_by_volatility() now applies post-calculation filtering
- _resolve_period_overlaps() merges baseline + relaxed periods intelligently
- Relaxed periods marked with relaxation_level, relaxation_threshold_* attributes
- Overlap detection prevents double-counting same intervals
Binary sensor attribute ordering improvements:
- Added helper methods for consistent attribute priority
- Relaxation info grouped in priority 6 (after detail attributes)
- Only shown when period was actually relaxed (relaxation_active=true)
Translation updates:
- Added UI labels + descriptions for 6 new config options (all 5 languages)
- Explained relaxation concept with examples in data_description fields
- Clarified volatility filter now applies per-period, not per-day
Impact: Users can configure integration to guarantee minimum number of
periods per day. System automatically relaxes filters when needed while
preserving baseline periods found with strict filters. Particularly useful
for automation reliability on days with flat pricing or unusual patterns.
Fixes edge case where no periods were found despite prices varying enough
for meaningful optimization decisions.
Moved filter logic and all period attribute calculations from binary_sensor.py
to coordinator.py and period_utils.py, following Home Assistant best practices
for data flow architecture.
ARCHITECTURE CHANGES:
Binary Sensor Simplification (~225 lines removed):
- Removed _build_periods_summary, _add_price_diff_for_period (calculation logic)
- Removed _get_period_intervals_from_price_info (107 lines, interval reconstruction)
- Removed _should_show_periods, _check_volatility_filter, _check_level_filter
- Removed _build_empty_periods_result (filtering result builder)
- Removed _get_price_hours_attributes (24 lines, dead code)
- Removed datetime import (unused after cleanup)
- New: _build_final_attributes_simple (~20 lines, timestamp-only)
- Result: Pure display-only logic, reads pre-calculated data from coordinator
Coordinator Enhancement (+160 lines):
- Added _should_show_periods(): UND-Verknüpfung of volatility and level filters
- Added _check_volatility_filter(): Checks min_volatility threshold
- Added _check_level_filter(): Checks min/max level bounds
- Enhanced _calculate_periods_for_price_info(): Applies filters before period calculation
- Returns empty periods when filters don't match (instead of calculating unnecessarily)
- Passes volatility thresholds (moderate/high/very_high) to PeriodConfig
Period Utils Refactoring (+110 lines):
- Extended PeriodConfig with threshold_volatility_moderate/high/very_high
- Added PeriodData NamedTuple: Groups timing data (start, end, length, position)
- Added PeriodStatistics NamedTuple: Groups calculated stats (prices, volatility, ratings)
- Added ThresholdConfig NamedTuple: Groups all thresholds + reverse_sort flag
- New _calculate_period_price_statistics(): Extracts price_avg/min/max/spread calculation
- New _build_period_summary_dict(): Builds final dict with correct attribute ordering
- Enhanced _extract_period_summaries(): Now calculates ALL attributes (no longer lightweight):
* price_avg, price_min, price_max, price_spread (in minor units: ct/øre)
* volatility (low/moderate/high/very_high based on absolute thresholds)
* rating_difference_% (average of interval differences)
* period_price_diff_from_daily_min/max (period avg vs daily reference)
* aggregated level and rating_level
* period_interval_count (renamed from interval_count for clarity)
- Removed interval_starts array (redundant - start/end/count sufficient)
- Function signature refactored from 9→4 parameters using NamedTuples
Code Organization (HA Best Practice):
- Moved calculate_volatility_level() from const.py to price_utils.py
- Rule: const.py should contain only constants, no functions
- Removed duplicate VOLATILITY_THRESHOLD_* constants from const.py
- Updated imports in sensor.py, services.py, period_utils.py
DATA FLOW:
Before:
API → Coordinator (basic enrichment) → Binary Sensor (calculate everything on each access)
After:
API → Coordinator (enrichment + filtering + period calculation with ALL attributes) →
Cached Data → Binary Sensor (display + timestamp only)
ATTRIBUTE STRUCTURE:
Period summaries now contain (following copilot-instructions.md ordering):
1. Time: start, end, duration_minutes
2. Decision: level, rating_level, rating_difference_%
3. Prices: price_avg, price_min, price_max, price_spread, volatility
4. Differences: period_price_diff_from_daily_min/max (conditional)
5. Details: period_interval_count, period_position
6. Meta: periods_total, periods_remaining
BREAKING CHANGES: None
- Period data structure enhanced but backwards compatible
- Binary sensor API unchanged (state + attributes)
Impact: Binary sensors now display pre-calculated data from coordinator instead
of calculating on every access. Reduces complexity, improves performance, and
centralizes business logic following Home Assistant coordinator pattern. All
period filtering (volatility + level) now happens in coordinator before caching.
Major improvements to release note generation system:
**AI Model Optimization:**
- Switch from Claude Sonnet 4.5 to Haiku 4.5 (67% cheaper, 50% faster)
- Cost reduced from 1.0 to 0.33 Premium requests per generation
- Generation time reduced from ~30s to ~15s
- Quality maintained through improved prompt engineering
**Improved Prompt Structure:**
- Restructured prompt: instructions first, commit data last
- Added explicit user-feature prioritization rules (sensors > config > developer tools)
- Integrated file change statistics with each commit
- Added file path guidance (custom_components/ = HIGH, scripts/ = LOW)
- Added 3-step decision process with walkthrough example
- Added explicit output constraints to prevent meta-commentary
**Auto-Update Feature:**
- Consolidated improve-release-notes functionality into generate-release-notes
- Automatic detection of existing GitHub releases
- Interactive prompt to update both title and body
- Shows comparison: current title vs. new AI-generated title
**File Statistics Integration:**
- Added --stat --compact-summary to git log
- Shows which files changed in each commit with line counts
- Helps AI quantitatively assess change importance (100+ lines = significant)
- Enables better prioritization of user-facing features
**Testing Results:**
- Generated title: "Price Volatility Analysis & Configuration" (user-focused!)
- Successfully prioritizes user features over developer/CI changes
- No more generic "New Features & Bug Fixes" titles
- Thematic titles that capture main release highlights
Impact: Release note generation is now faster, cheaper, and produces
higher-quality user-focused titles. Single consolidated script handles
both generation and updating existing releases.
Release titles now automatically reflect the type of changes:
- 'vX.Y.Z - New Features & Bug Fixes' (both present)
- 'vX.Y.Z - New Features' (only features)
- 'vX.Y.Z - Bug Fixes' (only fixes)
- 'vX.Y.Z' (fallback for other changes)
Determined by analyzing commit messages between previous tag and current tag.
Impact: Release titles are more descriptive and immediately show what
changed, making it easier for users to understand the release at a glance.
Added concurrency groups with cancel-in-progress to validate.yml, lint.yml,
and auto-tag.yml workflows.
This ensures that when multiple commits are pushed quickly:
- Only the latest validation/lint run continues
- Older runs are automatically cancelled
- Saves CI minutes and provides faster feedback
Release workflow intentionally excluded (each tag is unique).
Impact: More efficient CI usage, faster feedback on rapid commits.
Release workflow now trusts that validate.yml and lint.yml have already
run on the main branch commit before tag creation. This prevents duplicate
workflow executions.
Workflow execution flow:
1. Push to main → validate.yml + lint.yml run (quality gate)
2. prepare-release or auto-tag creates version tag
3. release.yml runs (generates release notes, no validation)
This ensures:
- Every main commit is validated/linted before tag creation
- No duplicate workflow runs (validate/lint run once per commit)
- Release workflow is faster (no redundant checks)
- Simple, predictable workflow chain
Impact: Release process is more efficient and workflows don't run twice.
Added mandatory validation steps to release workflow:
- Job 1: validate (hassfest + HACS) - runs before release
- Job 2: lint (Ruff check + format) - runs before release
- Job 3: sync-manifest - only runs if validation passes
- Job 4: release-notes - only runs if all previous jobs pass
This ensures no release is created if code doesn't pass validation.
Fixed generate-release-notes script to suppress colored output in CI:
- Added log_info() wrapper that sends output to stderr in CI
- Keeps release notes clean (only markdown, no ANSI codes)
- Local execution still shows colored output for better UX
Impact: Release workflow now fails fast if validation fails. Release
notes are clean without shell output artifacts.
Migrated all settings from .vscode/settings.json to devcontainer.json
for team-wide consistency. Removed .vscode/settings.json entirely.
Changes:
- Added python.analysis.exclude to prevent Pylance from analyzing
.venv, .github, docs and other non-code directories (eliminates
2000+ false errors)
- Added python.analysis.diagnosticMode: workspace for comprehensive
analysis of integration code
- Added source.organizeImports.ruff for automatic import sorting
- Added markdown.wordWrap and disabled markdown link validation
- Removed deprecated python.linting.* settings (deprecated since 2023)
- Removed editor.formatOnPaste (conflicts with Copilot)
- Changed source.organizeImports to source.organizeImports.ruff
(Ruff-specific, prevents conflicts with Pylance)
- Changed source.fixAll to source.fixAll.ruff (explicit Ruff action)
Impact: All developers get identical Copilot-friendly environment
without local overrides. No Pylance errors from .venv directories,
no markdown validation warnings, no conflicts between Copilot and
auto-formatting.
Updated copilot-instructions.md with comprehensive documentation for
new release workflows and validation requirements.
Added sections:
- Selector validation rules for hassfest compliance
- Pattern requirement: [a-z0-9-_]+ (lowercase only)
- Common pitfalls with SelectOptionDict and translation_key
- Validation examples (correct vs incorrect)
- Legacy/Backwards compatibility guidelines
- When to add migration code vs breaking changes
- check-if-released script usage
- Rule: Only migrate for released changes
- Prefer documentation over complexity
- Semantic versioning workflow
- Pre-1.0 vs Post-1.0 versioning rules
- suggest-version script usage and output
- prepare-release integration
- Version check in CI/CD
- Release notes generation
- Updated with auto-sync and version check features
- Backend comparison (AI vs git-cliff vs manual)
- Complete workflow examples
Impact: AI assistant and developers have clear guidance on hassfest
requirements, legacy migration decisions, and the complete release
automation workflow. Reduces errors and maintains consistency across
sessions.
Implemented automatic manifest.json synchronization and semantic
versioning validation in the release workflow.
Auto-Sync Manifest (sync-manifest job):
- Extracts version from Git tag (v*.*.*)
- Compares with manifest.json version
- Auto-updates manifest.json if mismatch detected
- Commits changes back to main branch
- Sets outputs (updated, version) for downstream jobs
- Prevents HACS version mismatches and conflicts with auto-tag.yml
Version Check Warning System (version_check step):
- Analyzes commits between tags for breaking changes, features, fixes
- Applies semantic versioning rules (pre-1.0 and post-1.0)
- Detects inappropriate version bumps:
- Features with only PATCH bump → suggests MINOR
- Breaking changes with only MINOR bump → suggests MAJOR (post-1.0)
- Breaking changes with only PATCH bump → suggests MINOR (pre-1.0)
- Shows warnings in GitHub Step Summary (prominent)
- Appends warnings to release notes body
- Provides fix instructions but doesn't fail workflow
- Updates final summary with version check status
Workflow changes:
- release-notes job now depends on sync-manifest
- Checks out main branch to get updated manifest if synced
- Summary shows manifest sync status and version check result
Impact: Prevents manual version tag issues, maintains manifest
consistency, and warns about semantic versioning violations without
blocking releases. Fully transparent workflow with clear guidance.
Added intelligent version suggestion system based on Conventional Commits
analysis to support proper semantic versioning.
New scripts:
- check-if-released: Verify if commit exists in any version tag
- Helps decide if legacy migration code is needed
- Shows guidance for breaking changes vs simple migrations
- suggest-version: Analyze commits and suggest next version
- Counts breaking changes, features, and bug fixes
- Applies pre-1.0 rules: breaking→MINOR, feat→MINOR, fix→PATCH
- Applies post-1.0 rules: breaking→MAJOR, feat→MINOR, fix→PATCH
- Checks manifest.json and suggests alternatives (MAJOR/MINOR/PATCH)
- Provides preview and release commands
Updated scripts:
- prepare-release: Now calls suggest-version when no argument provided
- Shows suggested version before prompting
- Maintains manual override capability
Impact: Developers get intelligent version suggestions based on actual
commit content, reducing versioning mistakes and following semver correctly.
Changed all selector option keys from uppercase to lowercase to comply
with Home Assistant's hassfest validation pattern [a-z0-9-_]+.
Fixed inconsistency in PEAK_PRICE_MIN_LEVEL_OPTIONS where some values
were uppercase while others were lowercase.
Changes:
- translations/*.json: All selector keys now lowercase (volatility, price_level)
- const.py: Added .lower() to all PEAK_PRICE_MIN_LEVEL_OPTIONS values
- binary_sensor.py: Added .upper() conversion when looking up price levels
in PRICE_LEVEL_MAPPING to handle lowercase config values
Impact: Config flow now works correctly with translated selector options.
Hassfest validation passes without selector key errors.
Created professional documentation structure:
**User Documentation (docs/user/):**
- README.md: Documentation hub with quick start guide
- Placeholder files for future content migration:
* installation.md, configuration.md, sensors.md
* services.md, automation-examples.md, troubleshooting.md
**Developer Documentation (docs/development/):**
- README.md: Comprehensive contributor guide with AI section
- setup.md: DevContainer and environment setup
- architecture.md: Code structure overview
- testing.md: Testing guidelines
- coding-guidelines.md: Style guide and critical patterns
- release-management.md: Complete release workflow documentation
**AI Development Disclosure:**
- README.md: "🤖 Development Note" section before license
* Honest disclosure about extensive AI assistance
* Quality assurance measures mentioned
* Invitation for bug reports with positive tone
- docs/development/README.md: Detailed AI section
* What AI handles (patterns, generation, refactoring)
* Benefits (rapid development, consistency)
* Limitations (edge cases, complex patterns)
* Quality assurance process
- CONTRIBUTING.md: Brief AI note with practical tip
**Updated:**
- README.md: Simplified to landing page with documentation links
- CONTRIBUTING.md: Modernized with new docs structure
- copilot-instructions.md: Added documentation organization section
Impact: Clear separation of user vs. developer documentation following
open-source best practices. Transparent about AI-assisted development
approach without being defensive. Scalable structure for future growth.
- Added ghcr.io/devcontainers/features/rust:1 (minimal profile)
- Reorganized extension IDs into categories (Python, GitHub, Tools)
- Sorted extensions alphabetically within categories
Impact: DevContainer now includes Rust toolchain for building git-cliff
(release notes backend). No user-visible changes.
Added comprehensive volatility analysis system:
- 4 new volatility sensors (today, tomorrow, next_24h, today+tomorrow)
- Volatility classification (LOW/MODERATE/HIGH/VERY HIGH) based on price spread
- Configurable thresholds in options flow (step 6 of 6)
- Best/Peak price period filters using volatility and price level
- Price spread calculation in get_price service
Volatility sensors help users decide if price-based optimization is worthwhile.
For example, battery optimization only makes sense when volatility ≥ MODERATE.
Period filters allow AND-logic combinations:
- best_price_min_volatility: Only show cheap periods on volatile days
- best_price_max_level: Only show periods when prices reach desired level
- peak_price_min_volatility: Only show peaks on volatile days
- peak_price_min_level: Only show peaks when expensive levels occur
All 5 language files updated (de, en, nb, nl, sv) with:
- Volatility sensor translations (name, states, descriptions)
- Config flow step 6 "Volatility" with threshold settings
- Step progress indicators added to all config steps
- Period filter translations with usage tips
Impact: Users can now assess daily price volatility and configure period
sensors to only activate when conditions justify battery cycling or load
shifting. Reduces unnecessary battery wear on low-volatility days.
Expanded the documentation to include a comprehensive update process for maintaining consistency between code and documentation. Added sections on automatic inconsistency detection, documentation update proposals, and guidelines for testing changes and git workflow.
Impact: Ensures accurate documentation and streamlined workflows for future development sessions.
- Introduced a new utility module `period_utils.py` for calculating price periods.
- Implemented `_get_period_config` method to retrieve configuration for best and peak price calculations.
- Added `_calculate_periods_for_price_info` method to compute best and peak price periods based on price data.
- Enhanced `TibberPricesDataUpdateCoordinator` to include calculated periods in the data transformation methods.
- Updated configuration constants for best and peak price settings.