I’ve noticed every time I update OH that a particular script stops working and throws an error in the logs. It’s a JS script that sends an MQTT message directly.
I thought there might be API changes the first few times it happened, but I realised all that needs to be done is re-saving the script to reinitialise it, at which point the script works normally.
Is there a way to do a mass reinit of scripts when upgrading? The closest thing I found when searching is perhaps something through the Karaf console (bundle:restart)
Failed to execute script: TypeError: Cannot read property "publishMQTT" from null at <js>.:anonymous(<eval>:2) at <js>.:program(<eval>:1) at org.graalvm.polyglot.Context.eval(Context.java:419) at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:490) at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:458) ... 23 more
Just to elaborate a little bit on @jimtng’s reply, what is likely happening is as follows.
during an upgrade the OH cache is cleared which forces the reinstallation of all add-ons on that first boot after the upgrade
the system run levels for OH are rules engine starting at start level 40, rules loaded at start level 50, and Things loaded at start level 80
Combine these two and it is almost certainly the case that the the MQTT Thing either doesn’t yet exist at all, exists but is not yet initialized, or the Thing exists but the binding is not yet reinstalled when the rule starts running. Consequently the MQTT action doesn’t exist and you get the null error.
And if you’ve written your rule so that you pull the MQTT action just once instead of every time the rule runs your rule will never get the valid action even after the MQTT binding is installed and the MQTT Broker Thing comes online. So rather than reinitializing the rule, it might be sufficient to just pull the MQTT action every time the rule runs, and just assume that there will be some errors from the rule during boot time, depending on how quickly the MQTT broker can come online compared to the rule.
This is almost certainly not needed. This is what the LWT topics and messages are for. Configure the MQTT Broker Thing with:
Heartbeat: 60
Last Will Message: OFFLINE
Last Will Topic: openhab/status
Last Will QOS: 2
Last Will Retain: on
Birth Message: ONLINE
Birth Message Topic: openhab/status
Birth Message Retain: on
Shutdown Message: OFFLINE
Shutdown Message Topic: openhab/status
Shutdown Message Retain: on
With this configuration, when OH comes online and connects to the MQTT broker, it will publish ONLINE to openhab/status. When OH starts shutting down the MQTT broker Thing, it will publish OFFLINE to openhab/status. And if the heartbeat between OH and the MQTT broker fails, the MQTT broker will publish OFFLINE to openhab/status.
All of these messages are retained so at any given time, subscribing to this topic will tell that client the current online status of OH even if that client wasn’t subscribed when OH/the broker published the message.
In short, heartbeat functionality is built into MQTT. you don’t need to implement this yourself.
It’s a tangent to go into an in-depth explanation of why it’s needed, but the heartbeat is a signal to a separate system/network, and isn’t for OH or the mosquitto broker’s benefit. Using the LWT messages from OH means I just have to implement the 5s periodic signal elsewhere, so currently its more convenient to get OH to do the logic.
The rule is a main UI based rule, it uses a cron trigger, and then runs an inline script:
That’s all there is to it. At least to my understanding this script is pulling the broker object on each run. So to recap, whatever the JS engine has cached or compiled, the object pointed to by :
The code looks innocent. However, it’s possible that the cron job ran before the MQTT Binding had loaded, and the MQTT Thing have had a chance to initialize. It is particularly during an upgrade that the new version of the binding had to be downloaded first and then openhab usually restarts itself too.
You could try guarding it against this situation (null) to avoid seeing the errors. Something like
The whole purpose of the LWT is for the other system’s benefit. OH already knows if it’s online or not and the broker doesn’t care if OH is online or not. The LWT is there to advertise to other systems whether OH is online or not.
The 5s periodic signal is implemented in the MQTT broker and it’s a core part of the MQTT protocol. MQTT implements the heartbeat signal for you.
The other system would just need to subscribe to the LWT topic same as any other topic. If OH goes offline it will receive an OFFLINE message immediately on that topic. As long as the message on that toipic is ONLINE, openHAB is online and connectd to the broker. So instead of relying on a message every five seconds, the other system just needs to check the content of the message when it’s received.
The polling/checking is provided for you by MQTT. You don’t need to implement the periodic check yourself anywhere. You just need to look at the message.