mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-05-28 18:43:40 +00:00
feat(sensor): add next/previous/rolling-hour price rank sensors
Rename the three existing price rank sensors from price_rank_* to
current_interval_price_rank_* to clarify they rank the current
quarter-hour interval's price, not a daily aggregate — consistent with
current_interval_price_level / current_interval_price_rating naming.
Add 8 new rank sensors covering additional subjects and reference windows:
- next_interval_price_rank_{today,today_tomorrow}
- previous_interval_price_rank_{today,today_tomorrow}
- current_hour_price_rank_{today,today_tomorrow} (5-interval rolling avg)
- next_hour_price_rank_{today,today_tomorrow} (5-interval rolling avg)
All new sensors are disabled by default. The volatility calculator gains a
subject parameter (_get_subject_price / _get_subject_price_attr_key /
_get_rolling_hour_avg_price) to select which price to rank. Sensor key
routing in value_getters.py and attributes/__init__.py updated accordingly.
No migration entries needed — the original price_rank_* sensors were never
released to users.
All 5 translation files updated. sensor-reference.md regenerated (129 entities).
Impact: Users can now track price rank for the next interval (look-ahead),
the previous interval (logging), and rolling hourly averages — for both
same-day and two-day reference windows.
This commit is contained in:
parent
dd59c687e3
commit
51a62d712f
17 changed files with 3915 additions and 3319 deletions
|
|
@ -351,21 +351,6 @@
|
||||||
"long_description": "Zeigt die Gesamtvolatilität, wenn heute und morgen gemeinsam betrachtet werden (sobald die morgigen Daten verfügbar sind). Zeigt, ob über die Tagesgrenze hinweg deutliche Preisunterschiede bestehen. Fällt auf nur-heute zurück, wenn morgige Daten noch fehlen. Hilfreich für mehrtägige Optimierung. `price_coefficient_variation_%` zeigt den Prozentwert, `price_spread` die absolute Preisspanne.",
|
"long_description": "Zeigt die Gesamtvolatilität, wenn heute und morgen gemeinsam betrachtet werden (sobald die morgigen Daten verfügbar sind). Zeigt, ob über die Tagesgrenze hinweg deutliche Preisunterschiede bestehen. Fällt auf nur-heute zurück, wenn morgige Daten noch fehlen. Hilfreich für mehrtägige Optimierung. `price_coefficient_variation_%` zeigt den Prozentwert, `price_spread` die absolute Preisspanne.",
|
||||||
"usage_tips": "Nutze dies für Aufgaben, die sich über mehrere Tage erstrecken. Prüfe, ob die Preisunterschiede groß genug für eine Planung sind. Die einzelnen Tages-Sensoren zeigen die Beiträge pro Tag, falls du mehr Details brauchst."
|
"usage_tips": "Nutze dies für Aufgaben, die sich über mehrere Tage erstrecken. Prüfe, ob die Preisunterschiede groß genug für eine Planung sind. Die einzelnen Tages-Sensoren zeigen die Beiträge pro Tag, falls du mehr Details brauchst."
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"description": "Position des aktuellen Preises in der heutigen Rangliste — sein Perzentilrang (0 % = günstigster Moment)",
|
|
||||||
"long_description": "Zeigt, wie günstig oder teuer der aktuelle Preis im Vergleich zu allen 96 Viertelstunden-Slots von heute ist. 0 % bedeutet: Dies ist der günstigste Moment des Tages — jeder andere Slot kostet mehr. 50 % bedeutet, dass die Hälfte der Slots günstiger ist. ~99 % bedeutet: teuerster Slot des Tages. Formel (Perzentilrang): Wie viele Slots sind günstiger ÷ Gesamt-Slots × 100. Attribute: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Ideal für Automatisierungen: 'Wenn Preisrang heute < 25, Geschirrspüler starten' (günstigstes Viertel des Tages). Oder 'Wenn Preisrang heute > 75, Wärmepumpe pausieren' (teuerstes Viertel). Wert 0 garantiert den günstigsten Slot des Tages."
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"description": "Perzentilrang des aktuellen Preises in der morgigen Rangliste (0 % = günstigster von morgen)",
|
|
||||||
"long_description": "Zeigt, wie der aktuelle Preis im Vergleich zu allen 96 Viertelstunden-Slots von morgen abschneidet — sein Perzentilrang innerhalb der morgigen Preisverteilung. Nützlich, um zu entscheiden, ob es sich lohnt, bis morgen zu warten. 0 % bedeutet, dass der aktuelle Preis günstiger als jeder morgige Slot ist. Gibt 'Unbekannt' zurück, bis die morgigen Daten vorliegen (in der Regel nach 13:00 Uhr). Attribute: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Nutze zur Entscheidung, ob Warten sinnvoll ist: 'Wenn Preisrang morgen < 10, morgen gibt es noch günstigere Slots — Aufgabe verschieben'. Am besten mit einem Binärsensor kombinieren, der sicherstellt, dass die Aufgabe morgen durchgeführt werden kann."
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"description": "Perzentilrang des aktuellen Preises über heute+morgen zusammen (0 % = günstigstes des Zweitages-Fensters)",
|
|
||||||
"long_description": "Zeigt, wie günstig oder teuer der aktuelle Preis im Vergleich zu allen Slots von heute und morgen zusammen ist — sein Perzentilrang innerhalb der Zweitages-Verteilung (bis zu 192 Slots, wenn beide Tage verfügbar). Gibt den breitesten Überblick für flexible Aufgaben. Fällt auf nur-heute zurück, wenn morgige Daten noch fehlen. 0 % = günstigstes des kombinierten Fensters. Attribute: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Das breiteste Signal für 'Ist jetzt ein guter Zeitpunkt?'. Nutze 'Wenn Preisrang heute+morgen < 20, energieintensive Aufgabe jetzt ausführen'. Besonders wertvoll, wenn Aufgaben einen Tag lang warten können — ein Wert nahe 0 über zwei Tage ist ein wirklich außergewöhnlicher Preis."
|
|
||||||
},
|
|
||||||
"data_lifecycle_status": {
|
"data_lifecycle_status": {
|
||||||
"description": "Aktueller Status des Preisdaten-Lebenszyklus und der Zwischenspeicherung",
|
"description": "Aktueller Status des Preisdaten-Lebenszyklus und der Zwischenspeicherung",
|
||||||
"long_description": "Zeigt an, ob die Integration zwischengespeicherte Daten oder frische Daten von der API verwendet. Zeigt aktuellen Lebenszyklus-Status: 'cached' (verwendet gespeicherte Daten), 'fresh' (gerade von API abgerufen), 'refreshing' (wird gerade abgerufen), 'searching_tomorrow' (sucht aktiv nach Morgendaten nach 13:00 Uhr), 'turnover_pending' (innerhalb 15 Minuten vor Mitternacht, 23:45-00:00) oder 'error' (Abruf fehlgeschlagen). Enthält umfassende Attribute wie Cache-Alter, nächste API-Abfragezeit, Datenvollständigkeit und API-Aufruf-Statistiken.",
|
"long_description": "Zeigt an, ob die Integration zwischengespeicherte Daten oder frische Daten von der API verwendet. Zeigt aktuellen Lebenszyklus-Status: 'cached' (verwendet gespeicherte Daten), 'fresh' (gerade von API abgerufen), 'refreshing' (wird gerade abgerufen), 'searching_tomorrow' (sucht aktiv nach Morgendaten nach 13:00 Uhr), 'turnover_pending' (innerhalb 15 Minuten vor Mitternacht, 23:45-00:00) oder 'error' (Abruf fehlgeschlagen). Enthält umfassende Attribute wie Cache-Alter, nächste API-Abfragezeit, Datenvollständigkeit und API-Aufruf-Statistiken.",
|
||||||
|
|
@ -525,6 +510,61 @@
|
||||||
"description": "Leichtgewichtige Metadaten für Diagrammkonfiguration",
|
"description": "Leichtgewichtige Metadaten für Diagrammkonfiguration",
|
||||||
"long_description": "Liefert wesentliche Diagrammkonfigurationswerte als Sensor-Attribute. Nützlich für jede Diagrammkarte, die Y-Achsen-Grenzen benötigt. Der Sensor ruft get_chartdata im Nur-Metadaten-Modus auf (keine Datenverarbeitung) und extrahiert: yaxis_min, yaxis_max (vorgeschlagener Y-Achsenbereich für optimale Skalierung). Der Status spiegelt das Service-Call-Ergebnis wider: 'ready' bei Erfolg, 'error' bei Fehler, 'pending' während der Initialisierung.",
|
"long_description": "Liefert wesentliche Diagrammkonfigurationswerte als Sensor-Attribute. Nützlich für jede Diagrammkarte, die Y-Achsen-Grenzen benötigt. Der Sensor ruft get_chartdata im Nur-Metadaten-Modus auf (keine Datenverarbeitung) und extrahiert: yaxis_min, yaxis_max (vorgeschlagener Y-Achsenbereich für optimale Skalierung). Der Status spiegelt das Service-Call-Ergebnis wider: 'ready' bei Erfolg, 'error' bei Fehler, 'pending' während der Initialisierung.",
|
||||||
"usage_tips": "Konfiguriere über configuration.yaml unter tibber_prices.chart_metadata_config (optional: day, subunit_currency, resolution). Der Sensor aktualisiert sich automatisch bei Preisdatenänderungen. Greife auf Metadaten aus Attributen zu: yaxis_min, yaxis_max. Verwende mit config-template-card oder jedem Tool, das Entity-Attribute liest - perfekt für dynamische Diagrammkonfiguration ohne manuelle Berechnungen."
|
"usage_tips": "Konfiguriere über configuration.yaml unter tibber_prices.chart_metadata_config (optional: day, subunit_currency, resolution). Der Sensor aktualisiert sich automatisch bei Preisdatenänderungen. Greife auf Metadaten aus Attributen zu: yaxis_min, yaxis_max. Verwende mit config-template-card oder jedem Tool, das Entity-Attribute liest - perfekt für dynamische Diagrammkonfiguration ohne manuelle Berechnungen."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"description": "Position des aktuellen Intervallpreises in der heutigen Rangliste — Perzentilrang (0 % = günstigster Moment)",
|
||||||
|
"long_description": "Zeigt, wie günstig oder teuer der aktuelle Viertelstunden-Intervallpreis im Vergleich zu allen 96 heutigen Slots ist. 0 % bedeutet: Dieser Moment ist der günstigste des Tages. 50 % bedeutet: Die Hälfte der Slots ist günstiger. ca. 99 % bedeutet: Dieser Slot ist der teuerste des Tages. Formel (Perzentilrang): Anzahl günstigerer Slots ÷ Gesamtanzahl × 100. Attribute: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Ideal für Automationen: 'Wenn current_interval_price_rank_today < 25, Spülmaschine starten' (günstigstes Viertel des Tages). Oder 'Wenn current_interval_price_rank_today > 75, Wärmepumpe pausieren'. Ein Wert von 0 garantiert den günstigsten Slot des Tages."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"description": "Perzentilrang des aktuellen Intervallpreises in der morgigen Rangliste (0 % = günstigster von morgen)",
|
||||||
|
"long_description": "Zeigt, wie der aktuelle Intervallpreis im Vergleich zu allen 96 morgigen Viertelstunden-Slots abschneidet. Nützlich, um zu entscheiden, ob man bis morgen warten soll. 0 % bedeutet: Der aktuelle Preis ist günstiger als jeder morgige Slot. Gibt 'Unbekannt' zurück, bis die morgigen Daten verfügbar sind (typischerweise nach 13:00 Uhr). Attribute: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Warten lohnt sich? 'Wenn current_interval_price_rank_tomorrow < 10, gibt es morgen noch günstigere Slots — Aufgabe verschieben'. Am besten mit einem Binärsensor kombinieren."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Perzentilrang des aktuellen Intervallpreises über heute+morgen zusammen (0 % = günstigstes des Zweitages-Fensters)",
|
||||||
|
"long_description": "Zeigt, wie günstig oder teuer der aktuelle Intervallpreis im Vergleich zu allen Slots über heute und morgen zusammen ist (bis zu 192 Viertelstunden-Slots). Fällt auf nur heute zurück, wenn morgige Daten noch nicht verfügbar sind. 0 % = günstigster Slot des kombinierten Zweitages-Fensters. Attribute: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Das breiteste Signal für 'Ist jetzt ein guter Zeitpunkt?'. Verwende 'Wenn current_interval_price_rank_today_tomorrow < 20, energieintensive Aufgabe jetzt starten'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"description": "Perzentilrang des nächsten Intervallpreises in der heutigen Rangliste (0 % = günstigster Moment heute)",
|
||||||
|
"long_description": "Zeigt den Perzentilrang des nächsten Viertelstunden-Intervalls innerhalb der 96 heutigen Slots. Ermöglicht einen Blick voraus, bevor das nächste Intervall beginnt. Attribute: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Für Vorbereitung: 'Wenn next_interval_price_rank_today < 15, jetzt vorheizen, damit das Gerät im nächsten günstigen Slot läuft'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Perzentilrang des nächsten Intervallpreises über heute+morgen zusammen (0 % = günstigstes des Zweitages-Fensters)",
|
||||||
|
"long_description": "Zeigt den Perzentilrang des nächsten Viertelstunden-Intervalls innerhalb des kombinierten heute+morgen-Pools (bis zu 192 Slots). Fällt auf nur heute zurück, wenn morgige Daten nicht verfügbar sind. Attribute: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Weitester Vorausblick: 'Wenn next_interval_price_rank_today_tomorrow < 10, ist das nächste Intervall eines der günstigsten im Zweitages-Fenster'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"description": "Perzentilrang des letzten Intervallpreises in der heutigen Rangliste (0 % = günstigster Moment heute)",
|
||||||
|
"long_description": "Zeigt den Perzentilrang des gerade beendeten Viertelstunden-Intervalls innerhalb der 96 heutigen Slots. Nützlich für Protokollierung. Attribute: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Für retrospektive Automationen: 'Preisniveau des letzten Intervalls für Energieberichte aufzeichnen'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Perzentilrang des letzten Intervallpreises über heute+morgen zusammen (0 % = günstigstes des Zweitages-Fensters)",
|
||||||
|
"long_description": "Zeigt den Perzentilrang des gerade beendeten Viertelstunden-Intervalls innerhalb des kombinierten heute+morgen-Pools (bis zu 192 Slots). Fällt auf nur heute zurück. Attribute: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Für retrospektive Vergleiche über ein Zweitages-Fenster."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"description": "Perzentilrang des gleitenden Stunden-Durchschnittspreises in der heutigen Rangliste (0 % = günstigste Stunde heute)",
|
||||||
|
"long_description": "Zeigt, wo der gleitende 5-Intervall-Durchschnitt (2 Intervalle vor + aktuell + 2 danach, ca. 1 Stunde) in der heutigen Preisrangliste liegt. Glättet kurze Preisspitzen für eine breitere Einschätzung. Attribute: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Für Aufgaben, die ca. eine Stunde dauern: 'Wenn current_hour_price_rank_today < 20, ist jetzt eine günstige Stunde — Waschmaschine starten'."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Gleitender Stunden-Durchschnittspreisrang über heute+morgen zusammen (0 % = günstigste Stunde im Zweitages-Fenster)",
|
||||||
|
"long_description": "Zeigt, wo der gleitende 5-Intervall-Durchschnitt (±2 Intervalle, ca. 1 Stunde) in der kombinierten heute+morgen-Rangliste liegt (bis zu 192 Slots). Fällt auf nur heute zurück. Attribute: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Weitestes Stundensignal: 'Wenn current_hour_price_rank_today_tomorrow < 15, ist dies eine der günstigsten Stunden im Zweitages-Fenster'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"description": "Perzentilrang des nächsten gleitenden Stunden-Durchschnittspreises in der heutigen Rangliste (0 % = günstigste Stunde heute)",
|
||||||
|
"long_description": "Zeigt, wo der auf das nächste Intervall zentrierte gleitende 5-Intervall-Durchschnitt in der heutigen Preisrangliste liegt. Ermöglicht Planung eine Stunde im Voraus. Attribute: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Eine Stunde vorausplanen: 'Wenn next_hour_price_rank_today < 20, ist die kommende Stunde günstig — Aufgabe jetzt starten'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Nächster gleitender Stunden-Durchschnittspreisrang über heute+morgen zusammen (0 % = günstigste Stunde im Zweitages-Fenster)",
|
||||||
|
"long_description": "Zeigt, wo der auf das nächste Intervall zentrierte gleitende 5-Intervall-Durchschnitt in der kombinierten heute+morgen-Rangliste liegt (bis zu 192 Slots). Fällt auf nur heute zurück. Attribute: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Weitester Stundenvorausblick: 'Wenn next_hour_price_rank_today_tomorrow < 10, ist die kommende Stunde eine der günstigsten im Zweitages-Fenster'."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -351,21 +351,6 @@
|
||||||
"long_description": "Shows overall price volatility when considering both today and tomorrow together (when available). Indicates whether there are significant price differences across the day boundary. Falls back to today-only when tomorrow's data isn't available yet. Useful for understanding multi-day optimization opportunities. Check `price_coefficient_variation_%` for the variance percentage and `price_spread` for the absolute price span.",
|
"long_description": "Shows overall price volatility when considering both today and tomorrow together (when available). Indicates whether there are significant price differences across the day boundary. Falls back to today-only when tomorrow's data isn't available yet. Useful for understanding multi-day optimization opportunities. Check `price_coefficient_variation_%` for the variance percentage and `price_spread` for the absolute price span.",
|
||||||
"usage_tips": "Use for planning tasks that span multiple days. Check if prices vary enough to make scheduling worthwhile. The individual day volatility sensors show breakdown per day if you need more detail."
|
"usage_tips": "Use for planning tasks that span multiple days. Check if prices vary enough to make scheduling worthwhile. The individual day volatility sensors show breakdown per day if you need more detail."
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"description": "Where the current price sits in today's ranking — its percentile rank (0% = cheapest moment)",
|
|
||||||
"long_description": "Shows how cheap or expensive the current price is compared to all of today's 96 quarter-hour slots. 0% means this is the cheapest moment of the day — every other slot costs more. 50% means half of today's slots are cheaper. ~99% means it's the most expensive slot of the day. Formula (percentile rank): how many slots are cheaper ÷ total slots × 100. Attributes: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Ideal for automations: 'If price_rank_today < 25, start dishwasher' (cheapest quarter of the day). Or 'If price_rank_today > 75, pause heat pump' (most expensive quarter). A value of 0 guarantees you're at the cheapest slot of the day."
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"description": "Where the current price sits in tomorrow's percentile ranking (0% = cheapest of tomorrow)",
|
|
||||||
"long_description": "Shows how the current price compares to all of tomorrow's 96 quarter-hour slots — its percentile rank within tomorrow's distribution. Useful for deciding whether to wait until tomorrow. 0% means the current price is cheaper than every slot tomorrow. Returns 'Unknown' until tomorrow's data arrives (typically after 13:00). Attributes: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Use to decide whether to wait: 'If price_rank_tomorrow < 10, tomorrow has even cheaper slots — postpone the task'. Best combined with a binary sensor to confirm the task can actually run tomorrow."
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"description": "Percentile rank across today and tomorrow combined (0% = cheapest of the two-day window)",
|
|
||||||
"long_description": "Shows how cheap or expensive the current price is compared to all slots across today and tomorrow together (up to 192 quarter-hour slots when both days are available) — the percentile rank within the two-day distribution. Gives the broadest view for flexible tasks. Falls back to today-only when tomorrow's data isn't available yet. 0% = cheapest of the combined two-day window. Attributes: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "The broadest signal for 'is now a good time?'. Use 'If price_rank_today_tomorrow < 20, run energy-intensive task now'. Especially valuable when tasks can wait a full day — a value near 0 across two days is a genuinely exceptional price."
|
|
||||||
},
|
|
||||||
"data_lifecycle_status": {
|
"data_lifecycle_status": {
|
||||||
"description": "Current state of price data lifecycle and caching",
|
"description": "Current state of price data lifecycle and caching",
|
||||||
"long_description": "Shows whether the integration is using cached data or fresh data from the API. Displays current lifecycle state: 'cached' (using stored data), 'fresh' (just fetched from API), 'refreshing' (currently fetching), 'searching_tomorrow' (actively polling for tomorrow's data after 13:00), 'turnover_pending' (within 15 minutes of midnight, 23:45-00:00), or 'error' (fetch failed). Includes comprehensive attributes like cache age, next API poll time, data completeness, and API call statistics.",
|
"long_description": "Shows whether the integration is using cached data or fresh data from the API. Displays current lifecycle state: 'cached' (using stored data), 'fresh' (just fetched from API), 'refreshing' (currently fetching), 'searching_tomorrow' (actively polling for tomorrow's data after 13:00), 'turnover_pending' (within 15 minutes of midnight, 23:45-00:00), or 'error' (fetch failed). Includes comprehensive attributes like cache age, next API poll time, data completeness, and API call statistics.",
|
||||||
|
|
@ -525,6 +510,61 @@
|
||||||
"description": "Lightweight metadata for chart configuration",
|
"description": "Lightweight metadata for chart configuration",
|
||||||
"long_description": "Provides essential chart configuration values as sensor attributes. Useful for any chart card that needs Y-axis bounds. The sensor calls get_chartdata with metadata-only mode (no data processing) and extracts: yaxis_min, yaxis_max (suggested Y-axis range for optimal scaling). The state reflects the service call result: 'ready' when successful, 'error' on failure, 'pending' during initialization.",
|
"long_description": "Provides essential chart configuration values as sensor attributes. Useful for any chart card that needs Y-axis bounds. The sensor calls get_chartdata with metadata-only mode (no data processing) and extracts: yaxis_min, yaxis_max (suggested Y-axis range for optimal scaling). The state reflects the service call result: 'ready' when successful, 'error' on failure, 'pending' during initialization.",
|
||||||
"usage_tips": "Configure via configuration.yaml under tibber_prices.chart_metadata_config (optional: day, subunit_currency, resolution). The sensor automatically refreshes when price data updates. Access metadata from attributes: yaxis_min, yaxis_max. Use with config-template-card or any tool that reads entity attributes - perfect for dynamic chart configuration without manual calculations."
|
"usage_tips": "Configure via configuration.yaml under tibber_prices.chart_metadata_config (optional: day, subunit_currency, resolution). The sensor automatically refreshes when price data updates. Access metadata from attributes: yaxis_min, yaxis_max. Use with config-template-card or any tool that reads entity attributes - perfect for dynamic chart configuration without manual calculations."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"description": "Where the current interval's price sits in today's ranking — its percentile rank (0% = cheapest moment)",
|
||||||
|
"long_description": "Shows how cheap or expensive the current quarter-hour interval's price is compared to all of today's 96 quarter-hour slots. 0% means this is the cheapest moment of the day — every other slot costs more. 50% means half of today's slots are cheaper. ~99% means it's the most expensive slot of the day. Formula (percentile rank): how many slots are cheaper ÷ total slots × 100. Attributes: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Ideal for automations: 'If current_interval_price_rank_today < 25, start dishwasher' (cheapest quarter of the day). Or 'If current_interval_price_rank_today > 75, pause heat pump' (most expensive quarter). A value of 0 guarantees you're at the cheapest slot of the day."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"description": "Where the current interval's price sits in tomorrow's percentile ranking (0% = cheapest of tomorrow)",
|
||||||
|
"long_description": "Shows how the current interval's price compares to all of tomorrow's 96 quarter-hour slots — its percentile rank within tomorrow's distribution. Useful for deciding whether to wait until tomorrow. 0% means the current price is cheaper than every slot tomorrow. Returns 'Unknown' until tomorrow's data arrives (typically after 13:00). Attributes: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Use to decide whether to wait: 'If current_interval_price_rank_tomorrow < 10, tomorrow has even cheaper slots — postpone the task'. Best combined with a binary sensor to confirm the task can actually run tomorrow."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Current interval's percentile rank across today and tomorrow combined (0% = cheapest of the two-day window)",
|
||||||
|
"long_description": "Shows how cheap or expensive the current interval's price is compared to all slots across today and tomorrow together (up to 192 quarter-hour slots when both days are available) — the percentile rank within the two-day distribution. Gives the broadest view for flexible tasks. Falls back to today-only when tomorrow's data isn't available yet. 0% = cheapest of the combined two-day window. Attributes: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "The broadest signal for 'is now a good time?'. Use 'If current_interval_price_rank_today_tomorrow < 20, run energy-intensive task now'. Especially valuable when tasks can wait a full day — a value near 0 across two days is a genuinely exceptional price."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"description": "Where the next interval's price sits in today's ranking (0% = cheapest moment of today)",
|
||||||
|
"long_description": "Shows the percentile rank of the upcoming quarter-hour interval's price within today's 96 slots. Lets you see at a glance how the next interval compares to the rest of the day before it starts. Attributes: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Use to prepare for the next interval: 'If next_interval_price_rank_today < 15, start pre-heating now so the device runs during the next cheap slot'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Next interval's percentile rank across today and tomorrow combined (0% = cheapest of the two-day window)",
|
||||||
|
"long_description": "Shows the percentile rank of the upcoming quarter-hour interval's price within the combined today+tomorrow pool (up to 192 slots). Falls back to today-only when tomorrow's data isn't available. Attributes: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Broadest look-ahead: 'If next_interval_price_rank_today_tomorrow < 10, the next interval is among the cheapest slots of the two-day window — optimal time to start long tasks'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"description": "Where the previous interval's price sat in today's ranking (0% = cheapest moment of today)",
|
||||||
|
"long_description": "Shows the percentile rank of the just-ended quarter-hour interval's price within today's 96 slots. Useful for logging how cheap/expensive the last interval was. Attributes: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Useful for retrospective automations or logging: 'Record the cost tier of the last interval for energy reports'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Previous interval's percentile rank across today and tomorrow combined (0% = cheapest of the two-day window)",
|
||||||
|
"long_description": "Shows the percentile rank of the just-ended quarter-hour interval's price within the combined today+tomorrow pool (up to 192 slots). Falls back to today-only when tomorrow's data isn't available. Attributes: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Useful for retrospective comparisons across a two-day window."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"description": "Percentile rank of the current rolling hour's average price within today's distribution (0% = cheapest hour)",
|
||||||
|
"long_description": "Shows where the 5-interval rolling average (2 intervals before + current + 2 after, ~1 hour) sits in today's price ranking. Smooths out short spikes and gives a broader view of whether this hour is cheap or expensive relative to the day. Attributes: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "For tasks that take about an hour: 'If current_hour_price_rank_today < 20, this is a cheap hour — run the washing machine'."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Current rolling hour's average price rank across today and tomorrow combined (0% = cheapest hour of the two-day window)",
|
||||||
|
"long_description": "Shows where the 5-interval rolling average (±2 intervals, ~1 hour) sits in the combined today+tomorrow price ranking (up to 192 slots). Falls back to today-only when tomorrow's data isn't available. Attributes: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Broadest hourly signal: 'If current_hour_price_rank_today_tomorrow < 15, this is one of the cheapest hours across two days — ideal for long flexible tasks'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"description": "Percentile rank of the next rolling hour's average price within today's distribution (0% = cheapest hour of today)",
|
||||||
|
"long_description": "Shows where the 5-interval rolling average centered on the next interval sits in today's price ranking. Lets you plan one hour ahead — is the upcoming hour cheap or expensive relative to today? Attributes: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Plan one hour ahead: 'If next_hour_price_rank_today < 20, the upcoming hour is cheap — start a task now to run through it'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Next rolling hour's average price rank across today and tomorrow combined (0% = cheapest hour of the two-day window)",
|
||||||
|
"long_description": "Shows where the 5-interval rolling average centered on the next interval sits in the combined today+tomorrow price ranking (up to 192 slots). Falls back to today-only when tomorrow's data isn't available. Attributes: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Broadest hourly look-ahead: 'If next_hour_price_rank_today_tomorrow < 10, the upcoming hour is among the cheapest of the two-day window'."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -351,21 +351,6 @@
|
||||||
"long_description": "Viser samlet volatilitet når i dag og i morgen sees sammen (når morgendata er tilgjengelig). Viser om det finnes klare prisforskjeller over dagsgrensen. Faller tilbake til kun i dag hvis morgendata mangler. Nyttig for flerdagers optimalisering. `price_coefficient_variation_%` viser prosentverdien, `price_spread` viser den absolutte prisspennet.",
|
"long_description": "Viser samlet volatilitet når i dag og i morgen sees sammen (når morgendata er tilgjengelig). Viser om det finnes klare prisforskjeller over dagsgrensen. Faller tilbake til kun i dag hvis morgendata mangler. Nyttig for flerdagers optimalisering. `price_coefficient_variation_%` viser prosentverdien, `price_spread` viser den absolutte prisspennet.",
|
||||||
"usage_tips": "Bruk for oppgaver som går over flere dager. Sjekk om prisforskjellene er store nok til å planlegge etter. De enkelte dagssensorene viser bidrag per dag om du trenger mer detalj."
|
"usage_tips": "Bruk for oppgaver som går over flere dager. Sjekk om prisforskjellene er store nok til å planlegge etter. De enkelte dagssensorene viser bidrag per dag om du trenger mer detalj."
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"description": "Den gjeldende prisens posisjon i dagens rangering — dens persentilrang (0 % = billigste øyeblikk)",
|
|
||||||
"long_description": "Viser hvor billig eller dyr den gjeldende prisen er sammenlignet med alle 96 kvartersintervaller for i dag. 0 % betyr at dette er dagens billigste øyeblikk — alle andre intervaller koster mer. 50 % betyr at halvparten av intervallene er billigere. ~99 % betyr: dyreste intervall på dagen. Formel (persentilrang): Hvor mange intervaller er billigere ÷ totalt antall × 100. Attributter: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Ideelt for automasjoner: 'Hvis prisrang < 25, start oppvaskmaskin' (billigste fjerdedel av dagen). Eller 'Hvis prisrang > 75, sett varmepumpen på pause' (dyreste fjerdedel). Verdien 0 garanterer at du er på dagens billigste intervall."
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"description": "Persentilrang for gjeldende pris i morgendagens rangering (0 % = billigst i morgen)",
|
|
||||||
"long_description": "Viser hvordan den gjeldende prisen sammenlignes med alle 96 kvartersintervaller for i morgen — dens persentilrang innenfor morgendagens prisfordeling. Nyttig for å avgjere om det lønner seg å vente til i morgen. 0 % betyr at gjeldende pris er billigere enn alle morgendagens intervaller. Returnerer 'Ukjent' til morgendagens data ankommer (typisk etter 13:00). Attributter: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Bruk for å avgjøre om det lønner seg å vente: 'Hvis prisrang i morgen < 10, finnes det enda billigere tidspunkter i morgen — utsett oppgaven'. Best kombinert med en binærsensor som bekrefter at oppgaven faktisk kan utføres i morgen."
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"description": "Persentilrang for gjeldende pris over i dag+i morgen kombinert (0 % = billigst i todagersvinduet)",
|
|
||||||
"long_description": "Viser hvor billig eller dyr den gjeldende prisen er sammenlignet med alle intervaller for i dag og i morgen kombinert — dens persentilrang innenfor todagersfordelingen (opptil 192 intervaller når begge dagene er tilgjengelige). Gir det bredeste todagers-oversikten for fleksible oppgaver. Faller tilbake til kun i dag når morgendagens data mangler. 0 % = billigst i det kombinerte vinduet. Attributter: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Det bredeste signalet for 'Er nå et godt tidspunkt?'. Bruk 'Hvis prisrang i dag+i morgen < 20, kjør energikrevende oppgave nå'. Spesielt verdifullt når oppgaver kan vente en hel dag — en verdi nær 0 over to dager er en virkelig eksepsjonell pris."
|
|
||||||
},
|
|
||||||
"data_lifecycle_status": {
|
"data_lifecycle_status": {
|
||||||
"description": "Gjeldende tilstand for prisdatalivssyklus og hurtigbufring",
|
"description": "Gjeldende tilstand for prisdatalivssyklus og hurtigbufring",
|
||||||
"long_description": "Viser om integrasjonen bruker hurtigbufrede data eller ferske data fra API-et. Viser gjeldende livssyklustilstand: 'cached' (bruker lagrede data), 'fresh' (nettopp hentet fra API), 'refreshing' (henter for øyeblikket), 'searching_tomorrow' (søker aktivt etter morgendagens data etter 13:00), 'turnover_pending' (innen 15 minutter før midnatt, 23:45-00:00), eller 'error' (henting mislyktes). Inkluderer omfattende attributter som cache-alder, neste API-spørring, datafullstendighet og API-anropsstatistikk.",
|
"long_description": "Viser om integrasjonen bruker hurtigbufrede data eller ferske data fra API-et. Viser gjeldende livssyklustilstand: 'cached' (bruker lagrede data), 'fresh' (nettopp hentet fra API), 'refreshing' (henter for øyeblikket), 'searching_tomorrow' (søker aktivt etter morgendagens data etter 13:00), 'turnover_pending' (innen 15 minutter før midnatt, 23:45-00:00), eller 'error' (henting mislyktes). Inkluderer omfattende attributter som cache-alder, neste API-spørring, datafullstendighet og API-anropsstatistikk.",
|
||||||
|
|
@ -525,6 +510,61 @@
|
||||||
"description": "Lettvekts metadata for diagramkonfigurasjon",
|
"description": "Lettvekts metadata for diagramkonfigurasjon",
|
||||||
"long_description": "Gir essensielle diagramkonfigurasjonsverdier som sensorattributter. Nyttig for ethvert diagramkort som trenger Y-aksegrenser. Sensoren kaller get_chartdata med kun-metadata-modus (ingen databehandling) og trekker ut: yaxis_min, yaxis_max (foreslått Y-akseområde for optimal skalering). Status reflekterer tjenestekallresultatet: 'ready' ved suksess, 'error' ved feil, 'pending' under initialisering.",
|
"long_description": "Gir essensielle diagramkonfigurasjonsverdier som sensorattributter. Nyttig for ethvert diagramkort som trenger Y-aksegrenser. Sensoren kaller get_chartdata med kun-metadata-modus (ingen databehandling) og trekker ut: yaxis_min, yaxis_max (foreslått Y-akseområde for optimal skalering). Status reflekterer tjenestekallresultatet: 'ready' ved suksess, 'error' ved feil, 'pending' under initialisering.",
|
||||||
"usage_tips": "Konfigurer via configuration.yaml under tibber_prices.chart_metadata_config (valgfritt: day, subunit_currency, resolution). Sensoren oppdateres automatisk når prisdata endres. Få tilgang til metadata fra attributter: yaxis_min, yaxis_max. Bruk med config-template-card eller ethvert verktøy som leser entitetsattributter - perfekt for dynamisk diagramkonfigurasjon uten manuelle beregninger."
|
"usage_tips": "Konfigurer via configuration.yaml under tibber_prices.chart_metadata_config (valgfritt: day, subunit_currency, resolution). Sensoren oppdateres automatisk når prisdata endres. Få tilgang til metadata fra attributter: yaxis_min, yaxis_max. Bruk med config-template-card eller ethvert verktøy som leser entitetsattributter - perfekt for dynamisk diagramkonfigurasjon uten manuelle beregninger."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"description": "Hvor nåværende intervallpris plasserer seg i dagens rangering — som prosentilrang (0 % = billigste øyeblikk)",
|
||||||
|
"long_description": "Viser hvor billig eller dyr prisen for det gjældende kvarter er sammenlignet med alle 96 kvarterstimer i dag. 0 % betyr at dette er det billigste øyeblikket i dag. 50 % betyr at halvparten av dagens tidsluker er billigere. ca. 99 % betyr det dyreste tidssluket i dag. Formel: antall billigere tidsluker ÷ totalt antall × 100. Attributter: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Ideelt for automatiseringer: 'Hvis current_interval_price_rank_today < 25, start oppvaskmaskinen'. A value of 0 garanterer at du er på det billigste tidssluket i dag."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"description": "Prosentilrang for gjældende intervallpris i morgendagens rangering (0 % = billigste av i morgen)",
|
||||||
|
"long_description": "Viser hvordan gjældende intervallpris sammenlignes med alle 96 kvarterstimer i morgen. 0 % betyr at gjældende pris er billigere enn alle morgendagens tidsluker. Returnerer 'Ukjent' til morgendagens data er tilgjengelig (vanligvis etter kl. 13:00). Attributter: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Bruk for å avgjøre om det er verdt å vente: 'Hvis current_interval_price_rank_tomorrow < 10, finnes det enda billigere tidsluker i morgen — utsett oppgaven'."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Prosentilrang for gjældende intervallpris over i dag+i morgen samlet (0 % = billigste i to-dagers-vinduet)",
|
||||||
|
"long_description": "Viser hvor billig eller dyr gjældende intervallpris er sammenlignet med alle tidsluker over i dag og i morgen samlet (opptil 192 kvarterstimer). Fæller tilbake til kun i dag når morgendagens data ikke er tilgjengelig. Attributter: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Det bredeste signalet for 'er det nå et godt tidspunkt?'. Bruk 'Hvis current_interval_price_rank_today_tomorrow < 20, kjør energikrevende oppgave nå'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"description": "Prosentilrang for neste intervalls pris i dagens rangering (0 % = billigste øyeblikk i dag)",
|
||||||
|
"long_description": "Viser prosentilrangen for det kommende kvarter innenfor dagens 96 tidsluker. Gir forhåndsvisning før neste intervall begynner. Attributter: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "For forberedelse: 'Hvis next_interval_price_rank_today < 15, start forvarming nå så enheten kjører i neste billige tidsluke'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Prosentilrang for neste intervalls pris over i dag+i morgen samlet (0 % = billigste i to-dagers-vinduet)",
|
||||||
|
"long_description": "Viser prosentilrangen for det kommende kvarter innenfor det kombinerte i dag+i morgen-bassenget (opptil 192 tidsluker). Fæller tilbake til kun i dag. Attributter: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Bredeste fremtidsvisning: 'Hvis next_interval_price_rank_today_tomorrow < 10, er neste intervall blant de billigste i to-dagers-vinduet'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"description": "Prosentilrang for forrige intervalls pris i dagens rangering (0 % = billigste øyeblikk i dag)",
|
||||||
|
"long_description": "Viser prosentilrangen for det nettopp avsluttede kvarter innenfor dagens 96 tidsluker. Nyttig for logging. Attributter: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "For retrospektive automatiseringer: 'Registrer prisnivyå for forrige intervall i energirapporter'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Prosentilrang for forrige intervalls pris over i dag+i morgen samlet (0 % = billigste i to-dagers-vinduet)",
|
||||||
|
"long_description": "Viser prosentilrangen for det nettopp avsluttede kvarter innenfor det kombinerte i dag+i morgen-bassenget (opptil 192 tidsluker). Fæller tilbake til kun i dag. Attributter: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "For retrospektive sammenligninger over et to-dagers-vindu."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"description": "Prosentilrang for glidende timegjennomsnittpris i dagens rangering (0 % = billigste time i dag)",
|
||||||
|
"long_description": "Viser plasseringen til det glidende 5-intervall-gjennomsnittet (2 intervaller før + gjældende + 2 etter, ca. 1 time) i dagens prisrangering. Jevner ut korte pristopper. Attributter: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "For oppgaver som tar omtrent en time: 'Hvis current_hour_price_rank_today < 20, er dette en billig time — start vaskemaskinen'."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Glidende timegjennomsnittprisrang over i dag+i morgen samlet (0 % = billigste time i to-dagers-vinduet)",
|
||||||
|
"long_description": "Viser plasseringen til det glidende 5-intervall-gjennomsnittet (±2 intervaller, ca. 1 time) i den kombinerte i dag+i morgen-rangeringen (opptil 192 tidsluker). Fæller tilbake til kun i dag. Attributter: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Bredeste timesignal: 'Hvis current_hour_price_rank_today_tomorrow < 15, er dette en av de billigste timene i to-dagers-vinduet'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"description": "Prosentilrang for neste glidende timegjennomsnittpris i dagens rangering (0 % = billigste time i dag)",
|
||||||
|
"long_description": "Viser plasseringen til det 5-intervall-gjennomsnittet sentrert på neste intervall i dagens prisrangering. Muliggjør planlegging en time frem i tid. Attributter: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Forutse en time frem: 'Hvis next_hour_price_rank_today < 20, er den kommende timen billig — start en oppgave nå'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Neste glidende timegjennomsnittprisrang over i dag+i morgen samlet (0 % = billigste time i to-dagers-vinduet)",
|
||||||
|
"long_description": "Viser plasseringen til det 5-intervall-gjennomsnittet sentrert på neste intervall i den kombinerte i dag+i morgen-rangeringen (opptil 192 tidsluker). Fæller tilbake til kun i dag. Attributter: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Bredeste timefremtidsvisning: 'Hvis next_hour_price_rank_today_tomorrow < 10, er den kommende timen blant de billigste i to-dagers-vinduet'."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -351,21 +351,6 @@
|
||||||
"long_description": "Geeft de totale volatiliteit weer wanneer vandaag en morgen samen worden bekeken (zodra morgengegevens beschikbaar zijn). Toont of er duidelijke prijsverschillen over de daggrens heen zijn. Valt terug naar alleen vandaag als morgengegevens ontbreken. Handig voor meerdaagse optimalisatie. `price_coefficient_variation_%` toont het percentage, `price_spread` de absolute prijsspanne.",
|
"long_description": "Geeft de totale volatiliteit weer wanneer vandaag en morgen samen worden bekeken (zodra morgengegevens beschikbaar zijn). Toont of er duidelijke prijsverschillen over de daggrens heen zijn. Valt terug naar alleen vandaag als morgengegevens ontbreken. Handig voor meerdaagse optimalisatie. `price_coefficient_variation_%` toont het percentage, `price_spread` de absolute prijsspanne.",
|
||||||
"usage_tips": "Gebruik voor taken die meerdere dagen beslaan. Kijk of de prijsverschillen groot genoeg zijn om plannen op te baseren. De afzonderlijke dag-sensoren tonen per-dag bijdragen als je meer detail wilt."
|
"usage_tips": "Gebruik voor taken die meerdere dagen beslaan. Kijk of de prijsverschillen groot genoeg zijn om plannen op te baseren. De afzonderlijke dag-sensoren tonen per-dag bijdragen als je meer detail wilt."
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"description": "De positie van de huidige prijs in de ranglijst van vandaag — zijn percentielrang (0% = goedkoopst)",
|
|
||||||
"long_description": "Toont hoe goedkoop of duur de huidige prijs is ten opzichte van alle 96 kwartiersslots van vandaag. 0% betekent dat dit het goedkoopste moment van de dag is — elk ander slot kost meer. 50% betekent dat de helft van de slots goedkoper is. ~99% betekent het duurste slot van de dag. Formule (percentielrang): hoeveel slots zijn goedkoper ÷ totaal aantal × 100. Attributen: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Ideaal voor automatiseringen: 'Als prijsrang < 25, start vaatwasser' (goedkoopste kwart van de dag). Of 'Als prijsrang > 75, pauzeer warmtepomp' (duurste kwart). Waarde 0 garandeert dat je op het goedkoopste slot van de dag zit."
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"description": "Percentielrang van de huidige prijs in de ranglijst van morgen (0% = goedkoopst van morgen)",
|
|
||||||
"long_description": "Toont hoe de huidige prijs zich verhoudt tot alle 96 kwartiersslots van morgen — zijn percentielrang binnen de verdeling van morgen. Handig om te beslissen of het loont om tot morgen te wachten. 0% betekent dat de huidige prijs goedkoper is dan elk slot van morgen. Geeft 'Onbekend' terug totdat de gegevens van morgen arriveren (meestal na 13:00). Attributen: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Gebruik om te beslissen of wachten loont: 'Als prijsrang morgen < 10, zijn er morgen nog goedkopere slots — taak uitstellen'. Het beste gecombineerd met een binaire sensor die bevestigt dat de taak morgen daadwerkelijk uitgevoerd kan worden."
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"description": "Percentielrang van de huidige prijs over vandaag en morgen gecombineerd (0% = goedkoopst van het tweedaagse venster)",
|
|
||||||
"long_description": "Toont hoe goedkoop of duur de huidige prijs is ten opzichte van alle slots van vandaag en morgen samen — zijn percentielrang binnen de tweedaagse verdeling (tot 192 slots wanneer beide dagen beschikbaar zijn). Geeft het breedste overzicht voor flexibele taken. Valt terug naar alleen vandaag als de gegevens van morgen nog niet beschikbaar zijn. 0% = goedkoopst van het gecombineerde venster. Attributen: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Het breedste signaal voor 'Is dit nu een goed moment?'. Gebruik 'Als prijsrang vandaag+morgen < 20, voer energieverbruikende taak nu uit'. Bijzonder waardevol als taken een dag kunnen wachten — een waarde dicht bij 0 over twee dagen is een werkelijk uitzonderlijke prijs."
|
|
||||||
},
|
|
||||||
"data_lifecycle_status": {
|
"data_lifecycle_status": {
|
||||||
"description": "Huidige status van prijsgegevenslevenscyclus en caching",
|
"description": "Huidige status van prijsgegevenslevenscyclus en caching",
|
||||||
"long_description": "Toont of de integratie gebruikmaakt van gecachte gegevens of verse gegevens van de API. Toont huidige levenscyclusstatus: 'cached' (gebruikt opgeslagen gegevens), 'fresh' (net opgehaald van API), 'refreshing' (momenteel aan het ophalen), 'searching_tomorrow' (actief aan het zoeken naar morgengegevens na 13:00), 'turnover_pending' (binnen 15 minuten voor middernacht, 23:45-00:00), of 'error' (ophalen mislukt). Bevat uitgebreide attributen zoals cache-leeftijd, volgende API-poll-tijd, gegevensvolledigheid en API-aanroepstatistieken.",
|
"long_description": "Toont of de integratie gebruikmaakt van gecachte gegevens of verse gegevens van de API. Toont huidige levenscyclusstatus: 'cached' (gebruikt opgeslagen gegevens), 'fresh' (net opgehaald van API), 'refreshing' (momenteel aan het ophalen), 'searching_tomorrow' (actief aan het zoeken naar morgengegevens na 13:00), 'turnover_pending' (binnen 15 minuten voor middernacht, 23:45-00:00), of 'error' (ophalen mislukt). Bevat uitgebreide attributen zoals cache-leeftijd, volgende API-poll-tijd, gegevensvolledigheid en API-aanroepstatistieken.",
|
||||||
|
|
@ -525,6 +510,61 @@
|
||||||
"description": "Lichtgewicht metadata voor diagramconfiguratie",
|
"description": "Lichtgewicht metadata voor diagramconfiguratie",
|
||||||
"long_description": "Biedt essentiële diagramconfiguratiewaarden als sensorattributen. Nuttig voor elke grafiekkaart die Y-as-grenzen nodig heeft. De sensor roept get_chartdata aan in alleen-metadata-modus (geen dataverwerking) en extraheert: yaxis_min, yaxis_max (gesuggereerd Y-asbereik voor optimale schaling). De status weerspiegelt het service-aanroepresultaat: 'ready' bij succes, 'error' bij fouten, 'pending' tijdens initialisatie.",
|
"long_description": "Biedt essentiële diagramconfiguratiewaarden als sensorattributen. Nuttig voor elke grafiekkaart die Y-as-grenzen nodig heeft. De sensor roept get_chartdata aan in alleen-metadata-modus (geen dataverwerking) en extraheert: yaxis_min, yaxis_max (gesuggereerd Y-asbereik voor optimale schaling). De status weerspiegelt het service-aanroepresultaat: 'ready' bij succes, 'error' bij fouten, 'pending' tijdens initialisatie.",
|
||||||
"usage_tips": "Configureer via configuration.yaml onder tibber_prices.chart_metadata_config (optioneel: day, subunit_currency, resolution). De sensor wordt automatisch bijgewerkt bij prijsgegevenswijzigingen. Krijg toegang tot metadata vanuit attributen: yaxis_min, yaxis_max. Gebruik met config-template-card of elk hulpmiddel dat entiteitsattributen leest - perfect voor dynamische diagramconfiguratie zonder handmatige berekeningen."
|
"usage_tips": "Configureer via configuration.yaml onder tibber_prices.chart_metadata_config (optioneel: day, subunit_currency, resolution). De sensor wordt automatisch bijgewerkt bij prijsgegevenswijzigingen. Krijg toegang tot metadata vanuit attributen: yaxis_min, yaxis_max. Gebruik met config-template-card of elk hulpmiddel dat entiteitsattributen leest - perfect voor dynamische diagramconfiguratie zonder handmatige berekeningen."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"description": "Waar de huidige intervalprijs staat in de ranglijst van vandaag — percentielrang (0% = goedkoopste moment)",
|
||||||
|
"long_description": "Toont hoe goedkoop of duur de prijs van het huidige kwartier is vergeleken met alle 96 kwartierslots van vandaag. 0% betekent dat dit het goedkoopste moment van de dag is. 50% betekent dat de helft van de slots goedkoper is. ca. 99% betekent het duurste slot van de dag. Formule: aantal goedkopere slots ÷ totaal slots × 100. Attributen: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Ideaal voor automatiseringen: 'Als current_interval_price_rank_today < 25, start de vaatwasser'. Een waarde van 0 garandeert het goedkoopste slot van de dag."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"description": "Percentielrang van de huidige intervalprijs in de ranglijst van morgen (0% = goedkoopste van morgen)",
|
||||||
|
"long_description": "Toont hoe de huidige intervalprijs zich verhoudt tot alle 96 kwartierslots van morgen. 0% betekent dat de huidige prijs goedkoper is dan elk slot van morgen. Geeft 'Onbekend' terug totdat de data van morgen beschikbaar is (doorgaans na 13:00). Attributen: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Gebruik om te beslissen of wachten loont: 'Als current_interval_price_rank_tomorrow < 10, zijn er morgen nog goedkopere slots — stel de taak uit'."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Percentielrang van de huidige intervalprijs over vandaag+morgen samen (0% = goedkoopste van het twee-dagenvenster)",
|
||||||
|
"long_description": "Toont hoe goedkoop of duur de huidige intervalprijs is vergeleken met alle slots over vandaag en morgen samen (tot 192 kwartierslots). Valt terug op alleen vandaag als de data van morgen nog niet beschikbaar is. Attributen: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Het breedste signaal voor 'is dit nu een goed moment?'. Gebruik 'Als current_interval_price_rank_today_tomorrow < 20, voer energieintensieve taak nu uit'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"description": "Percentielrang van de volgende intervalprijs in de ranglijst van vandaag (0% = goedkoopste moment van vandaag)",
|
||||||
|
"long_description": "Toont de percentielrang van het komende kwartier binnen de 96 slots van vandaag. Biedt een vooruitblik voordat het volgende interval begint. Attributen: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Voor voorbereiding: 'Als next_interval_price_rank_today < 15, begin nu met voorverwarmen zodat het apparaat in het volgende goedkope slot draait'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Percentielrang van de volgende intervalprijs over vandaag+morgen samen (0% = goedkoopste van het twee-dagenvenster)",
|
||||||
|
"long_description": "Toont de percentielrang van het komende kwartier binnen de gecombineerde pool van vandaag+morgen (tot 192 slots). Valt terug op alleen vandaag. Attributen: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Breedste vooruitblik: 'Als next_interval_price_rank_today_tomorrow < 10, is het volgende interval één van de goedkoopste van het twee-dagenvenster'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"description": "Percentielrang van de vorige intervalprijs in de ranglijst van vandaag (0% = goedkoopste moment van vandaag)",
|
||||||
|
"long_description": "Toont de percentielrang van het zojuist afgelopen kwartier binnen de 96 slots van vandaag. Nuttig voor logging. Attributen: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Voor retrospectieve automatiseringen: 'Leg het prijsniveau van het vorige interval vast voor energierapporten'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Percentielrang van de vorige intervalprijs over vandaag+morgen samen (0% = goedkoopste van het twee-dagenvenster)",
|
||||||
|
"long_description": "Toont de percentielrang van het zojuist afgelopen kwartier binnen de gecombineerde pool van vandaag+morgen (tot 192 slots). Valt terug op alleen vandaag. Attributen: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Voor retrospectieve vergelijkingen over een twee-dagenvenster."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"description": "Percentielrang van het huidige voortschrijdend uurgemiddelde in de ranglijst van vandaag (0% = goedkoopste uur vandaag)",
|
||||||
|
"long_description": "Toont waar het voortschrijdend gemiddelde van 5 intervallen (2 voor + huidig + 2 na, ca. 1 uur) staat in de prijsranglijst van vandaag. Egaliseer prijspieken voor een bredere inschatting. Attributen: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Voor taken van ongeveer een uur: 'Als current_hour_price_rank_today < 20, is dit een goedkoop uur — start de wasmachine'."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Voortschrijdend uurgemiddelde prijsrang over vandaag+morgen samen (0% = goedkoopste uur van het twee-dagenvenster)",
|
||||||
|
"long_description": "Toont waar het voortschrijdend gemiddelde van 5 intervallen (±2 intervallen, ca. 1 uur) staat in de gecombineerde ranglijst vandaag+morgen (tot 192 slots). Valt terug op alleen vandaag. Attributen: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Breedste uursignaal: 'Als current_hour_price_rank_today_tomorrow < 15, is dit één van de goedkoopste uren van het twee-dagenvenster'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"description": "Percentielrang van het volgende voortschrijdend uurgemiddelde in de ranglijst van vandaag (0% = goedkoopste uur vandaag)",
|
||||||
|
"long_description": "Toont waar het voortschrijdend gemiddelde van 5 intervallen gecentreerd op het volgende interval staat in de prijsranglijst van vandaag. Maakt planning een uur vooruit mogelijk. Attributen: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Plan een uur vooruit: 'Als next_hour_price_rank_today < 20, is het komende uur goedkoop — start nu een taak'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Volgend voortschrijdend uurgemiddelde prijsrang over vandaag+morgen samen (0% = goedkoopste uur van het twee-dagenvenster)",
|
||||||
|
"long_description": "Toont waar het voortschrijdend gemiddelde van 5 intervallen gecentreerd op het volgende interval staat in de gecombineerde ranglijst vandaag+morgen (tot 192 slots). Valt terug op alleen vandaag. Attributen: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Breedste uurvooruitblik: 'Als next_hour_price_rank_today_tomorrow < 10, is het komende uur één van de goedkoopste van het twee-dagenvenster'."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -351,21 +351,6 @@
|
||||||
"long_description": "Visar den samlade volatiliteten när idag och imorgon ses tillsammans (när morgondatan finns). Visar om det finns tydliga prisskillnader över dagsgränsen. Faller tillbaka till endast idag om morgondatan saknas. Nyttig för flerdagarsoptimering. `price_coefficient_variation_%` visar procentvärdet, `price_spread` visar den absoluta prisspannet.",
|
"long_description": "Visar den samlade volatiliteten när idag och imorgon ses tillsammans (när morgondatan finns). Visar om det finns tydliga prisskillnader över dagsgränsen. Faller tillbaka till endast idag om morgondatan saknas. Nyttig för flerdagarsoptimering. `price_coefficient_variation_%` visar procentvärdet, `price_spread` visar den absoluta prisspannet.",
|
||||||
"usage_tips": "Använd för uppgifter som sträcker sig över flera dagar. Kontrollera om prisskillnaderna är stora nog för att planera efter. De enskilda dag-sensorerna visar bidrag per dag om du behöver mer detaljer."
|
"usage_tips": "Använd för uppgifter som sträcker sig över flera dagar. Kontrollera om prisskillnaderna är stora nog för att planera efter. De enskilda dag-sensorerna visar bidrag per dag om du behöver mer detaljer."
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"description": "Den aktuella prisens position i dagens ranking — dess percentilrang (0% = billigast)",
|
|
||||||
"long_description": "Visar hur billig eller dyr den aktuella prisen är jämfört med alla 96 kvartersintervall för idag. 0% innebär att detta är dagens billigaste ögonblick — varje annat slot kostar mer. 50% innebär att hälften av dagens slots är billigare. ~99% innebär det dyraste slot på dagen. Formel (percentilrang): hur många slots är billigare ÷ totalt antal × 100. Attribut: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Perfekt för automatiseringar: 'Om prisrang < 25, starta diskmaskin' (billigaste fjärdedelen av dagen). Eller 'Om prisrang > 75, pausa värmepump' (dyraste fjärdedelen). Värde 0 garanterar att du är på dagens billigaste intervall."
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"description": "Percentilrang för aktuellt pris i morgondagens ranking (0% = billigast imorgon)",
|
|
||||||
"long_description": "Visar hur den aktuella prisen jämförs med alla 96 kvartersintervall för imorgon — dess percentilrang inom morgondagens prisfördelning. Användbart för att avgöra om det lönar sig att vänta till imorgon. 0% innebär att den aktuella prisen är billigare än varje intervall imorgon. Returnerar 'Okänt' tills morgondagens data anlänger (typiskt efter 13:00). Attribut: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Använd för att avgöra om det lönar sig att vänta: 'Om prisrang imorgon < 10, finns det ännu billigare slots imorgon — skjut upp uppgiften'. Bäst kombinerat med en binär sensor som bekräftar att uppgiften kan utföras imorgon."
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"description": "Percentilrang för aktuellt pris över idag och imorgon kombinerat (0% = billigast i tvådagarsfönstret)",
|
|
||||||
"long_description": "Visar hur billig eller dyr den aktuella prisen är jämfört med alla slots för idag och imorgon tillsammans — dess percentilrang inom tvådagarsfördelningen (upp till 192 intervall när båda dagarna är tillgängliga). Ger den bredaste tvådagarsvyn för flexibla uppgifter. Faller tillbaka till enbart idag när morgondagens data inte är tillgänglig än. 0% = billigast i det kombinerade fönstret. Attribut: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
|
||||||
"usage_tips": "Det bredaste signalet för 'Passar det bra nu?'. Använd 'Om prisrang idag+imorgon < 20, kör energikrävande uppgift nu'. Särskilt värdefullt när uppgifter kan vänta en hel dag — ett värde nära 0 över två dagar är ett verkligt exceptionellt pris."
|
|
||||||
},
|
|
||||||
"data_lifecycle_status": {
|
"data_lifecycle_status": {
|
||||||
"description": "Gjeldende tilstand for prisdatalivssyklus og hurtigbufring",
|
"description": "Gjeldende tilstand for prisdatalivssyklus og hurtigbufring",
|
||||||
"long_description": "Viser om integrasjonen bruker hurtigbufrede data eller ferske data fra API-et. Viser gjeldende livssyklustilstand: 'cached' (bruker lagrede data), 'fresh' (nettopp hentet fra API), 'refreshing' (henter for øyeblikket), 'searching_tomorrow' (søker aktivt etter morgendagens data etter 13:00), 'turnover_pending' (innen 15 minutter før midnatt, 23:45-00:00), eller 'error' (henting mislyktes). Inkluderer omfattende attributter som cache-alder, neste API-spørring, datafullstendighet og API-anropsstatistikk.",
|
"long_description": "Viser om integrasjonen bruker hurtigbufrede data eller ferske data fra API-et. Viser gjeldende livssyklustilstand: 'cached' (bruker lagrede data), 'fresh' (nettopp hentet fra API), 'refreshing' (henter for øyeblikket), 'searching_tomorrow' (søker aktivt etter morgendagens data etter 13:00), 'turnover_pending' (innen 15 minutter før midnatt, 23:45-00:00), eller 'error' (henting mislyktes). Inkluderer omfattende attributter som cache-alder, neste API-spørring, datafullstendighet og API-anropsstatistikk.",
|
||||||
|
|
@ -525,6 +510,61 @@
|
||||||
"description": "Lättviktig metadata för diagramkonfiguration",
|
"description": "Lättviktig metadata för diagramkonfiguration",
|
||||||
"long_description": "Tillhandahåller väsentliga diagramkonfigurationsvärden som sensorattribut. Användbart för vilket diagramkort som helst som behöver Y-axelgränser. Sensorn anropar get_chartdata med endast-metadata-läge (ingen databehandling) och extraherar: yaxis_min, yaxis_max (föreslagen Y-axelomfång för optimal skalning). Statusen återspeglar tjänstanropsresultatet: 'ready' vid framgång, 'error' vid fel, 'pending' under initialisering.",
|
"long_description": "Tillhandahåller väsentliga diagramkonfigurationsvärden som sensorattribut. Användbart för vilket diagramkort som helst som behöver Y-axelgränser. Sensorn anropar get_chartdata med endast-metadata-läge (ingen databehandling) och extraherar: yaxis_min, yaxis_max (föreslagen Y-axelomfång för optimal skalning). Statusen återspeglar tjänstanropsresultatet: 'ready' vid framgång, 'error' vid fel, 'pending' under initialisering.",
|
||||||
"usage_tips": "Konfigurera via configuration.yaml under tibber_prices.chart_metadata_config (valfritt: day, subunit_currency, resolution). Sensorn uppdateras automatiskt vid pris dataändringar. Få tillgång till metadata från attribut: yaxis_min, yaxis_max. Använd med config-template-card eller vilket verktyg som helst som läser entitetsattribut - perfekt för dynamisk diagramkonfiguration utan manuella beräkningar."
|
"usage_tips": "Konfigurera via configuration.yaml under tibber_prices.chart_metadata_config (valfritt: day, subunit_currency, resolution). Sensorn uppdateras automatiskt vid pris dataändringar. Få tillgång till metadata från attribut: yaxis_min, yaxis_max. Använd med config-template-card eller vilket verktyg som helst som läser entitetsattribut - perfekt för dynamisk diagramkonfiguration utan manuella beräkningar."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"description": "Var det aktuella intervallpriset placerar sig i dagens rangordning — percentilrang (0 % = billigaste tillfället)",
|
||||||
|
"long_description": "Visar hur billigt eller dyrt det aktuella kvartspriset är jämfört med alla 96 kvartsslotar idag. 0 % innebär att detta är det billigaste tillfället under dagen. 50 % innebär att hälften av dagens slotar är billigare. ca. 99 % innebär det dyraste slottet. Formel: antal billigare slotar ÷ totalt antal × 100. Attribut: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Idealiskt för automatiseringar: 'Om current_interval_price_rank_today < 25, starta diskmaskinen'. Ett värde på 0 garanterar att du är på det billigaste slottet under dagen."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"description": "Percentilrang för aktuellt intervallpris i morgondagens rangordning (0 % = billigaste imorgon)",
|
||||||
|
"long_description": "Visar hur det aktuella intervallpriset jämförs med alla 96 kvartslotar imorgon. 0 % innebär att det aktuella priset är billigare än varje slot imorgon. Returnerar 'Okänd' tills morgondagens data är tillgänglig (vanligtvis efter kl. 13:00). Attribut: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Används för att avgöra om väntan lönar sig: 'Om current_interval_price_rank_tomorrow < 10, finns det ännu billigare slotar imorgon — skjut upp uppgiften'."
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Percentilrang för aktuellt intervallpris över idag+imorgon sammantaget (0 % = billigaste i tvådagarsperioden)",
|
||||||
|
"long_description": "Visar hur billigt eller dyrt det aktuella intervallpriset är jämfört med alla slotar idag och imorgon tillsammans (upp till 192 kvartsslotar). Faller tillbaka på enbart idag när morgondagens data inte är tillgänglig. Attribut: `current_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Den bredaste signalen för 'är det ett bra tillfälle nu?'. Använd 'Om current_interval_price_rank_today_tomorrow < 20, kör energikrävande uppgift nu'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"description": "Percentilrang för nästa intervalls pris i dagens rangordning (0 % = billigaste tillfället idag)",
|
||||||
|
"long_description": "Visar percentilrangen för det kommande kvartalet inom dagens 96 slotar. Ger en förhandstitt innan nästa intervall börjar. Attribut: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "För förberedelse: 'Om next_interval_price_rank_today < 15, börja förvärmningen nu så att enheten körs under nästa billiga slot'."
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Percentilrang för nästa intervalls pris över idag+imorgon sammantaget (0 % = billigaste i tvådagarsperioden)",
|
||||||
|
"long_description": "Visar percentilrangen för det kommande kvartalet inom den kombinerade idag+imorgon-poolen (upp till 192 slotar). Faller tillbaka på enbart idag. Attribut: `next_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Bredaste framtidsskick: 'Om next_interval_price_rank_today_tomorrow < 10, är nästa intervall bland de billigaste i tvådagarsfönstret'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"description": "Percentilrang för föregående intervalls pris i dagens rangordning (0 % = billigaste tillfället idag)",
|
||||||
|
"long_description": "Visar percentilrangen för det nyligen avslutade kvartalet inom dagens 96 slotar. Användbart för loggning. Attribut: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "För retrospektiva automatiseringar: 'Registrera prisnivån för det förra intervallet i energirapporter'."
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"description": "Percentilrang för föregående intervalls pris över idag+imorgon sammantaget (0 % = billigaste i tvådagarsperioden)",
|
||||||
|
"long_description": "Visar percentilrangen för det nyligen avslutade kvartalet inom den kombinerade idag+imorgon-poolen (upp till 192 slotar). Faller tillbaka på enbart idag. Attribut: `previous_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "För retrospektiva jämförelser inom ett tvådagarsfönster."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"description": "Percentilrang för aktuellt rullande timgenomsnittspris i dagens rangordning (0 % = billigaste timmen idag)",
|
||||||
|
"long_description": "Visar var det rullande 5-intervallets genomsnitt (2 intervall före + aktuellt + 2 efter, ca. 1 timme) placerar sig i dagens prisrangordning. Jämnar ut korta pristoppar. Attribut: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "För uppgifter som tar ungefär en timme: 'Om current_hour_price_rank_today < 20, är detta en billig timme — starta tvättmaskinen'."
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Rullande timgenomsnittsprisrang över idag+imorgon sammantaget (0 % = billigaste timmen i tvådagarsfönstret)",
|
||||||
|
"long_description": "Visar var det rullande 5-intervallets genomsnitt (±2 intervall, ca. 1 timme) placerar sig i den kombinerade idag+imorgon-rangordningen (upp till 192 slotar). Faller tillbaka på enbart idag. Attribut: `current_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Bredaste timsignal: 'Om current_hour_price_rank_today_tomorrow < 15, är detta en av de billigaste timmarna i tvådagarsfönstret'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"description": "Percentilrang för nästa rullande timgenomsnittspris i dagens rangordning (0 % = billigaste timmen idag)",
|
||||||
|
"long_description": "Visar var det 5-intervallsgenomsnitt centrerat på nästa intervall placerar sig i dagens prisrangordning. Möjliggör planering en timme framåt. Attribut: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Planera en timme framåt: 'Om next_hour_price_rank_today < 20, är den kommande timmen billig — starta en uppgift nu'."
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"description": "Nästa rullande timgenomsnittsprisrang över idag+imorgon sammantaget (0 % = billigaste timmen i tvådagarsfönstret)",
|
||||||
|
"long_description": "Visar var det 5-intervallsgenomsnitt centrerat på nästa intervall placerar sig i den kombinerade idag+imorgon-rangordningen (upp till 192 slotar). Faller tillbaka på enbart idag. Attribut: `next_hour_avg_price`, `prices_below_count`, `interval_count`, `reference_min`, `reference_max`, `reference_mean`.",
|
||||||
|
"usage_tips": "Bredaste timframtidsskick: 'Om next_hour_price_rank_today_tomorrow < 10, är den kommande timmen bland de billigaste i tvådagarsfönstret'."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ def build_sensor_attributes( # noqa: PLR0912
|
||||||
elif _is_timing_or_volatility_sensor(key):
|
elif _is_timing_or_volatility_sensor(key):
|
||||||
_add_timing_or_volatility_attributes(attributes, key, cached_data, native_value, time=time)
|
_add_timing_or_volatility_attributes(attributes, key, cached_data, native_value, time=time)
|
||||||
|
|
||||||
elif key in ("price_rank_today", "price_rank_tomorrow", "price_rank_today_tomorrow"):
|
elif "_price_rank_" in key:
|
||||||
add_percentile_rank_attributes(attributes, cached_data, time=time)
|
add_percentile_rank_attributes(attributes, cached_data, time=time)
|
||||||
|
|
||||||
elif key in ("day_pattern_yesterday", "day_pattern_today", "day_pattern_tomorrow"):
|
elif key in ("day_pattern_yesterday", "day_pattern_today", "day_pattern_tomorrow"):
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ from custom_components.tibber_prices.const import (
|
||||||
DEFAULT_VOLATILITY_THRESHOLD_VERY_HIGH,
|
DEFAULT_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
get_display_unit_factor,
|
get_display_unit_factor,
|
||||||
)
|
)
|
||||||
from custom_components.tibber_prices.entity_utils import add_icon_color_attribute
|
from custom_components.tibber_prices.coordinator.helpers import get_intervals_for_day_offsets
|
||||||
|
from custom_components.tibber_prices.entity_utils import add_icon_color_attribute, find_rolling_hour_center_index
|
||||||
from custom_components.tibber_prices.sensor.attributes import (
|
from custom_components.tibber_prices.sensor.attributes import (
|
||||||
add_volatility_type_attributes,
|
add_volatility_type_attributes,
|
||||||
get_prices_for_volatility,
|
get_prices_for_volatility,
|
||||||
|
|
@ -159,18 +160,25 @@ class TibberPricesVolatilityCalculator(TibberPricesBaseCalculator):
|
||||||
"""
|
"""
|
||||||
return self._last_volatility_attributes
|
return self._last_volatility_attributes
|
||||||
|
|
||||||
def get_percentile_rank_value(self, *, percentile_type: str) -> float | None:
|
def get_percentile_rank_value(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
percentile_type: str,
|
||||||
|
subject: str = "current_interval",
|
||||||
|
) -> float | None:
|
||||||
"""
|
"""
|
||||||
Calculate the percentile rank of the current price within a reference set.
|
Calculate the percentile rank of a subject price within a reference set.
|
||||||
|
|
||||||
The result is 0-100: percentage of reference prices strictly cheaper than
|
The result is 0-100: percentage of reference prices strictly cheaper than
|
||||||
the current interval price. 0% = cheapest, ~99% = most expensive.
|
the subject price. 0% = cheapest, ~99% = most expensive.
|
||||||
|
|
||||||
Also stores detailed attributes in self._last_percentile_rank_attributes
|
Also stores detailed attributes in self._last_percentile_rank_attributes
|
||||||
for use in extra_state_attributes.
|
for use in extra_state_attributes.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
percentile_type: One of "today", "tomorrow", "today_tomorrow".
|
percentile_type: Reference window - one of "today", "tomorrow", "today_tomorrow".
|
||||||
|
subject: Price to rank - one of "current_interval" (default), "next_interval",
|
||||||
|
"previous_interval", "current_hour", "next_hour".
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Percentile rank (0.0-100.0) or None if unavailable.
|
Percentile rank (0.0-100.0) or None if unavailable.
|
||||||
|
|
@ -179,14 +187,10 @@ class TibberPricesVolatilityCalculator(TibberPricesBaseCalculator):
|
||||||
if not self.has_data():
|
if not self.has_data():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Get current interval price
|
# Get the price of the subject to rank
|
||||||
current_interval = self.coordinator.get_current_interval()
|
subject_price = self._get_subject_price(subject)
|
||||||
if current_interval is None:
|
if subject_price is None:
|
||||||
return None
|
return None
|
||||||
current_price_raw = current_interval.get("total")
|
|
||||||
if current_price_raw is None:
|
|
||||||
return None
|
|
||||||
current_price = float(current_price_raw)
|
|
||||||
|
|
||||||
# Get reference prices for this type (reuse volatility helper)
|
# Get reference prices for this type (reuse volatility helper)
|
||||||
reference_prices = get_prices_for_volatility(
|
reference_prices = get_prices_for_volatility(
|
||||||
|
|
@ -198,16 +202,17 @@ class TibberPricesVolatilityCalculator(TibberPricesBaseCalculator):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Calculate percentile rank
|
# Calculate percentile rank
|
||||||
rank = calculate_percentile_rank(current_price, reference_prices)
|
rank = calculate_percentile_rank(subject_price, reference_prices)
|
||||||
if rank is None:
|
if rank is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Convert to display units for attribute storage
|
# Convert to display units for attribute storage
|
||||||
factor = get_display_unit_factor(self.config_entry)
|
factor = get_display_unit_factor(self.config_entry)
|
||||||
|
price_attr_key = self._get_subject_price_attr_key(subject)
|
||||||
|
|
||||||
self._last_percentile_rank_attributes = {
|
self._last_percentile_rank_attributes = {
|
||||||
"current_price": round(current_price * factor, 2),
|
price_attr_key: round(subject_price * factor, 2),
|
||||||
"prices_below_count": bisect.bisect_left(sorted(reference_prices), current_price),
|
"prices_below_count": bisect.bisect_left(sorted(reference_prices), subject_price),
|
||||||
"interval_count": len(reference_prices),
|
"interval_count": len(reference_prices),
|
||||||
"reference_min": round(min(reference_prices) * factor, 2),
|
"reference_min": round(min(reference_prices) * factor, 2),
|
||||||
"reference_max": round(max(reference_prices) * factor, 2),
|
"reference_max": round(max(reference_prices) * factor, 2),
|
||||||
|
|
@ -216,6 +221,78 @@ class TibberPricesVolatilityCalculator(TibberPricesBaseCalculator):
|
||||||
|
|
||||||
return rank
|
return rank
|
||||||
|
|
||||||
|
def _get_subject_price(self, subject: str) -> float | None:
|
||||||
|
"""
|
||||||
|
Get the price of the subject to rank.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subject: One of "current_interval", "next_interval", "previous_interval",
|
||||||
|
"current_hour", "next_hour".
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Price as float or None if unavailable.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if subject == "current_interval":
|
||||||
|
interval = self.find_interval_at_offset(0)
|
||||||
|
elif subject == "next_interval":
|
||||||
|
interval = self.find_interval_at_offset(1)
|
||||||
|
elif subject == "previous_interval":
|
||||||
|
interval = self.find_interval_at_offset(-1)
|
||||||
|
elif subject in ("current_hour", "next_hour"):
|
||||||
|
hour_offset = 0 if subject == "current_hour" else 1
|
||||||
|
return self._get_rolling_hour_avg_price(hour_offset)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if interval is None:
|
||||||
|
return None
|
||||||
|
raw = interval.get("total")
|
||||||
|
return float(raw) if raw is not None else None
|
||||||
|
|
||||||
|
def _get_subject_price_attr_key(self, subject: str) -> str:
|
||||||
|
"""Return the attribute key name for the subject's price."""
|
||||||
|
return {
|
||||||
|
"current_interval": "current_price",
|
||||||
|
"next_interval": "next_price",
|
||||||
|
"previous_interval": "previous_price",
|
||||||
|
"current_hour": "current_hour_avg_price",
|
||||||
|
"next_hour": "next_hour_avg_price",
|
||||||
|
}.get(subject, "ranked_price")
|
||||||
|
|
||||||
|
def _get_rolling_hour_avg_price(self, hour_offset: int) -> float | None:
|
||||||
|
"""
|
||||||
|
Get the rolling 1h average price for the given hour offset.
|
||||||
|
|
||||||
|
Uses the same 5-interval window as current_hour_average_price.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hour_offset: 0 for current hour, 1 for next hour.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Average price as float or None if unavailable.
|
||||||
|
|
||||||
|
"""
|
||||||
|
all_prices = get_intervals_for_day_offsets(self.coordinator_data, [-1, 0, 1])
|
||||||
|
if not all_prices:
|
||||||
|
return None
|
||||||
|
|
||||||
|
time = self.coordinator.time
|
||||||
|
now = time.now()
|
||||||
|
center_idx = find_rolling_hour_center_index(all_prices, now, hour_offset, time=time)
|
||||||
|
if center_idx is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
window: list[float] = []
|
||||||
|
for offset in range(-2, 3):
|
||||||
|
idx = center_idx + offset
|
||||||
|
if 0 <= idx < len(all_prices):
|
||||||
|
raw = all_prices[idx].get("total")
|
||||||
|
if raw is not None:
|
||||||
|
window.append(float(raw))
|
||||||
|
|
||||||
|
return calculate_mean(window) if window else None
|
||||||
|
|
||||||
def get_percentile_rank_attributes(self) -> dict[str, Any]:
|
def get_percentile_rank_attributes(self) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Get stored percentile rank attributes from last calculation.
|
Get stored percentile rank attributes from last calculation.
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,22 @@ MIN_HOURS_FOR_LATER_HALF = 3 # Minimum hours needed to calculate later half ave
|
||||||
_SENTINEL = object()
|
_SENTINEL = object()
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_percentile_rank_type(key: str) -> str | None:
|
||||||
|
"""
|
||||||
|
Extract the reference-window type from a price rank sensor key.
|
||||||
|
|
||||||
|
Returns "today_tomorrow", "tomorrow", or "today" based on the key suffix.
|
||||||
|
Returns None if the key is not a price rank sensor key.
|
||||||
|
"""
|
||||||
|
if "_rank_today_tomorrow" in key:
|
||||||
|
return "today_tomorrow"
|
||||||
|
if "_rank_tomorrow" in key:
|
||||||
|
return "tomorrow"
|
||||||
|
if "_rank_today" in key:
|
||||||
|
return "today"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class TibberPricesSensor(TibberPricesEntity, RestoreSensor):
|
class TibberPricesSensor(TibberPricesEntity, RestoreSensor):
|
||||||
"""tibber_prices Sensor class with state restoration."""
|
"""tibber_prices Sensor class with state restoration."""
|
||||||
|
|
||||||
|
|
@ -1165,7 +1181,7 @@ class TibberPricesSensor(TibberPricesEntity, RestoreSensor):
|
||||||
"trend_change_attributes": self._trend_calculator.get_trend_change_attributes(),
|
"trend_change_attributes": self._trend_calculator.get_trend_change_attributes(),
|
||||||
"volatility_attributes": self._volatility_calculator.get_volatility_attributes(),
|
"volatility_attributes": self._volatility_calculator.get_volatility_attributes(),
|
||||||
"percentile_rank_attributes": self._volatility_calculator.get_percentile_rank_attributes(),
|
"percentile_rank_attributes": self._volatility_calculator.get_percentile_rank_attributes(),
|
||||||
"percentile_rank_type": key.removeprefix("price_rank_") if key.startswith("price_rank_") else None,
|
"percentile_rank_type": _extract_percentile_rank_type(key),
|
||||||
"coordinator_data": self.coordinator.data,
|
"coordinator_data": self.coordinator.data,
|
||||||
"last_extreme_interval": self._daily_stat_calculator.get_last_extreme_interval(),
|
"last_extreme_interval": self._daily_stat_calculator.get_last_extreme_interval(),
|
||||||
"last_energy_tax_averages": self._daily_stat_calculator.get_last_energy_tax_averages(),
|
"last_energy_tax_averages": self._daily_stat_calculator.get_last_energy_tax_averages(),
|
||||||
|
|
|
||||||
|
|
@ -753,21 +753,24 @@ VOLATILITY_SENSORS = (
|
||||||
# - today_tomorrow: 192 combined intervals when tomorrow is available
|
# - today_tomorrow: 192 combined intervals when tomorrow is available
|
||||||
#
|
#
|
||||||
# Use case: "Is now the right time to run a large appliance?"
|
# Use case: "Is now the right time to run a large appliance?"
|
||||||
# - price_rank_today < 25 → bottom quartile, great time to use energy
|
# - current_interval_price_rank_today < 25 → bottom quartile, great time to use energy
|
||||||
# - price_rank_today > 75 → top quartile, consider delaying consumption
|
# - current_interval_price_rank_today > 75 → top quartile, consider delaying consumption
|
||||||
|
|
||||||
PERCENTILE_RANK_SENSORS = (
|
PERCENTILE_RANK_SENSORS = (
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# Current interval rank sensors
|
||||||
|
# ----------------------------------------------------------------
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key="price_rank_today",
|
key="current_interval_price_rank_today",
|
||||||
translation_key="price_rank_today",
|
translation_key="current_interval_price_rank_today",
|
||||||
icon="mdi:percent",
|
icon="mdi:percent",
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=None, # Position metric: no statistics
|
state_class=None, # Position metric: no statistics
|
||||||
suggested_display_precision=0,
|
suggested_display_precision=0,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key="price_rank_tomorrow",
|
key="current_interval_price_rank_tomorrow",
|
||||||
translation_key="price_rank_tomorrow",
|
translation_key="current_interval_price_rank_tomorrow",
|
||||||
icon="mdi:percent",
|
icon="mdi:percent",
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=None, # Position metric: no statistics
|
state_class=None, # Position metric: no statistics
|
||||||
|
|
@ -775,14 +778,95 @@ PERCENTILE_RANK_SENSORS = (
|
||||||
entity_registry_enabled_default=False, # Available once tomorrow's data arrives
|
entity_registry_enabled_default=False, # Available once tomorrow's data arrives
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
SensorEntityDescription(
|
||||||
key="price_rank_today_tomorrow",
|
key="current_interval_price_rank_today_tomorrow",
|
||||||
translation_key="price_rank_today_tomorrow",
|
translation_key="current_interval_price_rank_today_tomorrow",
|
||||||
icon="mdi:percent",
|
icon="mdi:percent",
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=None, # Position metric: no statistics
|
state_class=None, # Position metric: no statistics
|
||||||
suggested_display_precision=0,
|
suggested_display_precision=0,
|
||||||
entity_registry_enabled_default=False, # Advanced overview use case
|
entity_registry_enabled_default=False, # Advanced overview use case
|
||||||
),
|
),
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# Next interval rank sensors
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="next_interval_price_rank_today",
|
||||||
|
translation_key="next_interval_price_rank_today",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="next_interval_price_rank_today_tomorrow",
|
||||||
|
translation_key="next_interval_price_rank_today_tomorrow",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# Previous interval rank sensors
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="previous_interval_price_rank_today",
|
||||||
|
translation_key="previous_interval_price_rank_today",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="previous_interval_price_rank_today_tomorrow",
|
||||||
|
translation_key="previous_interval_price_rank_today_tomorrow",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# Rolling-hour rank sensors (rank of 1h rolling average)
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="current_hour_price_rank_today",
|
||||||
|
translation_key="current_hour_price_rank_today",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="current_hour_price_rank_today_tomorrow",
|
||||||
|
translation_key="current_hour_price_rank_today_tomorrow",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="next_hour_price_rank_today",
|
||||||
|
translation_key="next_hour_price_rank_today",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
|
SensorEntityDescription(
|
||||||
|
key="next_hour_price_rank_today_tomorrow",
|
||||||
|
translation_key="next_hour_price_rank_today_tomorrow",
|
||||||
|
icon="mdi:percent",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=None,
|
||||||
|
suggested_display_precision=0,
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -250,10 +250,42 @@ def get_value_getter_mapping( # noqa: PLR0913 - needs all calculators as parame
|
||||||
volatility_type="today_tomorrow"
|
volatility_type="today_tomorrow"
|
||||||
),
|
),
|
||||||
# Price rank sensors (via VolatilityCalculator - reuses same price extraction)
|
# Price rank sensors (via VolatilityCalculator - reuses same price extraction)
|
||||||
"price_rank_today": lambda: volatility_calculator.get_percentile_rank_value(percentile_type="today"),
|
# Current interval rank
|
||||||
"price_rank_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(percentile_type="tomorrow"),
|
"current_interval_price_rank_today": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
"price_rank_today_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(
|
subject="current_interval", percentile_type="today"
|
||||||
percentile_type="today_tomorrow"
|
),
|
||||||
|
"current_interval_price_rank_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="current_interval", percentile_type="tomorrow"
|
||||||
|
),
|
||||||
|
"current_interval_price_rank_today_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="current_interval", percentile_type="today_tomorrow"
|
||||||
|
),
|
||||||
|
# Next interval rank
|
||||||
|
"next_interval_price_rank_today": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="next_interval", percentile_type="today"
|
||||||
|
),
|
||||||
|
"next_interval_price_rank_today_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="next_interval", percentile_type="today_tomorrow"
|
||||||
|
),
|
||||||
|
# Previous interval rank
|
||||||
|
"previous_interval_price_rank_today": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="previous_interval", percentile_type="today"
|
||||||
|
),
|
||||||
|
"previous_interval_price_rank_today_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="previous_interval", percentile_type="today_tomorrow"
|
||||||
|
),
|
||||||
|
# Rolling-hour rank (1h average)
|
||||||
|
"current_hour_price_rank_today": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="current_hour", percentile_type="today"
|
||||||
|
),
|
||||||
|
"current_hour_price_rank_today_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="current_hour", percentile_type="today_tomorrow"
|
||||||
|
),
|
||||||
|
"next_hour_price_rank_today": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="next_hour", percentile_type="today"
|
||||||
|
),
|
||||||
|
"next_hour_price_rank_today_tomorrow": lambda: volatility_calculator.get_percentile_rank_value(
|
||||||
|
subject="next_hour", percentile_type="today_tomorrow"
|
||||||
),
|
),
|
||||||
# ================================================================
|
# ================================================================
|
||||||
# BEST/PEAK PRICE TIMING SENSORS - via TimingCalculator
|
# BEST/PEAK PRICE TIMING SENSORS - via TimingCalculator
|
||||||
|
|
|
||||||
|
|
@ -866,15 +866,6 @@
|
||||||
"very_high": "Sehr hoch"
|
"very_high": "Sehr hoch"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"name": "Preisrang heute"
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"name": "Preisrang morgen"
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"name": "Preisrang heute+morgen"
|
|
||||||
},
|
|
||||||
"best_price_end_time": {
|
"best_price_end_time": {
|
||||||
"name": "Bestpreis endet"
|
"name": "Bestpreis endet"
|
||||||
},
|
},
|
||||||
|
|
@ -1036,6 +1027,39 @@
|
||||||
"ready": "Bereit",
|
"ready": "Bereit",
|
||||||
"error": "Fehler"
|
"error": "Fehler"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"name": "Aktueller Preisrang (heute)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"name": "Aktueller Preisrang (morgen)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Aktueller Preisrang (heute+morgen)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"name": "Nächster Preisrang (heute)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Nächster Preisrang (heute+morgen)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"name": "Letzter Preisrang (heute)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Letzter Preisrang (heute+morgen)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Stündlicher Preisrang Aktuell (heute)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Stündlicher Preisrang Aktuell (heute+morgen)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Stündlicher Preisrang Nächste (heute)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Stündlicher Preisrang Nächste (heute+morgen)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -866,15 +866,6 @@
|
||||||
"very_high": "Very High"
|
"very_high": "Very High"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"name": "Today's Price Rank"
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"name": "Tomorrow's Price Rank"
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"name": "Today+Tomorrow Price Rank"
|
|
||||||
},
|
|
||||||
"best_price_end_time": {
|
"best_price_end_time": {
|
||||||
"name": "Best Price End"
|
"name": "Best Price End"
|
||||||
},
|
},
|
||||||
|
|
@ -1036,6 +1027,39 @@
|
||||||
"ready": "Ready",
|
"ready": "Ready",
|
||||||
"error": "Error"
|
"error": "Error"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"name": "Current Price Rank (Today)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"name": "Current Price Rank (Tomorrow)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Current Price Rank (Today+Tomorrow)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"name": "Next Price Rank (Today)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Next Price Rank (Today+Tomorrow)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"name": "Last Price Rank (Today)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Last Price Rank (Today+Tomorrow)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Hourly Price Current Rank (Today)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Hourly Price Current Rank (Today+Tomorrow)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Hourly Price Next Rank (Today)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Hourly Price Next Rank (Today+Tomorrow)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -866,15 +866,6 @@
|
||||||
"very_high": "Svært Høy"
|
"very_high": "Svært Høy"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"name": "Prisrang i dag"
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"name": "Prisrang i morgen"
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"name": "Prisrang i dag+i morgen"
|
|
||||||
},
|
|
||||||
"best_price_end_time": {
|
"best_price_end_time": {
|
||||||
"name": "Beste pris slutter"
|
"name": "Beste pris slutter"
|
||||||
},
|
},
|
||||||
|
|
@ -1036,6 +1027,39 @@
|
||||||
"ready": "Klar",
|
"ready": "Klar",
|
||||||
"error": "Feil"
|
"error": "Feil"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"name": "Aktuell prisrang (i dag)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"name": "Aktuell prisrang (i morgen)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Aktuell prisrang (i dag+i morgen)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"name": "Neste prisrang (i dag)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Neste prisrang (i dag+i morgen)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"name": "Forrige prisrang (i dag)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Forrige prisrang (i dag+i morgen)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Timesprisrang nå (i dag)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Timesprisrang nå (i dag+i morgen)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Timesprisrang neste (i dag)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Timesprisrang neste (i dag+i morgen)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -866,15 +866,6 @@
|
||||||
"very_high": "Zeer Hoog"
|
"very_high": "Zeer Hoog"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"name": "Prijsrang vandaag"
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"name": "Prijsrang morgen"
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"name": "Prijsrang vandaag+morgen"
|
|
||||||
},
|
|
||||||
"best_price_end_time": {
|
"best_price_end_time": {
|
||||||
"name": "Beste Prijs Einde"
|
"name": "Beste Prijs Einde"
|
||||||
},
|
},
|
||||||
|
|
@ -1036,6 +1027,39 @@
|
||||||
"ready": "Gereed",
|
"ready": "Gereed",
|
||||||
"error": "Fout"
|
"error": "Fout"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"name": "Huidige prijsrang (vandaag)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"name": "Huidige prijsrang (morgen)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Huidige prijsrang (vandaag+morgen)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"name": "Volgende prijsrang (vandaag)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Volgende prijsrang (vandaag+morgen)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"name": "Vorige prijsrang (vandaag)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Vorige prijsrang (vandaag+morgen)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Uurlijkse prijsrang huidig (vandaag)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Uurlijkse prijsrang huidig (vandaag+morgen)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Uurlijkse prijsrang volgende (vandaag)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Uurlijkse prijsrang volgende (vandaag+morgen)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -866,15 +866,6 @@
|
||||||
"very_high": "Mycket hög"
|
"very_high": "Mycket hög"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"price_rank_today": {
|
|
||||||
"name": "Prisrang idag"
|
|
||||||
},
|
|
||||||
"price_rank_tomorrow": {
|
|
||||||
"name": "Prisrang imorgon"
|
|
||||||
},
|
|
||||||
"price_rank_today_tomorrow": {
|
|
||||||
"name": "Prisrang idag+imorgon"
|
|
||||||
},
|
|
||||||
"best_price_end_time": {
|
"best_price_end_time": {
|
||||||
"name": "Bästa pris slutar"
|
"name": "Bästa pris slutar"
|
||||||
},
|
},
|
||||||
|
|
@ -1036,6 +1027,39 @@
|
||||||
"ready": "Redo",
|
"ready": "Redo",
|
||||||
"error": "Fel"
|
"error": "Fel"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today": {
|
||||||
|
"name": "Aktuellt prisrang (idag)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_tomorrow": {
|
||||||
|
"name": "Aktuellt prisrang (imorgon)"
|
||||||
|
},
|
||||||
|
"current_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Aktuellt prisrang (idag+imorgon)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today": {
|
||||||
|
"name": "Nästa prisrang (idag)"
|
||||||
|
},
|
||||||
|
"next_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Nästa prisrang (idag+imorgon)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today": {
|
||||||
|
"name": "Förra prisrang (idag)"
|
||||||
|
},
|
||||||
|
"previous_interval_price_rank_today_tomorrow": {
|
||||||
|
"name": "Förra prisrang (idag+imorgon)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Timprisrang aktuell (idag)"
|
||||||
|
},
|
||||||
|
"current_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Timprisrang aktuell (idag+imorgon)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today": {
|
||||||
|
"name": "⌀ Timprisrang nästa (idag)"
|
||||||
|
},
|
||||||
|
"next_hour_price_rank_today_tomorrow": {
|
||||||
|
"name": "⌀ Timprisrang nästa (idag+imorgon)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"binary_sensor": {
|
"binary_sensor": {
|
||||||
|
|
|
||||||
|
|
@ -214,12 +214,20 @@ explanations of each sensor's purpose, attributes, and automation examples.
|
||||||
|
|
||||||
| Entity ID suffix | 🇬🇧 English | 🇩🇪 Deutsch | 🇳🇴 Norsk | 🇳🇱 Nederlands | 🇸🇪 Svenska | Default |
|
| Entity ID suffix | 🇬🇧 English | 🇩🇪 Deutsch | 🇳🇴 Norsk | 🇳🇱 Nederlands | 🇸🇪 Svenska | Default |
|
||||||
|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|
|
||||||
|
| <span id="ref-current_hour_price_rank_today" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`current_hour_price_rank_today` | ⌀ Hourly Price Current Rank (Today) | ⌀ Stündlicher Preisrang Aktuell (heute) | ⌀ Timesprisrang nå (i dag) | ⌀ Uurlijkse prijsrang huidig (vandaag) | ⌀ Timprisrang aktuell (idag) | ❌ |
|
||||||
|
| <span id="ref-current_hour_price_rank_today_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`current_hour_price_rank_today_tomorrow` | ⌀ Hourly Price Current Rank (Today+Tomorrow) | ⌀ Stündlicher Preisrang Aktuell (heute+morgen) | ⌀ Timesprisrang nå (i dag+i morgen) | ⌀ Uurlijkse prijsrang huidig (vandaag+morgen) | ⌀ Timprisrang aktuell (idag+imorgon) | ❌ |
|
||||||
|
| <span id="ref-current_interval_price_rank_today" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`current_interval_price_rank_today` | Current Price Rank (Today) | Aktueller Preisrang (heute) | Aktuell prisrang (i dag) | Huidige prijsrang (vandaag) | Aktuellt prisrang (idag) | ✅ |
|
||||||
|
| <span id="ref-current_interval_price_rank_today_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`current_interval_price_rank_today_tomorrow` | Current Price Rank (Today+Tomorrow) | Aktueller Preisrang (heute+morgen) | Aktuell prisrang (i dag+i morgen) | Huidige prijsrang (vandaag+morgen) | Aktuellt prisrang (idag+imorgon) | ❌ |
|
||||||
|
| <span id="ref-current_interval_price_rank_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`current_interval_price_rank_tomorrow` | Current Price Rank (Tomorrow) | Aktueller Preisrang (morgen) | Aktuell prisrang (i morgen) | Huidige prijsrang (morgen) | Aktuellt prisrang (imorgon) | ❌ |
|
||||||
| <span id="ref-day_pattern_today" class="entity-anchor"></span>`day_pattern_today` | Today's Price Pattern | Preismuster Heute | Prismønster i dag | Prijspatroon Vandaag | Prismönster Idag | ✅ |
|
| <span id="ref-day_pattern_today" class="entity-anchor"></span>`day_pattern_today` | Today's Price Pattern | Preismuster Heute | Prismønster i dag | Prijspatroon Vandaag | Prismönster Idag | ✅ |
|
||||||
| <span id="ref-day_pattern_tomorrow" class="entity-anchor"></span>`day_pattern_tomorrow` | Tomorrow's Price Pattern | Preismuster Morgen | Prismønster i morgen | Prijspatroon Morgen | Prismönster Imorgon | ❌ |
|
| <span id="ref-day_pattern_tomorrow" class="entity-anchor"></span>`day_pattern_tomorrow` | Tomorrow's Price Pattern | Preismuster Morgen | Prismønster i morgen | Prijspatroon Morgen | Prismönster Imorgon | ❌ |
|
||||||
| <span id="ref-day_pattern_yesterday" class="entity-anchor"></span>`day_pattern_yesterday` | Yesterday's Price Pattern | Preismuster Gestern | Prismønster i går | Prijspatroon Gisteren | Prismönster Igår | ❌ |
|
| <span id="ref-day_pattern_yesterday" class="entity-anchor"></span>`day_pattern_yesterday` | Yesterday's Price Pattern | Preismuster Gestern | Prismønster i går | Prijspatroon Gisteren | Prismönster Igår | ❌ |
|
||||||
| <span id="ref-price_rank_today" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`price_rank_today` | Today's Price Rank | Preisrang heute | Prisrang i dag | Prijsrang vandaag | Prisrang idag | ✅ |
|
| <span id="ref-next_hour_price_rank_today" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`next_hour_price_rank_today` | ⌀ Hourly Price Next Rank (Today) | ⌀ Stündlicher Preisrang Nächste (heute) | ⌀ Timesprisrang neste (i dag) | ⌀ Uurlijkse prijsrang volgende (vandaag) | ⌀ Timprisrang nästa (idag) | ❌ |
|
||||||
| <span id="ref-price_rank_today_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`price_rank_today_tomorrow` | Today+Tomorrow Price Rank | Preisrang heute+morgen | Prisrang i dag+i morgen | Prijsrang vandaag+morgen | Prisrang idag+imorgon | ❌ |
|
| <span id="ref-next_hour_price_rank_today_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`next_hour_price_rank_today_tomorrow` | ⌀ Hourly Price Next Rank (Today+Tomorrow) | ⌀ Stündlicher Preisrang Nächste (heute+morgen) | ⌀ Timesprisrang neste (i dag+i morgen) | ⌀ Uurlijkse prijsrang volgende (vandaag+morgen) | ⌀ Timprisrang nästa (idag+imorgon) | ❌ |
|
||||||
| <span id="ref-price_rank_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`price_rank_tomorrow` | Tomorrow's Price Rank | Preisrang morgen | Prisrang i morgen | Prijsrang morgen | Prisrang imorgon | ❌ |
|
| <span id="ref-next_interval_price_rank_today" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`next_interval_price_rank_today` | Next Price Rank (Today) | Nächster Preisrang (heute) | Neste prisrang (i dag) | Volgende prijsrang (vandaag) | Nästa prisrang (idag) | ❌ |
|
||||||
|
| <span id="ref-next_interval_price_rank_today_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`next_interval_price_rank_today_tomorrow` | Next Price Rank (Today+Tomorrow) | Nächster Preisrang (heute+morgen) | Neste prisrang (i dag+i morgen) | Volgende prijsrang (vandaag+morgen) | Nästa prisrang (idag+imorgon) | ❌ |
|
||||||
|
| <span id="ref-previous_interval_price_rank_today" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`previous_interval_price_rank_today` | Last Price Rank (Today) | Letzter Preisrang (heute) | Forrige prisrang (i dag) | Vorige prijsrang (vandaag) | Förra prisrang (idag) | ❌ |
|
||||||
|
| <span id="ref-previous_interval_price_rank_today_tomorrow" class="entity-anchor" data-refs="sensors-volatility#available-sensors"></span>`previous_interval_price_rank_today_tomorrow` | Last Price Rank (Today+Tomorrow) | Letzter Preisrang (heute+morgen) | Forrige prisrang (i dag+i morgen) | Vorige prijsrang (vandaag+morgen) | Förra prisrang (idag+imorgon) | ❌ |
|
||||||
## Binary Sensors
|
## Binary Sensors
|
||||||
|
|
||||||
### Binary Sensors
|
### Binary Sensors
|
||||||
|
|
|
||||||
|
|
@ -139,44 +139,81 @@ The `price_spike_count` attribute (Tukey fence method: Q25 − 1.5×IQR to Q75 +
|
||||||
|
|
||||||
## Price Rank Sensors (Percentile Rank)
|
## Price Rank Sensors (Percentile Rank)
|
||||||
|
|
||||||
The price rank sensors answer the simple question: **"Is the current price cheap or expensive compared to the rest of the day?"**
|
The price rank sensors answer the simple question: **"Is this price cheap or expensive compared to the rest of the day?"**
|
||||||
|
|
||||||
Unlike the volatility sensors (which measure the _shape_ of the entire price distribution), price rank sensors place the _current price_ within that distribution — technically its **percentile rank**. A value of **0% means cheapest interval of the day**, while a value near **99% means most expensive**.
|
Unlike the volatility sensors (which measure the _shape_ of the entire price distribution), price rank sensors place a _specific price_ within that distribution — technically its **percentile rank**. A value of **0% means cheapest interval of the reference set**, while a value near **99% means most expensive**.
|
||||||
|
|
||||||
|
Each sensor ranks a different **subject price** against a **reference window**:
|
||||||
|
|
||||||
|
- **Subject** — Which price is being ranked: current interval, next interval, previous interval, or the rolling hourly average
|
||||||
|
- **Reference window** — Which pool of slots to compare against: today only, tomorrow only, or today+tomorrow combined
|
||||||
|
|
||||||
### How It Works (Percentile Rank Formula)
|
### How It Works (Percentile Rank Formula)
|
||||||
|
|
||||||
```
|
```
|
||||||
Price rank (percentile rank) = (number of intervals strictly cheaper than now) ÷ total intervals × 100
|
Price rank (percentile rank) = (number of intervals strictly cheaper than subject) ÷ total intervals × 100
|
||||||
```
|
```
|
||||||
|
|
||||||
The cheapest interval always returns 0% — you can use `state == 0` to detect the absolute cheapest moment.
|
The cheapest interval always returns 0% — you can use `state == 0` to detect the absolute cheapest moment.
|
||||||
|
|
||||||
### Available Sensors
|
### Available Sensors
|
||||||
|
|
||||||
|
**Current interval** (price of the active quarter-hour):
|
||||||
|
|
||||||
| Sensor | Reference Set | Enabled by Default |
|
| Sensor | Reference Set | Enabled by Default |
|
||||||
| ------------------------------------------------------------------------------- | ----------------------------------------------- | ------------------ |
|
| ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------ |
|
||||||
| <EntityRef id="price_rank_today">Today's Price Rank</EntityRef> | All of today's 96 quarter-hour intervals | ✅ Yes |
|
| <EntityRef id="current_interval_price_rank_today">Current Price Rank (Today)</EntityRef> | Today's 96 quarter-hour intervals | ✅ Yes |
|
||||||
| <EntityRef id="price_rank_tomorrow">Tomorrow's Price Rank</EntityRef> | All of tomorrow's 96 intervals (once available) | ❌ No |
|
| <EntityRef id="current_interval_price_rank_tomorrow">Current Price Rank (Tomorrow)</EntityRef> | Tomorrow's 96 intervals (once avail.) | ❌ No |
|
||||||
| <EntityRef id="price_rank_today_tomorrow">Today+Tomorrow Price Rank</EntityRef> | Combined pool (up to 192 intervals) | ❌ No |
|
| <EntityRef id="current_interval_price_rank_today_tomorrow">Current Price Rank (Today+Tomorrow)</EntityRef> | Combined pool (up to 192 intervals) | ❌ No |
|
||||||
|
|
||||||
|
**Next interval** (price of the upcoming quarter-hour):
|
||||||
|
|
||||||
|
| Sensor | Reference Set | Enabled by Default |
|
||||||
|
| ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------ |
|
||||||
|
| <EntityRef id="next_interval_price_rank_today">Next Price Rank (Today)</EntityRef> | Today's 96 quarter-hour intervals | ❌ No |
|
||||||
|
| <EntityRef id="next_interval_price_rank_today_tomorrow">Next Price Rank (Today+Tomorrow)</EntityRef> | Combined pool (up to 192 intervals) | ❌ No |
|
||||||
|
|
||||||
|
**Previous interval** (price of the just-ended quarter-hour):
|
||||||
|
|
||||||
|
| Sensor | Reference Set | Enabled by Default |
|
||||||
|
| ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------ |
|
||||||
|
| <EntityRef id="previous_interval_price_rank_today">Last Price Rank (Today)</EntityRef> | Today's 96 quarter-hour intervals | ❌ No |
|
||||||
|
| <EntityRef id="previous_interval_price_rank_today_tomorrow">Last Price Rank (Today+Tomorrow)</EntityRef> | Combined pool (up to 192 intervals) | ❌ No |
|
||||||
|
|
||||||
|
**Rolling hourly average** (5-interval window, ~1 hour):
|
||||||
|
|
||||||
|
| Sensor | Reference Set | Enabled by Default |
|
||||||
|
| ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------ |
|
||||||
|
| <EntityRef id="current_hour_price_rank_today">⌀ Hourly Price Current Rank (Today)</EntityRef> | Today's 96 quarter-hour intervals | ❌ No |
|
||||||
|
| <EntityRef id="current_hour_price_rank_today_tomorrow">⌀ Hourly Price Current Rank (Today+Tomorrow)</EntityRef> | Combined pool (up to 192 intervals) | ❌ No |
|
||||||
|
| <EntityRef id="next_hour_price_rank_today">⌀ Hourly Price Next Rank (Today)</EntityRef> | Today's 96 quarter-hour intervals | ❌ No |
|
||||||
|
| <EntityRef id="next_hour_price_rank_today_tomorrow">⌀ Hourly Price Next Rank (Today+Tomorrow)</EntityRef> | Combined pool (up to 192 intervals) | ❌ No |
|
||||||
|
|
||||||
### Key Attributes
|
### Key Attributes
|
||||||
|
|
||||||
All price rank sensors share these attributes:
|
All price rank sensors share most of these attributes. The price attribute key reflects the subject:
|
||||||
|
|
||||||
| Attribute | Description | Example |
|
| Attribute | Description | Subject |
|
||||||
| -------------------- | --------------------------------------------- | ------- |
|
| ------------------------ | -------------------------------------------------------- | ------------------ |
|
||||||
| `current_price` | The price being ranked | `14.2` |
|
| `current_price` | The price being ranked (current interval) | Current interval |
|
||||||
| `prices_below_count` | How many intervals are strictly cheaper | `23` |
|
| `next_price` | The price being ranked (next interval) | Next interval |
|
||||||
| `interval_count` | Total intervals in the reference set | `96` |
|
| `previous_price` | The price being ranked (previous interval) | Previous interval |
|
||||||
| `reference_min` | The cheapest price in the reference set | `8.1` |
|
| `current_hour_avg_price` | The rolling average being ranked (current hour) | Current hour avg |
|
||||||
| `reference_max` | The most expensive price in the reference set | `27.3` |
|
| `next_hour_avg_price` | The rolling average being ranked (next hour) | Next hour avg |
|
||||||
| `reference_mean` | Average price of the reference set | `15.8` |
|
| `prices_below_count` | How many reference intervals are strictly cheaper | All sensors |
|
||||||
|
| `interval_count` | Total intervals in the reference set | All sensors |
|
||||||
|
| `reference_min` | The cheapest price in the reference set | All sensors |
|
||||||
|
| `reference_max` | The most expensive price in the reference set | All sensors |
|
||||||
|
| `reference_mean` | Average price of the reference set | All sensors |
|
||||||
|
|
||||||
### When to Use Which Sensor
|
### When to Use Which Sensor
|
||||||
|
|
||||||
- **`price_rank_today`** — For same-day scheduling. "Is now within the cheapest quarter of today? (< 25%)"
|
- **Current (Today)** — Same-day scheduling. "Is the active quarter-hour within the cheapest 25% of today?"
|
||||||
- **`price_rank_tomorrow`** — To compare today's price against what tomorrow offers. "Is it worth waiting until tomorrow?"
|
- **Next (Today)** — Prepare for the next interval. "Should I pre-heat now so the device runs in the coming cheap slot?"
|
||||||
- **`price_rank_today_tomorrow`** — Broadest view for flexible tasks. "Is this among the cheapest moments of a 48-hour window?"
|
- **Current (Today+Tomorrow)** — Broadest view for flexible tasks. "Is this among the cheapest moments of a 48-hour window?"
|
||||||
|
- **Current (Tomorrow)** — Decide whether to wait until tomorrow. "Is today's price worse than what tomorrow offers?"
|
||||||
|
- **⌀ Hourly Current (Today)** — For tasks that take about an hour. "Is this hour cheap enough to start a 60-minute cycle?"
|
||||||
|
- **⌀ Hourly Next (Today)** — One-hour look-ahead. "Will the upcoming hour be cheap enough to start now?"
|
||||||
|
|
||||||
### Usage in Automations
|
### Usage in Automations
|
||||||
|
|
||||||
|
|
@ -188,7 +225,7 @@ automation:
|
||||||
- alias: "Start dishwasher at cheapest time of day"
|
- alias: "Start dishwasher at cheapest time of day"
|
||||||
trigger:
|
trigger:
|
||||||
- platform: numeric_state
|
- platform: numeric_state
|
||||||
entity_id: sensor.<home_name>_today_s_price_rank
|
entity_id: sensor.<home_name>_current_price_rank_today
|
||||||
below: 25
|
below: 25
|
||||||
condition:
|
condition:
|
||||||
- condition: state
|
- condition: state
|
||||||
|
|
@ -214,10 +251,32 @@ automation:
|
||||||
# Only postpone if tomorrow's cheapest quartile is better than the current price
|
# Only postpone if tomorrow's cheapest quartile is better than the current price
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >
|
value_template: >
|
||||||
{{ states('sensor.<home_name>_tomorrow_s_price_rank') | float(100) < 25 }}
|
{{ states('sensor.<home_name>_current_price_rank_tomorrow') | float(100) < 25 }}
|
||||||
action:
|
action:
|
||||||
- service: input_boolean.turn_off
|
- service: input_boolean.turn_off
|
||||||
entity_id: input_boolean.ev_charge_tonight
|
entity_id: input_boolean.ev_charge_tonight
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Show YAML: Pre-heat when the next interval is cheap</summary>
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
automation:
|
||||||
|
- alias: "Pre-heat if next interval is top quartile cheapest"
|
||||||
|
trigger:
|
||||||
|
- platform: time_pattern
|
||||||
|
minutes: "/15"
|
||||||
|
condition:
|
||||||
|
- condition: numeric_state
|
||||||
|
entity_id: sensor.<home_name>_next_price_rank_today
|
||||||
|
below: 25
|
||||||
|
action:
|
||||||
|
- service: climate.set_hvac_mode
|
||||||
|
entity_id: climate.living_room
|
||||||
|
data:
|
||||||
|
hvac_mode: heat
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue