Getting a deterministic item state from postUpdate (equivalent to "receivedCommand")

Tags: #<Tag:0x00007fe05e0a3688>

(B K) #1

From an old topic about rule variables:

This is driving me crazy right now - I’ve got two MQTT events (button presses) coming in with an “ON” state, followed by “OFF” (with a time delta determined by the length of the button press). I can definitely see the issue of “non-determinism”, as evidenced by the log entries below:

2019-02-10 21:26:32.642 [vent.ItemStateChangedEvent] - HASP_Plate03_Plate_State_JSON changed from {"event":"p[2].b[6]", "value":"OFF"} to {"event":"p[2].b[5]", "value":"ON"}

2019-02-10 21:26:32.648 [vent.ItemStateChangedEvent] - HASP_Plate03_Plate_State_JSON changed from {"event":"p[2].b[5]", "value":"ON"} to {"event":"p[2].b[5]", "value":"OFF"}

2019-02-10 21:26:32.657 [ome.event.ItemCommandEvent] - Item 'HASP_Plate03_Plate_State_JSON_Value' received command OFF

2019-02-10 21:26:32.671 [ome.event.ItemCommandEvent] - Item 'HASP_Plate03_Plate_State_JSON_Value' received command OFF

I need to handle the ON event, but ignore the OFF event in my rule logic, but button presses that are too quick, are both being ignored (since the ItemCommandEvent is OFF for both).

Is there an equivalent to “receivedCommand” for “item changed” or “item received update” rule triggers?

Edit to add: Re-entrant lock didn’t work in this case, either…

(Rossko57) #2

It’s not really clear what you are doing. You get some JSON sent into a text Item? And the JSON might change while you are processing it in a rule?

EDIT - looking more closely at the log shown, Item state changes within 6mS.
openHAB is never going to deal very gracefully with that, it’s not intended to be a real-time system. Whatever is the source of this?

(Udo Hartmann) #3

Yes, that’s correct.
As an Item received a command, it’s very likely that it may change its state.
But that will happen asynchronous - either (autoupdate=“true”) because openHAB is setting the state according to the sent command - or (autoupdate=“false”) because openHAB receives a state update from elsewhere after sent command.
So, you can’t predict when the state is updated or changed. When the trigger is received command, only use receivedCommand. triggeringItem is ok, but not triggeringItem.state.
On the other hand, when a rule was triggered by received update or changed, you may use previousState or triggeringItem.state, as it’s unlikely that the state may change a few millis after a change again.

(B K) #4

But therein lies the problem - my item state is changing very fast (quick button press with both the ON and OFF events sent out) - the proper way to deal with this for commands is to use the receivedCommand variable, which holds the instance of the item state when the rule is triggered- so I could deal with both events at the rate the rule engine fires each rule (asymchromously to item state changes). I’m just realizing that there is no equivalent state buffer for update triggers - shouldn’t there be?

(B K) #5

But it’s set up to deal with this if the item receives a command (receivedCommand holds an instance of the state, unaffected by future changes). It doesn’t appear to have the same type of buffer for item updates, though.

The source of this data is the HASP (Home Automation Switch Plate (HASP) - DIY touch controller) - which I’ve recently modified to send all button events via a single MQTT topic. I was hoping to use the OFF event for possible future improvements (long button press actions,for example), but I am only sending the rising edge (ON) event for now as a workaround to this issue.

(Udo Hartmann) #6

Not true :slight_smile: receivedCommand holds the received command, not the state.

Think of a dimmer Item. A dimmer Item will always have a state of type number (0 to 100) or NULL (which is, the Item is not initialized yet)
But the commands are either ON,OFF, INCREASE, DECREASE or a Number 0 to 100. The state will never be INCREASE nor DECREASE.
You could get a state ON or OFF when using .getStateAs(OnOffType), but you will never get INCREASE or DECREASE, because that’re commands, not states.

(Rich Koshak) #7

The big problem is that commands are events unto themselves on the event bus. Changed and updates are events that only take place after the Item processes the event. There are no pre-update event and pre-changed events. There will always be a bit of a delay and events that occur this close together cannot be guaranteed they are processed in order.

Can you use commands here? If there is only 6 ms between events I have no reason to believe that even those will be processed in order but you can get closer that way.

Do you have control over the source device and can you do some processing there? Maybe detect the long-press/short-press there and send “short” and “long-start” “long-stop” events from the device or the like.

Udo said it better.

To elaborate a bit in a different direction though, because the command is an event itself, it carries the command. Your received command Rules will trigger based on that command event but, because we cannot guarantee that the Item can, has, or will ever actually become the state it was commanded to (e.g. autoupdate=false and the device failed to process the command), we need the receivedCommand implicit variable to see what the command was. But for changed and received update the Item has already processed the event so MyItem.state will reflect the update/change.

(Rossko57) #8

Is that the nub for your project? Doing just that is very easy.

rule "blah"
   Item xxx received command ON

But … you haven’t got commands, you’re updating a String item with a chunk of JSON ?
Why not use the MQTT binding, a transformation if necessary, and postCommand option to actually send the wanted ON/OFF to an Item?

On this topic:

Nope, it’s still not going to deal well with commands streaming in at 6mS intervals. receivedCommand might appear to be consistent within a rule - but by the time you get to the end of rule it isn’t really any longer, because a new-most-recent-command has arrived. Another copy of the rule is already processing that in parallel.
Might not matter depending what you are doing, but it is not truly safe and consistent.

This is not what receivedCommand was intended for. Consider sending a Number Item a command “22.3”.
When triggering a rule off that command, the value of the command isn’t available anywhere else.
For simple switches we could workaround, and have a rule triggered by command OFF, another rule by command ON, etc. but that’s clearly a non starter for selecting 22.1 , 22.15, 22.2 etc.
receivedCommand gives the appearance of “capturing a snapshot” but that’s how it works, not what it’s for.

There’s no receivedState analogue, because it’s not needed for that purpose, state is freely available. There is a previousState, because that, like command,is not readily available.

For practical purposes,

rule "blah"
    Item xxx updated
    val captureState = xxx.state

If that’s not quick enough, you got fundamental problems :smiley:

(B K) #9

Thanks all :slight_smile:

I have a better understanding of the difference (subtle it may be) between state and command now…My frustration stemmed from the fact I was trying to do too much with a single channel. Part of that is due to the fact I’m a hardware guy trying to force software to work my way…In my world, I/O takes priority (interrupt driven), change of state is honored and always synchronous and Nyquist rules (in fact, this is a perfect example of aliasing due to low sampling rate). Anyway, I’ve removed the OFF state from the possible message states, the ON state still works perfectly, and I can do what @rlkoshak suggested in the hardware device for determining/reporting long-press actions.