Add a comprehensive entity reference system that helps users find
entities across all 5 supported languages (EN, DE, NO, NL, SV).
Core components:
- Generator script (scripts/docs/generate-sensor-reference) that
builds sensor-reference.md from translation files with --check
mode for CI validation
- EntityRef component for compact inline entity annotations with
tooltip and version-aware linking to the reference table
- EntitySearch component with live filtering, clickable results,
keyboard navigation, "/" shortcut to focus, category filter chips,
match highlighting, copy-entity-ID button per row, back-links to
documentation pages, persistent row highlights, hash-based deep
linking, and mobile-responsive layout
- MDXComponents theme override for global component registration
Documentation updates:
- New sensor-reference.md page (115 entities x 5 languages)
- EntityRef annotations across 10 documentation pages
- Sidebar entry for quick navigation
- CI integration (docusaurus.yml + scripts/check)
- Ruff per-file-ignores for scripts/ (T201, INP001)
Impact: Users can now find any entity by its localized display name
regardless of their UI language. Inline EntityRef annotations link
directly to the multi-language lookup table with version-aware URLs.
All YAML code blocks >12-14 lines in example and concept pages are now
wrapped in HTML <details>/<summary> elements, reducing scroll depth
and making complex pages easier to navigate.
Pages affected:
- automation-examples.md: 9 blocks (heat pump, EV, battery automations)
- dashboard-examples.md: 6 blocks (button-card, mushroom, grid layouts)
- sensors.md: 7 blocks (practical examples, energy/tax templates, timing)
- icon-colors.md: 8 blocks (card_mod methods, complete dashboard, custom colors)
- period-calculation.md: 3 blocks (sensor attr reference, midnight example, automations)
Blocks left visible: short examples (<13 lines), Good/Bad comparisons,
Method 1 (primary recommended approach in icon-colors.md).
Impact: Users can scan page structure without scrolling past long YAML.
Code is still one click away, not hidden behind navigation.
New dedicated page for community-contributed examples, starting with
Dutch solar feed-in compensation (saldering) patterns adapted from
GitHub Discussion #105 (OdynBrouwer). Includes input_number helpers
for country-specific tax rates, template sensors for feed-in with
and without saldering, smart export automation, and dashboard card.
German spot price share template as starting point. Norwegian/Swedish
sections as placeholders for future contributions.
YAML code blocks use collapsible details elements to keep the page
scannable. Page is framed generically to accommodate any type of
community example in the future (not just country-specific).
Added cross-reference from sensors.md Energy Price section and new
"Community" sidebar category.
Impact: Users (especially Netherlands) can find ready-to-adapt template
examples for country-specific price calculations using the energy_price
and tax attributes. Framework ready for additional community examples.
Added Entity Migration & Breaking Change Repairs section (Common Pitfalls #6)
documenting the separation between migrations.py, coordinator/repairs.py, and
_migrate_config_options().
Additional changes:
- migrations.py added to allowed root files list and component structure tree
- Common Tasks "Add a new sensor": step 6 for ENTITY_KEY_RENAMES registration
- Duration sensor pattern (native=MINUTES, suggested=HOURS) documented
Impact: Future sessions generate correct migration code on first try without
rediscovering the pattern.
Adds migrations.py with automatic entity registry migration for renamed
sensor keys. Separated from coordinator/repairs.py (runtime issues) and
__init__.py _migrate_config_options() (config format changes).
- ENTITY_KEY_RENAMES dict maps old→new entity keys (extensible)
- _auto_migrate_entity_keys() updates unique_id, preserves entity_id
- Handles partial migration (new entity already exists → remove old)
- Creates persistent HA repair issue after migration via ir.async_create_issue()
- Called in async_setup_entry() after _migrate_config_options()
Migrates: trend_change_in_minutes → next_price_trend_change_in
Repair issue informs users about:
- Auto-migrated entity renames (entity_id preserved, no action needed)
- Duration sensor value unit change (hours → minutes): update automation
thresholds from `state < 0.25` to `state < 15` for 15-minute checks
All 5 language files (en, de, nb, nl, sv) updated with translations.
BREAKING CHANGE: Duration sensors (remaining time, starts in, period
duration, trend change countdown) now report state values in minutes
instead of hours. Display unit in dashboards remains hours by default.
Update numeric comparisons in automations accordingly.
Impact: Users upgrading from previous releases see an informational
repair notice guiding them through any required automation updates.
Entity renames are handled transparently with no loss of history.
Replaced int(time.minutes_until()) with time.minutes_until_rounded()
in trend calculator (3 locations). The int() call truncated values
(14.7 → 14) while timing sensors used standard rounding (14.7 → 15).
All duration sensors now use the same rounding method
(math.floor(seconds/60 + 0.5)), matching HA's timestamp rendering
behavior.
Impact: Trend countdown values may differ by ±1 minute compared to
previous behavior. Consistency across all duration sensors improved.
Changed native_unit_of_measurement from HOURS to MINUTES for all 7
duration sensors. HA auto-converts to hours for display via
suggested_unit_of_measurement=HOURS.
Sensors affected:
- next_price_trend_change_in
- 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
Removed _minutes_to_hours() conversion function — calculator values
(minutes) are now passed through directly.
BREAKING CHANGE: State values for all duration sensors change from
hours to minutes (e.g. 1.5 → 90). The display unit remains hours
(suggested_unit_of_measurement). Automations using numeric state
comparisons must be updated (multiply old thresholds by 60).
Impact: Users with automations comparing duration sensor states
numerically need to update thresholds. Dashboard display is unchanged
for new installations. Existing installations retain their configured
display unit but the underlying numeric value changes.
Renamed trend_change_in_minutes → next_price_trend_change_in to align
with its sibling sensor next_price_trend_change (timestamp variant).
Follows the established best/peak price naming pattern where related
sensors share a common prefix (e.g. best_price_next_start_time /
best_price_next_in_minutes).
Updated entity key, translation key, friendly names (all 5 languages),
custom translations, coordinator constants, attribute routing, and
cache-clear mapping.
BREAKING CHANGE: Entity ID changes from
sensor.<home>_trend_change_in_minutes to
sensor.<home>_next_price_trend_change_in. Automations and dashboards
referencing the old entity ID must be updated.
Impact: Users with automations or dashboard cards referencing the old
sensor name need to update references. The sensor retains identical
functionality and attributes.
Skip expensive async_write_ha_state() when native_value hasn't changed
since last write. HA's state machine has built-in change detection, but
it only runs AFTER all properties and attributes are evaluated — the
expensive part we now avoid entirely.
Sensor platform (Timer #2 + #3):
- New _write_if_changed() method compares native_value before writing
- Timer #3 (30s, 7 entities): Skips all writes when no period active
- Timer #2 (15min, ~45 entities): Skips enum levels/ratings that stay
constant across quarter-hour intervals
- Replaces data_lifecycle_status-only pattern with unified approach
Binary sensor platform (Timer #2):
- Period sensors only write at actual period boundaries, not every 15min
Coordinator push updates always write (sentinel reset ensures freshness).
Impact: Eliminates asyncio "Executing TimerHandle took 1.4s" warnings
caused by redundant property evaluation in Timer #3 callbacks. Reduces
event loop blocking from ~1.4s to microseconds when values unchanged.
Replace the inline KaTeX block in the Energy Price & Tax Breakdown
section with a plain inline equation string.
The previous expression caused a Docusaurus SSG runtime failure on the
sensors page (ReferenceError during static rendering).
Impact: User docs build now succeeds consistently for the sensors page.
Add a local pre-commit hook that builds Docusaurus when files under
docs/user or docs/developer are staged.
Introduced scripts/docs/build-changed-sites to detect which docs site
was touched and run only the required npm build(s).
Impact: Prevents broken MDX/Docusaurus changes from being committed by
failing fast in pre-commit before CI.
Add new section 'Energy Price & Tax Breakdown' to sensors.md:
- Attribute overview table (interval, min/max, daily avg sensors)
- Use cases: solar feed-in/net metering, price composition analysis,
dashboard cost breakdown with example YAML templates
- Cache transition note for gradual data availability after update
Add 'Energy & Tax Fields in get_chartdata' section to actions.md:
- Parameter documentation with defaults
- Example service call YAML
- ApexCharts integration example with custom field names
Impact: Users can discover and utilize the new energy/tax attributes
with ready-to-use automation and dashboard examples.
Add four optional parameters to the get_chartdata service:
- include_energy: Include raw energy/spot price (default: false)
- include_tax: Include tax component (default: false)
- energy_field: Custom field name (default: energy_price)
- tax_field: Custom field name (default: tax)
Custom field names allow direct compatibility with ApexCharts
and other charting tools without post-processing.
All code paths (all/segments/none insert_nulls modes) and the
last-interval handler include energy/tax when enabled.
Added translations for all 5 languages (en, de, nl, nb, sv).
Impact: Users can include price composition data in chart exports,
enabling visual breakdowns of energy cost vs. taxes in dashboards.
Add energy_price and tax attributes to interval and daily stat sensors:
- Interval sensors (current/next/previous): energy_price and tax from
the specific 15-minute interval
- Daily min/max sensors: energy_price and tax from the extreme interval
- Daily average sensors: energy_price_mean, energy_price_median,
tax_mean, tax_median — matching the existing mean/median pattern
used for the main price attribute
Calculator caches both mean and median for energy/tax using
calculate_median() from utils/average. All new attributes are
excluded from Recorder to prevent database bloat.
Impact: Users can see price composition (spot price vs. taxes) on
all major price sensors. Enables solar feed-in and net metering
automations based on raw energy prices.
Request `energy` and `tax` fields alongside `total` in both
quarter-hourly price queries. These represent the raw spot price and
the tax/fee component that together make up the total consumer price.
Updated hourly aggregation in formatters.py to carry energy/tax
values through to aggregated output.
Impact: Enables downstream consumers (sensors, services) to expose
price composition data. Useful for solar feed-in compensation and
net metering (saldering) calculations where the raw energy price
is needed separately from taxes.
Added brand/ directory to custom_components/tibber_prices/ with all
8 supported PNG variants, generated from existing SVGs in images/:
- icon.png / dark_icon.png (256×256)
- icon@2x.png / dark_icon@2x.png (512×512)
- logo.png / dark_logo.png (500×128)
- logo@2x.png / dark_logo@2x.png (1000×256)
Local brand images automatically take priority over CDN images and
are served via the HA brands proxy API (/api/brands/integration/).
Silently ignored on HA < 2026.3, no changes to manifest.json needed.
Updated AGENTS.md to document the brand/ directory under "ALLOWED in root".
Impact: Integration icon and logo now display correctly in HA ≥ 2026.3
without requiring a separate submission to the HA brands repository.
test_trend_sensors_use_quarter_hour_timer():
- Replaced price_trend_Xh keys with price_outlook_Xh
- Added 7 price_trajectory_Xh keys to the assertion list
- Updated docstring from "price trend" to "price outlook/trajectory"
Impact: Test suite passes with renamed and new sensor keys.
Updated user documentation to reflect renamed and new sensors.
sensors.md:
- Section renamed "Simple Trend Sensors" → "Price Outlook Sensors (1h–12h)"
- All price_trend_Xh entity references → price_outlook_Xh
- Callout box updated: explains that outlook sensors can mislead at a
price minimum and recommends combining with trajectory sensors
- New section "Price Trajectory Sensors (2h–12h)" added before
"Current Price Trend":
- Table showing which halves are compared per window
- Callout box with the 4 outlook+trajectory combination patterns
(falling+rising = AT the minimum, etc.)
- Key attributes table (first_half_avg, second_half_avg, half_diff_%)
- "Trend Sensors vs Average Sensors" → "Outlook & Trajectory Sensors vs
Average Sensors"
icon-colors.md:
- "Price trend sensors (e.g., price_trend_3h)" → "Price outlook sensors
(e.g., price_outlook_3h)"
- Example entity updated to sensor.<home_name>_price_outlook_3h
automation-examples.md:
- All price_trend_1h/2h/3h/4h/6h references → price_outlook_Xh
- current_price_trend and next_price_trend_change unchanged (correct names)
Impact: Documentation matches actual entity names. New trajectory section
helps users understand when to use outlook vs trajectory sensors together.
Renamed 8 price_trend_Xh entries to price_outlook_Xh and added 15 new
price_trajectory_Xh entries (2h–12h) in all 5 languages (de, en, nb, nl, sv).
translations/ (HA-native: name + 5 states per sensor):
- EN: "Price Outlook (Xh)" / "Price Trajectory (Xh)"
- DE: "Preisausblick (Xh)" / "Preisverlauf (Xh)"
- NB: "Prisutblikk (Xt)" / "Prisforløp (Xt)"
- NL: "Prijsvooruitzicht (Xu)" / "Prijstrajectorie (Xu)"
- SV: "Prisöversikt (Xh)" / "Prisutveckling (Xh)"
custom_translations/ (description + long_description + usage_tips):
- Outlook descriptions updated to explain window-average comparison
semantics (not price direction)
- Trajectory descriptions explain first-half vs second-half logic and
the "outlook: falling + trajectory: rising = you're AT the minimum" pattern
- Trajectory long_description and usage_tips in English for all languages;
description field in native language
Impact: Entity display names update to reflect the corrected semantic meaning.
Renamed 8 sensors to clarify what they actually measure, and added 7 new
sensors for a different (and often more useful) calculation.
--- WHY THE RENAME ---
The old name "price_trend_Xh" implied the sensor shows where prices are
heading. It doesn't — it compares CURRENT price vs the FUTURE WINDOW AVERAGE.
At a price minimum, it shows "strongly_falling" (because the cheap minimum
pulls the average below your current high price), which is the opposite of
intuitive. The name "price_outlook_Xh" correctly conveys: "is now cheaper
or more expensive than the next Nh on average?"
--- NEW: price_trajectory_Xh ---
These sensors compare FIRST HALF vs SECOND HALF of the window, revealing
actual price direction within the window:
price_trajectory_2h: avg(hour 1) vs avg(hour 2)
price_trajectory_3h: avg(first 1.5h) vs avg(second 1.5h)
price_trajectory_4h: avg(first 2h) vs avg(second 2h)
price_trajectory_5h: avg(first 2.5h) vs avg(second 2.5h)
price_trajectory_6h: avg(first 3h) vs avg(second 3h)
price_trajectory_8h: avg(first 4h) vs avg(second 4h)
price_trajectory_12h: avg(first 6h) vs avg(second 6h)
The key use case: at a price minimum, price_outlook_Xh shows "strongly_falling"
but price_trajectory_Xh shows "rising" — correctly revealing the upcoming
reversal. "outlook: falling + trajectory: rising" = you're AT the minimum.
--- IMPLEMENTATION ---
sensor/calculators/trend.py:
- get_price_outlook_value() (was: get_price_trend_value())
- New: get_price_trajectory_value(*, hours: int)
- New: _calculate_first_half_average(hours, next_interval_start)
- New: get_trajectory_attributes() → first_half_avg, second_half_avg, half_diff_%
- clear_trend_cache() also resets _trajectory_attributes
sensor/definitions.py:
- 8 SensorEntityDescription entries: key/translation_key price_trend_Xh → price_outlook_Xh
- New PRICE_TRAJECTORY_SENSORS tuple (2h–5h enabled by default, 6h/8h/12h disabled)
sensor/value_getters.py:
- 8 lambda entries renamed
- 7 new trajectory lambda entries added
sensor/attributes/trend.py:
- startswith("price_trend_") → startswith("price_outlook_")
- New elif branch routing price_trajectory_* to cached trajectory_attributes
sensor/core.py:
- startswith checks updated for both prefix families
- cached_data dict extended with "trajectory_attributes"
coordinator/constants.py:
- TIME_SENSITIVE_ENTITY_KEYS: 8 renamed + 7 new trajectory keys added
config_flow_handlers/entity_check.py:
- volatility + price_trend affected-entity lists: 8 renamed + 7 new
BREAKING CHANGE: Sensors price_trend_1h, price_trend_2h, price_trend_3h,
price_trend_4h, price_trend_5h, price_trend_6h, price_trend_8h,
price_trend_12h have been removed without a deprecation period.
Migration:
Replace price_trend_Xh → price_outlook_Xh everywhere (automations,
dashboards, templates). Behavior is identical — only the entity name
changed. If you want to detect actual price direction within the window
(e.g. "are prices rising or falling right now?"), use the new
price_trajectory_Xh sensors instead.
Impact: Users must update automations and dashboards. Entity IDs change from
sensor.<home>_price_trend_Xh to sensor.<home>_price_outlook_Xh. New
price_trajectory_Xh sensors provide complementary direction information.
Added `suggested_unit_of_measurement=UnitOfTime.HOURS` to all 7 DURATION
sensors to prevent HA from auto-selecting minutes as the display unit.
Without this, HA would pick "min" for small values (e.g., 0.75 h) and then
display large values as "1238 Min." instead of the intended "20 Std. 38 Min."
Affected sensors:
- trend_change_in_minutes
- best_price_period_duration / peak_price_period_duration
- best_price_remaining_minutes / peak_price_remaining_minutes
- best_price_next_in_minutes / peak_price_next_in_minutes
BREAKING CHANGE: Sensor state unit changes from minutes to hours for users
whose entity registry stored "min" as the display unit (the previous default).
Automations using the raw state value (e.g., `state < 60` for "less than 60
minutes") must be updated to use hours (e.g., `state < 1`).
The state attributes `remaining_minutes` and `next_in_minutes` continue to
provide integer minutes and are unaffected.
Impact: Duration sensors now display dynamically as "X h Y min" (e.g.,
"1 h 15 min") instead of a large minutes value like "1238 Min.". Users who
manually customized the unit in HA settings are not affected.
cliff.toml has trim=true which strips git-cliff's trailing newline.
When written to GITHUB_OUTPUT via heredoc, the closing delimiter was
appended to the last content line instead of its own line, causing
"Matching delimiter not found" error.
Added printf '\n' in the workflow and echo "" in generate-notes to
guarantee a newline before the heredoc closing delimiter.
Impact: Release workflow no longer fails when generating release notes.
$GITHUB_OUTPUT heredoc blocks used literal 'EOF' as delimiter, which
breaks parsing if generated release notes contain 'EOF' on its own line.
Replace static 'EOF' with openssl rand -hex 16 random delimiter in
both the version-warning and release-notes output blocks.
Impact: Release workflow no longer fails when commit message bodies
contain 'EOF'.