homeassistant==2026.3.4 requires Python>=3.14.2. The lint workflow was
specifying Python 3.13, and uv venv was ignoring actions/setup-python and
picking up the system Python (3.14.0) instead.
Changes:
- lint.yml: python-version 3.13 → 3.14
- bootstrap: uv venv now uses $(which python) to respect
actions/setup-python and local pyenv/asdf setups
Impact: lint workflow no longer fails with Python version unsatisfiable
dependency error when installing homeassistant.
grep -q "refs/tags/$TAG" matched substrings, so v0.27.0b0
would block release of v0.27.0. Changed to "refs/tags/${TAG}$"
to require exact end-of-line match.
_get_cached_intervals() used fixed-offset datetimes from fromisoformat()
for iteration. When start and end boundaries span a DST transition (e.g.,
+01:00 CET → +02:00 CEST), the loop's end check compared UTC values,
stopping 1 hour early on spring-forward days.
This caused the last 4 quarter-hourly intervals of "tomorrow" to be
missing, making the binary sensor "Tomorrow data available" show Off
even when full data was present.
Changed iteration to use naive local timestamps, matching the index key
format (timezone stripped via [:19]). The end boundary comparison now
works correctly regardless of DST transitions.
Impact: Binary sensor "Tomorrow data available" now correctly shows On
on DST spring-forward days. Affects all European users on the last
Sunday of March each year.
When runtime config override entities (number/switch) are enabled,
the Options Flow now displays warning indicators at the top of each
affected section. Users see which fields are being managed by config
entities and can still edit the base values if needed.
Changes:
- Add ConstantSelector warnings in Best Price/Peak Price sections
- Implement multi-language support for override warnings (de, en, nb, nl, sv)
- Add _get_override_translations() to load translated field labels
- Add _get_active_overrides() to detect enabled override entities
- Extend get_best_price_schema/get_peak_price_schema with translations param
- Add 14 number/switch config entities for runtime period tuning
- Document runtime configuration entities in user docs
Warning format adapts to overridden fields:
- Single: "⚠️ Flexibility controlled by config entity"
- Multiple: "⚠️ Flexibility and Minimum Distance controlled by config entity"
Impact: Users can now dynamically adjust period calculation parameters
via Home Assistant automations, scripts, or dashboards without entering
the Options Flow. Clear UI indicators show which settings are currently
overridden.
Add visual indicators to distinguish hourly aggregated data from
original 15-minute interval data in ApexCharts output.
Changes:
- Chart title: Append localized suffix like "(Ø hourly)" / "(Ø stündlich)"
- Y-axis label: Append "(Ø)" suffix, e.g., "øre/kWh (Ø)"
The suffix pattern avoids confusion with Scandinavian currency symbols
(øre/öre) which look similar to the average symbol (Ø) when used as prefix.
Added hourly_suffix translations for all 5 languages (en, de, sv, nb, nl).
Impact: Users can now clearly see when a chart displays averaged hourly
data rather than original 15-minute prices.
Implement clickable legend items to show/hide best/peak price period
overlays in generated ApexCharts YAML configuration.
Legend behavior by configuration:
- Only best price: No legend (overlay always visible)
- Only peak price: Legend shown, peak toggleable (starts hidden)
- Both enabled: Legend shown, both toggleable (best visible, peak hidden)
Changes:
- Best price overlay: in_legend only when peak also enabled
- Peak price overlay: always in_legend with hidden_by_default: true
- Enable experimental.hidden_by_default when peak price active
- Price level series (LOW/NORMAL/HIGH): hidden from legend when
overlays active, visible otherwise (preserves easy legend enable)
- Add triangle icons (▼/▲) before overlay names for visual distinction
- Custom legend markers (size: 0) only when overlays active
- Increased itemMargin for better visual separation
Impact: Users can toggle best/peak price period visibility directly
in the chart via legend click. Without overlays, legend behavior
unchanged - users can still enable it by setting show: true.
Add resolution parameter to get_chartdata and get_apexcharts_yaml services,
allowing users to choose between original 15-minute intervals or aggregated
hourly values for chart visualization.
Implementation uses rolling 5-interval window aggregation (-2, -1, 0, +1, +2
around :00 of each hour = 60 minutes total), matching the sensor rolling
hour methodology. Respects user's CONF_AVERAGE_SENSOR_DISPLAY setting for
mean vs median calculation.
Changes:
- formatters.py: Add aggregate_to_hourly() function preserving original
field names (startsAt, total, level, rating_level) for unified processing
- get_chartdata.py: Pre-aggregate data before processing when resolution is
'hourly', enabling same code path for filters/insert_nulls/connect_segments
- get_apexcharts_yaml.py: Add resolution parameter, pass to all 4 get_chartdata
service calls in generated JavaScript
- services.yaml: Add resolution field with interval/hourly selector
- icons.json: Add section icons for get_apexcharts_yaml fields
- translations: Add highlight_peak_price and resolution field translations
for all 5 languages (en, de, sv, nb, nl)
Impact: Users can now generate cleaner charts with 24 hourly data points
instead of 96 quarter-hourly intervals. The unified processing approach
ensures all chart features (filters, null insertion, segment connection)
work identically for both resolutions.
Added dynamic warnings when users configure settings for sensors that
are currently disabled. This improves UX by informing users that their
configuration changes won't have any visible effect until they enable
the relevant sensors.
Changes:
- Created entity_check.py helper module with sensor-to-step mappings
- Added check_relevant_entities_enabled() to detect disabled sensors
- Integrated warnings into 6 options flow steps (price_rating,
price_level, best_price, peak_price, price_trend, volatility)
- Made Chart Data Export info page content-aware: shows configuration
guide when sensor is enabled, shows enablement instructions when disabled
- Updated all 5 translation files (de, en, nb, nl, sv) with dynamic
placeholders {entity_warning} and {sensor_status_info}
Impact: Users now receive clear feedback when configuring settings for
disabled sensors, reducing confusion about why changes aren't visible.
Chart Data Export page now provides context-appropriate guidance.
Fixed inconsistency between "Current Electricity Price" and "Current Electricity Price
(Energy Dashboard)" sensors that were showing different prices and icons.
Changes:
- Add current_interval_price_base to TIME_SENSITIVE_ENTITY_KEYS so it updates at
quarter-hour boundaries instead of only on API polls. This ensures both sensors
update synchronously when a new 15-minute interval starts.
- Use interval_data["startsAt"] as timestamp for current interval price sensors
(both variants) instead of rounded calculation time. This prevents timestamp
divergence when sensors update at slightly different times.
- Include current_interval_price_base in icon color attribute mapping so both
sensors display the same dynamic cash icon based on current price level.
- Include current_interval_price_base in dynamic icon function so it gets the
correct icon based on current price level (VERY_CHEAP/CHEAP/NORMAL/EXPENSIVE).
Impact: Both sensors now show identical prices, timestamps, and icons as intended.
They update synchronously at interval boundaries (00, 15, 30, 45 minutes) and
correctly represent the Energy Dashboard compatible variant without lag or
inconsistencies.
Convert best_price and peak_price timing sensors to display in hours (UI-friendly)
while retaining minute values in attributes (automation-friendly). This improves
readability in dashboards by using Home Assistant's automatic duration formatting
"1 h 35 min" instead of decimal "1.58 h".
BREAKING CHANGE: State unit changed from minutes to hours for 6 timing sensors.
Affected sensors:
* best_price_period_duration, best_price_remaining_minutes, best_price_next_in_minutes
* peak_price_period_duration, peak_price_remaining_minutes, peak_price_next_in_minutes
Migration guide for users:
- If your automations use {{ state_attr(..., 'remaining_time') }} or similar:
No action needed - attribute values remain in minutes
- If your automations use {{ states('sensor.best_price_remaining_minutes') }} directly:
Update to use the minute attribute instead: {{ state_attr('sensor.best_price_remaining_minutes', 'remaining_minutes') }}
- If your dashboards display the state value:
Values now show as "1 h 35 min" instead of "95" - this is the intended improvement
- If your templates do math with the state: multiply by 60 to convert hours back to minutes
Before: remaining * 60
After: remaining_minutes (use attribute directly)
Implementation details:
- Timing sensors now use device_class=DURATION, unit=HOURS, precision=2
- State values converted from minutes to hours via _minutes_to_hours()
- New minute-precision attributes added for automation compatibility:
* period_duration_minutes (for checking if period is long enough)
* remaining_minutes (for countdown-based automation logic)
* next_in_minutes (for time-to-event automation triggers)
- Translation improvements across all 5 languages (en, de, nb, nl, sv):
* Descriptions now clarify state in hours vs attributes in minutes
* Long descriptions explain dual-format architecture
* Usage tips updated to reference minute attributes for automations
* All translation files synchronized (fixed order, removed duplicates)
- Type safety: Added type assertions (cast) for timing calculator results to
satisfy Pyright type checking (handles both float and datetime return types)
Home Assistant now automatically formats these durations as "1 h 35 min" for improved
UX, matching the behavior of battery.remaining_time and other duration sensors.
Rationale for breaking change:
The previous minute-based state was unintuitive for users ("95 minutes" doesn't
immediately convey "1.5 hours") and didn't match Home Assistant's standard duration
formatting. The new hour-based state with minute attributes provides:
- Better UX: Automatic "1 h 35 min" formatting in UI
- Full automation compatibility: Minute attributes for all calculation needs
- Consistency: Matches HA's duration sensor pattern (battery, timer, etc.)
Impact: Timing sensors now display in human-readable hours with full backward
compatibility via minute attributes. Users relying on direct state access must
migrate to minute attributes (simple change, documented above).
- Remove pool stats/fetch-age from lifecycle sensor to avoid stale data under state-change filtering; add `next_api_poll` for transparency.
- Clean lifecycle calculator by dropping unused helpers/constants and delete the obsolete cache age test.
- Clarify lifecycle state is diagnostics-only in coordinator comments, keep state-change filtering in timer test, and retain quarter-hour precision notes in constants.
- Keep sensor core aligned with lifecycle state filtering.
Impact: Lifecycle sensor now exposes only state-relevant fields without recorder noise, next API poll is visible, and dead code/tests tied to removed attributes are gone.
Added `highlight_peak_price` (default: false) to `get_apexcharts_yaml` service
and implemented a subtle red overlay analogous to best price periods using
`period_filter: 'peak_price'`. Tooltips now dynamically exclude overlay
series to prevent overlay tooltips.
Impact: Users can visualize peak-price periods in ApexCharts cards
when desired, with default opt-out behavior.
Added a consistent "Entity ID tip" block and normalized all example
entity IDs to the `<home_name>` placeholder across user docs. Updated
YAML and example references to current entity naming (e.g.,
`sensor.<home_name>_current_electricity_price`,
`sensor.<home_name>_price_today`,
`sensor.<home_name>_today_s_price_volatility`,
`binary_sensor.<home_name>_best_price_period`, etc.). Refreshed
automation examples to use language-independent attributes (e.g.
`price_volatility`) and improved robustness. Aligned ApexCharts examples
to use `sensor.<home_name>_chart_metadata` and corrected references for
tomorrow data availability.
Changed files:
- docs/user/docs/actions.md
- docs/user/docs/automation-examples.md
- docs/user/docs/chart-examples.md
- docs/user/docs/configuration.md
- docs/user/docs/dashboard-examples.md
- docs/user/docs/dynamic-icons.md
- docs/user/docs/faq.md
- docs/user/docs/icon-colors.md
- docs/user/docs/period-calculation.md
- docs/user/docs/sensors.md
Impact: Clearer, language-independent examples that reduce confusion and
prevent brittle automations; easier copy/paste adaptation across setups;
more accurate guidance for chart configuration and period/volatility usage.
Expose the `price_coefficient_variation_%` value across period statistics, binary sensor attributes, and the volatility calculator, and refresh the volatility descriptions/translations to mention the coefficient-of-variation metric.
The lifecycle sensor was always showing "fresh" state because
_last_price_update was set on every coordinator update, regardless of
whether data came from API or cache.
Changes:
- interval_pool/manager.py: get_intervals() and get_sensor_data() now
return tuple[data, bool] where bool indicates actual API call
- coordinator/price_data_manager.py: All fetch methods propagate
api_called flag through the call chain
- coordinator/core.py: Only update _last_price_update when api_called=True,
added debug logging to distinguish API calls from cached data
- services/get_price.py: Updated to handle new tuple return type
Impact: Lifecycle sensor now correctly shows "cached" during normal
15-minute updates (using pool cache) and only "fresh" within 5 minutes
of actual API calls. This fixes the issue where the sensor would never
leave the "fresh" state during frequent HA restarts or normal operation.