This page is part of archived documentation for openHAB 4.0. Go to the current stable version
# Energi Data Service Binding
This binding integrates electricity prices from the Danish Energi Data Service ("Open energy data from Energinet to society").
This can be used to plan energy consumption, for example to calculate the cheapest period for running a dishwasher or charging an EV.
# Supported Things
All channels are available for thing type service
.
# Thing Configuration
# service
Thing Configuration
Name | Type | Description | Default | Required |
---|---|---|---|---|
priceArea | text | Price area for spot prices (same as bidding zone) | yes | |
currencyCode | text | Currency code in which to obtain spot prices | DKK | no |
gridCompanyGLN | integer | Global Location Number of the Grid Company | no | |
energinetGLN | integer | Global Location Number of Energinet | 5790000432752 | no |
# Global Location Number of the Grid Company
The Global Location Number of your grid company can be selected from a built-in list of grid companies. To find the company in your area, you can go to Find netselskab (opens new window), enter your address, and the company will be shown.
If your company is not on the list, you can configure it manually. To obtain the Global Location Number of your grid company:
- Open a browser and go to Eloverblik (opens new window).
- Click "Private customers" and log in with MitID (confirmation will appear as Energinet).
- Click "Retrieve data" and select "Price data".
- Open the file and look for the rows having Price_type = "Subscription".
- In the columns Name and/or Description you should see the name of your grid company.
- In column Owner you can find the GLN ("Global Location Number").
- Most rows will have this Owner. If in doubt, try to look for rows not having 5790000432752 as owner.
# Channels
# Channel Group electricity
Channel | Type | Description | Advanced |
---|---|---|---|
spot-price | Number | Current spot price in DKK or EUR per kWh | no |
net-tariff | Number | Current net tariff in DKK per kWh. Only available when gridCompanyGLN is configured | no |
system-tariff | Number | Current system tariff in DKK per kWh | no |
electricity-tax | Number | Current electricity tax in DKK per kWh | no |
transmission-net-tariff | Number | Current transmission net tariff in DKK per kWh | no |
hourly-prices | String | JSON array with hourly prices from 24 hours ago and onward | yes |
Please note: There is no channel providing the total price.
Instead, create a group item with SUM
as aggregate function and add the individual price items as children.
This has the following advantages:
- Full customization possible: Freely choose the channels which should be included in the total.
- An additional item containing the kWh fee from your electricity supplier can be added also.
- Spot price can be configured in EUR while tariffs are in DKK.
# Value-Added Tax
VAT is not included in any of the prices.
To include VAT for items linked to the Number
channels, the VAT profile (opens new window) can be used.
This must be installed separately.
Once installed, simply select "Value-Added Tax" as Profile when linking an item.
# Net Tariff
Discounts are automatically taken into account for channel net-tariff
so that it represents the actual price.
The tariffs are downloaded using pre-configured filters for the different Grid Company GLN's.
If your company is not in the list, or the filters are not working, they can be manually overridden.
To override filters, the channel net-tariff
has the following configuration parameters:
Name | Type | Description | Default | Required | Advanced |
---|---|---|---|---|---|
chargeTypeCodes | text | Comma-separated list of charge type codes | no | yes | |
notes | text | Comma-separated list of notes | no | yes | |
start | text | Query start date parameter expressed as either YYYY-MM-DD or dynamically as one of StartOfDay , StartOfMonth or StartOfYear | no | yes | |
offset | text | Query start date offset expressed as an ISO 8601 duration | no | yes |
The parameters chargeTypeCodes
and notes
are logically combined with "AND", so if only one parameter is needed for the filter, only provide this parameter and leave the other one empty.
Using any of these parameters will override the pre-configured filter entirely.
The parameter start
can be used independently to override the query start date parameter.
If used while leaving chargeTypeCodes
and notes
empty, only the date will be overridden.
The parameter offset
can be used in combination with start
to provide an offset to a dynamic start date parameter, i.e. StartOfDay
, StartOfMonth
or StartOfYear
.
The needed amount of historic hours is automatically taken into consideration.
This parameter is ignored when start date is supplied as YYYY-MM-DD.
Determining the right filters can be tricky, so if in doubt ask in the community forum. See also Datahub Price List (opens new window).
# Filter Examples
N1:
Parameter | Value |
---|---|
chargeTypeCodes | CD,CD R |
notes |
Nord Energi Net:
Parameter | Value |
---|---|
chargeTypeCodes | TAC |
notes | Nettarif C |
start | StartOfDay |
offset | -P1D |
# Hourly Prices
The format of the hourly-prices
JSON array is as follows:
[
{
"hourStart": "2023-01-24T15:00:00Z",
"spotPrice": 1.67076001,
"spotPriceCurrency": "DKK",
"netTariff": 0.432225,
"systemTariff": 0.054000,
"electricityTax": 0.008000,
"transmissionNetTariff": 0.058000
},
{
"hourStart": "2023-01-24T16:00:00Z",
"spotPrice": 1.859880005,
"spotPriceCurrency": "DKK",
"netTariff": 1.05619,
"systemTariff": 0.054000,
"electricityTax": 0.008000,
"transmissionNetTariff": 0.058000
}
]
Future spot prices for the next day are usually available around 13:00 CET and are fetched around that time. Historic prices older than 24 hours are removed from the JSON array each hour.
# Thing Actions
Thing actions can be used to perform calculations as well as import prices directly into rules without deserializing JSON from the hourly-prices channel. This is more convenient, much faster, and provides automatic summation of the price elements of interest.
Actions use cached data for performing operations.
Since data is only fetched when an item is linked to a channel, there might not be any cached data available.
In this case the data will be fetched on demand and cached afterwards.
The first action triggered on a given day may therefore be a bit slower, and is also prone to failing if the server call fails for any reason.
This potential problem can be prevented by linking the individual channels to items, or by linking the hourly-prices
channel to an item.
# calculateCheapestPeriod
This action will determine the cheapest period for using energy. It comes in four variants with different input parameters.
The result is a Map
with the following keys:
Key | Type | Description |
---|---|---|
CheapestStart | Instant | Start time of cheapest calculated period |
LowestPrice | BigDecimal | The total price when starting at cheapest start |
MostExpensiveStart | Instant | Start time of most expensive calculated period |
HighestPrice | BigDecimal | The total price when starting at most expensive start |
# calculateCheapestPeriod
from Duration
Parameter | Type | Description |
---|---|---|
earliestStart | Instant | Earliest start time allowed |
latestEnd | Instant | Latest end time allowed |
duration | Duration | The duration to fit within the timeslot |
This is a convenience method that can be used when the power consumption is not known.
The calculation will assume linear consumption and will find the best timeslot based on that.
For this reason the resulting Map
will not contain the keys LowestPrice
and HighestPrice
.
Example:
var Map<String, Object> result = actions.calculateCheapestPeriod(now.toInstant(), now.plusHours(12).toInstant(), Duration.ofMinutes(90))
# calculateCheapestPeriod
from Duration and Power
Parameter | Type | Description |
---|---|---|
earliestStart | Instant | Earliest start time allowed |
latestEnd | Instant | Latest end time allowed |
duration | Duration | The duration to fit within the timeslot |
power | QuantityType<Power> | Linear power consumption |
This action is identical to the variant above, but with a known linear power consumption. As a result the price is also included in the result.
Example:
var Map<String, Object> result = actions.calculateCheapestPeriod(now.toInstant(), now.plusHours(12).toInstant(), Duration.ofMinutes(90), 250 | W)
# calculateCheapestPeriod
from Power Phases
Parameter | Type | Description |
---|---|---|
earliestStart | Instant | Earliest start time allowed |
latestEnd | Instant | Latest end time allowed |
durationPhases | List<Duration> | List of durations for the phases |
powerPhases | List<QuantityType<Power>> | List of power consumption for each corresponding phase |
This variant is similar to the one above, but is based on a supplied timetable.
The timetable is supplied as two individual parameters, durationPhases
and powerPhases
, which must have the same size.
This can be considered as different phases of using power, so each list member represents a period with a linear use of power.
durationPhases
should be a List populated by Duration
objects, while powerPhases
should be a List populated by QuantityType<Power>
objects for that duration of time.
Example:
val ArrayList<Duration> durationPhases = new ArrayList<Duration>()
durationPhases.add(Duration.ofMinutes(37))
durationPhases.add(Duration.ofMinutes(8))
durationPhases.add(Duration.ofMinutes(4))
durationPhases.add(Duration.ofMinutes(2))
durationPhases.add(Duration.ofMinutes(4))
durationPhases.add(Duration.ofMinutes(36))
durationPhases.add(Duration.ofMinutes(41))
durationPhases.add(Duration.ofMinutes(104))
val ArrayList<QuantityType<Power>> powerPhases = new ArrayList<QuantityType<Power>>()
powerPhases.add(162.162 | W)
powerPhases.add(750 | W)
powerPhases.add(1500 | W)
powerPhases.add(3000 | W)
powerPhases.add(1500 | W)
powerPhases.add(166.666 | W)
powerPhases.add(146.341 | W)
powerPhases.add(0 | W)
var Map<String, Object> result = actions.calculateCheapestPeriod(now.toInstant(), now.plusHours(12).toInstant(), durationPhases, powerPhases)
Please note that the total duration will be calculated automatically as a sum of provided duration phases.
Therefore, if the total duration is longer than the sum of phase durations, the remaining duration must be provided as last item with a corresponding 0 W power item.
This is to ensure that the full program will finish before the provided latestEnd
.
# calculateCheapestPeriod
from Energy per Phase
Parameter | Type | Description |
---|---|---|
earliestStart | Instant | Earliest start time allowed |
latestEnd | Instant | Latest end time allowed |
totalDuration | Duration | The total duration of all phases |
durationPhases | List<Duration> | List of durations for the phases |
energyUsedPerPhase | QuantityType<Energy> | Fixed amount of energy used per phase |
This variant will assign the provided amount of energy into each phase. The use case for this variant is a simplification of the previous variant. For example, a dishwasher may provide energy consumption in 0.1 kWh steps. In this case it's a simple task to create a timetable accordingly without having to calculate the average power consumption per phase. Since a last phase may use no significant energy, the total duration must be provided also.
Example:
val ArrayList<Duration> durationPhases = new ArrayList<Duration>()
durationPhases.add(Duration.ofMinutes(37))
durationPhases.add(Duration.ofMinutes(8))
durationPhases.add(Duration.ofMinutes(4))
durationPhases.add(Duration.ofMinutes(2))
durationPhases.add(Duration.ofMinutes(4))
durationPhases.add(Duration.ofMinutes(36))
durationPhases.add(Duration.ofMinutes(41))
// 0.7 kWh is used in total (number of phases × energy used per phase)
var Map<String, Object> result = actions.calculateCheapestPeriod(now.toInstant(), now.plusHours(12).toInstant(), Duration.ofMinutes(236), phases, 0.1 | kWh)
# calculatePrice
Parameter | Type | Description |
---|---|---|
start | Instant | Start time |
end | Instant | End time |
power | QuantityType<Power> | Linear power consumption |
Result: Price as BigDecimal
.
This action calculates the price for using given amount of power in the period from start
till end
.
Example:
var price = actions.calculatePrice(now.toInstant(), now.plusHours(4).toInstant, 200 | W)
# getPrices
Parameter | Type | Description |
---|---|---|
priceElements | String | Comma-separated list of price elements to include |
Result: Map<Instant, BigDecimal>
The parameter priceElements
is a case-insensitive comma-separated list of price elements to include in the returned hourly prices.
These elements can be requested:
Price element | Description |
---|---|
SpotPrice | Spot price |
NetTariff | Net tariff |
SystemTariff | System tariff |
ElectricityTax | Electricity tax |
TransmissionNetTariff | Transmission net tariff |
Using null
as parameter returns the total prices including all price elements.
Example:
var priceMap = actions.getPrices("SpotPrice,NetTariff");
# Full Example
# Thing Configuration
Thing energidataservice:service:energidataservice "Energi Data Service" [ priceArea="DK1", currencyCode="DKK", gridCompanyGLN="5790001089030" ] {
Channels:
Number : electricity#net-tariff [ chargeTypeCodes="CD,CD R", start="StartOfYear" ]
}
# Item Configuration
Group:Number:SUM TotalPrice "Current Total Price" <price>
Number SpotPrice "Current Spot Price" <price> (TotalPrice) { channel="energidataservice:service:energidataservice:electricity#spot-price" [profile="transform:VAT"] }
Number NetTariff "Current Net Tariff" <price> (TotalPrice) { channel="energidataservice:service:energidataservice:electricity#net-tariff" [profile="transform:VAT"] }
Number SystemTariff "Current System Tariff" <price> (TotalPrice) { channel="energidataservice:service:energidataservice:electricity#system-tariff" [profile="transform:VAT"] }
Number ElectricityTax "Current Electricity Tax" <price> (TotalPrice) { channel="energidataservice:service:energidataservice:electricity#electricity-tax" [profile="transform:VAT"] }
Number TransmissionNetTariff "Current Transmission Tariff" <price> (TotalPrice) { channel="energidataservice:service:energidataservice:electricity#transmission-net-tariff" [profile="transform:VAT"] }
String HourlyPrices "Hourly Prices" <price> { channel="energidataservice:service:energidataservice:electricity#hourly-prices" }
# Thing Actions Example
← ELRO Connects Enigma2 →