[SOLVED] Refresh Rule with Update Rule - habpanel race condition

I’m querying an api every 10 seconds to get the status of switches using exec and a rule to tranform the json response when the ouput channel gets changed.

I am also using the exec binding to post to the api when for instance a switch gets changed.

What really grates me, is if i update a switch in habpanel to off, the refresh rule may have just got the result but the rule hadnt finished executing. The switch therefore returns to its previous state until the next refresh pass ( 10 seconds later).

How do others deal with this so that the switch doesnt ‘freak out’…

'Ive considered:
some form of lock item
while loops
using the REST api to disable the thing for say 11 seconds.

Im sure there are others out there with a valid workaround.

If your switches support SNMP Traps that would be less resource intensive on your server. You could then check periodically (10 minutes or more) in case the UDP trap packet is dropped.

Hi, It’s a remote api, not internal.

Set autoupdate=false on those Items. Then the Item shouldn’t change state until the API reports that it changed state. With autoupdate=true (the default) OH takes an educated guess as to what the Item’s new state will be as a result of the command and immediately sets the Item to that state. But realize this will mean that the Item will still show as the old state until the next time the API is polled.

There really is no way to deal with this short of coming up with some other way to communicate with your devices or tightening the polling so it’s fast enough that the inconsistencies are not that noticeable.

1 Like

If you disable autoupdate on your Item, this will get rid of the “flapping”. When you send a command, the state will remain unchanged until the next routine update.

What you might well find unacceptable, is you would then have an up to ten second delay before the “new” state gets shown on your UI.

You might be able to issue a REFRESH or otherwise force an prompt data fetch for the “new” state, but we don’t know how you’ve implemented polling to begin with. A sort of “hurry up”, bringing the next scheduled poll forward would be effective.

Alternatively, a delayed “autoupdate” effect could be created, where you schedule a state update derived from the command for, say, a half second later - after any recent data fetch has settled down.

So ive played about and have a working solution to my problem, bit clunky but it works and I have no more freaky habpanel. (single item example)
i have created a proxy item for each item in play here to act as a lock (string)

Switch  Lightwave_BBarLeft_switch "BBar Left" <switch> (GroupGroundSockets)
String  Lightwave_BBarLeft_switch_Lock 

exec is collecting json every 10 seconds:

Thing exec:command:LwGet [ command="sh /share/QPKGs/OpenHab/conf/scripts/Lw_Get.sh %2$s", interval=6,timeout=10, autorun=true ]

when the output is changed a rule fires to go through all the items and post updates if its not locked:

`if(Lightwave_BBarLeft_switch_Lock.state.toString == ""){if(transform("JSONPATH","$.5c7d64783c570522afb151b5-76-3157331848+1", Readme) == "1"){Lightwave_BBarLeft_switch.postUpdate(ON)} else {Lightwave_BBarLeft_switch.postUpdate(OFF)}}

In the meantime, my rule to update on change is like so to add the lock:

//BBar Left switch Rules 
rule "BBar Left switch Rule" when Item Lightwave_BBarLeft_switch received command then 
val temp = now
Lightwave_BBarLeft_switch_Lock.postUpdate(temp.toString)
if(receivedCommand==ON){LwUpdate_Inp.sendCommand("5c7d64783c570522afb151b5-76- 3157331848+1 " + Access_Token.state.toString + " 1")}
else if (receivedCommand==OFF){LwUpdate_Inp.sendCommand("5c7d64783c570522afb151b5-76-3157331848+1 " + Access_Token.state.toString + " 0")}
createTimer(now.plusSeconds(10),[|
if(Lightwave_BBarLeft_switch_Lock.state.toString == temp.toString) 
{Lightwave_BBarLeft_switch_Lock.postUpdate("")}])
end

so this puts the current date/time in a variable.
it posts this to the lock proxy item.
it then updates the api (right now if the refresh rule runs it cant update the item as its locked)
i then run a timer equal to the interval of the refresh rule to make sure it doesnt pass values.
when this timer finishes it takes the lock off, only if the date is still from this run, this way if the state is changed again then the next run would remove the lock

obviously the downside is that if i change the switch in the devices app or manually on the switch then it wont hit openhab for upto 10 seconds, however this is only if the state has been changed from within openhab at basically the same time, probably not going to happen tbh.
I also chose to do this on a ‘per item’ basis rather than the whole refresh rule as then things such as the current power usage will still update

You might consider the “hurry up and get the new status” method, this is possible alongside exec binding auto-polls.

Assuming the end device new status available promptly, and does not mess up

Needs a new Switch type Item linked to existing exec Thing run channel

...
   xxx.sendCommand(blah)
   createTimer(now.plusMillis(300),[ |
      if (execSwitch.state != ON) { // skip if already in progress
         execSwitch.sendCommand(ON)   // do extra poll
      }
   ])
...

That would run with the last used %2 parameter; if you needed to alter that you could instead do something like

    execInput.sendCommand("your param")  // will trigger autorun

but note that only works if input content actually changes.

Cool cheers for that.
That’s a quick way of doing it, does have the pitfall of making the habpanel icon flicker tho and as I’m already down low (6 second minimum intervals to stay in the green) I’m going to hit the api limit with the extra call and get a 404 :grimacing: