hass.tibber_prices/docs/user/docs/sensors-volatility.md
Julian Pawlowski 2adb64e5a0 refactor(translations): update terminology for previous interval price ranks
Revised the descriptions and names for the previous interval price rank entities across multiple language translation files to enhance clarity and consistency.

Impact: Users will see improved terminology in the interface, making it clearer that the ranks refer to the previous interval's prices.
2026-04-15 10:43:29 +00:00

18 KiB
Raw Blame History

Volatility Sensors

:::tip Entity ID tip <home_name> is a placeholder for your Tibber home display name in Home Assistant. Entity IDs are derived from the displayed name (localized), so the exact slug may differ. Can't find a sensor? Use the Entity Reference (All Languages) to search by name in your language. :::

Volatility sensors help you understand how much electricity prices fluctuate over a given period. Instead of just looking at the absolute price, they measure the relative price variation, which is a great indicator of whether it's a good day for price-based energy optimization.

The calculation is based on the Coefficient of Variation (CV), a standardized statistical measure defined as:

CV = (Standard Deviation / Arithmetic Mean) * 100%

This results in a percentage that shows how much prices deviate from the average. A low CV means stable prices, while a high CV indicates significant price swings and thus, a high potential for saving money by shifting consumption.

The sensor's state can be low, moderate, high, or very_high, based on configurable thresholds.

Available Volatility Sensors

Sensor Description Time Window
Today's Price Volatility Volatility for the current calendar day 00:00 - 23:59 today
Tomorrow's Price Volatility Volatility for the next calendar day 00:00 - 23:59 tomorrow
Next 24h Price Volatility (next_24h_volatility) Volatility for the next 24 hours from now Rolling 24h forward
Today + Tomorrow Price Volatility Volatility across both today and tomorrow Up to 48 hours

Configuration

You can adjust the CV thresholds that determine the volatility level:

  1. Go to Settings → Devices & Services → Tibber Prices.
  2. Click Configure.
  3. Go to the Price Volatility Thresholds step.

Default thresholds are:

  • Moderate: 15%
  • High: 30%
  • Very High: 50%

Key Attributes

All volatility sensors provide these attributes:

Attribute Description Example
price_volatility Volatility level (language-independent, always English) "moderate"
price_coefficient_variation_% The calculated Coefficient of Variation 23.5
price_spread The difference between the highest and lowest price 12.3
price_min The lowest price in the period 10.2
price_max The highest price in the period 22.5
price_mean The arithmetic mean of all prices in the period 15.1
price_median Median price (50th percentile, robust to outliers) 14.8
price_q25 25th percentile — lower quartile price 11.0
price_q75 75th percentile — upper quartile price 19.5
price_typical_spread Typical price band width — IQR (Q75 Q25, the middle 50% of prices) 8.5
price_typical_spread_% Typical price band as a percentage of the median (IQR%) 57.4
price_spike_count Intervals outside the Tukey fence (Q251.5×IQR … Q75+1.5×IQR) — spikes/dips 3
interval_count Number of price intervals included in the calculation 96

Usage in Automations & Best Practices

You can use the volatility sensor to decide if a price-based optimization is worth it. For example, if your solar battery has conversion losses, you might only want to charge and discharge it on days with high volatility.

Best Practice: Use the price_volatility Attribute

For automations, it is strongly recommended to use the price_volatility attribute instead of the sensor's main state.

  • Why? The main state of the sensor is translated into your Home Assistant language (e.g., "Hoch" in German). If you change your system language, automations based on this state will break. The price_volatility attribute is always in lowercase English ("low", "moderate", "high", "very_high") and therefore provides a stable, language-independent value.

Good Example (Robust Automation): This automation triggers only if the volatility is classified as high or very_high, respecting your central settings and working independently of the system language.

Show YAML: Good Example (Robust Automation)
automation:
    - alias: "Enable battery optimization only on volatile days"
      trigger:
          - platform: template
            value_template: >
                {{ state_attr('sensor.<home_name>_today_s_price_volatility', 'price_volatility') in ['high', 'very_high'] }}                
      action:
          - service: input_boolean.turn_on
            entity_id: input_boolean.battery_optimization_enabled

Avoid Hard-Coding Numeric Thresholds

You might be tempted to use the numeric price_coefficient_variation_% attribute directly in your automations. This is not recommended.

  • Why? The integration provides central configuration options for the volatility thresholds. By using the classified price_volatility attribute, your automations automatically adapt if you decide to change what you consider "high" volatility (e.g., changing the threshold from 30% to 35%). Hard-coding values means you would have to find and update them in every single automation.

Bad Example (Brittle Automation): This automation uses a hard-coded value. If you later change the "High" threshold in the integration's options to 35%, this automation will not respect that change and might trigger at the wrong time.

Show YAML: Bad Example (Brittle Automation)
automation:
    - alias: "Brittle - Enable battery optimization"
      trigger:
          #
          # BAD: Avoid hard-coding numeric values
          #
          - platform: numeric_state
            entity_id: sensor.<home_name>_today_s_price_volatility
            attribute: price_coefficient_variation_%
            above: 30
      action:
          - service: input_boolean.turn_on
            entity_id: input_boolean.battery_optimization_enabled

By following the "Good Example", your automations become simpler, more readable, and much easier to maintain.

Typical Price Band Statistics (IQR)

In addition to the CV-based volatility level, every volatility sensor provides typical price band statistics as attributes. These are derived from the IQR (Interquartile Range) — the spread of the middle 50% of prices — making them more robust to isolated price spikes than the CV.

Metric CV (state) IQR attributes
Sensitive to spikes? Yes — spikes inflate CV No — IQR ignores the outer 25%
Use for optimization? "Is today worth optimizing?" "How wide is the core price band?"
Best for Triggering battery/EV charging strategies Understanding price structure

The price_typical_spread_% attribute (IQR as a percentage of the median) tells you how wide the core price band is relative to the median. Even on a high-CV day with isolated spikes, a low price_typical_spread_% means most of the day has stable prices — only a few intervals are outliers.

The price_spike_count attribute (Tukey fence method: Q25 1.5×IQR to Q75 + 1.5×IQR) tells you how many intervals fall outside the normal range. A high price_spike_count day with a high CV is a classic "spiky" day: mostly stable prices with a few expensive or cheap peaks.


Price Rank Sensors (Percentile Rank)

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 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)

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.

:::note 100% is never reached By design, the most expensive interval of the day will never show 100%. The formula counts how many intervals are strictly cheaper than the subject price. For the daily maximum, every other interval is cheaper — but the interval itself is not counted. With 96 quarter-hour intervals per day, the maximum value is 95 ÷ 96 × 100 = 99.0%.

This means:

  • state == 0 → cheapest interval of the reference set
  • state == 100never true
  • state >= 99 → most expensive interval of the day (use this instead) :::

Available Sensors

Current interval (price of the active quarter-hour):

Sensor Reference Set Enabled by Default
Current Price Rank (Today) Today's 96 quarter-hour intervals Yes
Current Price Rank (Tomorrow) Tomorrow's 96 intervals (once avail.) No
Current Price Rank (Today+Tomorrow) Combined pool (up to 192 intervals) No

Next interval (price of the upcoming quarter-hour):

Sensor Reference Set Enabled by Default
Next Price Rank (Today) Today's 96 quarter-hour intervals No
Next Price Rank (Today+Tomorrow) Combined pool (up to 192 intervals) No

Previous interval (price of the just-ended quarter-hour):

Sensor Reference Set Enabled by Default
Previous Price Rank (Today) Today's 96 quarter-hour intervals No
Previous Price Rank (Today+Tomorrow) Combined pool (up to 192 intervals) No

Rolling hourly average (5-interval window, ~1 hour):

Sensor Reference Set Enabled by Default
⌀ Hourly Price Current Rank (Today) Today's 96 quarter-hour intervals No
⌀ Hourly Price Current Rank (Today+Tomorrow) Combined pool (up to 192 intervals) No
⌀ Hourly Price Next Rank (Today) Today's 96 quarter-hour intervals No
⌀ Hourly Price Next Rank (Today+Tomorrow) Combined pool (up to 192 intervals) No

Key Attributes

All price rank sensors share most of these attributes. The price attribute key reflects the subject:

Attribute Description Subject
current_price The price being ranked (current interval) Current interval
next_price The price being ranked (next interval) Next interval
previous_price The price being ranked (previous interval) Previous interval
current_hour_avg_price The rolling average being ranked (current hour) Current hour avg
next_hour_avg_price The rolling average being ranked (next hour) Next hour avg
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

  • Current (Today) — Same-day scheduling. "Is the active quarter-hour within the cheapest 25% of today?"
  • Next (Today) — Prepare for the next interval. "Should I pre-heat now so the device runs in the coming cheap slot?"
  • 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

Show YAML: Start dishwasher in bottom quartile
automation:
    - alias: "Start dishwasher at cheapest time of day"
      trigger:
          - platform: numeric_state
            entity_id: sensor.<home_name>_current_price_rank_today
            below: 25
      condition:
          - condition: state
            entity_id: binary_sensor.<home_name>_best_price_period
            state: "on"
      action:
          - service: switch.turn_on
            entity_id: switch.dishwasher
Show YAML: Postpone task if tomorrow is cheaper
automation:
    - alias: "Skip charging tonight if tomorrow is cheaper"
      trigger:
          - platform: time
            at: "21:00:00"
      condition:
          # Only postpone if tomorrow's cheapest quartile is better than the current price
          - condition: template
            value_template: >
                {{ states('sensor.<home_name>_current_price_rank_tomorrow') | float(100) < 25 }}                
      action:
          - service: input_boolean.turn_off
            entity_id: input_boolean.ev_charge_tonight
Show YAML: Avoid running devices at the most expensive time of day
automation:
    - alias: "Pause non-essential devices at peak price"
      trigger:
          - platform: numeric_state
            entity_id: sensor.<home_name>_current_price_rank_today
            above: 99  # 100 is never reached — use >= 99 to catch the daily maximum
      action:
          - service: switch.turn_off
            entity_id: switch.dishwasher
Show YAML: Pre-heat when the next interval is cheap
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