@rlkoshak it seems like my cut/paste is removing the first line when I paste for some reason. I noticed that it also didn’t paste the first of the two lines from the log file. That first line for the logger was supposed to be there.
OK so thanks for the explanation of what I should log and why, but I’m unclear on exactly how to do that. The examples I see seem to all be different. The first line after importing the logger is: var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
So do I do this? logger.info(ScriptExecution = Java.type);
Ah, I just figured out that the closing `'s can’t be on the next line.
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
logger.info("My rule has started running...");
...
logger.info("this.timer = " + this.timer);
That depends on the device and the local interpretation of ‘online’. How would you expect a Thing representing a sleeping battery smoke alarm to look? If we smash it with a hammer, what would you expect then?
Treat it as telling you about the pathway to a device. Have I got all the resources needed to await a communication from the device? Then its ONLINE.
zwave doesn’t really poll, the devices report autonomously. The last thing you want is twice as much mesh traffic, implied by active poling.
You can detect missing reports if you know when to expect them. Generally people will look for missing periodic battery reports or similar.
This doesn’t really have much to do with Things.
That thread explains a lot, thanks. Not the answer I wanted though. I’m coming from Vera where we would get pretty reliable notifications for things offline.
I’m more concerned with grid-powered devices, though we DO have some leak sensors which would certainly be good to know if were offline.
It seems like failed polling would work but I just tested that & I’m not getting anything. I also tried sending a REFRESH command, which I saw in another post put that had no effect. Strange, you’d think there would be some built-in status report for zwave devices which would do this. That’s what I thought polling would do. Poll, no answer, alert!
Polling is undesirable in zwave technology. It uses twice as many transactions as autonomous reporting, and it’s useless for battery devices which are an essential part of zwave.
Don’t like it, use wired or other technology.
Or live with it, learn how to predict and/or control those unsolicited device reports. Detecting missing updates at the openHAB end is then fairly trivial in comparison.
@rlkoshak I have some logging working (small miracle) but I’m stuck about 1/2 way down the list you provided of what to log. I don’t know how to get the value of this.timer inside of runme. Right now the logs I have just show whatever text I inserted like this:
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Scratch");
var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
logger.info("Thing Offline Alert Rule Started");
var ZonedDateTime = Java.type("java.time.ZonedDateTime");
var now = ZonedDateTime.now();
var runme = function(){
logger.info("Function");
var Actions = Java.type("org.openhab.core.model.script.actions.Things");
var mailActions = Actions.getActions("mail","mail:smtp:SMTP_Server");
mailActions.sendHtmlMail("skye@bpsgreenhomes.com", "Thing Offline", "A device has gone offline. Please contact BPS at monitors@bpsgreenhomes.com or 910-470-8203");
this.timer = undefined; // reset the timer back to undefined
}
logger.info("timer = undefined");
if(this.timer === undefined) {
this.timer = ScriptExecution.createTimer(now.plusSeconds(30), runme);
}
logger.info("Timer Created");
else {
this.timer.reschedule(now.plusSeconds(30));
}
I get good logs that show teh script running & email sent after the timer ends, until I add the logger.info line after the If line. Then I get this error:
2021-06-14 15:03:30.880 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Alert_Thing_Offline' failed: <eval>:26:0 Expected an operand but found else
else {
^ in <eval> at line number 26 at column number 0
I thought I was supposed to log the first line after the If & the first line after the Else.
OK these are the logs I get if I make the device offline and then put it back online before the timer has expired it still sends the email. That’s the problem:
2021-06-14 15:39:54.190 [INFO ] [org.openhab.model.script.Scratch ] - Thing Offline Alert Rule Started
2021-06-14 15:39:54.199 [INFO ] [org.openhab.model.script.Scratch ] - this.timer = undefined
2021-06-14 15:39:54.202 [INFO ] [org.openhab.model.script.Scratch ] - this.timer = org.openhab.core.model.script.internal.actions.TimerImpl@5b9675
==> /var/log/openhab/events.log <==
2021-06-14 15:39:54.189 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing 'zwave:device:Z-Wave_Serial_Controller:node4' changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): Node is not communicating with controller
2021-06-14 15:40:01.678 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing 'zwave:device:Z-Wave_Serial_Controller:node4' changed from OFFLINE (COMMUNICATION_ERROR): Node is not communicating with controller to ONLINE
==> /var/log/openhab/openhab.log <==
2021-06-14 15:40:24.198 [INFO ] [org.openhab.model.script.Scratch ] - Email Sent
It’s all but impossible to figure out a problem like this if you don’t have a basic understanding of how your own code works. It would be well worth your time to spend it studying this code to understand it because otherwise we will spend many many more hours going back and forth with you trying something blindly without understanding why and making mistakes as a result and me needing to correct those mistakes just to answer one simple question: is the value of this.timer the same inside runme and it is outside of runme. And I don’t have many more hours to help with this.
Simplify. Make sure you understand what every line of code in this rule does. Make sure you understand the basic rules of syntax for the language. There are tons of freely available courses and tutorials out there to help with that. Slowly rebuild the rule little by little. Experiment to make sure you understand what the lines are really doing.
I’ll give you a little bit of help. As currently written in post 22 the code does the following:
import the logger
import ScriptExecution so you can create a Timer
log to indicate the rule started
import ZonedDateTime so you can create a Timer
save now to a variable, now is the current date/time
define a function named runme that gets called by the timer
a. log to indicate when runme is called
b. import Actions
c. import Mail Actions
d. send the email
e. set this.timer to undefined so a new timer will be created the next time the rule runs
log out the value of this.timer so you can see whether a new timer should be created or if the timer should be rescheduled
if this.timer === undefined
a. create a new timer for 30 seconds and set the handle to this.timer
if this.timer !== undefined
a. reschedule the existing timer for another 30 seconds.
Notice what might be missing here. Nowhere is the timer ever cancelled. An email will always be sent because you have no code to cancel the timer when the Thing goes back online. Is that the root problem? If so, the problem is that you didn’t implement it.
Also notice how the indentation is used in the list above. It makes it way easier to see what’s going on. Do the same in your code (the lines under runme between the { } should be indented).
Yes. Didn’t you want it to run a second time, to reschedule the timer?
So here you’ve asked it to run only when the Thing changes to OFFLINE.
It will not run when the Thing changes to ONLINE.
I don’t think that’s all you’ve got to look at though; if it only reschedules the Timer then it just puts off the email, it doesn’t go away.
You’re going to need to take different actions depending on what the Thing status changed to, ONLINE or OFFLINE.
Yes I realized it was just rescheduling and replaced that line with:
this.timer.cancel();
Which seems to work.
And I do realize now that it doesn’t trigger again to cancel the email when the Thing comes back online. My history with these types of rules is in Vera using Reactor which includes an action when the condition is no longer true & I thought this script might be doing that somehow.
I DO like the alternate structure you propose but fear it’s another rabbit hole for me because I find this code so difficult to understand (it IS starting to get better though).
So here are my questions regarding that:
Triggering from any Thing: I would really like to trigger off of any Thing status change. When making the rule in the UI though, you can only pick one Thing for the trigger. I looked at the docs where it talks about Thing triggers but there is nothing there about triggering from any Thing status. Is this a peice of code or is there some other way of doing this?
Cancelling the timer and examining the new status: Will my line above work to cancel the timer? I assume checking the status of all things is another line of code I need.
Regarding Things popping in & out and the reliability of ONLINE/OFFLINE status, it seems that it will work good enough for our use-case for most of our devices. For our battery-powered devices, I can look for missing battery reports as you suggested previously.