Thanks a lot, it works after removing the channels
My use-cases are:
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?
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.
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
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.
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.
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:
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. 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.
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)?
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:
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.
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
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:
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.
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
Thanks for reporting back, Iâm glad to hear itâs working as expected.
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.
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!