Stuck again --not sure why will not do while loop


1) Give a description of the problem
My goal is to start a piston when garage door is open, wait a period of time and then start checking whether there is no motion and then close the garage door.

looking at trace it does not go into while loop…but I cannot see why… the contact is open

2) What is the expected behaviour?
Should go into while loop where it would check if enough time has passed with no motion and then do a CLOSE

3) What is happening/not happening?
skips right over while loop

**4) Post a Green Snapshot of the piston![image|45x37]


5) Attach logs after turning logging level to Full
5/22/2020, 8:07:48 PM +95ms
╔Received event [Home].time/recovery = 1590196068094 with a delay of 0ms
║RunTime Analysis CS > 45ms > PS > 63ms > PE > 28ms > CE
║Runtime (40969 bytes) successfully initialized in 63ms (v0.3.110.20191009) (137ms)
║╔Execution stage started
║╚Execution stage complete. (3ms)
╚Event processed successfully (145ms)
5/22/2020, 8:07:36 PM +447ms
╔Received event [Home].execute = recovery with a delay of 36ms
║RunTime Analysis CS > 16ms > PS > 18ms > PE > 14ms > CE
║Runtime (40953 bytes) successfully initialized in 18ms (v0.3.110.20191009) (49ms)
║╔Execution stage started
║║Cancelling condition #2’s schedules…
║║Condition #2 evaluated false (7ms)
║║Cancelling condition #1’s schedules…
║║Condition group #1 evaluated false (state changed) (8ms)
║║Condition #16 evaluated false (5ms)
║║Condition group #15 evaluated false (state did not change) (6ms)
║╚Execution stage complete. (23ms)
╚Event processed successfully (75ms)
5/22/2020, 8:04:03 PM +689ms
╔Received event [GarDoor (doorControl1)].contact = open with a delay of 70ms
║RunTime Analysis CS > 18ms > PS > 28ms > PE > 15ms > CE
║Runtime (40974 bytes) successfully initialized in 28ms (v0.3.110.20191009) (62ms)
║╔Execution stage started
║║Comparison (enum) open changes_to (string) open = true (1ms)
║║Cancelling condition #2’s schedules…
║║Condition #2 evaluated true (5ms)
║║Cancelling condition #1’s schedules…
║║Condition group #1 evaluated true (state changed) (7ms)
║║Cancelling statement #3’s schedules…
║║Executed virtual command setVariable (4ms)
║║Executed virtual command wait (0ms)
║║Requesting a wake up for Fri, May 22 2020 @ 8:07:03 PM CDT (in 180.0s)
║╚Execution stage complete. (31ms)
║Setting up scheduled job for Fri, May 22 2020 @ 8:07:03 PM CDT (in 179.996s)
╚Event processed successfully (104ms)Preformatted text


If a solution is found for your question then please mark the post as the solution.


I think what is happening is when the first 3 minute wait is over your condition has changed.

In the first trace @ 8:04 everything is ok. Then at 8:07 after the if contact sensor is changing to open is no longer valid, because it is open.

I think setting the TCP to never cancel for the IF would fix it. I am still getting the hang of the Task cancellation policy but I believe that is the problem.

{edit}On further review I think moving the first wait inside the do loop would fix it as well.


Also notice how both “failures” are listed as a “recovery”…
(IE: they did not properly run on schedule)


simple if / then statements works great.
as soon as i put a wait in, things go south
i have a few questions about how it really works …
I’m used to following the flow of code as I see it
so it would seem that if #2 is true, i fall to 19 and 4 (timer)…when 4 timer is done I expect to go to next statement down,the while loop#5 … is that true? if not why not? It seems like if it doesn’t follow top to bottom and wait at delays it will be hopeless to write anything complicated and get it to work.
When I was testing I would see #16 be true but #18 not get executed… is there anything (i.e. executing code in above if/then block that would prevent #18 from getting executed?


Basically with a wait, the program is halted and a timer is set to re-excute the piston after the wait is over. Webcore is not straight line, every time a trigger occurs things can change on you.

Here is a pretty good discussion about waits started by non other that the resident expert WCmore.

Also this discussion on triggers and conditions is helpful.


Thanks for the response…I read through the information and I’m unfortunately still confused.
I still don’t understand why webcore would WANT to start over because there was a timer…why wouldn’t it schedule a timer and when the time expires go to the next line. Who cares if ANY conditions already evaluated changed…If I cared I could test those things after the wait.
I read through the conditions and triggers but still also curious about my second question
#16 be true … is there anything that would prevent #18 from getting executed? I guess its asking if there is several if checks will then each get evaluated if the IF condition triggers…


If I may interject here… Most of the time, we want the conditions checked after the timer.
(IE: it is normal to abort if things change)

Nope. Each time the sensor is INactive, and changes to active, that variable will be set.
(you have not shown us a log for the motion sensor yet)

This also means if you do jumping jacks in front of the sensor for 20 minutes, the time stamp will only change when you first enter the room. It is important to keep in mind that during activity, the variable will be static, showing old data.

IE: {lastMotionPlusDelay} will not be updated until after motion goes inactive, and then active again.

The command “Log to console” is your friend, and a great learning tool to determine this.
(you can stick in one inside each THEN block to easily see what is happening behind the scenes)

If the logic is complex, I may add one before the WAIT, and another after.


you guys are rock stars to keep answering my dumb questions…
and thanks for the Log To Console idea that should help
still struggling with the webcore mechanisms …seems like there should be an option to go top to bottom…since sensor events can require multiple things in order

for example if piston checked for A happens then B happens, then C happens and now I wait… when I get done with the wait, I dont expect A to be true anymore… so if i go back to the top…i fail …like what happened in my piston above…the “contact changes to open” is no longer true- fail

last… maybe I’m just approaching this all wrong… how would you experts accomplish …

“If garage door IS open after 8pm and no motion for the last 30 mins, close the door”

so obviously if there was motion 7:59, then the door would have to wait to close at 8:29 …and if there was any motion before 8:29, the time gets moved out 30 mins…


like in embedded systems…if there is a delay/sleep, the OS does swap tasks for the duration but then it resumes on the next set of instructions…it doesn’t start at the beginning of the program again


The piston is running in the SmartThings cloud and is allowed twenty seconds runtime. In order to avoid running out of time, any wait over five seconds is always implemented by setting a timer and exiting rather than going into a busy loop. When the end of wait timer event occurs a new instance of the piston starts up, figures out that it was in a wait (it was a ‘scheduled task’), fast forwards to where it was, and continues with the next line. No re-testing of conditions or anything. So it basically works as you describe, but has to stop and start to avoid the runtime limit. Except …

If the piston happens to be fired again (for any reason) while the piston is in a long wait, a new instance starts up and runs from the top. This time it may take a different path through the code and do something different. However what does the piston do about the scheduled task? Does it assume it is still needed, even though the conditions that caused it to be created are no longer true, and leave it alone? It could do. However what it actually does, by default, is to assume it is no longer needed and cancel the scheduled task so that when the timer fires there is nothing for it to do.

Personally I think that makes sense as a default. If it isn’t what you want to do you just tell it by changing the Task Cancellation Policy on the affected task so it continues after the wait regardless.

There are other instances where the piston has to choose. If you have a simple piston saying ‘wait ten seconds, do something’, and you hit the Test button on the piston, then five seconds later hit the Test button again, what do you expect to happen? Do you want the ‘something’ to be done after ten seconds and then again five seconds later? Or do you want the wait to effectively be reset and the ‘something’ to just be done after fifteen seconds. The default is the latter (but that is called the Task Scheduling Policy and you can choose).

One of the joys of webCoRE is that it can handle things like that.

All of which is a bit of a distraction from the original post, where as @WCmore points out, you had recovery events. That just means the timer events weren’t received because something went tits up with SmartThings, and webCoRE realised this and sent its own events to your piston to try and help.


Ahhhhhhhhhhhhh…that makes sense … so I change to TCP to never and added some extra logging…but I have one new weird issue… I’m not getting any #xx numbers associated with my lines (at the end of lines)… I even tried on 2 browsers…any ideas


Excellent description @orangebucket

You can turn on Trace to see these numbers.


THANKS !!! I knew it had to be something simple : )


I think I finally got it…what was key is understanding Task Cancellation …thanks to all for explaining it over and over again.
The Log To Console really helped also
I think I was hitting the recovery because I was in a loop and it was just spinning…by adding in a little delay I think I have resolved it.
Thanks again !!