# Tibber Binding
The Tibber Binding retrieves prices from the Tibber API (opens new window).
If you have Tibber Pulse hardware, you can also use the live group and statistics group.
# Supported Things
| Type | ID | Description |
|---|---|---|
| Thing | tibberapi | Connection to Tibber API |
# Thing Configuration
| Name | Type | Description | Default | Required |
|---|---|---|---|---|
| token | text | Tibber Personal Token | N/A | yes |
| homeid | text | Tibber Home ID | N/A | yes |
| updateHour | integer | Local hour when spot prices are updated | 13 | yes |
Note: The Tibber token is retrieved from your Tibber account: Tibber Account (opens new window)
Note: The Tibber Home ID is retrieved from developer.tibber.com (opens new window):
- Sign in (Tibber user account) and "load" personal token.
- Copy query from below and paste into the Tibber API Explorer, and run query.
- If Tibber Pulse is connected, the Tibber API Explorer will report "true" for "realTimeConsumptionEnabled"
- Copy the Home ID from the Tibber API Explorer, without quotation marks, and use it in the binding configuration.
{
viewer {
homes {
id
features {
realTimeConsumptionEnabled
}
}
}
}
If you have multiple Home IDs/Pulse devices, create separate Things for each Home ID.
# Channels
# price group
Current and forecast Tibber price information. All values are read-only.
| Channel ID | Type | Description | Time Series |
|---|---|---|---|
| total | Number:EnergyPrice | Total price including energy and taxes | yes |
| spot | Number:EnergyPrice | Spot prices for energy today and tomorrow | yes |
| tax | Number:EnergyPrice | Taxes and additional expenses | yes |
| level | Number | Price levels for today and tomorrow | yes |
| average | Number:EnergyPrice | Average price from last 24 hours | yes |
Channel spot-price is deprecated and will be removed in the next major update.
It's still available as an advanced channel.
The naming was misleading as it reflected the total price and not the Nord Pool spot price (opens new window) used by Tibber.
The level number maps the Tibber Rating (opens new window) into numbers.
Zero reflects normal price, while values above 0 are expensive and values below 0 are cheap.
Mapping:
- Very Cheap: -2
- Cheap: -1
- Normal: 0
- Expensive: 1
- Very Expensive: 2
The average values are not delivered by the Tibber API.
They are calculated by the binding to provide a trend line for the last 24 hours.
After the initial setup, the average values will remain NULL until the next day because the previous 24 h prices cannot be obtained by the Tibber API.
Please note that time series are not supported by the default rrd4j (opens new window) persistence. The items connected to the above channels need to be stored in, e.g., InfluxDB (opens new window) or InMemory (opens new window).
# Trigger Channels
Channel event can trigger the following events:
| Event | Description |
|---|---|
| DAY_AHEAD_AVAILABLE | Day-ahead prices are available |
# live group
Live information from Tibber Pulse. All values are read-only.
| Channel ID | Type | Description |
|---|---|---|
| consumption | Number:Power | Consumption at the moment in watts |
| minimum-consumption | Number:Power | Minimum power consumption since midnight in watts |
| peak-consumption | Number:Power | Peak power consumption since midnight in watts |
| average-consumption | Number:Power | Average power consumption since midnight in watts |
| production | Number:Power | Net power production at the moment in watts |
| minimum-production | Number:Power | Minimum net power production since midnight in watts |
| peak-production | Number:Power | Maximum net power production since midnight in watts |
| power-balance | Number:Power | Current power consumption (as positive value) and production (as negative value) |
| voltage1 | Number:ElectricPotential | Electric potential on phase 1 |
| voltage2 | Number:ElectricPotential | Electric potential on phase 2 |
| voltage3 | Number:ElectricPotential | Electric potential on phase 3 |
| current1 | Number:ElectricCurrent | Electric current on phase 1 |
| current2 | Number:ElectricCurrent | Electric current on phase 2 |
| current3 | Number:ElectricCurrent | Electric current on phase 3 |
# statistics group
Statistical information about total, daily, and last-hour energy consumption and production. All values are read-only.
| Channel ID | Type | Description |
|---|---|---|
| total-consumption | Number:Energy | Total energy consumption measured by Tibber Pulse meter |
| daily-consumption | Number:Energy | Energy consumed since midnight in kilowatt-hours |
| daily-cost | Number:Currency | Accumulated cost since midnight |
| last-hour-consumption | Number:Energy | Energy consumed since last hour shift in kilowatt-hours |
| total-production | Number:Energy | Total energy production measured by Tibber Pulse meter |
| daily-production | Number:Energy | Net energy produced since midnight in kilowatt-hours |
| last-hour-production | Number:Energy | Net energy produced since last hour shift in kilowatt-hours |
# Thing Actions
Thing actions can be used to perform calculations on the currently available price information cached by the binding.
The cache contains energy prices for today and, after reaching the updateHour, also for tomorrow.
This helps plan when to run a device and at what cost.
Performing a calculation requires a parameters object containing, e.g., your boundaries for the calculation.
The parameter object allows two types: a Java Map or a JSON String.
The result is returned as a JSON-encoded String.
See the sections below for the result format.
If the action cannot be performed, a warning will be logged and an empty String will be returned.
Some real-life scenarios are shown in the Thing Actions section.
# priceInfoStart
Returns the starting point as an Instant of the first available energy price.
Calculations must not start before this timestamp.
In case of error Instant.MAX is returned.
# priceInfoEnd
Returns the end point as an Instant of the last available energy price.
Calculations must not extend beyond this timestamp.
In case of error Instant.MIN is returned.
# listPrices
List prices in ascending or descending price order. Use persistence extensions (opens new window) if you need time ordering.
# Parameters
| Name | Type | Description | Default | Required |
|---|---|---|---|---|
| earliestStart | Instant | Earliest start time | now | no |
| latestEnd | Instant | Latest end time | priceInfoEnd | no |
| ascending | boolean | Price sorting order | true | no |
# Example
rule "Tibber Price List"
when
System started // use your trigger
then
var actions = getActions("tibber","tibber:tibberapi:xyz")
// parameters empty => default parameters are used = starting from now till end of available price information, ascending
var parameters = "{}"
var result = actions.listPrices(parameters)
val numberOfPrices = transform("JSONPATH", "$.size", result)
logInfo("TibberPriceList",result)
for(var i=0; i<Integer.valueOf(numberOfPrices); i++) {
// get values and convert them into correct format
val priceString = transform("JSONPATH", "$.priceList["+i+"].price", result)
val price = Double.valueOf(priceString)
val startsAtString = transform("JSONPATH", "$.priceList["+i+"].startsAt", result)
val startsAt = Instant.parse(startsAtString)
logInfo("TibberPriceList","PriceInfo "+i+" : " + price + " Starts at : " + startsAt.atZone(ZoneId.systemDefault()))
}
end
# Console output
2025-05-29 15:52:31.345 [INFO ] [ab.core.model.script.TibberPriceList] - PriceInfo 0 : 0.1829 Starts at : 2025-05-30T13:00+02:00[Europe/Berlin]
2025-05-29 15:52:31.349 [INFO ] [ab.core.model.script.TibberPriceList] - PriceInfo 1 : 0.183 Starts at : 2025-05-30T14:00+02:00[Europe/Berlin]
2025-05-29 15:52:31.352 [INFO ] [ab.core.model.script.TibberPriceList] - PriceInfo 2 : 0.1842 Starts at : 2025-05-29T15:52:31.341193101+02:00[Europe/Berlin]
...
# Result
JSON-encoded String result with keys
| Key | Type | Description |
|---|---|---|
| size | int | Size of price list |
| priceList | JSON array | Array of priceInfo entries |
JSON Object priceInfo
| Key | Type | Description |
|---|---|---|
| startsAt | String | String encoded Instant |
| duration | int | Price duration in seconds |
| price | double | Price in your currency |
# Example
{
"size": 4,
"priceList": [
{
"price": 0.1623,
"duration": 3600,
"level": -1,
"startsAt": "2025-06-01T12:00:00Z"
},
{
"price": 0.168,
"duration": 3600,
"level": -1,
"startsAt": "2025-06-01T13:00:00Z"
},
{
"price": 0.1712,
"duration": 3600,
"level": -1,
"startsAt": "2025-06-01T11:00:00Z"
},
{
"price": 0.1794,
"duration": 3600,
"level": -1,
"startsAt": "2025-06-01T14:00:00Z"
}
]
}
# bestPricePeriod
Calculates the lowest cost for a consecutive period. For use cases like a dishwasher or laundry.
# Parameters
| Name | Type | Description | Default | Required |
|---|---|---|---|---|
| earliestStart | Instant | Earliest start time | now | no |
| latestStop | Instant | Latest end time | priceInfoEnd | no |
| power | int | Power in watts | N/A | no |
| duration | String | Duration as String with units h,m or s | N/A | true |
| curve | JsonArray | Array with curveEntry elements | N/A | no |
Provide either
poweranddurationfor constant consumption orcurvefor sophisticated use cases like a recorded laundry power time series
JSON Object curveEntry
| Key | Type | Description |
|---|---|---|
| timestamp | String | String encoded Instant |
| power | int | Power in watts |
| duration | int | Duration in seconds |
# Example
import java.util.Map;
var Timer bestPriceTimer = null
rule "Tibber Best Price"
when
System started // use your trigger
then
// get actions
var actions = getActions("tibber","tibber:tibberapi:xyz")
//create parameters for calculation
var parameters = Map.of("duration", "1 h 34 m")
// perform calculation
var result = actions.bestPricePeriod(parameters)
// log result, no prices given because no power value given
logInfo("TibberBestPrice",result)
// parameters with power value - as example use java Map instead of JSON
parameters = Map.of("duration", "1 h 34 m","power",423,"latestEnd",Instant.now().plusSeconds(7200))
result = actions.bestPricePeriod(parameters)
logInfo("TibberBestPrice",result)
// calculate time between now and cheapest start and start timer to execute action
val startsAt = transform("JSONPATH", "$.cheapestStart", result)
var secondsTillStart = Duration.between(Instant.now(), Instant.parse(startsAt)).getSeconds()
// if the start should happen immediately, avoid negative values
secondsTillStart = Math::max(0,secondsTillStart)
bestPriceTimer = createTimer(now.plusSeconds(secondsTillStart), [|
logInfo("TibberBestPrice","Start your device")
])
end
Console output:
2025-05-29 16:07:40.858 [TRACE] [.internal.calculator.PriceCalculator] - Calculation time 2 ms for 1819 iterations
2025-05-29 16:07:40.860 [INFO ] [ab.core.model.script.TibberBestPrice] - {"cheapestStart":"2025-05-30T11:00:40.856950656Z","mostExpensiveStart":"2025-05-30T18:25:40.856950656Z"}
2025-05-29 16:07:40.861 [TRACE] [.internal.calculator.PriceCalculator] - Calculation time 0 ms for 26 iterations
2025-05-29 16:07:40.863 [INFO ] [ab.core.model.script.TibberBestPrice] - {"highestPrice":0.138712416,"lowestPrice":0.13126169399999998,"cheapestStart":"2025-05-29T14:07:40.861730141Z","averagePrice":0.134152053,"mostExpensiveStart":"2025-05-29T14:32:40.861730141Z"}
2025-05-29 16:07:40.967 [INFO ] [ab.core.model.script.TibberBestPrice] - Start your device
# Result
JSON-encoded String result with keys
| Key | Type | Description |
|---|---|---|
| cheapestStart | String | Timestamp of cheapest start |
| lowestPrice | double | Price of the cheapest period |
| mostExpensiveStart | String | Timestamp of most expensive start |
| highestPrice | double | Price of the most expensive period |
| averagePrice | double | Average price within the period |
# Result Example
{
"highestPrice": 0.18921223574999999,
"lowestPrice": 0.17497929625,
"cheapestStart": "2025-05-31T15:12:58.135876781Z",
"averagePrice": 0.1810258046730769,
"mostExpensiveStart": "2025-05-31T15:37:58.135876781Z"
}
# bestPriceSchedule
Calculates the lowest cost for a non-consecutive schedule. For use cases like a battery electric vehicle or a heat pump.
# Parameters
| Name | Type | Description | Default | Required |
|---|---|---|---|---|
| earliestStart | Instant | Earliest start time | now | no |
| latestStop | Instant | Latest end time | priceInfoEnd | no |
| power | int | Needed power | N/A | no |
| duration | int | Duration in seconds or String (8h 15m) | N/A | yes |
# Example
rule "Tibber Schedule Calculation"
when
System started // use your trigger
then
var actions = getActions("tibber","tibber:tibberapi:xyz")
// long period with constant power value
var parameters = "{\"power\": 11000, \"duration\": \"8h 15m\"}"
var result = actions.bestPriceSchedule(parameters)
// get cost and convert it into double value
val costString = transform("JSONPATH", "$.cost", result)
val cost = Double.valueOf(costString)
val scheduleSize = transform("JSONPATH", "$.size", result)
logInfo("TibberSchedule",result)
logInfo("TibberSchedule","Cost : " + cost+" Number of schedules : " + scheduleSize)
for(var i=0; i<Integer.valueOf(scheduleSize); i++) {
val schedule = transform("JSONPATH", "$.schedule["+i+"]", result)
logInfo("TibberSchedule","Schedule "+i+": " + schedule)
val scheduleStartString = transform("JSONPATH", "$.schedule["+i+"].start", result)
val scheduleStart = Instant.parse(scheduleStartString)
logInfo("TibberSchedule","Schedule "+i+" start: " + scheduleStart.atZone(ZoneId.systemDefault()).toString)
}
end
Console output
2025-05-29 19:42:38.223 [INFO ] [hab.core.model.script.TibberSchedule] - {"cost":17.004625,"size":2,"schedule":[{"start":"2025-05-30T08:00:00Z","stop":"2025-05-30T16:00:00Z","duration":28800,"cost":16.407600000000002},{"start":"2025-05-29T23:00:00Z","stop":"2025-05-29T23:15:00Z","duration":900,"cost":0.5970249999999999}]}
2025-05-29 19:42:38.225 [INFO ] [hab.core.model.script.TibberSchedule] - Cost : 17.004625 Number of schedules : 2
2025-05-29 19:42:38.227 [INFO ] [hab.core.model.script.TibberSchedule] - Schedule 0: {start=2025-05-30T08:00:00Z, stop=2025-05-30T16:00:00Z, duration=28800, cost=16.407600000000002}
2025-05-29 19:42:38.230 [INFO ] [hab.core.model.script.TibberSchedule] - Schedule 0 start: 2025-05-30T10:00+02:00[Europe/Berlin]
2025-05-29 19:42:38.232 [INFO ] [hab.core.model.script.TibberSchedule] - Schedule 1: {start=2025-05-29T23:00:00Z, stop=2025-05-29T23:15:00Z, duration=900, cost=0.5970249999999999}
2025-05-29 19:42:38.234 [INFO ] [hab.core.model.script.TibberSchedule] - Schedule 1 start: 2025-05-30T01:00+02:00[Europe/Berlin]
# Result
JSON encoded String result with keys
| Key | Type | Description |
|---|---|---|
| size | int | Number of schedules |
| schedule | JSON array | Array of scheduleEntry elements |
JSON Object scheduleEntry
| Key | Type | Description |
|---|---|---|
| start | String | Start time (Instant as string) |
| stop | String | Stop time (Instant as string) |
| duration | int | Duration in seconds |
| cost | double | Cost in your currency |
# Result Example
{
"cost": 16.092450000000003,
"size": 2,
"schedule": [
{
"start": "2025-06-01T08:00:00Z",
"stop": "2025-06-01T16:00:00Z",
"duration": 28800,
"cost": 15.579300000000002
},
{
"start": "2025-06-01T07:00:00Z",
"stop": "2025-06-01T07:15:00Z",
"duration": 900,
"cost": 0.51315
}
]
}
# Full Example
Full example with demo.things and demo.items
# demo.things Example
Thing tibber:tibberapi:xyz [ homeid="xxx", token="xxxxxxx", updateHour=13 ]
# demo.items Example
Number:EnergyPrice Tibber_API_Spot_Prices "Spot Prices" {channel="tibber:tibberapi:xyz:price#spot"}
Number Tibber_API_Price_Level "Price Level" {channel="tibber:tibberapi:xyz:price#level"}
Number:EnergyPrice Tibber_API_Average "Average Price" {channel="tibber:tibberapi:xyz:price#average"}
Number:Power Tibber_API_Live_Consumption "Live Consumption" {channel="tibber:tibberapi:xyz:live#consumption"}
Number:Power Tibber_API_Minimum_Consumption "Minimum Consumption" {channel="tibber:tibberapi:xyz:live#minimum-consumption"}
Number:Power Tibber_API_Peak_Consumption "Peak Consumption" {channel="tibber:tibberapi:xyz:live#peak-consumption"}
Number:Power Tibber_API_Average_Consumption "Average Consumption" {channel="tibber:tibberapi:xyz:live#average-consumption"}
Number:Power Tibber_API_Live_Production "Live Production" {channel="tibber:tibberapi:xyz:live#production"}
Number:Power Tibber_API_Minimum_Production "Minimum Production" {channel="tibber:tibberapi:xyz:live#minimum-production"}
Number:Power Tibber_API_Peak_Production "Peak Production" {channel="tibber:tibberapi:xyz:live#peak-production"}
Number:Power Tibber_API_Power_Balance "Power Balance" {channel="tibber:tibberapi:xyz:live#power-balance"}
Number:ElectricPotential Tibber_API_Voltage_1 "Voltage 1" {channel="tibber:tibberapi:xyz:live#voltage1"}
Number:ElectricPotential Tibber_API_Voltage_2 "Voltage 2" {channel="tibber:tibberapi:xyz:live#voltage2"}
Number:ElectricPotential Tibber_API_Voltage_3 "Voltage 3" {channel="tibber:tibberapi:xyz:live#voltage3"}
Number:ElectricCurrent Tibber_API_Current_1 "Current 1" {channel="tibber:tibberapi:xyz:live#current1"}
Number:ElectricCurrent Tibber_API_Current_2 "Current 2" {channel="tibber:tibberapi:xyz:live#current2"}
Number:ElectricCurrent Tibber_API_Current_3 "Current 3" {channel="tibber:tibberapi:xyz:live#current3"}
Number:Energy Tibber_API_Total_Consumption "Total Consumption" {channel="tibber:tibberapi:xyz:statistics#total-consumption"}
Number:Energy Tibber_API_Daily_Consumption "Daily Consumption" {channel="tibber:tibberapi:xyz:statistics#daily-consumption"}
Number:Currency Tibber_API_Daily_Cost "Daily Cost" {channel="tibber:tibberapi:xyz:statistics#daily-cost"}
Number:Energy Tibber_API_Last_Hour_Consumption "Last Hour Consumption" {channel="tibber:tibberapi:xyz:statistics#last-hour-consumption"}
Number:Energy Tibber_API_Total_Production "Total Production" {channel="tibber:tibberapi:xyz:statistics#total-production"}
Number:Energy Tibber_API_Daily_Production "Daily Production" {channel="tibber:tibberapi:xyz:statistics#daily-production"}
Number:Energy Tibber_API_Last_Hour_Production "Last Hour Production" {channel="tibber:tibberapi:xyz:statistics#last-hour-production"}
# Rule listen to day-ahead price update
rule "Tibber day-ahead prices available"
when
Channel 'tibber:tibberapi:xyz:price#event' triggered
then
logInfo("Tibber Update","Price event {}", receivedEvent)
end