Piston reading stale door sensor value when triggered by a timer?


#1

1) Give a description of the problem
Recently added a new door sensor to a piston. The piston seems to be using “stale” state from that sensor when it is triggered by a timeout, and therefore evaluating incorrectly. I am puzzled why this would be.

2) What is the expected behavior?
I expect the most recent (“live”) state of the door sensor to be used when the piston triggers by an subsequent timeout event.

3) What is happening/not happening?
A timer checks that the door has not been open for 45’, and if it has then notifications are sent. (This is on line 32 of the attached piston screenshot.) What seems to be happening is that when the timer expires, the wrong state of the door sensor is used and the notification condition is incorrectly satisfied.
The IDE logs show that the door sensor does change to “closed” (after bouncing open briefly), and should be in the closed state when the piston evaluates from the timeout. The piston’s logs show that the previous state (5:56:10 AM) from the contact was “open”, with no subsequent “closed” state activity being seen.

I would think that the latest and greatest live state of the sensors would always be used (in line 28 of the piston) when the timeout occurs (at 6:41:09 AM in the log) … apparently that is not happening.

I can add some type of workaround, but I’d prefer understanding why this is happening first.

BTW, the other two door sensors read closed through the events, so they are not involved in the problem.

4) Post a Green Snapshot of the pistonimage

5) Attach any logs (From ST IDE and by turning logging level to Full)
4/3/2019, 6:41:09 AM +72ms
+0ms ╔Received event [HayekHome].time = 1554298870626 with a delay of -1555ms
+188ms ║Runtime (44911 bytes) successfully initialized in 124ms (v0.3.10a.20190223) (186ms)
+189ms ║╔Execution stage started
+219ms ║║ TIMEOUT EXPIRED IN INNER LOOP
+220ms ║║Executed virtual command log (1ms)
+286ms ║║Executed virtual command sendPushNotification (49ms)
+295ms ║║Executed virtual command setVariable (4ms)
+398ms ║║Executed [Echo - Family Room].setVolumeSpeakAndRestore (91ms)
+436ms ║║Executed [Echo - Master Bedroom].setVolumeSpeakAndRestore (35ms)
+474ms ║║Executed [Echo - Media Room].setVolumeSpeakAndRestore (34ms)
+577ms ║║Executed virtual command sendSMSNotification (24ms)
+586ms ║╚Execution stage complete. (396ms)
+587ms ╚Event processed successfully (588ms)
4/3/2019, 5:56:10 AM +399ms
+2ms ╔Received event [Garage Door - Ctr].contact = open with a delay of 138ms
+181ms ║Runtime (44915 bytes) successfully initialized in 124ms (v0.3.10a.20190223) (178ms)
+182ms ║╔Execution stage started
+210ms ║║Executed virtual command setState (1ms)
+232ms ║╚Execution stage complete. (50ms)
+234ms ║Setting up scheduled job for Wed, Apr 3 2019 @ 6:41:10 AM PDT (in 2699.994s)
+245ms ╚Event processed successfully (245ms)Preformatted text

IDE LOG SHOWING THE CONTACT “BOUNCE” EVENT:

2019-04-03 5:56:10.309 AM PDT
4 hours ago
DEVICE contact closed Garage Door - Ctr was closed
2019-04-03 5:56:10.261 AM PDT
4 hours ago
DEVICE contact open Garage Door - Ctr was opened
2019-04-03 5:56:10.026 AM PDT
4 hours ago
DEVICE contact closed Garage Door - Ctr was closed

REMOVE BELOW AFTER READING
If a solution is found for your question then please mark the post as the solution.


#2

I usually place the trigger first, and the conditions below it. Something like this:

IF Motion's motion stays inactive for 45 min     <-- Trigger
Then
    IF any of Contact Sensor 4, 1, or 2 is open  <-- Condition
    Then
        Do stuff
    END IF
END IF

With this method, the conditions are not checked until after the trigger fires.


Pro Tip :
If that door is prone to vibration when closing (close/open/close), then you can add a 1 second wait right before the 2nd IF (to give the door a moment to settle down)


#3

In my application, the true “trigger” is the door being opened, after which the watchdog timer based on motion is started.

But the problem I have seems to be an invalid state of the sensor being used by the piston for reasons I don’t understand.


#4

Wellllll… To be honest, you forced a condition to become a trigger (line 28)… and then placed a trigger inside another trigger… (which is usually a recipe for disaster)


#5

So nested triggers are subject to invalid results of sensor state tests?


#6

The way I look at it is this:

  • A trigger is only true for a brief moment, and then returns to being false.
  • A condition can be true for long periods of time.

When you have a precise trigger inside a precise trigger, the odds are against you that they will both be true simultaneously.

This is why my recommendation is to place a precise trigger first, and the conditions below it.


#7

OK. So I just need to add a condition type qualifier to the inner timer test.

Or restructure the trigger based on the door state change to kick things off (not sure there was an appropriate one available, which is why I used the condition then forced subscribe).

(It doesn’t make logical sense to me to trigger starting the piston based on the inactivity timer.)


#8

I would go with restructuring…

IF Contact changes to open
is a great trigger to simply set the piston state.

Then you can use the sample code I posted above (in a new block) to do the real work.


#9

But isn’t this the exact moment that you want stuff done?!?
(after 45 minutes of no activity)


#10

I’m checking for the door being open for 45’ with no activity.

It should be more efficient to wait for the door being opened to start checking for the error condition, since a door opening is a relatively infrequent event as compared to 45’ of inactivity. 45’ minutes of inactivity happens all the time in that area.


#11

I understand. I guess my logic is it is worth 10 ms of processing power for this:

IF Motion's motion stays inactive for 45 min     <-- Trigger
Then
    IF any of Contact Sensor 4, 1, or 2 is open  <-- Condition
    Then
        Do stuff
    END IF
END IF

If all contacts are closed at the 45 min mark, then the piston immediately stops executing.


At the risk of stating the obvious…
I should probably mention that this trigger can not fire more than once for every 46 min.
(the countdown resets each time it sees activity)


#12

That code would “Do stuff” if the sensor was open when the timeout occurred.
What I want is to “Do stuff” if the sensor has been open for the duration of the inactivity time period.

So the trigger itself is somehow an “AND” of the two.


#13

If your motion sensor and contacts are not near each other (meaning possible conflict), then I think you will have to use additional variables to complexify your piston even more.


#14

My original code is close to working correctly. All I need to do is (re) check the current “correct” state of the physical sensor in the inner code section where the decision to send notification exists.

Is there some reason a simple “if contact sensor is open” should not accomplish this?


#15

Thinking outloud here:

IF any Contact stays open for 45 minutes
    Then Set variable {contactOpened} = true
    Wait 1 sec
END IF

IF Motion stays inactive for 45 minutes
    Then Set variable {motionInactive} = true
    Wait 1 sec
END IF

IF {motionInactive} = true
   and
   {contactOpened} = true
Then
    Do stuff
    Set both variables back to false
END IF

#16

I do not code the way you have here… but it is easy for you to test


#17

Fair enough. I was really asking more about how the system works than coding style, but I was not being clear. I have always assumed that condition tests check the latest reported sensor data, but the problem I ran into with my piston suggests that is not always the case. And not with triggers as you noted.

I guess I did not realize that the “always subscribe” setting for line 28 (a conditional test) had the side effect of making that a trigger. I thought that subscribe simply ensured the piston was called when any changes to the subscribed things happened. The piston seemed to “miss” the change in state of the subscribed event (i.e. final change to “closed” state of that sensor). So this seems more like a bug to me than a trigger vs condition choice problem.

Thanks for your time trying to help!


#18

You have perfectly described a trigger.


One additional note is that any trigger (or subscribed device) will run thru the entire code (from top to bottom) whenever the device changes in either direction.

For example:

IF Switch changes to on  <-- Trigger
    Then do "X"
END IF

With Location
    Do "Y"
END WITH

“X” will execute only when the switch changes to on
“Y” will execute for both events (switch changing to on or off)


#19

I knew the entire code (or piston) was executed on subscribed events, but I now think I understand a different subtlety. When subsequent top to bottom executions happen, triggers unrelated to the latest triggering event are NOT re-evaluated.

In my example, line 28 is a such a “trigger” (even though it is shown as a condition which subscribes to the event). When line 32’s events (i.e. the timeout) trigger the piston to fire again, line 28 is not re-evaluated even though the piston executes top to bottom.

Did I get that right?


#20

Untested on my end, but from what you have described, it sounds like you may be right.

I never experience that with conditions inside of triggers, but with this inverted logic (apologies) it may do just that.

IE: Line 28 (+) is definitely a trigger, but it may also be seen as a condition…