Startup rule publishMQTT' is not a member of 'org.eclipse.smarthome.core.thing.binding.ThingActions

after Openhab2 starts I see the following message in my log is this just a startup issue or have I coded the syntax incorrectly as it doesn’t complain when I save it now

openhab.log
Error during the execution of startup rule ‘Garage Initialisation’: ‘publishMQTT’ is not a member of ‘org.eclipse.smarthome.core.thing.binding.ThingActions’; line 23, column 5, length 64

which is from the following rule file:

rule "Garage Initialisation"
when
	System started 
then
    val mqttActions = getActions("mqtt","mqtt:broker:mqttbroker")
    mqttActions.publishMQTT("sensors/garage/command/door1", "STATUS")
	mqttActions.publishMQTT("sensors/garage/command/door2", "STATUS")
	
end

Hi, are you sure, you want to publish to your sensors in this rule? In this case, when system started, you’ll publish to your sensors the command “STATUS”. Usually this is an automated message, what the sensors send periodically to the MQTT broker. In this case this rule is unnecessary. Sensors usually send periodically telemetry (TELE) messages with the current state. If you define this topic under your .things file, the item states will refresh based on this kind of message. My sonoffs with tasmota firmware send this status messages in every 5 minutes.

yes I need to know status, as this is my custom sensor,
I want to report the status of a door when I boot openhab

Have you tried delaying the the rule with a timer? It could be that the rule is loaded and triggered before the mqtt binding finished loading. I think I remember something similar happening to me before mostly switching to jython and for me it was related to the early fire of the rule.
So I would try to delay the execution of the publish after the system started trigger for a minute or two whith a timer.
Maybe this helps.
Johannes

Are you certain you have the MQTT 2.x binding installed and properly configured?

Which version of OH are you running?

The more “correct” way to achieve this using MQTT is to use retained messages. Your sensor publishes it’s state as a retained message. When OH comes up it will retrieve that retained message and set the Item with that state. OH doesn’t have to be online to get the state in this case and therefore there is no need to request the latest state.

Beyond that, this does sound like the Rule is firing before the MQTT is ready.

Doe retained MQTT work when the broker is rebooted as well? Or some brokers?

I’ll give that a qualified “yes”.

The behavior is actually a bit complicated. By default, Mosquitto saves them so they will survive a reboot of the broker. But when and how it saves them can have a lot of variability based on it’s settings. I can’t remember if I changed these parameters or if they were the default, but here is the relevant section from my mosquitto.conf.

# =================================================================
# Persistence
# =================================================================

# If persistence is enabled, save the in-memory database to disk
# every autosave_interval seconds. If set to 0, the persistence
# database will only be written when mosquitto exits. See also
# autosave_on_changes.
# Note that writing of the persistence database can be forced by
# sending mosquitto a SIGUSR1 signal.
autosave_interval 1800

# If true, mosquitto will count the number of subscription changes, retained
# messages received and queued messages and if the total exceeds
# autosave_interval then the in-memory database will be saved to disk.
# If false, mosquitto will save the in-memory database to disk by treating
# autosave_interval as a time in seconds.
#autosave_on_changes false

# Save persistent message data to disk (true/false).
# This saves information about all messages, including
# subscriptions, currently in-flight messages and retained
# messages.
# retained_persistence is a synonym for this option.
persistence true

# The filename to use for the persistent database, not including
# the path.
persistence_file mosquitto.db

# Location for persistent database. Must include trailing /
# Default is an empty string (current directory).
# Set to e.g. /var/lib/mosquitto/ if running as a proper service on Linux or
# similar.
persistence_location /mosquitto/data/

In my case, it flushes out to disk all the retained messages every half hour. Given that, it is possible that a retained message could be lost, but it would be relatively rare and unlikely.

I have less experience with other brokers like the embedded broker or HiveMQ so can’t speak to them.

Thanks for replies, I can’t really rely on mqtt or persistent has my broker would have been rebooted as well so the door state is unknown during start up or reboot. So the only reliable way is ask sensor the current door status.
so it seems I need to schedule a delayed check.
I assume openhab can’t be configured to wait for the binding to be completed to fire a rule?

Like I responded in my reply to rossko57, the message would have been saved to disk and restored on a reboot. How often they get saved out to the disk depends on how you configure it. If you want to guarantee that the retained message get’s written to disk and therefore get’s restored, for Mosquitto, set the autosave_interval to 1 and autosave_on_changed to true. Then all changes will be written to disk when they are made guaranteeing that you never miss a retained message when the broker comes back up from a reboot.

It would also be a good idea for your sensor to publish it’s current state whenever it comes up after a reboot or power loss and to publish the current state when it reconnects to the broker.

In short, with a retained message and a configuration tuned to your needs on the broker, there is no need to query the sensor for it’s current state if you use retained messages, even after a reboot of the broker.

This cannot be done.

Note the sensor and Openhab server are independent devices, so in most cases may not boot at the same time. For a reboot saving the state probably ok but if server is down for unknown time I can’t assume real state hasn’t changed.
so from my reading so far I should put a delay into startup function to get my sensor current state.

update with time throws error…

rule "Garage Initialisation"
when
	System started 
then
//	wait for 2 minutes and check door state
   	createTimer(now.plusMinutes(2), [|
		 val mqttActions = getActions("mqtt","mqtt:broker:mqttbroker")
		 logInfo("garage", "checking door state")
		 mqttActions.publishMQTT("sensors/garage/command/door1", "STATUS")
		 mqttActions.publishMQTT("sensors/garage/command/door2", "STATUS")
						])	
end

openhab.log>

   at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]

2019-06-20 18:56:43.585 [ERROR] [org.quartz.core.ErrorLogger ] - Job (DEFAULT.2019-06-20T18:56:43.563+10:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
val mqttActions
.publishMQTT(,)
.publishMQTT(,)
} ] threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]
Caused by: java.lang.NullPointerException
at org.eclipse.smarthome.model.script.engine.ScriptError.(ScriptError.java:66) ~[?:?]
at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:140) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:865) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:224) ~[?:?]
at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]
at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:772) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]
at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]
at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]
at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]
at com.sun.proxy.$Proxy166.apply(Unknown Source) ~[?:?]
at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]
… 1 more

Putting in a Timer muddles the error messaging unfortunately, just because Timers.

For diagnostic purposes, try the (usually bad practice) of just having a sleep before doing the action.

My guess is you’ll see the same error. Sure that is a good broker you have in getActions param?

I put a var timeMQ = in the beginning which seems to fix it, although it complains about it not being used.

None of what I described above assumes they are on the same device. In fact I am assuming that the broker and OH are separate because they can both be restarted independently.

Let’s say that your broker goes down but OH does not. Then your sensor changes state while the broker is down.

  1. The sensor will be unable to publish that state because the broker is down.
  2. The sensor should therefore keep trying to publish that state (or the latest state) until the broker comes back up. Or, alternatively, the sensor will wait until the broker connection is restored and immediately publishes it’s current state.
  3. When the broker comes back up, it will restore the retained messages and, depending on the retry rate very shortly thereafter get the sensor’s current state as a retained message.

This is all independent of OH. From the OH side of things, assuming the MQTT 2 binding the following will happen.

  1. OH will lose the connection to the broker and mark the broker Thing and all the Things using that broker Thing as Offline.
  2. All Items linked to those channels will be set to UNDEF.
  3. When the broker comes back online OH will get any retained messages and immediately update the Items with the retained messages on any topics that have a retained message.
  4. Because the sensor readings are retained messages, OH doesn’t have to be online to get the most recently published sensor reading. There might be a small race condition where OH connects before the sensor connects to the broker in which case OH will first get the old sensor reading and then after at most a few seconds it will get the most recent sensor reading when the sensor comes back online.

As someone who has implemented a “query the sensors for the most recent value” to solve exactly this same problem before, I can tell you, it is far more reliable, far more robust, and a much better and standard use of MQTT to use retained messages like I describe than to have OH send out a message to poll for the latest states.

Use the tools built into the technologies you are using to their best effect and you will have a better system over all.

Now what happens if OH goes offline but the broker stays online? In that case when OH comes back up:

  1. The MQTT binding will connect to the broker.
  2. It will receive any retained messages from any topics it subscribes to.

So there is no need to query for the current state from the sensors. The sensors have already published their most recent state to the broker and the broker retained that message. So even if OH was offline when the message was received, it will get that sensor reading as soon as it comes back online.

NOTE: Retained messages should not be used for command topics, only sensor and status topics.

While we are on the topic of retained messages, another good use for them is in the LWT topic. Configure your device to publish ONLINE as a retained message to the LWT topic when it comes online. The configure the LWT to publish OFFLINE as a retained message to the LWT topic when the broker detects that the device is offline. This way the LWT topic will always reflect the online/offline status of the device meaning that everyone who cares about it’s status (e.g. openHAB) doesn’t have to be online when the LWT message was published to know the device’s state.

This is one of those cases where a sleep is probably better. But I’m not 100% certain that this will work either. The problem is I don’t know if the context of the Rule get’s updated while the Rule is running. So if the Rule starts running before stuff has come up to the point where the publishMQTT is known before the sleep, I wouldn’t expect that it will exist after the sleep either, no matter how long the sleep is. But it might work in this case since we are going through an Action to get access to the publishMQTT action so the context may not matter that much.

What you would need to do is probably create a Timer that sends a command to an Item that kicks off another Rule after the timeout instead of trying to do it all within the System started Rule. It would probably be safest to use the Expire binding for the Timer in this case.

1 Like

I’m suggesting the sleep goes before the getActions. It’s a diagnostic move in case the binding that provides the actions is lazy at system start.

Yep, that is what I assumed. What isn’t clear is that whether getActions gets “updated” as the stuff going on in the background eventually loads publishMQTT or whether getActions is “fixed” for that run of the Rule in which case neither the sleep nor the Timer will work.

I suspect the sleep before the getActions will work just fine though.