openHAB · price and CO2
Use electricity price and CO2 in openHAB without building a custom add-on
For openHAB, the compact summary is the easiest starting point via HTTP Binding and JSONPATH. If you want more control later, there is now also a dedicated raw price-series path for your own rules or JS scripting.
- dedicated openHAB endpoint with a compact structure for HTTP Binding and rules
- summary for the quick start, price series for advanced custom logic
- optional API key support, for example up to 120h in the current test phase
Core logic explained early
The price logic is not “forecast only”. It deliberately works in two steps so that official market data wins whenever it exists.
You do not need a special add-on. For the first step, the HTTP Binding together with the JSONPATH transformation is enough in openHAB.
Install the HTTP Binding and the JSONPATH Transformation in openHAB. Without JSONPATH, the fields stay empty even if the endpoint itself works correctly.
Recommended entry point: summary
There is a dedicated summary path for openHAB. Technically it returns the same compact automation summary as the other integrations, but with a structure that fits directly into HTTP Binding, JSONPATH and rules.
https://api.energypriceforecast.eu/api/v1/openhab/summary?country=de&hours=48&window_hours=4flat.current_price, flat.is_cheapest_window_now and price.next_full_window for robust rules.flat.current_co2_g_kwh, flat.is_greenest_window_now and co2.best_window.meta.allowed_horizon_hours, meta.used_calls_today and other API hints.Alternative for your own price logic: openhab/prices
For more advanced setups there is now also a second openHAB path that returns only the price series. It is intended for your own rules, JS scripting, charts or external preprocessing.
https://api.energypriceforecast.eu/api/v1/openhab/prices?country=de&hours=48&mode=mixed&resolution=15msummaryBeginner path with current price, CO2 and already computed windows.pricesRaw price series for your own logic, charts and custom rules.summary. The price-series path is more useful when you really want to process arrays yourself.What the API actually returns
The openHAB summary path does not return a special openHAB-only structure. It returns a compact automation summary instead. That is exactly the benefit: the same core information stays readable and testable outside openHAB as well.
| Part | What it contains | Why it is useful |
|---|---|---|
flat | The simplest fields such as current price, current CO2, boolean flags for active best windows and remaining minutes. | Perfect for a fast start without much parsing. |
price | Current price slot plus best_window and next_full_window as structured objects. | More context for rules and visualization. |
co2 | Current CO2 value plus best_window and next_full_window for CO2. | For ecologically oriented logic. |
combined | A combined price/CO2 window. | Useful if you do not want to create your own weighting. |
source | Metadata that shows whether price values come from day-ahead or forecast. | Important for interpretation and debugging. |
meta | Access and contract information such as API key state, allowed horizon and daily counters. | Helpful for troubleshooting, limits and checking key status. |
If you need a real price series for your own calculations instead of the compact summary, use /api/v1/openhab/prices. The summary intentionally stays compact. The price-series path is meant for advanced openHAB logic.
Price series for your own rules: openhab/prices
The extra price-series path deliberately returns prices only, without CO2 fields and without precomputed window logic. That is the point: you decide yourself how to evaluate the slots or combine them with house state, PV, battery or your own thresholds.
| Parameter | Meaning | Typical use |
|---|---|---|
mode=mixed | Day-ahead first, forecast only for future hours not yet covered by official day-ahead data. | Practical default. |
mode=forecast_only | Forecast only, without day-ahead mixing. | Comparison or intentionally forecast-centered logic. |
price_mode=base | Default mode with base or market prices. | When the relative shape is enough for your automation. |
price_mode=retail | Assumption-based total retail price with markups, grid fees and VAT for supported markets. | When you want to automate closer to an end-customer price. |
plz=10115 | Required for Germany in retail mode so regional grid-fee assumptions fit better. | Mandatory for price_mode=retail in Germany. |
resolution=15m | Continuous quarter-hour series. Forecast hours are repeated across four quarter-hour slots. | Charts and uniform slot logic. |
resolution=native | Day-ahead stays quarter-hourly, forecast stays hourly. | When you want to keep the original source resolution. |
https://api.energypriceforecast.eu/api/v1/openhab/prices?country=de&hours=48&mode=mixed&resolution=15m
https://api.energypriceforecast.eu/api/v1/openhab/prices?country=de&hours=48&mode=mixed&resolution=15m&price_mode=retail&plz=10115
Important: in 15m mode, forecast values are not smoothed between hours. The API does not invent intermediate prices. Instead, each forecast hour is simply repeated across four quarter-hour slots.
Base price or total retail price?
The openHAB summary path still deliberately returns base or market prices. The prices path also returns base prices by default, but can optionally return assumption-based retail totals.
summaryStays compact and deliberately remains on base prices.prices with price_mode=retailCan return an optional 15-minute or native series as an assumption-based total retail price.Horizon and resolution
The examples use hours=48 and window_hours=4. That is only a starting value, not the full technical ceiling.
hours you define how far the API should look into the future. As a public commitment, we currently communicate a maximum price forecast horizon of 120 hours.meta.allowed_horizon_hours.summary_hours as well.Important: source.price.day_ahead_entries and source.price.forecast_entries count slots, not hours. If day-ahead arrives in quarter-hour slots, values such as 97 or 132 can be perfectly plausible. A forecast_entries value of 0 is also possible when the requested horizon is already fully covered by published day-ahead slots.
Quick start for copy-paste
- Install the HTTP Binding and JSONPATH in openHAB.
- Create a file named
strompreisvorhersage.thingsand paste in the Thing block below. - Create a file named
strompreisvorhersage.itemsand paste in the Item block below. - Save the files and reload openHAB. After that, the Items should have values.
country=de. For Denmark, always use dk1 or dk2.Thing file for openHAB
This variant runs without an API key and refreshes the data every 15 minutes.
Thing http:url:strompreisvorhersage "StrompreisVorhersage" [
baseURL="https://api.energypriceforecast.eu/api/v1/openhab/summary?country=de&hours=48&window_hours=4",
refresh=900
] {
Channels:
Type number : currentPrice "Current price" [ stateTransformation="JSONPATH($.flat.current_price)" ]
Type number : currentCo2 "Current CO2 intensity" [ stateTransformation="JSONPATH($.flat.current_co2_g_kwh)" ]
Type string : cheapestWindowStart "Cheapest window start" [ stateTransformation="JSONPATH($.flat.cheapest_window_start)" ]
Type string : greenestWindowStart "Greenest window start" [ stateTransformation="JSONPATH($.flat.greenest_window_start)" ]
Type string : isCheapestWindowNow "Best price window active now" [ stateTransformation="JSONPATH($.flat.is_cheapest_window_now)" ]
Type number : cheapestWindowRemainingMinutes "Best price window remaining minutes" [ stateTransformation="JSONPATH($.flat.cheapest_window_remaining_minutes)" ]
Type string : nextFullCheapestWindowStart "Next full price window" [ stateTransformation="JSONPATH($.price.next_full_window.start)" ]
}
If you want another market, usually only the country parameter in the URL changes.
Optional with your own API key
For higher limits or later product tiers, you can add a Bearer token to the same request. In openHAB, that can be done directly via the header of the HTTP Thing.
Thing http:url:strompreisvorhersage "StrompreisVorhersage" [
baseURL="https://api.energypriceforecast.eu/api/v1/openhab/summary?country=de&hours=72&window_hours=4",
refresh=900,
headers="Authorization=Bearer YOUR_API_KEY"
] {
Channels:
Type number : currentPrice "Current price" [ stateTransformation="JSONPATH($.flat.current_price)" ]
Type number : currentCo2 "Current CO2 intensity" [ stateTransformation="JSONPATH($.flat.current_co2_g_kwh)" ]
Type string : apiKeyState "API key state" [ stateTransformation="JSONPATH($.meta.api_key_state)" ]
Type number : allowedHorizon "Allowed horizon" [ stateTransformation="JSONPATH($.meta.allowed_horizon_hours)" ]
Type number : usedCallsToday "Used calls today" [ stateTransformation="JSONPATH($.meta.used_calls_today)" ]
}
If you do not have your own key, simply leave out the header. Basic usage still works without a key.
Item file for openHAB
These Items bind the most important channels directly.
Number Strompreis_Aktuell "Current price [%.4f EUR/kWh]" { channel="http:url:strompreisvorhersage:currentPrice" }
Number Strompreis_CO2 "Current CO2 intensity [%.1f gCO2/kWh]" { channel="http:url:strompreisvorhersage:currentCo2" }
String Strompreis_Guenstigstes_Fenster_Start "Cheapest window start [%s]" { channel="http:url:strompreisvorhersage:cheapestWindowStart" }
String Strompreis_Gruenstes_Fenster_Start "Greenest window start [%s]" { channel="http:url:strompreisvorhersage:greenestWindowStart" }
String Strompreis_Bestes_Fenster_Jetzt "Best price window active now [%s]" { channel="http:url:strompreisvorhersage:isCheapestWindowNow" }
Number Strompreis_Bestes_Fenster_Restminuten "Best price window remaining [%.0f min]" { channel="http:url:strompreisvorhersage:cheapestWindowRemainingMinutes" }
String Strompreis_Naechstes_Vollfenster_Start "Next full price window [%s]" { channel="http:url:strompreisvorhersage:nextFullCheapestWindowStart" }
If you also use the meta channels from the API-key example, you can add matching Number or String Items for them as well.
For automations: do not wait only for future start times
For display purposes, cheapest_window_start can be enough. For automations, however, it is usually more important to know whether the mathematically best window is already active. That is exactly what flat.is_cheapest_window_now is for. If that value is true, you do not need to trigger on a future start time.
rule "Allow load in best price window"
when
Time cron "0 */5 * * * ?"
then
if (Strompreis_Bestes_Fenster_Jetzt.state.toString == "true") {
// turn device on or set release flag
}
end
Pragmatic rule: price.next_full_window.start is good for planning. flat.is_cheapest_window_now is better for the actual runtime decision.
Meta fields worth knowing
| Field | Meaning | Typical use |
|---|---|---|
meta.api_key_state | missing, valid, inactive or another error state. | See quickly whether a configured key is actually being applied. |
meta.allowed_horizon_hours | The server-side maximum horizon allowed for this access. | Check whether your plan or key unlocks more than 48 hours. |
meta.used_horizon_hours | The horizon actually used for the response. | Detect when a request was shortened server-side. |
flat.is_cheapest_window_now | true when the best price window is already active. | Clean automation condition instead of waiting only for a start time. |
flat.cheapest_window_remaining_minutes | Remaining runtime of the currently best price window. | Let a device run only as long as the window is still active. |
price.best_window | Best price window in the horizon, even if it is already active. | Main source for automation logic. |
price.next_full_window | Next complete price window that starts in the future. | Planning and visualization. |
meta.rate_limit_daily | Daily limit for this access. | Clean monitoring per integration or customer. |
meta.used_calls_today | How many requests the key has already used today. | Makes support and limits understandable. |
meta.features | Which response capabilities were actually delivered in this response. | Debugging if you switch between summary and other data styles. |
Caching and error cases
How often should openHAB poll?
A 15-minute interval is a sensible starting point. The summary is not a second-by-second feed. Shorter polling intervals usually only increase load without helping much in practice.
What does 401 mean?
The API key is missing, wrong or deactivated. Open the URL in a browser or test it with a tool such as curl and check the Authorization header.
What does 403 mean?
Access is recognized in principle, but not allowed for that route, market or contract state. That is not a typo but a server-side permission decision.
What does 429 mean?
The daily limit for this access has been reached. That is exactly why meta.rate_limit_daily and meta.used_calls_today are useful.
Small test phase
There is currently a small test phase for the new openHAB integration. The main thing we are looking for is feedback from real installations: is the copy-paste guide clear enough, do the JSONPATH fields resolve cleanly, and does the API behaviour feel plausible in daily use?
If you actively use openHAB and want to test it, send a short note with your setup and market to StrompreisVorhersage@proton.me. The first tests are still handled personally on purpose.
Related: Home Assistant, ioBroker and Node-RED.