Race conditions: best practices in rules?

Trying to add Xiaomi/Aqara Zigbee motion sensor (via zigbee2mqtt), I found the following issue: after some time of inactivity, when motions detected the sensor reports with 2 updates in this order:

zigbee2mqtt/0x00158d0003fb1a41 {“illuminance”:43,“linkquality”:2,“occupancy”:false,“battery”:100,“voltage”:3065}
zigbee2mqtt/0x00158d0003fb1a41 {“illuminance”:43,“linkquality”:2,“occupancy”:true,“battery”:100,“voltage”:3065}

That is there was no motion, and it is detected right now.

Since OpenHAB is multi-threaded, 2 events are subject to race conditions. And with 50% probability they arrive in opposite order. So initially the motion is detected, then immediately lost instead of correct sequence (missing -> detected).

What are the best practices fighting with such races? If OH was single-threaded, all events would come in proper order. I can ignore “false” event and use timer or expire binding to emulate “no motion” condition. But in that case I will lose the real event which may be useful. Another option is to check if interval between events is small and ignore “false” events in that case - sounds lame.

How would you recommend to handle such cases properly? Remember, it is not my device, I can’t change the reported data from this sensor. I need a method to ensure the correct order of events.

Any ideas?

Welcome to the forum! This sounds like a possible binding issue that should be reported in GH to the maintainer. Have you tried the Zigbee binding? I have not seen the issue you are reporting with that binding.

Yes you can use 2 rules with two different triggers
Or you can check for the state in the rule
Generally speaking "occupancy":false is not interesting as a trigger
Use the true trigger only and use a timer/expire binding to determine end of occupation

See:Design Pattern: Motion Sensor Timer

1 Like

I don’t think it’s a binding issue. I use zigbee2mqtt which is quite sequential in events. Also this sequence does not look impossible (while not quite logical). It is just an example, but I can observe similar effects with some Xiaomi MIIO events as well. I will check the source data, but still wonder how to ensure events processing in a specific order when all come from the SAME source and sometimes the order is significant. So this is a generic question, not zigbee-specific.

I tried to use the OH Zigbee binding but it currently does not work for me. I use CC2531 USB stick reflashed according to OH binding description with exactly that firmware (sha256 checked). The binding comes ONLINE, but cannot find any devices and does not generate events. All this on armbian on pcduino3 board, openhabian setup, 2.5-SNAPSHOT of 2 weeks old.
I also unable to login to karaf console to enable detailed debug, OH instantly disconnects after login (it was mentioned on this forum too).
I will try it later on my Mac (have OH installed for local tests), but at the moment it does not work for me on linux.

Yes, I can use timers. But as I said above, the question is generic. If some events come in order from the same source, I should be able to process them in the same order when it is important. In programming I can use many parallel threads or a single thread in such cases. But I don’t know if there is a way to implement this in OH rules.

openHAB is not intended to be a real-time system. It’s never going to be very good at dealing with rapid changes, even if you ensured your events arrived on the internal events bus in the “correct” order. (There is so far no evidence that they don’t)

For us users dealing with it, a general good-practice approach is to avoid using “static” Item states and instead using events, e.g. changed to X, Rules alow this flexibility.

I agreed, and it is an issue with this particular sensor which sends to events near at the same time. Other Xiaomi sensors do not do that (say, door sensor or wireless switch sensor). But I wish to know if there is an any options to deal with this. An answer “NO” is also the answer :slight_smile:

Not related question: what is the rationale behind of using OPEN as active for Contact, and CLOSED as inactive? I would expect to have CLOSED (button pushed) as active. Of course, it depends on contact use case, but… Is it an arbitrary choice?

Legacy from “burgler alarm” door and window sensing. Invariably these are designed so that electrical “open” indicates physical window open, basic failsafe.

Actually using this sensor events instead of states leads to the problem I explained. If I use static state, I would know that currently it is active or not. But I use events to trigger some other actions, and those events sometimes first turn off the (off already) light, then turn it on (as expected). Or they do the opposite. In case of motion sensor it is not an issue because I would want own timers instead of hard-coded 90 seconds. But in similar cases I need to know if there is any option to deal with it, or it is by design, and I really have to think better how to process them. Well, ok, got it. Thanks to all.

You are going to have to provide hard examples with time frames here. This is NOT the sort of issue routinely faced by openHAB users.

tl;dr: You can’t. Especially since you are working with MQTT on the OH side which does not guarantee the order of delivery. And even if it did, as already discussed, OH doesn’t guarantee the order of processing.

This. Since you cannot guarantee the order of arrival of the events, why not depend on how close together the events occur within OH? You can set a timestamp variable when one comes in and then check the current time with that timestamp when the other comes in. If it’s close enough, you know that the events occurred close together and you’ve detected your sequence of events, even if they occurred out of order from OH’s perspective.

Another approach is to set a Timer on the first event. If the Timer is still active for the second event you know that the events occurred close enough together.

Then code it to not do that. This is not a fundamental problem with rossko57’s approach, it’s a problem with how you’ve chosen to implement it thus far.

Were I to code something like this, give the limited amount of information available, I would create a proxy Item, probably a Switch, that goes to ON when the two events occur close together. Then I’d use the state of this proxy Item to drive the other behaviors. I’d use Expire binding to set the proxy Item back to OFF after an appropriate amount of time.

That’s exactly what I am doing now (use proxy items). Do “global” rule variables exist? Or I only can use items to store data between rule calls?

Not in Rules DSL. You have to use Items. Items have the additional benefit over variables in that they can survive a restart of OH/reload of the .rules file if configured with Persistence and restoreOnStartup.

I’ll qualify Rich’s answer a bit - yes, there are “global” variables in rules DSL but they are only global to the rules in one xxx.rules file.

In practice, you declare
var myglobal = 0
at the head of rules file abc.rules
and any rule in abc.rules can share it myglobal = myglobal + 1
but rules in def.rules file cannot.

That has many uses, even if only for preserving a value like a counter between runs of the same rule.

I’ll still ask that when you have a race condition, show us your events.log for some hard data.
Most users brushes with “race” conditions arise from a misunderstanding of openHABs asynchronous events bus.