Hello,
I have been eager to get real time information on Danish electricity prices into Openhab for potential automation - inspired by this Rest-API setup in openhab. In Denmark it is possible to create an account into https://watts.dk/ for example and use their app to see both real time electricity prices (for your concrete electricity meter) as well as 3 days delayed usage statistics. This is nice if you can remember to check if you should start the washing machine now or set it for 3 hours later but letâs face it⌠who can remember such simple things. Wouldnât it be better to sink some hours into automation and never check again?
Hang in there - this will be long.
What WILL we do?
- Get real time data for the electricity prices - valid for the Flex plans â this will come from energidataservice.dk
- fetch all applicable charges and fees (distribution and state) for YOUR specific meter - this will come from eloverblik.dk
- add VAT to all values (25% in Denmark)
- compute total current running cost of electricity in Danish kroner (DKK) per kWh
- show all of the above nicely in an Openhab sitemap/android app
What we WILL NOT do (but i will try to create later on and would appreciate co-conspirators!)
- use the values for any automation (schedule the washing machine like here for example - Dishwasher price calculation automation)
- fetch usage data (display a dynamic usage chart like here: GitHub - JonasPed/homeassistant-eloverblik: Home Assistant Custom Component showing data from eloverblik.dk. I think however pulling this in Grafana and web-embedding in Openhab might be easierâŚprobably better looking)
- plot anything (a projection of future prices and/or usage data either live from sensor or delayed from energidataservice.dk)
As i started without knowing much about the electricity market in Denmark i figure a recap of my learning will give a good context of why things are structured the way they are:
- in Denmark (and many other EU countries) there is a law that all electricity, gas and other data is public (as annonimized averages)
- monster databases exist showing real time and historical data of electricity generation/consumption/prices, gas storage/consumption etc. - this is at https://www.energidataservice.dk/
- all information shown here is available freely at https://www.energidataservice.dk/ yet some is pulled from https://www.eloverblik.dk where a log in is required - why? because https://www.eloverblik.dk has all charges filtered by validity and because my plan was to pull usage data as well
- https://www.eloverblik.dk itself is an electricity self-service portal where your own electricity meter is accessible behind a log in page - that is not public obviously.
- in Denmark there are three main things that contribute to the total cost of electricity - state transportation taxes (country level - you pay to the government), local transportation taxes (municipality - you pay to the local electricity distribution company - N1 in my case) and of course actual electricity cost (you pay to the people who buy the electricity from the common exchange and deliver to you and make up the final bill for all parties - Norlys in my case). All these can be fetched from https://www.energidataservice.dk/ if you know exactly what to look for. See this video (in Danish) for explanation - Hvordan er din elregning skruet sammen? - ForstĂĽ din elregning her
- you need to log in to https://www.eloverblik.dk and register your electricity meter and register an API refresh token - see this guide: https://energinet.dk/media/gmgpcgfm/eloverblik-tredjeparters-adgang-til-kunders-data-via-api-kald.pdf
- at the end of this preparation step you should have: refresh token (a very long string), the metering point of your electricity meter (18 digits long number, which we will store as string because thatâs how we will use it in the REST API) - both from https://www.eloverblik.dk
Ok letâs finally begin â Items. Everything is under single equipment group. The first two items hold the two fixed values - refresh token and metering point - everything else i dynamically pulled. GLN numbers are the IDs of who gets your money. They can be used to fetch the same data from https://www.energidataservice.dk/
eloverblik.items
Group geEloverblikAPI "Eloverblik API" <energy> (Apt_Facility) ["Equipment"]
// Basic inputs - states updated on Openhab start and whenever NULL for whatever reason
String Eloverblik_metering_point "Metering Point [%s]" <settings> (geEloverblikAPI) ["Status"]
String Eloverblik_refresh_token "Refresh token [%s]" <settings> (geEloverblikAPI) ["Status"]
// Populated by get_eloverblik_access_token.script on openhab start up and every 12 hours after that
String Eloverblik_access_token "Access Token [%s]" <settings> (geEloverblikAPI) ["Status"]
// Updated by get_eloverblik_charges.script on openhab start up and every day at midnight after that
// Fees
// this section is empty on purpose.
// Subscribtions
Number Eloverblik_subscription_price "Subscription price [%.3 DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_subscription_price_discount "Subscription price discount [%.3f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
String Eloverblik_subscription_gln_number "Subscription GLN Number [%s]" <suitcase> (geEloverblikAPI) ["Status"]
String Eloverblik_subscription_name "Subscription name [%s]" <suitcase> (geEloverblikAPI) ["Status"]
String Eloverblik_subscription_description "Subscription description [%s]" <suitcase> (geEloverblikAPI) ["Status"]
// Tariffs
// Nettarif C
Number Eloverblik_nettarif_c_price_0_1 "Nettarif C price 0_1 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_1_2 "Nettarif C price 1_2 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_2_3 "Nettarif C price 2_3 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_3_4 "Nettarif C price 3_4 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_4_5 "Nettarif C price 4_5 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_5_6 "Nettarif C price 5_6 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_6_7 "Nettarif C price 6_7 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_7_8 "Nettarif C price 7_8 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_8_9 "Nettarif C price 8_9 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_9_10 "Nettarif C price 9_10 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_10_11 "Nettarif C price 10_11 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_11_12 "Nettarif C price 11_12 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_12_13 "Nettarif C price 12_13 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_13_14 "Nettarif C price 13_14 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_14_15 "Nettarif C price 14_15 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_15_16 "Nettarif C price 15_16 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_16_17 "Nettarif C price 16_17 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_17_18 "Nettarif C price 17_18 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_18_19 "Nettarif C price 18_19 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_19_20 "Nettarif C price 19_20 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_20_21 "Nettarif C price 20_21 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_21_22 "Nettarif C price 21_22 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_22_23 "Nettarif C price 22_23 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_23_24 "Nettarif C price 23_24 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
String Eloverblik_nettarif_c_gln_number "Nettarif C GLN Number [%s]" <suitcase> (geEloverblikAPI) ["Status"]
// Nettarif C discount
Number Eloverblik_nettarif_c_price_0_1_disc "Nettarif C discount price 0_1 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_1_2_disc "Nettarif C discount price 1_2 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_2_3_disc "Nettarif C discount price 2_3 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_3_4_disc "Nettarif C discount price 3_4 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_4_5_disc "Nettarif C discount price 4_5 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_5_6_disc "Nettarif C discount price 5_6 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_6_7_disc "Nettarif C discount price 6_7 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_7_8_disc "Nettarif C discount price 7_8 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_8_9_disc "Nettarif C discount price 8_9 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_9_10_disc "Nettarif C discount price 9_10 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_10_11_disc "Nettarif C discount price 10_11 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_11_12_disc "Nettarif C discount price 11_12 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_12_13_disc "Nettarif C discount price 12_13 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_13_14_disc "Nettarif C discount price 13_14 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_14_15_disc "Nettarif C discount price 14_15 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_15_16_disc "Nettarif C discount price 15_16 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_16_17_disc "Nettarif C discount price 16_17 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_17_18_disc "Nettarif C discount price 17_18 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_18_19_disc "Nettarif C discount price 18_19 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_19_20_disc "Nettarif C discount price 19_20 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_20_21_disc "Nettarif C discount price 20_21 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_21_22_disc "Nettarif C discount price 21_22 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_22_23_disc "Nettarif C discount price 22_23 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_nettarif_c_price_23_24_disc "Nettarif C discount price 23_24 [%.6f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
// Transmissions nettarif
Number Eloverblik_nettarif_price "Nettarif price [%.3f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
String Eloverblik_nettarif_gln_number "Nettarif GLN Number [%s]" <suitcase> (geEloverblikAPI) ["Status"]
// Systemtarif
Number Eloverblik_systemtarif_price "Systemtarif price [%.3f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
String Eloverblik_systemtarif_gln_number "Systemtarif GLN Number [%s]" <suitcase> (geEloverblikAPI) ["Status"]
//Elafgift
Number Eloverblik_elafgift_price "Elafgift price [%.3f DKK]" <piggybank> (geEloverblikAPI) ["Status"]
String Eloverblik_elafgift_gln_number "Elafgift GLN Number [%s]" <suitcase> (geEloverblikAPI) ["Status"]
// Updated by update_electricity_items.script on openhab start up and every hour after that
// Totals
DateTime Eloverblik_last_check "Last Check [%1$tR on %1$ta, %1$tb %1$td %1$tY]" <time> (geEloverblikAPI) ["Timestamp"]
Number Eloverblik_total_transport "Transport [%.2f DKK/kWh]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_total_taxes "Taxes [%.2f DKK/kWh]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_total_electricity "Electricity [%.2f DKK/kWh]" <piggybank> (geEloverblikAPI) ["Status"]
Number Eloverblik_total_cost "Total Cost [%.2f DKK/kWh]" <piggybank> (geEloverblikAPI) ["Status"]
With the items such defined we can proceed to the base rules using them.
eloverblik.rules
val refresh_token = "a stupidly long refresh token string goes here - you got that by making it for a third party API app in https://www.eloverblik.dk/"
val metering_point = "your 18 digit long metering point from https://www.eloverblik.dk/ goes here "
rule "Update Electricity Items"
when
Time cron "0 0 * * * ? *" // once an hour
then
if (Eloverblik_refresh_token.state==NULL) {
postUpdate(Eloverblik_refresh_token, refresh_token)
callScript("get_eloverblik_access_token")
}
if (Eloverblik_metering_point.state==NULL) {
postUpdate(Eloverblik_metering_point, metering_point)
callScript("get_eloverblik_charges")
}
callScript("update_electricity_items")
end
rule "Eloverblik initialization"
when
System started
then
// First update the items with proper state values
postUpdate(Eloverblik_refresh_token, refresh_token)
postUpdate(Eloverblik_metering_point, metering_point)
// Then update the access token
callScript("get_eloverblik_access_token")
// Then update the charges
callScript("get_eloverblik_charges")
// Then pull the current spot electricity prices
callScript("update_electricity_items")
end
rule "Update Eloverblik access token"
when
Time cron "0 0 0/12 * * ? *" // every 12 hours at 0 and 12 oclock
then
if (Eloverblik_refresh_token.state==NULL) postUpdate(Eloverblik_refresh_token, refresh_token)
callScript("get_eloverblik_access_token")
end
rule "Update Eloverblik charges"
when
Time cron "0 0 0 * * ? *" // once a day at midnight
then
if (Eloverblik_metering_point.state==NULL) postUpdate(Eloverblik_metering_point, metering_point)
callScript("get_eloverblik_charges")
end
Then come the scripts:
get_eloverblik_access_token.script:
val headers = newHashMap("Authorization" -> "Bearer " + Eloverblik_refresh_token.state.toString,
"Accept" -> "application/json")
var result = sendHttpGetRequest("https://api.eloverblik.dk/CustomerApi/api/Token", headers, 3000)
postUpdate(Eloverblik_access_token, transform("JSONPATH", "$.result", result))
get_eloverblik_charges.script
val headers = newHashMap("Authorization" -> "Bearer " + Eloverblik_access_token.state,
"Accept" -> "application/json",
"WWW-Authenticate" -> "Basic")
val body = '{"meteringPoints": {"meteringPoint": ["' + Eloverblik_metering_point.state.toString + '"]}}'
val contentType = "application/json"
// sendHttpPostRequest(String url, String contentType, String content, Map<String, String> headers, int timeout)
var result = sendHttpPostRequest("https://api.eloverblik.dk/CustomerApi/api/meteringpoints/meteringpoint/getcharges",
contentType, body, headers, 3000)
// Subscriptions updates
postUpdate(Eloverblik_subscription_price, transform("JSONPATH", ".result[0].result.subscriptions[0].price", result))
postUpdate(Eloverblik_subscription_price_discount, transform("JSONPATH", ".result[0].result.subscriptions[1].price", result))
postUpdate(Eloverblik_subscription_gln_number, transform("JSONPATH", ".result[0].result.subscriptions[0].owner", result))
postUpdate(Eloverblik_subscription_name, transform("JSONPATH", ".result[0].result.subscriptions[0].name", result))
postUpdate(Eloverblik_subscription_description, transform("JSONPATH", ".result[0].result.subscriptions[0].description", result))
// Tariffs updates
// Nettarif C
postUpdate(Eloverblik_nettarif_c_price_0_1, transform("JSONPATH", ".result[0].result.tariffs[0].prices[0].price", result))
postUpdate(Eloverblik_nettarif_c_price_1_2, transform("JSONPATH", ".result[0].result.tariffs[0].prices[1].price", result))
postUpdate(Eloverblik_nettarif_c_price_2_3, transform("JSONPATH", ".result[0].result.tariffs[0].prices[2].price", result))
postUpdate(Eloverblik_nettarif_c_price_3_4, transform("JSONPATH", ".result[0].result.tariffs[0].prices[3].price", result))
postUpdate(Eloverblik_nettarif_c_price_4_5, transform("JSONPATH", ".result[0].result.tariffs[0].prices[4].price", result))
postUpdate(Eloverblik_nettarif_c_price_5_6, transform("JSONPATH", ".result[0].result.tariffs[0].prices[5].price", result))
postUpdate(Eloverblik_nettarif_c_price_6_7, transform("JSONPATH", ".result[0].result.tariffs[0].prices[6].price", result))
postUpdate(Eloverblik_nettarif_c_price_7_8, transform("JSONPATH", ".result[0].result.tariffs[0].prices[7].price", result))
postUpdate(Eloverblik_nettarif_c_price_8_9, transform("JSONPATH", ".result[0].result.tariffs[0].prices[8].price", result))
postUpdate(Eloverblik_nettarif_c_price_9_10, transform("JSONPATH", ".result[0].result.tariffs[0].prices[9].price", result))
postUpdate(Eloverblik_nettarif_c_price_10_11, transform("JSONPATH", ".result[0].result.tariffs[0].prices[10].price", result))
postUpdate(Eloverblik_nettarif_c_price_11_12, transform("JSONPATH", ".result[0].result.tariffs[0].prices[11].price", result))
postUpdate(Eloverblik_nettarif_c_price_12_13, transform("JSONPATH", ".result[0].result.tariffs[0].prices[12].price", result))
postUpdate(Eloverblik_nettarif_c_price_13_14, transform("JSONPATH", ".result[0].result.tariffs[0].prices[13].price", result))
postUpdate(Eloverblik_nettarif_c_price_14_15, transform("JSONPATH", ".result[0].result.tariffs[0].prices[14].price", result))
postUpdate(Eloverblik_nettarif_c_price_15_16, transform("JSONPATH", ".result[0].result.tariffs[0].prices[15].price", result))
postUpdate(Eloverblik_nettarif_c_price_16_17, transform("JSONPATH", ".result[0].result.tariffs[0].prices[16].price", result))
postUpdate(Eloverblik_nettarif_c_price_17_18, transform("JSONPATH", ".result[0].result.tariffs[0].prices[17].price", result))
postUpdate(Eloverblik_nettarif_c_price_18_19, transform("JSONPATH", ".result[0].result.tariffs[0].prices[18].price", result))
postUpdate(Eloverblik_nettarif_c_price_19_20, transform("JSONPATH", ".result[0].result.tariffs[0].prices[19].price", result))
postUpdate(Eloverblik_nettarif_c_price_20_21, transform("JSONPATH", ".result[0].result.tariffs[0].prices[20].price", result))
postUpdate(Eloverblik_nettarif_c_price_21_22, transform("JSONPATH", ".result[0].result.tariffs[0].prices[21].price", result))
postUpdate(Eloverblik_nettarif_c_price_22_23, transform("JSONPATH", ".result[0].result.tariffs[0].prices[22].price", result))
postUpdate(Eloverblik_nettarif_c_price_23_24, transform("JSONPATH", ".result[0].result.tariffs[0].prices[23].price", result))
postUpdate(Eloverblik_nettarif_c_gln_number, transform("JSONPATH", ".result[0].result.tariffs[0].owner", result))
// Nettarif C discount
postUpdate(Eloverblik_nettarif_c_price_0_1_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[0].price", result))
postUpdate(Eloverblik_nettarif_c_price_1_2_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[1].price", result))
postUpdate(Eloverblik_nettarif_c_price_2_3_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[2].price", result))
postUpdate(Eloverblik_nettarif_c_price_3_4_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[3].price", result))
postUpdate(Eloverblik_nettarif_c_price_4_5_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[4].price", result))
postUpdate(Eloverblik_nettarif_c_price_5_6_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[5].price", result))
postUpdate(Eloverblik_nettarif_c_price_6_7_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[6].price", result))
postUpdate(Eloverblik_nettarif_c_price_7_8_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[7].price", result))
postUpdate(Eloverblik_nettarif_c_price_8_9_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[8].price", result))
postUpdate(Eloverblik_nettarif_c_price_9_10_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[9].price", result))
postUpdate(Eloverblik_nettarif_c_price_10_11_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[10].price", result))
postUpdate(Eloverblik_nettarif_c_price_11_12_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[11].price", result))
postUpdate(Eloverblik_nettarif_c_price_12_13_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[12].price", result))
postUpdate(Eloverblik_nettarif_c_price_13_14_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[13].price", result))
postUpdate(Eloverblik_nettarif_c_price_14_15_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[14].price", result))
postUpdate(Eloverblik_nettarif_c_price_15_16_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[15].price", result))
postUpdate(Eloverblik_nettarif_c_price_16_17_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[16].price", result))
postUpdate(Eloverblik_nettarif_c_price_17_18_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[17].price", result))
postUpdate(Eloverblik_nettarif_c_price_18_19_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[18].price", result))
postUpdate(Eloverblik_nettarif_c_price_19_20_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[19].price", result))
postUpdate(Eloverblik_nettarif_c_price_20_21_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[20].price", result))
postUpdate(Eloverblik_nettarif_c_price_21_22_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[21].price", result))
postUpdate(Eloverblik_nettarif_c_price_22_23_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[22].price", result))
postUpdate(Eloverblik_nettarif_c_price_23_24_disc, transform("JSONPATH", ".result[0].result.tariffs[1].prices[23].price", result))
// Transmissions nettarif
postUpdate(Eloverblik_nettarif_price, transform("JSONPATH", ".result[0].result.tariffs[2].prices[0].price", result))
postUpdate(Eloverblik_nettarif_gln_number, transform("JSONPATH", ".result[0].result.tariffs[2].owner", result))
// Systemtarif
postUpdate(Eloverblik_systemtarif_price, transform("JSONPATH", ".result[0].result.tariffs[3].prices[0].price", result))
postUpdate(Eloverblik_systemtarif_gln_number, transform("JSONPATH", ".result[0].result.tariffs[3].owner", result))
// Elafgift
postUpdate(Eloverblik_elafgift_price, transform("JSONPATH", ".result[0].result.tariffs[4].prices[0].price", result))
postUpdate(Eloverblik_elafgift_gln_number, transform("JSONPATH", ".result[0].result.tariffs[4].owner", result))
update_electricity_items.script â in the url for the API call below I use DK1 for west of Denmark - change to DK2 for CPH and east of Denmark.
// import org.openhab.core.model.script.ScriptServiceUtil
// Updating meta Items
val vat = 0.25
val ZonedDateTime currentJavaLocalDateTime = now
val current_time_transport = org.openhab.core.model.script.ScriptServiceUtil.getItemRegistry.getItem("Eloverblik_nettarif_c_price_" + currentJavaLocalDateTime.getHour().toString + "_" + (currentJavaLocalDateTime.getHour() + 1).toString)
val current_time_transport_disc = org.openhab.core.model.script.ScriptServiceUtil.getItemRegistry.getItem("Eloverblik_nettarif_c_price_" + currentJavaLocalDateTime.getHour().toString + "_" + (currentJavaLocalDateTime.getHour() + 1).toString + "_disc")
val transport = current_time_transport.state as Number
val transport_disc = current_time_transport_disc.state as Number
val nettarif = Eloverblik_nettarif_price.state as Number
val systemtarif = Eloverblik_systemtarif_price.state as Number
val elafgift = Eloverblik_elafgift_price.state as Number
val headers = newHashMap("accept" -> "*/*")
var result = sendHttpGetRequest("https://api.energidataservice.dk/dataset/Elspotprices?start=now-PT1h&filter=%7B%22PriceArea%22%3A%20%22DK1%22%7D&sort=HourDK", headers, 3000)
var electricity_str = transform("JSONPATH", ".records[0].SpotPriceDKK", result)
var float electricity = Float::parseFloat(String::format("%s",electricity_str).replace(' ',''))
var total_transport = (transport + transport_disc) + (transport + transport_disc) * vat
var total_taxes = (nettarif + systemtarif + elafgift) + (nettarif + systemtarif + elafgift) * vat
var electricity_per_kWh = (electricity / 1000) + (electricity / 1000) * vat
postUpdate(Eloverblik_total_transport, total_transport)
postUpdate(Eloverblik_total_taxes, total_taxes)
postUpdate(Eloverblik_total_electricity, electricity_per_kWh)
postUpdate(Eloverblik_total_cost, (total_transport + total_taxes + electricity_per_kWh))
postUpdate(Eloverblik_last_check, DateTimeType.valueOf(currentJavaLocalDateTime.toLocalDateTime().toString()))
And finally the sitemap:
Group item=Eloverblik_total_cost icon="energy" {
Frame label="Electricity Costs" icon="energy" {
Text item=Eloverblik_total_cost
Text item=Eloverblik_total_electricity
Text item=Eloverblik_total_transport
Text item=Eloverblik_total_taxes
Text item=Eloverblik_last_check label="Last Update [%1$tR on %1$ta, %1$tb %1$td %1$tY]"
}
With an end result:
Random thoughts and questions to the experts in case anyone makes this far downâŚ:
- when working with offline Openhab instance you need the following IPs to be allowed through the firewall: 40.118.61.157 for energidataservice.dk and 13.107.238.44 for eloverblik.dk
- i struggled with the thought of dumping stuff into persistnace but it felt wastefull to pull form the internet only to store locally⌠But how to plot if not from store? Perhaps Grafana i best with JSON data source? Ideas?
- why does import org.openhab.core.model.script.ScriptServiceUtil work in rules but not in scripts?
- why does running the same val ZonedDateTime currentJavaLocalDateTime = now seems to be 1 hours offset between being run in rules vs script? It seems the script does not get the timezone +1 for DK and uses UTCâŚ