Rule trigger speed issue, missing status updates

I have multiple IOT devices that I regularly want to check for available FW updates. By sending a MQTT announce command (MQTT binding v1.1), all devices will send their configuration states. All MQTT status updates are logged in the openhab event logfile (and thus properly received). As I want to know all results I try to add them into a single string using a rule.
The resulting string does however not contain all results, some are missed. As all IOT devices send their status updates close to eachother, I’m wondering if the rule that is triggered multiple times can cope with all the updates.

String announce_reply "announce reply [%s]"
    { mqtt="<[mosquitto:devices/announce:state:JSONPATH($)]" }
rule "yetanothertest"
when
	Item announce_reply changed
then
	updatelist=updatelist+announce_reply.state
	logInfo("test.rules", "Update string: " + updatelist)
end

How would I change implementation such that it does work?

Thanks

If you’re expecting a flood of changes to announce_reply, there is a flaw in your rule where the Item’s state may be changed between triggering and retrieving state in the rule body.

Using one of the rule systems implicit variable may improve the odds of capture? But there isn’t a receivedUpdate variable.

It might be worth trying to exploit Group trigger mechanism - put your Item in a Group of one ; trigger from Member of ... changed ; use triggeringItem.state in the rule. I don’t know if that gives you a solid capture.

Hi @rossko57

Thanks for the reply. I was exactly thinking in the same direction as you. Did not think about the group sollution though. I tried it but it does not work, Looking back, this is obvious, the implicit variable point towards the triggeringitem not to the triggering state (which in the background might still change as it most likely did before).
So any other tips are very welcome…

This may be a case where a lock might help

As soon as I enter the line

include java.util.concurrent.locks.ReentrantLock

as was mentioned here: Explain lock() command? by @rlkoshak my rules file does not compile anymore. I’m not known with including java packages inside openhab rule definition files. Am I overlooking something?

include java.util.concurrent.locks.ReentrantLock //AT THE VERY TOP OF THE RULES FILE

rule "yetanothertest"
when
    Item announce_reply changed
then
    try {
        stompingLock.lock()
	updatelist=updatelist+announce_reply.state
	logInfo("test.rules", "Update string: " + updatelist)
    } catch(Throwable t) { }
    finally {
        stompingLock.unlock()
    }
end

That’s what I have, but only the include line already makes the rule file not compile anymore.

Maybe I should add that I do not have an openhabian installation but a Package Repository Installation, so I might miss some addons?

The syntax has changed,
Rick’s post is old:

import java.util.concurrent.locks.ReentrantLock //AT THE VERY TOP OF THE RULES FILE
val ReentrantLock stompingLock = new ReentrantLock

rule "yetanothertest"
when
    Item announce_reply changed
then
    try {
        stompingLock.lock()
	updatelist=updatelist+announce_reply.state
	logInfo("test.rules", "Update string: " + updatelist)
    } catch(Throwable t) { }
    finally {
        stompingLock.unlock()
    }
end

Unfortunately it does not work. The times the rule is executed is now equal to the amount of replies. As the state change is not influenced by the rule I still get missed or double entries in log file
The missing link seems always to be the missing state information during trigger

The lock won’t address what we think is the problem, it can only confine the rule to one-copy-at-a-time processing. Doesn’t help with the case where an Item state is being rapidly changed during rule execution.

Conversely, it will help with the other potential problem I’ve just spotted … multiple copies of the rule each updating the shared updatelist variable with their own version of the text and destroying each other. That definitely needs a lock.

rule "yetanothertest"
when
    Item announce_reply changed
then
    val grab = announce_reply.state
        // capture as quick as we can and before queuing
    logInfo("test.rules", "Captured: " + grab)
    try {
        stompingLock.lock()    // queue for processing
	updatelist=updatelist + grab
	logInfo("test.rules", "Update string: " + updatelist)
     } catch(Throwable t) { }
     finally {
        stompingLock.unlock()
    }
end

There’s a system thread limit on how many rules you can queue up with a grabbed state. Others won’t get started and so won’t do the grab until later. You might see a clue if that is a problem by seeing logs for processing identical states.

Grabbing the state as soon as possible was indeed a nice thing to try, but it failed.
But then again, even if it did succeed, I’m not feeling comfortable with the race conditions that exist and I am really looking for a solid sollution, which after a whole evening of search I’m slowly giving up upon.

Two main questions remain.

  • All state changes are properly logged (in event.log), so the information is there, Can I intercept MQTT on a lower level?

  • This issue seems directly related to the absence of the “item.state@trigger time” information and thus affects openhab as a whole. Any idea about a time-referenced limitation that exists?; how long should two updates be spaced apart. And more important, is there any reason why an “item.state@trigger time” has not been implemented in openhab?

Thanks!

You probably already considered and ruled out the only possible scenario I can think of: create a different trigger item for each device (using different mqtt topics based on device id), put them in a group and trigger on group members…

Any scenario involving using the same item for each device runs into the issue of state updates before or while processing the previous state, as there is no ‘item-state@trigger-time’, as you mentioned, that I am aware of.

I think it’s down to OH is not, and never intended to be, a real time system. Funneling rapid fire data through a single Item is going to be problematic. It feels like the wrong approach, as presumably OH already “knows about” your devices as separate Items.

I know nothing about MQTT v2 binding, but I wonder if it would allow for the means to gather this kind of property or feature per ‘thing’ ?

@noppes123: In the end Openhab is made to be used as you state: one item per IOT device/property. This will work and will most likely be the way I have to go due to the current limitations.

@rossko57: I agree, openhab is not a real time system, meaning it is allowed to fail when dealing with continuous streams of real time data (my own interpretation). A reasonable buffer size to cope with a realistic number of multiple triggers would make it much more robust. Without any form of buffer being present (in the form of ‘item-state@trigger-time’) openhab will always have a good chance of failing.

OH is coping fine with multiple triggers as such … as we’d hope from an event-driven system. You say you can see all the events (in this case, updates to item.state) happening and logged. It’s easy for you to count them, for example.

Your problem boils down to getting hold of some kind of snapshot of the environment that goes with each event. Specifically here, there’s a state-update event triggers the rule but you can’t reliably get the state that caused it.

I’m sure there must be other use cases that could come up. (There may be other cases that require not just the item.state, but I can’t think of any.)

This kind of race problem is already solved for a stream of commands - each rule triggered by received command gets the implicit variable receivedCommand, which so far as I can tell is a “snapshot” of the trigger event. That suggests the needed working parts for a state snapshot are probably already there.

I think it’s reasonable to raise an enhancement request asking for a similar implicit variable - let’s call it receivedState - to be made available for updated and changed rule triggers. I’ll bet it has other uses beyond the one here, OH users are ingenious. Would you like to do that?


Meantime, two suggested workarounds.

Trigger rule from item changed, and exploit previousState. You’d probably set up your receiving string Item with “start” or suchlike before beginning this ‘announce’ process. And some kind of timeout could update with a final “end” to flush out the last incoming data and allow your string-gathering rule to know that it’s all over.

Alternatively, isn’t MQTT an unusual binding allowing incoming data to be put on the OH bus as commands? so that receivedCommand can be exploited.

Hi @bartsnijder,
are the replies all different? If you trigger the rule by the changed event you probably miss updates that look identical to the previous one (the update didn’t change the state of the item). Did you try to trigger the event on received update event?
bye

Since this post was originally written, a new implicit variable newState has been implemented, which should be available for both change and update DSL rules.