one of my rules which worked now throws an error on isBefore
here is rule:
rule "WaspTimerExpired"
when
Item BoxTimer changed from ON to OFF
then
var tally = WaspConf.state as Number
if (tally > 74) return;
val openTime = new DateTimeType(LastBoxOpen.state.toString)
val motionTime = new DateTimeType(LastBoxBuzz.state.toString)
if (DaddysPhone.state = ON) {tally = (tally + 20)}
if (DaddysPhone.state = OFF) {tally = (tally - 20)}
if (openTime.isBefore(motionTime)) {tally = (tally + 60)}
if (openTime.isAfter(motionTime)) {tally = (tally - 5)}
if (tally >= 100) {WaspConf.sendCommand(100)}
if (tally <= 0) {WaspConf.sendCommand(0)}
if (tally > 0 && tally < 100) {WaspConf.sendCommand(tally)}
if (tally < 75 && tally > 0) {BoxTimer.sendCommand(ON)}
end
here is error
18:45:48.189 [ERROR] [untime.internal.engine.RuleEngineImpl] - Rule 'WaspTimerExpired': 'isBefore' is not a member of 'org.eclipse.smarthome.core.library.types.DateTimeType'; line 41, column 9, length 29
Iām on openHAB 2.5.0~M5-1 on OpenHABian, and Iām not seeing this problem. Hereās my rule.
rule "Presence timer expired"
when
Item PresenceTimer received command OFF
then
logInfo("WaspInBox.rules", "Presence timer expired.")
var confidence = PresenceConfidence.state as Number
if (confidence > 0 && confidence < 100) { // we haven't made up our mind yet
val TimerExpired = new DateTime(LastTimerExpired.state.toString)
val JonsPhoneLastSeen = new DateTime(JonsPhone_LastSeen.state.toString)
val AlsPhoneLastSeen = new DateTime(AlsPhone_LastSeen.state.toString)
// Check if a phone was seen since the last timer expired
if (TimerExpired.isBefore(JonsPhoneLastSeen) || TimerExpired.isBefore(AlsPhoneLastSeen)) { confidence = confidence + 20 }
else { confidence = confidence - 5 }
if (confidence >= 100) { confidence = 100 }
else if (confidence <= 0) { confidence = 0 }
PresenceTimer.sendCommand(ON)
PresenceConfidence.sendCommand(confidence)
}
var time_now = new DateTimeType(now.toString)
LastTimerExpired.sendCommand(time_now)
end
My Java version:
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (Zulu 8.42.0.23-CA-linux64) (build 1.8.0_232-b18)
OpenJDK 64-Bit Server VM (Zulu 8.42.0.23-CA-linux64) (build 25.232-b18, mixed mode)
java -version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)
so down graded using:
sudo apt-get install openjdk-8-jre
then
sudo update-alternatives --config java
which I got from here:
worked like a charm
java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1ubuntu1~18.04.1-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
restarted OpenHABā¦ still no joy
19:30:13.155 [ERROR] [untime.internal.engine.RuleEngineImpl] - Rule 'WaspTimerExpired': 'isBefore' is not a member of 'org.eclipse.smarthome.core.library.types.DateTimeType'; line 41, column 9, length 29
restarted computer and still no joy
version of java is still
java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1ubuntu1~18.04.1-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
good catch Vincent, didnāt throw any errors in vscode so I missed it. I had to stare at your two examples for a couple minutes to even see the difference
Well, I can confirm that itās working OK for me, so itās not a 2.5M5 thing. Iām only guessing that itās Java related. I note that Iām running Zulu java, rather than the default Ubuntu OpenJDK.
On a separate note, I have found using the on/off state for phone presence unreliable. Iām using iPhones and the network binding. I find that phone presence state is frequently āoffā, even when the phone is present. I found it more reliable when using the phone ālast seenā item.
ā¦ and just another guess: are your LastBoxOpen and LastBoxBuzz items defined as DateTime types and initialised somewhere? My phone things were configured through paper UI, but my timers are defined in .items files:
Switch PresenceTimer "timer used for wasp in box" { expire="60s,command=OFF" }
Number PresenceConfidence "Wasp in Box confidence level" <none> (Home)
DateTime LastTimerExpired "Last timer expired at [%1$tI:%1$tM %1$Tp]" <none> (Home)
and my Wasp in Box rules initialise the items on startup.
rule "initializeSys"
when
System started
then
// initialize wasp in box unbound item values from null. Note the assumption is that no-one is
// present, and let the house correct that by itself
logInfo("WaspInBox.rules", "Wasp in Box items initialised.")
PresenceConfidence.postUpdate(50)
PresenceTimer.postUpdate(OFF)
var time_now = new DateTimeType(now.toString)
LastTimerExpired.sendCommand(time_now)
JonsPhone_LastSeen.sendCommand(time_now)
AlsPhone_LastSeen.sendCommand(time_now)
end
I recently discovered that if OpenHAB restarts when one of the phones isnāt present, and without the LastSeen item initialised (and it was therefore NULL) my presence rules were broken.
DateTime LastBoxOpen "last time door opened" <none> (gHome, gPersist)
DateTime LastBoxBuzz "last time motion detected" <none> (gHome)
initialization rule
//Wasp start up rule
// initialize wasp in box unbound item values from null
rule "WaspSystemStart"
when
System started
then
WaspInBox.postUpdate(OFF)
WaspConf.postUpdate(0)
LastBoxOpen.postUpdate(new DateTimeType(now.toString))
LastBoxBuzz.postUpdate(new DateTimeType(now.toString))
BoxTimer.postUpdate(OFF)
end
you do release this is my thread right
thanks for your help Jon. I was just starting clean to test 2.5M5 and copying my rules over from the old install.
val openTime = new DateTime(LastBoxOpen.state.toString)
val motionTime = new DateTime(LastBoxBuzz.state.toString)
There have been some recent PRs for DateTimeType that may have changed itās behavior in the rules DSL. I doubt that the functionality that previously worked for you (using DateTimeType as joda.time.DateTime) would be something that would be restored, since it was not intended functionality and so unlikely to be considered a regression. But you may want to create an issue to ask in GH. Iām not sure how many users will be affected by this, but to be safe, it might be something to consider adding to the update.lst. This is a good item to make note of in the 2.5M5 issues topic.
In that case, Iād rather not file an issue then. Iād rather figure out how to convert the time properly. You see the hack Iāve implemented in the post above yours to get my rules running again. Here is link to the thread where Rich taught me the hack. And the rule example in the post above yours also shows an example of using the same hack so that will need fixed.
Well, after looking at my rule I realized I was doing things a little wrong
My original line was as follows
val openTime = new DateTimeType(LastBoxOpen.state.toString)
according to Rudās great time conversion thread, what I seem to be doing here is taking a OpenHAB item (a DateTimeType) and converting it to a string to then create another OpenHAB DateTimeType from it??? Obviously stupid (as Scott pointed out)
So new version (just remove the Type from DateTimeType)
val openTime = new DateTime(LastBoxOpen.state.toString)
Converts OH item (DateTimeType) to a string and then from the string creates a Joda time which works with isBefore just fine. Iāll have to look at my old thread but Iām amazed my old version worked at all.
Is this still as you say Scott, unintended behavior? Is there a cleaner way of comparing OH DateTimeTypes or converting them to Joda?
Edit to add: This is really kind of crazyā¦ When I convert the rule to use millis, I changed the comparison line to this because millis is just a number
if (openTime < motionTime) {tally = (tally + 60)}
And when I just now tested it with the Joda timeā¦ the above still worked???
No isBefore needed???
If in fact your rules were working the way you describe, my guess is that the DSL was able to figure out what you were trying to do and converted DateTimeType to DateTime. Yes, Iād call it unexpected behavior, but Iām tempted to test it out to see first hand. The DSL is very good at figuring out what types you are going after, but there must have been a change in OHC, if this no longer works for you.
The DateTime conversion topic should replace org.joda.time with pure Java, since Joda will be going bye-bye, unless you use scripted automation, where you can import 3rd party libs. This also lets you use core.date for conversions. If you really want to future-proof yourself, use Java libraries.
I donāt think we can/should do that until now is no longer a Joda DateTime and createTimer no longer requires a Joda DateTime. Most of the time one is working with a Joda DateTime it is in these situations where itās still required. Itās bad enough that we have to have two DateTime types we have to use (Iām sure there is a reason, but why is DateTimeType not an instance of Joda DateTime in the first place, then thereād be no need to convert anything) Iām hesitant to bring in a third approach. Iād much rather provide āChange the joda DateTimes to Java DateTime using these stepsā in a migration tutorial and update the official docs for OH 3 to drop Joda at that time. Doing it now will lead to complexity and confusion.
I tend to agree with this, but with OH3 approaching, I feel it is time for us to change tacks and start prepping the documentation and socializing the change in the forum.
2.5 release isnāt even out yet. If we stick to the same release schedule OH3 is still six months away, though based on the experience with the 2.0 release Iām skeptical we can stick to that release cycle. So it is approaching but itās not like we are mere weeks or even a few months away.
And we donāt know if the devs will do something to make the transition from Joda to Java DateTime easier or just let it break everyoneās Rules (this was attempted at some point and we discovered that Java is not a drop in replacement for Joda and it broke Rules). I could see (and would absolutely love) that everything getās normalized on DateTimeType so there is no longer a need to do any of these conversions in the first place. (Iāve added a comment asking about this to the Issue).
I donāt think we know enough yet about what the impact to users for this change will be so itās hard to advise changing how itās currently done. At least not in the official docs for sure. When we know more Iāll be on board but I still think itās premature to modify the official docs or to recommend changing how we do things with DateTime. Iād wait for the PR to be submitted for review before doing that.
As unexperienced as I am in these matters, I have a gut feeling that a transition period would be very helpfulā¦? Because porting wonāt happen overnight. For myself I can say that I have a very varying time budget I can put in this hobby. This may be 0 for months and then again larger at some other timeā¦ Thatās why 6 months may not be that muchā¦
But of course the target setup should be available for that.
I think this is how you do it using a Java ZonedDateTime:
rule "WaspTimerExpired"
when
Item BoxTimer changed from ON to OFF
then
var tally = WaspConf.state as Number
if (tally > 74) return;
val openTime = (LastBoxOpen.state as DateTimeType).zonedDateTime
val motionTime = (LastBoxBuzz.state as DateTimeType).zonedDateTime
if (DaddysPhone.state = ON) {tally = (tally + 20)}
if (DaddysPhone.state = OFF) {tally = (tally - 20)}
if (openTime.isBefore(motionTime)) {tally = (tally + 60)}
if (openTime.isAfter(motionTime)) {tally = (tally - 5)}
if (tally >= 100) {WaspConf.sendCommand(100)}
if (tally <= 0) {WaspConf.sendCommand(0)}
if (tally > 0 && tally < 100) {WaspConf.sendCommand(tally)}
if (tally < 75 && tally > 0) {BoxTimer.sendCommand(ON)}
end
or if you prefer using getStateAs use:
val openTime = LastBoxOpen.getStateAs(DateTimeType).zonedDateTime
No need for now or toString conversions, this should also work: