[Solved] YTD Energy value calculation

Hello!

I’m trying to setup a Year-to-date calculation of my electrical energy consumption. The consumption is reported in Watthours in the item vpmEFAT ( persisted in rrd4j every minute). Next to the fact, that I’m absolutely not sure if the code below is correct, I have started persisting only in may this year. But if the rule could serve as general example for YTD-calculation as dela between a current value and the value at the beginning of the year, it wouldbe great if it could also handle such an issue.

rule "YTD energy values"
  when
    Item vpmEFAT received update or Time cron "0 */5 * * * ?"
  then
    val onTheFirstDayOfTheFirstWeek = dateTime.withWeekyear(dateTime.getYear()).withWeekOfWeekyear(1).withDayOfWeek(1)
    var Number YTDBezug = vpmEFATKWH.deltaSince(now.minus(onTheFirstDayOfTheFirstWeek))
    postUpdfate(vpmEFATYTD,YTDBezug)
    logInfo("Rules", "YTD Bezug updated to: "+vpmEFATYTD.state)

end 

Current error in the logs:
2017-10-24 23:51:28.521 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘YTD energy values’: An error occurred during the script execution: The name ‘dateTime’ cannot be resolved to an item or type.

Regards,
Herbert

Regarding the error:
Did you import the time functions?

import org.joda.time.*

If yes or if it doesn’t solve the error:
Try replacing dateTime with DateTime

Well, the error is pretty clear. You have not defined anything named dateTime. Do you mean to use now? What is dateTime supposed to be?

Ok after some further testing something general about the error.

From my understanding you are trying to get the first day of the first week of the year.
(I think you want to get this from the current date.)
You are doing this with DateTime Methods and trying it with static methods and without a DateTime instance

I have searched a bit in the Documentation of joda time and cant find that much static methods.
My simple suggestion would be: Create a DateTime instance first:

var DateTime myDate = new DateTime()
val onTheFirstDayOfTheFirstWeek = myDate.withWeekyear(myDate.getYear()).withWeekOfWeekyear(1).withDayOfWeek(1)

gives me the following:

11:08:30.029 [INFO ] [marthome.model.script.Testarea Rules] - 2017-01-02T11:08:30.022+01:00

I don’t know if DateTime can be used directly without creating an Instance.

Hi guys!

Thank you for the quick feedback.

@Confectrician: I thought the import is not necessary anymore in OH2

As output there should have been 1.1.2017 (00:00 hrs) --> beginning of the year. As it should automatically change every year, I thought I try the joda.time stuff.

So using the first day of the first week was a wrong approach by myself.

So I got it working, that I dynamically receive the first day of the first year - but still get an error:

ule "YTD energy values"
  when
    Item vpmEFAT changed or Time cron "0 */5 * * * ?"
  then
    val CurrentDate = new DateTime()
    val Yearbeginn = new DateTime(CurrentDate.getYear(),1, 1, 0, 0, 0) 
      logInfo("Rules", "Datum: "+Yearbeginn)

    var Number YTDBezug = vpmEFATKWH.deltaSince(now.minus(Yearbeginn))
    postUpdate(vpmEFATYTD,YTDBezug)
    logInfo("Rules", "YTD Bezug updated to: "+vpmEFATYTD.state)

end 

Log:
2017-10-26 22:37:54.469 [INFO ] [eclipse.smarthome.model.script.Rules] - Datum: 2017-01-01T00:00:00.000+01:00
2017-10-26 22:37:54.496 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘YTD energy values’: An error occurred during the script execution: Could not invoke method: org.joda.time.DateTime.minus(long) on instance: 2017-10-26T22:37:54.493+02

Is my delta-calculation wrong or is it due to a missing value in the rrd4j database on the 1.1.2017 00:00:00 ?

Thank you for your efforts,
Herbert

It seems like you are going about the date stuff the hard way.

// you don't need CurrentDate because now IS the current date
val Yearbeginn = now.withTimeAtStartOfDay.withDayOfYear(1)

And since Yearbeginn is the beginning of the year it makes no sense to subtract it from now. That will result in a timestamp that is completely wrong. Just use Yearbeginn.

var Number YTDBezug = vmpEFATKWH.deltaSince(Yearbeginn)

deltaSince literally expects a timestamp to start the query from, not a number of milliseconds from now.

However, this still might throw an error if you don’t have data that goes back that far. I think I remember that rrd4j tends to just trow an error when you try to go back before your first piece of data in the DB. You may have to gradually work with this rule until you have enough data for a full year.

2 Likes

Dear Rich!

Thank you very much!

It seems like you are going about the date stuff the hard way.

Why going the easy way? My way or the highway :wink:

You were right → result was a NULL value for this year. That’s why i put a check in it:

rule "YTD energy values"
  when
    Item vpmEFAT changed or Time cron "0 */5 * * * ?"
  then
   
    val Yearbeginn = now.withTimeAtStartOfDay.withDayOfYear(1)
      logInfo("Rules", "Datum: "+Yearbeginn)

    var Number YTDBezug = vpmEFATKWH.deltaSince(Yearbeginn)
    logInfo("Rules", "YTD Bezug updated to: "+YTDBezug)
    if (YTDBezug == null) {
      vpmEFATYTD.postUpdate(vpmEFATKWH.state)
    }

    else  {
    postUpdate(vpmEFATYTD,YTDBezug)
   
    }
    logInfo("Rules", "EFATYTD updated to: "+vpmEFATYTD.state)
end 

Thank you for your support - works!

2 Likes

Hi Herbert,

I’m trying to achieve about the same function, but can’t get it to work.

I got my meter value in kWh from the item P_BP8_ElMaalervisningKwh, and I have used it to trigger the rule instead of your item vpmEFAT

On my sitemap, I would like to have a YTD value next to my P_BP8_ElMaalervisningKwh which I imagine could be done by using the YTDBezug. However, I’m in doubt what your vpmEFATKWH item contain, and thereby what I should replace it with?

Can you help?

Best regards Ole.

Hi Ole!

Sorry, I’m still on a steep learing curve, but of course I will try to help.

If you receive your values already in kWh the items vpmEFAT and vpmEFATKWH are the same. In fact I could change that to the same name, as another rule triggers the conversion from watthours to kilowatthours.

I try to put your rule here (you’ve to try and see the logs):

rule "YTD energy values"
  when
    Item P_BP8_ElMaalervisningKwh changed or Time cron "0 */5 * * * ?"
  then
   
    val Yearbeginn = now.withTimeAtStartOfDay.withDayOfYear(1)
      logInfo("Rules", "Datum: "+Yearbeginn)

    var Number YTDConsumption = P_BP8_ElMaalervisningKwh.deltaSince(Yearbeginn)
    logInfo("Rules", "YTD consumption updated to: "+YTDConsumption )
    if (YTDConsumption == null) {
      YTDconsumptionITEM.postUpdate(P_BP8_ElMaalervisningKwh.state) //probably it would be nicer to put a not available info here
    }

    else  {
    postUpdate(YTDconsumptionITEM,YTDConsumption )
   
    }
    logInfo("Rules", "YTDconsumptionITEM updated to: "+YTDconsumptionITEM.state)
end 

You need two items:

  • P_BP8_ElMaalervisningKwh
  • YTDconsumptionITEM

Of course you have to persist P_BP8_ElMaalervisningKwh (I am currently using rrd4j, want to change to influxdb).

Hope that helps,
Herbert

1 Like

Hi Herbert, Thanks a lot for your effort!

I added your rule, it looks more or less the same to what I already did to your original rule from the October post. And it acts the same way, from what I can see in my log.

Reading your post once again, made me think a little bit more about you finally mentioning my meter value item must be persistent. In the first time I did not pay enough attention to that. The fact is, I assumed that was not necessary, since the value from the meter remains even I restart OpenHAB. But that’s of cores only the actual meter value, not the value at year begin, why deltaSince(Yearbeginn) is quite hard to use then, I guess!

However, I have chosen to solve it a little bit different.

rule "Set meter value year beginn"
when
	Time cron "0 01 00 01 01 ?"
then
	YearBeginnValue_El_kWh.state = P_BP8_ElMaalervisningKwh.state	as DecimalType
end

rule "Calculate YTD energy value"
when
	Item P_BP8_ElMaalervisningKwh changed
then
	var Number TotalConsumption  = P_BP8_ElMaalervisningKwh.state as DecimalType
	var Number YearBeginn = YearBeginnValue_El_kWh.state as DecimalType
	var Number YTDConsumption = TotalConsumption - YearBeginn
	postUpdate(SitemapYTD_El_kWh, YTDConsumption)
end 

I’m persisting YearBeginnValue_El_kWh with mapdb, which I’m already using for other items necessary to restore on startup.

Best regards Ole

1 Like

Many ways to go :wink:
Glad I could help!

1 Like