[SOLVED] DateTimeType - extract values to use it in rules

Hello,
I have just started to work with DateTimeType calculation and it’s really being a big deal for me: this page about rules warned me
https://docs.openhab.org/configuration/rules-dsl.html#datetime-item
and this post confirmed me


anyway I tried.
I use OpenHAB 2.3.0, installed from the repository, and it runs in a Raspberry 3 with Raspbian 8.
My aim is to create a chart (X axis-Time, Y-axis hour:minute of the day[0:00-23:59]) where to show at what time, everyday, a particular event happens (the event is the trigger channel of the Astro binding - thing sun, group rise, event START - but could be something else too).
I already created a chart with similar characteristics showing at which azimuth the sun rises every day (X axis-Time, Y-axis azimuth angle (0-359]) and it works as expected.

So, I created these items

DateTime RiseStartTime “sun rise start time: [%1$tH:%1$tM]” {channel=“astro:sun:home:rise#start”}
DateTime ProvaTime “prova time: [%1$tH:%1$tM]” (TimeChart)

I created this persitence line

ProvaTime : strategy = everyChange, restoreOnStartup

and, according to the rule page i linked before, I created this rule

rule “sun program”
when
Channel ‘astro:sun:home:rise#event’ triggered START
then
val time = (RiseStartTime.state as DateTimeType).calendar.get(Calendar::HOUR_OF_DAY)
ProvaTime.postUpdate(time)
end

(I know that with this function I would get just the “hour” and not “hour:minutes” anyway I started in this way to see what would happens)
The item doesn’t get updates and in openhab.log appear this rows

2018-07-18 16:03:14.108 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model ‘house_piossasco.rules’, using it anyway:
The method getCalendar() from the type DateTimeType is deprecated
2018-07-18 16:04:00.008 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule ‘sun program’: The name ‘Calendar’ cannot be resolved to an item or type; line 49, column 83, length 8

Then I thought that maybe the problem was the itemtype of ProvaTime and so I changed it to Number, but I kept on receiving the same error.
I searched for examples in internet and I understood that the old function about the DateTimeType are changing and the old form is now deprecated. Anyway the function reported in the rule page doesn’t work for me so I looked in this page
https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#add-int-int-
and I realized that probably the function that would allow me to reach in the easiest way my goal is the “set(int year, int month, int date)” function: everytime the rule is triggered I could take the RiseStartTime item, apply the set(0,0,0) function to give YEAR=0, MONTH=0 and DAY=0, postupdate ProvaTime with this value (with just the not null information about hours, minutes, seconds and eventually milliseconds) and persist this value once a day.
So I set again the items and the persitence line as I wrote before, and, according to the rule page i linked before, and I modify the rule in this way

rule “sun program”
when
Channel ‘astro:sun:home:rise#event’ triggered START
then
val time = (RiseStartTime.state as DateTimeType).zonedDateTime.toInstant.set(0,0,0)
ProvaTime.postUpdate(time)
end

but the item ProvaTime doesn’t get updated and I can see this error in openhab.log

2018-07-18 16:49:00.008 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule ‘sun program’: The name ‘time’ cannot be resolved to an item or type; line 66, column 39, length 4

I tried again a lot of ways and functions but I don’t know how to write in a good way this DateTimeType functions. The only one that I managed to use and reach the expected result is the “.zonedDateTime.toInstant.toEpochMilli”, but in order to reach my aim I can’t use just this one; I have to manipulate the incoming event time data erasing the information about year, month and day, in order to compare in the chart just the moment of the day when everyday the event happens.
I hope to have explained everything in a good way, try to work with these DateTimeType calculations is not easy without a clear documentation. Has anybody any suggestion that could help me?

1 Like

The easiest way to accomplish what you are after is the following:

  • Make ProvaTime be a Number. You cannot chart a DateTime Item and even if you could, a DateTime is an absolute value. Deep down it is the number of milliseconds since 1970-01-01T00:00:00. Two numbers separated by a colon is not sufficient. It has to represent an exact point in time.

  • Trigger the Rule when the event happens

  • Use the now implicit variable. Don’t try to convert anything.

rule “sun program”
when
Channel ‘astro:sun:home:rise#event’ triggered START
then
    ProvaTime.postUpdate(now.getHourOfDay)
end

If you wanted to get the hour from RiseStartTime, it is easiest to first convert it to a Joda DateTime.

val hour = new DateTime(RiseStartTime.state.toString).getHourOfDay

This is going to be a challenge because, like I said, a DateTime isn’t charitable because it represents a specific point in time. You can’t represent a time of day without the day/month/year part. You might be able to do some math to come up the the number seconds since midnight when the event occurs and chart that perhaps.

Wouldn’t it be easier to link the item to the channel? :smiley:

DateTime ProvaTime    "Rise Start [%1$tl:%1$tM%1$tp]"    <sun>    (gAstronomy)   {channel="astro:sun:home:rise#start"}

He wants to chart the hour and minute the sunrise happens each day. If he just links to the Channel then he can’t really chart it because every sunrise happens on a different day.

Besides perhaps looking interesting on a UI, I can’t imagine a practical use for this but I’m sure OP has his reasons.

Hello Rich, hello Scott,
thank you for your answers. I successfully insert in the Y-axis of my chart the DateTime value without manipulation of the data, but as you wrote before, i got a useless - for my purposes - chart with a line rising and rising, not something like a sine curve as I expect to be the line in the chart I want to realize. I did the same making a previous transformation of the DateTime item in a Number item but the chart was the same line rising.
As you’ve already understand, the problem is not really to provide to the item the time value of the event and to persist it once a day (I know how to do it in different ways now and you gave me more suggestions too), the problem is to subtract to the provided value the amount of time (for example, if I transform the DataTimeType with the “.zonedDateTime.toInstant.toEpochMilli” function, 86400000 milliseconds for every day passed from the 1st January 1970) needed to have the possibility to compare the values provided in several different days. Once made this subtraction, the item ProvaTime would have every day a value included between 0 and 86400000 and so the chart could have in the Y -axis these values and in the X-axis the time. If I would like to make this chart more clear I could divide the Y-axis values by 360000 and so show there the 24 hours of the day, in both way I will already have in the chart a clear vision about the change over the time of a daily event (or more related events if I want - I could represent sunrise, noon, sunset and solar midnight on the same chart to see how their time of the day change over the year; or I could represent other kind of events to see if they happen every day at the same time or how they change over the time).
So I wrote before that I thought about the “set(int year, int month, int date)” function, to use it with set(0,0,0) because I intended that in this way I would have done the subtraction of 86400000 milliseconds for every day passed from the 1st January 1970. But maybe I misunderstood the way this function works or maybe I don’t now how to use it in OpenHAB.
Do you gave any idea about how to subtract this amount of time that inhibits the comparison of these time values?

var secsToday = (new DateTime(RiseStartTime.state.toString).millis - now.withTimeAtStartOfDay.millis) / 1000

Thank you Rich,
after your last suggestion I can now obtain the chart I wanted to realize. I used the formulation of your last post, so I have the “seconds” (from the start of the day) in the Y-axis of the chart and not the “hours” (from the start of the day), but the trend of the line represented in the chart is exactly what I wanted to reach.
I summarize the contents of the files, in this final working version, in order to make them clear if somebody else would like to solve a similar issue

item lines:

DateTime RiseStartTime “sun rise start time: [%1$tH:%1$tM]” {channel=“astro:sun:home:rise#start”}
Number ProvaTime “prova time: [%.0f]” (TimeChart)

persistence line:

ProvaTime : strategy = everyChange, restoreOnStartup

rule lines:

rule “sun program”
when
Channel ‘astro:sun:home:rise#event’ triggered START
then
var timeseconds = (new DateTime(RiseStartTime.state.toString).millis - now.withTimeAtStartOfDay.millis) / 1000
RiseTime.postUpdate(timeseconds)
end

Now, even if the main issue has been solved, I still have two question:

  • I tried to divide by 3600000 in the timeseconds (secsToday) line to obtain a value of the RiseTime item expressed in hours (even if I understand that the value would be a decimal one - so 7:30 would be expressed as 7,50) but the result it’s not what I would desire: the RiseTime item is updated just with integer value - so 7,50 is truncated to 7, 9,34 is truncated to 9, etc. - and this approximation is not good for the my purpose (the chart would not represent the slow change of the event time). Is there a way to give to the timeseconds (secsToday) a value with, for example, two decimal numbers?

I tried to change the item file in this way

Number ProvaTime “prova time: [%.2f]” (TimeChart)

but, as I suspected, this affected just the way the value is represented and not the value itself and so I obtained just “,00” after the integer number.

  1. Why in the expression you suggested me you wrote “var” before the timeseconds (secsToday) value? It is not a value that changes during the single rule execution, so I would expect a “val” (sorry if it’s a stupid question but I feel still unexpert in the rule field).

Thank you very much for your help.

  1. Try dividing by 3600000.0 it should be giving you a decimal value anyway but this is the first thing I would try.

  2. Because I didn’t know what you were going to do with it. If it never changes then val is appropriate.

OK, I’ve set the division by 3600000.0 and now I get values with lots of decimal.
Now everything is working in the way I expected. Thanks again for the help and the clarifications.