Skip to main content
Version: Next ๐Ÿšง

Volatility Sensors

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โ€‹

SensorDescriptionTime Window
Today's Price VolatilityVolatility for the current calendar day00:00 - 23:59 today
Tomorrow's Price VolatilityVolatility for the next calendar day00:00 - 23:59 tomorrow
Next 24h Price Volatility (next_24h_volatility)Volatility for the next 24 hours from nowRolling 24h forward
Today + Tomorrow Price VolatilityVolatility across both today and tomorrowUp 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:

AttributeDescriptionExample
price_volatilityVolatility level (language-independent, always English)"moderate"
price_coefficient_variation_%The calculated Coefficient of Variation23.5
price_spreadThe difference between the highest and lowest price12.3
price_minThe lowest price in the period10.2
price_maxThe highest price in the period22.5
price_meanThe arithmetic mean of all prices in the period15.1
price_medianMedian price (50th percentile, robust to outliers)14.8
price_q2525th percentile โ€” lower quartile price11.0
price_q7575th percentile โ€” upper quartile price19.5
price_typical_spreadTypical 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_countIntervals outside the Tukey fence (Q25โˆ’1.5ร—IQR โ€ฆ Q75+1.5ร—IQR) โ€” spikes/dips3
interval_countNumber of price intervals included in the calculation96

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.

MetricCV (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 forTriggering battery/EV charging strategiesUnderstanding 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.

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 == 100 โ†’ never true โŒ
  • state >= 99 โ†’ most expensive interval of the day โœ… (use this instead)

Available Sensorsโ€‹

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

SensorReference SetEnabled 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):

SensorReference SetEnabled 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):

SensorReference SetEnabled 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):

SensorReference SetEnabled 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:

AttributeDescriptionSubject
current_priceThe price being ranked (current interval)Current interval
next_priceThe price being ranked (next interval)Next interval
previous_priceThe price being ranked (previous interval)Previous interval
current_hour_avg_priceThe rolling average being ranked (current hour)Current hour avg
next_hour_avg_priceThe rolling average being ranked (next hour)Next hour avg
prices_below_countHow many reference intervals are strictly cheaperAll sensors
interval_countTotal intervals in the reference setAll sensors
reference_minThe cheapest price in the reference setAll sensors
reference_maxThe most expensive price in the reference setAll sensors
reference_meanAverage price of the reference setAll 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

๐Ÿ’ฌ Comments are page-specific. For a new question or idea, open a dedicated Discussion on GitHub so it gets its own thread and proper visibility.