Language

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.

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.

Step 1As soon as official day-ahead is available for a slot, that value is preferred.
Step 2Forecast is used only for future slots not yet covered by already available day-ahead data.
Why this mattersThe API therefore combines real day-ahead prices with forecast values only for the still-open part of the horizon.
The pragmatic path

You do not need a special add-on. For the first step, the HTTP Binding together with the JSONPATH transformation is enough in openHAB.

What must be installed first

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=4
Priceflat.current_price, flat.is_cheapest_window_now and price.next_full_window for robust rules.
CO2flat.current_co2_g_kwh, flat.is_greenest_window_now and co2.best_window.
Metameta.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=15m
summaryBeginner path with current price, CO2 and already computed windows.
pricesRaw price series for your own logic, charts and custom rules.
Important honestyClassic HTTP Binding plus JSONPATH is usually the better start for 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
flatThe 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.
priceCurrent price slot plus best_window and next_full_window as structured objects.More context for rules and visualization.
co2Current CO2 value plus best_window and next_full_window for CO2.For ecologically oriented logic.
combinedA combined price/CO2 window.Useful if you do not want to create your own weighting.
sourceMetadata that shows whether price values come from day-ahead or forecast.Important for interpretation and debugging.
metaAccess 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=mixedDay-ahead first, forecast only for future hours not yet covered by official day-ahead data.Practical default.
mode=forecast_onlyForecast only, without day-ahead mixing.Comparison or intentionally forecast-centered logic.
price_mode=baseDefault mode with base or market prices.When the relative shape is enough for your automation.
price_mode=retailAssumption-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=10115Required for Germany in retail mode so regional grid-fee assumptions fit better.Mandatory for price_mode=retail in Germany.
resolution=15mContinuous quarter-hour series. Forecast hours are repeated across four quarter-hour slots.Charts and uniform slot logic.
resolution=nativeDay-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.
Important honestyRetail is not your exact bill amount. It is a modeled end price based on assumptions. In Germany, retail mode requires a postcode.

Horizon and resolution

The examples use hours=48 and window_hours=4. That is only a starting value, not the full technical ceiling.

Requested horizonWith 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.
Actually allowedWithout an API key, free access is currently limited server-side to 48 hours. With a key, more may be allowed, but more than 120 hours should not currently be treated as a reliable public promise. The authoritative field is always meta.allowed_horizon_hours.
Window searchThe best 4-hour window is searched within the next 24-hour horizon by default. If you want more, increase 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

  1. Install the HTTP Binding and JSONPATH in openHAB.
  2. Create a file named strompreisvorhersage.things and paste in the Thing block below.
  3. Create a file named strompreisvorhersage.items and paste in the Item block below.
  4. Save the files and reload openHAB. After that, the Items should have values.
Built for beginnersThe basic example deliberately uses only a few fields that are easy to understand in almost every setup.
What you usually changeUsually only country=de. For Denmark, always use dk1 or dk2.
What you get afterwardsCurrent price, current CO2 intensity, whether the best window is active now, and otherwise the next full start in the future.

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_statemissing, valid, inactive or another error state.See quickly whether a configured key is actually being applied.
meta.allowed_horizon_hoursThe server-side maximum horizon allowed for this access.Check whether your plan or key unlocks more than 48 hours.
meta.used_horizon_hoursThe horizon actually used for the response.Detect when a request was shortened server-side.
flat.is_cheapest_window_nowtrue when the best price window is already active.Clean automation condition instead of waiting only for a start time.
flat.cheapest_window_remaining_minutesRemaining runtime of the currently best price window.Let a device run only as long as the window is still active.
price.best_windowBest price window in the horizon, even if it is already active.Main source for automation logic.
price.next_full_windowNext complete price window that starts in the future.Planning and visualization.
meta.rate_limit_dailyDaily limit for this access.Clean monitoring per integration or customer.
meta.used_calls_todayHow many requests the key has already used today.Makes support and limits understandable.
meta.featuresWhich 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.