Display past and future electricity prices as a graph in Home Assistant - an out-of-the-box alternative to e.g. Apex Charts. Tibber Graph was originally built for the official Tibber integration but supports any price sensor as a data source, such as Nord Pool or EPEX Spot.
Tip
Check out tibber_graph.yaml with some examples from this README as a starting point for your own setup.
- Ensure that HACS is installed
- Open repository and click Download to install
- Restart Home Assistant
- Copy the contents of the
custom_components/tibber_graphfolder intoconfig/custom_components/tibber_graph - Restart Home Assistant
Configure the Tibber Graph integration:
Or:
- Go to Settings → Devices & services
- Click Add integration
- Search for "Tibber Graph"
You will now have camera and image entities that displays the electricity prices as a graph, see Provided entities below for details.
The integration will appear in Settings → Devices & services → Tibber Graph with the entity name you provided during setup (or your Tibber home name if no entity name was specified).
You can configure Tibber Graph to get price data from either:
-
Tibber Integration (default): Uses the official Tibber integration to fetch prices directly. You can sign up for Tibber using the invitation code
gqpkcwrnto get a €50/500 kr bonus for use in the Tibber Store. -
Price Sensor: Provide any Home Assistant price sensor that contains price data in its attributes. See Price Sensors as Data Source below for details.
Tip
The data source can be changed at any time using the tibber_graph.create_graph or tibber_graph.set_data_source actions.
All configurable options are available through the Home Assistant UI (Settings → Devices & services → Tibber Graph → [Entity Name] ⚙).
Key features include:
- Multiple graph views: Create separate entities with different configurations
- Flexible time ranges: Show all available data or specify a custom hour range
- Theme customization: Light and dark themes with optional transparent background
- Price highlighting: Highlight the cheapest price periods with colored backgrounds
- Grid and axis control: Customize gridlines, axis position, and tick formatting
- Label options: Configure min/max/current price labels with colors and positioning
For a complete list of available options, their descriptions, and default values, see OPTIONS.md.
You can reconfigure an existing Tibber Graph integration instance to reset specific settings back to their defaults by navigating to Settings → Devices & services → Tibber Graph → [Entity Name] ⋮ → Reconfigure
The reconfigure dialog allows you to:
- Reset nullable fields: Reset specific nullable configuration values (hours to show, Y-axis tick count, price decimals, currency override) back to their defaults
- Reset all settings: Clear all custom configuration and return to default settings
Tibber Graph provides the following entities:
This entity displays the electricity prices as a camera image. It also generates a .png image available here:
- http://homeassistant.local:8123/local/tibber_graph_{entity_name}.png
/config/www/tibber_graph_{entity_name}.png
This entity exposes the generated graph as an image.
Note
For the graph to update you will need to either access the camera entity, enable refresh on interval, or call the tibber_graph.render action.
This sensor provides the timestamp of the last successful image render for the corresponding camera entity. The sensor has a device class of timestamp and can be used in automations or to monitor when the graph was last updated.
Attributes:
data_source_entity_id: The entity ID of the price sensor used as a data source (empty string if using Tibber integration)data_source_friendly_name: The friendly name of the price sensor (or "Tibber Integration" if using Tibber integration)triggered_by: The source that triggered the rendering. Possible values:camera_access: Graph was rendered when the camera entity was accessedaction: Graph was rendered via thetibber_graph.renderactioninterval_refresh: Graph was rendered by the interval refresh mechanism
Tibber Graph provides actions for managing the graph configuration and rendering. These actions can be used in Home Assistant automations or scripts to dynamically update the graph appearance:
Update one or more configuration options for an entity. The entity will be reloaded automatically after the options are updated.
| Data attribute | Required | Description |
|---|---|---|
entity_id |
Yes | The entity ID of the camera to update. |
options |
Yes | Dictionary of options to update, where keys are option names (as defined in OPTIONS.md) and values are the new values. |
overwrite |
No | When true, all options not provided in the options dictionary will be reset to their default values. When false (default), only provided options are updated, existing options are preserved. |
Examples:
# Change theme to light mode
action: tibber_graph.set_option
data:
entity_id: camera.tibber_graph_nord_pool_price_per_kwh
options:
theme: "light"# Update multiple options at once
action: tibber_graph.set_option
data:
entity_id: camera.tibber_graph_nord_pool_price_per_kwh
options:
theme: "dark"
transparent_background: true
canvas_width: 1920
canvas_height: 1080
show_average_price_line: true
currency_override: null # reset nullable option to default# Update specific options and reset all others to defaults (overwrite mode)
action: tibber_graph.set_option
data:
entity_id: camera.tibber_graph_nord_pool_price_per_kwh
options:
theme: "light"
canvas_width: 1920
overwrite: true
# All options not listed (canvas_height, show_average_price_line, etc.)
# will be reset to their default valuesReset one or more configuration options to their default values for an entity. The entity will be reloaded automatically after the options are reset.
| Data attribute | Required | Description |
|---|---|---|
entity_id |
Yes | The entity ID of the camera to reset options for. |
options |
No | List of option names to reset (as defined in OPTIONS.md). Leave empty or omit to reset all options to their default values. |
Examples:
# Reset specific options to defaults
action: tibber_graph.reset_option
data:
entity_id: camera.tibber_graph_nord_pool_price_per_kwh
options:
- theme
- canvas_width
- show_average_price_line# Reset all options to defaults
action: tibber_graph.reset_option
data:
entity_id: camera.tibber_graph_nord_pool_price_per_kwhChange the data source for an entity. This allows you to switch between the Tibber integration and/or price sensors as a data source.
| Data attribute | Required | Description |
|---|---|---|
entity_id |
Yes | The entity ID of the camera to update the data source for. |
price_entity_id |
No | The entity ID of a sensor containing price data. Leave empty or omit to use the Tibber integration instead. |
See also Custom attributes & fields below for how to specify custom attributes and fields.
Examples:
# Switch to a price sensor as data source
action: tibber_graph.set_data_source
data:
entity_id: camera.tibber_graph_living_room_display
price_entity_id: sensor.nord_pool_price_per_kwh# Switch back to Tibber integration
action: tibber_graph.set_data_source
data:
entity_id: camera.tibber_graph_living_room_displayRender the graph for an entity. If entity_id is not provided, renders all Tibber Graph entities.
| Data attribute | Required | Description |
|---|---|---|
entity_id |
No | The entity ID (or list of entity IDs) of the camera to render. If not provided, all entities are rendered. |
Examples:
# Force render entities
action: tibber_graph.render
data:
entity_id:
- camera.tibber_graph_living_room_display
- camera.tibber_graph_nord_pool_price_per_kwh# Force render all Tibber Graph entities
action: tibber_graph.renderSet a custom theme for an entity, allowing you to dynamically change the graph's color scheme. Theme properties are optional — any properties omitted from theme_config will be taken from the selected built-in theme. Call without theme_config to clear the custom theme and revert to the configured theme.
| Data attribute | Required | Description |
|---|---|---|
entity_id |
Yes | The entity ID of the camera to set the custom theme for. |
theme_config |
No | Dictionary containing theme properties. |
For detailed information about theme properties, complete examples, and automation ideas, see CUSTOM_THEME.md.
Examples:
# Set a custom purple theme
action: tibber_graph.set_custom_theme
data:
entity_id: camera.tibber_graph_living_room_display
theme_config:
avgline_color: "#ff6b9d"
avgline_style: ":"
axis_label_color: "#d8b9ff"
background_color: "#1a0f2e"
cheap_price_color: "#2d3d5a"
cheapline_color: "#7cffb3"
cheapline_style: ":"
fill_alpha: 0.2
fill_color: "#9d7cff"
grid_alpha: 0.4
grid_color: "#3d2f50"
label_color: "#f0e6ff"
label_color_avg: "#ffb347"
label_color_max: "#ff6b9d"
label_color_min: "#7cffb3"
label_stroke: true
nowline_alpha: 0.6
nowline_color: "#ff6b9d"
plot_linewidth: 1.2
price_line_color: "#9d7cff"
price_line_color_above_avg: "#ff6b9d"
price_line_color_below_avg: "#9d7cff"
price_line_color_near_avg: "#ffb347"
spine_color: "#503d70"
tick_color: "#d8b9ff"
tickline_color: "#2e1f45"# Clear custom theme and revert to configured theme
action: tibber_graph.set_custom_theme
data:
entity_id: camera.tibber_graph_living_room_displayTip
Please do not hesitate to share your custom themes with the community by opening a pull request to get it added to the list of built-in themes.
Create a new Tibber Graph camera entity programmatically. This action allows you to create entities without using the UI, making it easy to set up multiple graphs with similar configurations. The action returns the entity ID of the created camera entity.
| Data attribute | Required | Description |
|---|---|---|
entity_name |
No | The name of the new entity. Must be unique. If not provided, auto-generated from the price entity friendly name or Tibber home name. Will be prefixed with "Tibber Graph" for the camera entity name. |
price_entity_id |
No | The entity ID of a sensor containing price data. If not provided, the Tibber integration will be used. |
options |
No | Dictionary of options to set for the new entity. Keys should be option names (as defined in OPTIONS.md). |
custom_theme |
No | Dictionary defining a custom theme. Keys should be theme property names (as defined in CUSTOM_THEME.md). |
recreate |
No | If true, recreate the entity if it already exists. If false (default), an error will be raised if an entity with the same name exists. |
See also Custom attributes & fields below for how to specify custom attributes and fields.
Examples:
# Create a basic entity using Tibber integration (auto-generated name)
action: tibber_graph.create_graph# Re-create an entity with a price sensor as data source and specific options
action: tibber_graph.create_graph
data:
entity_name: Living Room Display
price_entity_id: sensor.nord_pool_price_per_kwh
options:
theme: "light"
canvas_width: 1920
canvas_height: 1080
transparent_background: true
show_average_price_line: true
cheap_price_points: 3
recreate: true# Create an entity with custom theme
action: tibber_graph.create_graph
data:
entity_name: Purple Graph
price_entity_id: sensor.nord_pool_price_per_kwh
custom_theme:
avgline_color: "#ff6b9d"
avgline_style: ":"
axis_label_color: "#d8b9ff"
background_color: "#1a0f2e"
cheap_price_color: "#2d3d5a"
cheapline_color: "#7cffb3"
cheapline_style: ":"
fill_alpha: 0.2
fill_color: "#9d7cff"
grid_alpha: 0.4
grid_color: "#3d2f50"
label_color: "#f0e6ff"
label_color_avg: "#ffb347"
label_color_max: "#ff6b9d"
label_color_min: "#7cffb3"
label_stroke: true
nowline_alpha: 0.6
nowline_color: "#ff6b9d"
plot_linewidth: 1.2
price_line_color: "#9d7cff"
price_line_color_above_avg: "#ff6b9d"
price_line_color_below_avg: "#9d7cff"
price_line_color_near_avg: "#ffb347"
spine_color: "#503d70"
tick_color: "#d8b9ff"
tickline_color: "#2e1f45"Delete a Tibber Graph camera entity programmatically. This action removes the entity from Home Assistant.
| Data attribute | Required | Description |
|---|---|---|
entity_id |
Yes | The entity ID of the Tibber Graph camera to delete. |
Examples:
# Delete a specific entity
action: tibber_graph.delete_graph
data:
entity_id: camera.tibber_graph_nord_pool_price_per_kwhExport the current configuration for a Tibber Graph entity. This action returns a dictionary containing all explicitly set configuration options and their values, in a format suitable for use with the tibber_graph.create_graph or tibber_graph.set_option actions.
| Data attribute | Required | Description |
|---|---|---|
entity_id |
Yes | The entity ID of the Tibber Graph camera to export the config from. |
Examples:
# Export configuration for an entity
action: tibber_graph.export_config
data:
entity_id: camera.tibber_graph_living_room_displayThe action returns a response in the following format:
options:
canvas_height: 1080
canvas_width: 1920
cheap_price_points: 3
theme: light
custom_theme:
avgline_color: "#ff6b9d"
avgline_style: ":"
# ... other theme propertiesAny price sensor can be used as a data source as long as it exposes price data in its attributes in a compatible format. This allows you to use other electricity price providers or roll your own custom price sensor.
Sensors must either follow the data source format below (by transforming the data using a template sensors as with Nord Pool or directly as with EPEX Spot) or you can specify custom attributes and fields when using the tibber_graph.create_graph or tibber_graph.set_data_source actions.
# Data source format
attributes:
{prices|data}:
- {start_time|start|startsAt}: datetime # datetime string in ISO 8601 format
{price|price_per_kwh|total}: float # price per kWh
- ...
currency: string # (optional) currency stringTip
See the home-assistant-config repo for more complete examples.
Install and configure the official Nord Pool integration and create a template sensor:
Important
Replace {nord_pool_config_entry_id} and {nord_pool_area} area below with your Nord Pool config entry ID and area. You can get the config_entry_id by navigating to Settings → Devices & services → Entities, selecting one of the entities belonging to the integration, selecting ⋮ → Related → Integration and copying the last part of the URL (.../config/integrations/integration/nordpool#config_entry={nord_pool_config_entry_id}).
template:
- trigger:
- trigger: time
at: "14:00:00"
- trigger: homeassistant
event: start
- platform: event
event_type: call_service
event_data:
domain: template
service: reload
action:
- variables:
config_entry: "{nord_pool_config_entry_id}"
area: "{nord_pool_area}"
- action: nordpool.get_prices_for_date
data:
config_entry: "{{ config_entry }}"
date: "{{ now().date() }}"
response_variable: today_prices
- action: nordpool.get_prices_for_date
data:
config_entry: "{{ config_entry }}"
date: "{{ now().date() + timedelta(days=1) }}"
response_variable: tomorrow_prices
sensor:
- name: Nord Pool price per kWh
state: >
{% set prices = today_prices[area] + tomorrow_prices[area] %}
{{ (prices | map(attribute='price') | sum / prices | count / 1000 * 1.25 + 0.086) | round(3, default=0) }}
# ^ ^ ^
# | | |
# convert to SEK per kWh --┘ | |
# add 25% VAT --------------------┘ |
# add 0.086 SEK/kWh markup --------------┘
unit_of_measurement: SEK/kWh
state_class: total
device_class: monetary
unique_id: nord_pool_price_per_kwh
icon: mdi:cash-multiple
availability: >
{{ today_prices is mapping and today_prices[area] | length > 0 }}
attributes:
data: >
{% set prices = today_prices[area] + tomorrow_prices[area] %}
{% set ns = namespace(prices=[]) %}
{% for i in prices %}
{% set time = i.start | as_datetime | as_local %}
{% set price = i.price / 1000 * 1.25 + 0.086 %}
{% set ns.prices = ns.prices + [{'start': time.isoformat(), 'price_per_kwh': price | round(3, default=0)}] %}
{% endfor %}
{{ ns.prices }}
currency: kr per kWh # overrides currency from "unit_of_measurement"Install and configure the EPEX Spot integration. The price sensors provided by this integration can be used directly as a data source as they expose a compatible data attribute.
You can customize how price data is extracted and transformed using one or more of these parameters when calling the tibber_graph.create_graph or tibber_graph.set_data_source actions:
| Parameter | Type | Description |
|---|---|---|
data_attr |
String | Specify the attribute name containing the price data list. |
data_attr_start_field |
String | Specify the field name for the start time in each price point. |
data_attr_start_fmt |
String | Specify the datetime format string for parsing timestamps (using Python's format codes). If not set, ISO 8601 format is expected. |
data_attr_price_field |
String | Specify the field name for the price value in each price point. |
currency_attr |
String | Specify the attribute name to read the currency symbol from. |
Note
If any of the above parameters are not provided, the default values will be used (see Data source format above).
These parameters allow you to transform the price provided by the data source, in this order, before displaying them:
| Parameter | Type | Description |
|---|---|---|
data_attr_price_factor |
Number | Multiply each price by this factor. Useful for unit conversion (e.g., 0.001 for MWh to kWh) or adding VAT (e.g., 1.25 for 25% VAT). |
data_attr_price_add |
Number | Add this value to each price. Useful for adding fixed costs like grid fees. |
Given a price sensor exposing data in the following format (prices in SEK/MWh without VAT or markup):
sensor:
- name: Nord Pool spot price
...
unique_id: nord_pool_spot_price
...
attributes:
price_per_mwh:
- from: 11/17/2025 00:00:00
spot_price: 585.86
- from: 11/17/2025 00:15:00
spot_price: 578.4
...
price_unit: krCreate/update graph using the tibber_graph.create_graph and tibber_graph.set_data_source actions:
# Create a graph with prices in SEK/kWh, including 25% VAT and a 0.086 SEK/kWh markup
action: tibber_graph.create_graph
data:
entity_name: Nord Pool price from spot
price_entity_id: sensor.nord_pool_spot_price
data_attr: "price_per_mwh"
data_attr_start_field: "from"
data_attr_start_fmt: "%m/%d/%Y %H:%M:%S"
data_attr_price_field: "spot_price"
data_attr_price_factor: 0.00125 # convert MWh to kWh and add 25% VAT
data_attr_price_add: 0.086 # add 0.086 SEK/kWh markup
currency_attr: "price_unit"# Revert back to spot price per MWh by omitting price transformation parameters
action: tibber_graph.set_data_source
data:
entity_id: camera.tibber_graph_nord_pool_price_from_spot
price_entity_id: sensor.nord_pool_spot_price
data_attr: "price_per_mwh"
data_attr_start_field: "from"
data_attr_start_fmt: "%m/%d/%Y %H:%M:%S"
data_attr_price_field: "spot_price"
currency_attr: "price_unit"Tip
Use the configuration snippets below together with the tibber_graph.set_option action to reproduce the example graphs.
Graph rendered with version 0.2.1 defaults:
options:
# General settings
canvas_width: 1200
canvas_height: 700
color_price_line_by_average: false
# Price labels
label_current: "on_in_graph"
label_minmax_per_day: false
# Y-axis settings
show_y_axis: "on_with_tick_marks"Graph rendered with my personal Wear OS camera tile configuration:
options:
# General settings
theme: "dark"
transparent_background: true
canvas_width: 1280
canvas_height: 720
label_font_size: 17
start_graph_at: "current_hour"
cheap_price_points: 5
cheap_price_threshold: 0.5
show_cheap_price_line: true
# Price labels
use_hourly_prices: true
use_cents: true
currency_override: "öre"
label_current: "on_current_price_only"
label_min: "on_no_price"
label_max: "on_no_price"
label_minmax_per_day: false
# X-axis settings
show_x_axis: "on_with_tick_marks"
cheap_periods_on_x_axis: "on_comfy"
cheap_boundary_highlight: "underline"
# Y-axis settings
show_y_axis: "on_with_tick_marks"
y_tick_count: 2
y_axis_label_rotation_deg: 270
y_axis_side: "right"
y_tick_use_colors: trueGraph rendered with light mode, cheap periods on X-axis, and colored Y-axis tick marks:
options:
# General settings
theme: "light"
cheap_price_points: 5
cheap_price_threshold: 1.0
show_cheap_price_line: true
color_price_line_by_average: false
# Price labels
use_hourly_prices: true
label_current: "on_in_graph"
label_min: "off"
label_max: "off"
# X-axis settings
show_x_axis: "on_with_tick_marks"
cheap_periods_on_x_axis: "on"
show_vertical_grid: false
# Y-axis settings
y_tick_count: 3
y_tick_use_colors: true
# Footer settings
show_data_source_name: true
custom_theme:
avgline_style: "-."- Daniel Hjelseth Høyer for the original Tibber Custom integration
- Jvgvisser for inspiration






