Bringing electricity information from eloverblik.dk and energidataservice.dk into Openhab

Thanks a lot, it works after removing the channels :slight_smile:

My use-cases are:

  1. To show hourly prices in a table like what https://elspotpris.dk shows. What is would be the best way to show those prices with hourly or 3-hourly intervals?
  2. To calculate when cheapest to charge the car, but I think the action calculateCheapestPeriod you have implemented works much better. In my current rules I have a nested for loop to go hour by hour to find our when to start charging, and it won’t work when the price is updated every 15mins.

Best regards

Notice the timestamps are Instant, based on print out looks like it’s in GMT time:

  1. How can I check if Instant is today in local time
  2. and how to get local hour HH (2 digits) from Instant

Edit: found the issue please ignore the original post.

Did you also solve the problem of iterating the Map? If you could post your solution here, it could possibly help others finding this topic - and I might also be able to use it for improving the documentation.

EDIT: Okay, I just tested iterating - previously I only did key lookups in my rules:

val actions = getActions("energidataservice", "energidataservice:service:energidataservice");
var priceMap = actions.getPrices(null)
priceMap.forEach[ key, value | logInfo(key.toString, value.toString) ]

Hi, thanks for the reply!
The error message was misleading, it initially look like array out of bound. But it was because I only have one parameter when I logInfo, so iteration works perfectly fine. I’m now struggling to find out how to handle Instant, so far I have the following code (which is ugly I know), I will keep updating it:

    val actions = getActions("energidataservice", "energidataservice:service:energidataservice")
    var priceMap = actions.getPrices(null)
    var hourStart = now.toInstant().truncatedTo(ChronoUnit.HOURS)
    var String currentDate = new DateTimeType().format("%1$tY-%1$tm-%1$td")
    priceMap.forEach[ key, value | 
        logInfo("TEST", key.toString)
        var LocalDateTime ldt = LocalDateTime.ofInstant(key, ZoneOffset.systemDefault())
        var DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        var DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("HH");
        var String date = ldt.format(dateFormatter)
        var String hour = ldt.format(hourFormatter)
        if (hour.length < 2){
            hour = "0" + hour
        }
       var String itemName = "ElectricityPriceAt" + hour
        if(date != currentDate) {
  			gEnergiDataServiceTomorrow.members.findFirst[name.equals(itemName+"Tomorrow")].postUpdate(value)
        }
        else {
            gEnergiDataServiceToday.members.findFirst[name.equals(itemName+"Today")].postUpdate(value)
        }
    ]

The idea is to find the item called ElectricityPriceAtHHToday/Tomorrow and update with the value of the map

1 Like
  1. What kind of heating system is this Nilan device you’re planning to control? I have a Nibe F-1226 ground source heat pump which is NOT a so called inverter pump like most modern heat pumps are.

In other words, my heat pump is a traditional on/off pump whereas modern inverter pumps adjust the speed instead of toggling the compressor on/off.

There are different opinions/schools in the heat pump forums. One quite popular opinion related to on/off pumps is that trying to minimize the nimber of compressor starts will make it last longer. In other words, longer consequtive heating periods is preferred over many short periods.

  1. Regarding the ventilation: I don’t recommend you to interfere with this. The benefit of that is not worth it in my opinion compared to the downsides (decreased quality of the air, messed up humidity etc).

Cheers,
Markus

P.s. you might want to open a separate thread for heat pump control strategies, since that is easily a topic of its own. You can ping me there and I’ll be happy to share what I’ve learnt about heat pumps.

Looks good. :+1:

I’m wondering now if you need more history to fill out all hours for Today? Currently I populate prices only 12 hours back in time, but that’s an arbitrary number I selected just to have some kind of restriction/boundary. My own use-case for keeping historic prices at all is to be able to show the total price when the tumble dryer has finished: Dishwasher price calculation automation - #5 by laursen

My rule triggers when HourlyPrice changes, so I think it will catch the older prices if it updates frequently. How often does it update (or what event triggers an update)?
I’m trying to add VAT to my items with format already, the following doesn’t seem to work, I guess I misunderstand how to use it, any suggestion?

Number    ElectricityPriceAt01Today       "Price Today at 01:00 [VAT(25):%.2f kr]"       (gEnergiDataServiceToday)

It’s currently not possible to do that for future prices, only historic prices which are persisted hour by hour. That’s one of the things I expect to be solved by the mentioned core pull request 3597.

That should be possible with calculateCheapestPeriod, although I’d be interested to know if it fully covers your case. You probably know how much you want to charge it and either the charge speed or perhaps even the duration needed? Depending on the information you have available to making the decision, we might find some calculation methods missing.

Btw, I consider the calculations within the binding temporary as they don’t really belong there. Still, for the time being they are better to have there than scattered even more in user rules etc. End goal:

1 Like

Thank you for your reply!

I’m actually not sure what type of heat pump it is - it’s Nilan Compact P Geo 6. I asked the support today and they only suggest to pause the heating and hot water when on vacation for days. They told me if the heat pump is only off for some hours, it might take more energy to restore to the original temperature.

I will never turn off ventilation - as I understand it can cause serious damage especially during winter time when condensation can form inside the pipe which will cause fungus and other problems.

My current consumption is around 10 kWh during summer and 30kWh during winter per day. So maybe not much to save there. Today I tried to turn off hot water production, since we only have 180L tank now the temp drops to 18 degree and I have to enable electrical heater (1500w).

Yes, that should be sufficient then if your items are persisted. If not, you will lack some of the hours after a restart.

As rarely as possible. :slight_smile: Spot prices will be fetched around 13:00 each day. Tariffs etc. are fetched upon expiration, i.e. the binding will make sure to always have tomorrow cached as well.

FYI, the documentation is here: VAT - Transformation Services | openHAB

Just checking, have you installed the VAT transformation service?

There could be some issue when the date rolls - I need to find a smart way to remove prices from all items tomorrow I guess. The best way to do it is to remove all prices first and add them back based on the new date/getPrices, however it will give issue if there are only 12 hours history. Also if HourlyPrice is only updated once at 13:00 per day, I might miss an hour price at 00:00 (midnight). It would be nice to include all hours for “today” I think - it’s better than going back 12/24 hours as in that case the date can be yesterday.

Yes the VAT transformer is installed and working correctly for other items like spot price. I cannot use ItemChannelLink as my items don’t have channels, so I took the display example, maybe it’s only for display in UI (sorry I never use the UI part of OpenHAB)?

Thank you!

Yes, at least you could verify if it’s working by checking the UI. To apply VAT to your 48 channels, you might want to do that directly in your rule by:

transform("VAT", "DK", price.toString)

You could have a rule triggered at midnight (by cron event) which will copy “tomorrow” items into “today” items and set “tomorrow” items to UNDEF, i.e. to do the roll. Another trigger could be when an item linked to channel hourly-prices changed, i.e. when the prices are updated around 13:00. This could then update “tomorrow” items as this is the moment when they become available. This would also ensure it would work if the spot prices are not available at 13:00 for any reason - as soon as they will be, you will have your items updated.

I will update the binding to keep 12 hours of history or all hours today - whichever will be the most.

1 Like

I checked the event log, and it looks like HourlyPrice is updated once per hour at XX:00:00. I have modified my rule to the following which also reset tmr prices if none is in the price feed:

rule "Update electricity price list"
when     
    Item HourlyPrices changed
    or Time cron "0 * * * * ? *"
then
    val actions = getActions("energidataservice", "energidataservice:service:energidataservice")
    var priceMap = actions.getPrices(null)
    var DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
    var LocalDateTime today = LocalDateTime.now()
    var LocalDateTime tomorrow = today.plusDays(1)
    var Boolean isTmrPriceAvailable = false
    var Boolean isTmrPriceDefined = gEnergiDataServiceTomorrow.members.filter[ item | item.state == UNDEF ].size == 0
    priceMap.forEach[ key, value | 
        var LocalDateTime ldt = LocalDateTime.ofInstant(key, ZoneOffset.systemDefault())
        var DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("HH");
        var String dateStr = ldt.format(dateFormatter)
        var String hourStr = ldt.format(hourFormatter)
        var String itemName = "PriceAt" + hourStr
        if(dateStr == tomorrow.format(dateFormatter)) {
            isTmrPriceAvailable = true
  			gEnergiDataServiceTomorrow.members.findFirst[name.equals(itemName+"Tomorrow")].postUpdate(transform("VAT", "DK", value.toString))
        }
        else if (dateStr == today.format(dateFormatter)){
            gEnergiDataServiceToday.members.findFirst[name.equals(itemName+"Today")].postUpdate(transform("VAT", "DK", value.toString))
        }
    ]
    if (!isTmrPriceAvailable) {
        gEnergiDataServiceTomorrow.members.forEach[ item | 
            item.postUpdate(UNDEF)
        ]
        logInfo("EnergiDataService", "Reset tomorrow's electricity price to UNDEF")
    } else if (!isTmrPriceDefined) {
        logInfo("EnergiDataService", "Received tomorrow's electricity prices")
        sendNotification("xxxxxx", "Electricity for tomorrow is delivered at " + String.format("%1$tH:%1$tM", now))
    }
end
2 Likes

Hi.

I’ve been trying to make this binding for my OH 3.4 instance but struggling a little to build, as I have not done this before directly from the openhab-addons repo. Perhaps you can point me in the right direction.

I’m using VSC on a windows machine - I have maven installed and can build the Z-wave binding which I have, but from another repo.

What I have tried:
1 - download only the energidataservice binding folder. Failed to build - something with dependecies not being found.

2 - Fork the entire openhab-addons repo from the main branch - which does not include your binding. Copying your binding into that repo, and try and build. This showed the followinng message (I have not included all dependencies, but there are some 30-50 with the same absent message:

Could not resolve dependencies for project org.openhab.addons.bundles:org.openhab.binding.energidataservice:jar:4.0.0-SNAPSHOT: The following artifacts could not be resolved: org.openhab.core.bundles:org.openhab.core.test:jar:4.0.0-SNAPSHOT (absent)

3 - I then tried to change the pom.xml file where I changed the version to what I am currently using:

  <parent>
    <groupId>org.openhab.addons.bundles</groupId>
    <artifactId>org.openhab.addons.reactor.bundles</artifactId>
    <version>3.4.3-SNAPSHOT</version>
  </parent>

this then gave the following build error message (again only the first dependecy is shown - the list contains the same 30-50 dependencies - all with the same message):

Could not resolve dependencies for project org.openhab.addons.bundles:org.openhab.binding.energidataservice:jar:4.0.0-SNAPSHOT: The following artifacts could not be resolved: org.openhab.core.bundles:org.openhab.core.test:jar:4.0.0-SNAPSHOT (present)

I am running the release build of OH 3.4.3 on my RPi, but should this be an issue?

Hope you can help point me in the right direction
BR
Mark

The branch jlaur:14222-energidataservice is targeting the main branch, i.e. openHAB 4.0. It requires Java 17 as well as Gson 2.10. Therefore you cannot build it for 3.4.

I have backported it to a private branch. You can find a JAR that can be used directly with openHAB 3.4 here: Energi Data Service Binding [3.4.0.0;4.0.0.0)

You can also install it straight from the UI under Community Add-ons.

Thanks - I have no clue as to why I didn’t just check the UI first :person_facepalming: :laughing:

Just want to report in the past week the binding works flawlessly for me. Thank you for the great effort @laursen !
I received next day’s EL price every day at 13:00 - it is a big improvement over NordPool which I sometimes experience some delay. Maybe a small improvement suggestion: in case the price for next day is delivered earlier (NordPool sometimes delivers prices already at 12:40), it would be nice to trigger an update of HourlyPrices - instead of always update the item hourly.
The calculation for the cheapest period for charging my car also works perfect. The only issue I found is sometimes when I create an Instant for midnight, if I don’t set nanoseconds it doesn’t return a period for charging - I think maybe it’s because when nanoseconds > 0 it consider a new day and hence the algorithm doesn’t work to find the cheapest period. Anyways it’s easy fix :slight_smile:

Thanks for reporting back, I’m glad to hear it’s working as expected. :slight_smile:

All channels are updated as soon as new prices are available in the binding. However, since the prices are not guaranteed to be available before 13:00, the binding won’t try to fetch them before that time. In fact, I even add a small amount “jitter”, i.e. a random amount of time, so that you will receive the update between 13:00 and 13:01. This is to ensure that everyone will not call the service at the exact same time.

I know that prices are often available a little before 13:00. However, I’m afraid that trying to fetch them before the official availability time will only lead to more calls when they are not yet available, because the binding would then have to retry.

So even though you see hourly updates, in fact the binding only calls the service one time per day. The prices are then cached, and a scheduled job will update the channels accordingly each hour.

Is it a real problem waiting until 13:00-13:01, or only an observation? The time is kind of arbitrary, so for automations it probably shouldn’t make much of a difference waiting up to 20 minutes too much for next day’s prices. I understand though (believe me) that it can be slightly annoying waiting until 13:00 when getting the idea to check the prices at 12:50 and knowing they are probably available already, but that’s more a psychological problem. :wink:

Can you paste your rule code, then I’ll check that?

Looks like today there has been some problem with prices for tomorrow - now it’s 14:05 but it still hasn’t come. Do you mean you only try to call the service once per day? Does it mean if the delivery from NordPool is delayed after 13:00, the binding will never update tomorrow’s price (seems like my observation today)?
On a separate note: wouldn’t be a good idea to update the channels when the binding receives tomorrow’s price immediately (instead of caching and update per hourly schedule)?
Have a nice weekend!