OH! Good one. I must try that here and see what I get.
I think in this particular case, it would just reset the timer for another 2 minutes but still alert.
Yep, you are correct.
It appears to me, with Trace on, that the Piston gets to the 2 minute wait. However, as soon as it triggers again it cancels the wait and cycles again.
Yep, that’s exactly right. The piston is (re)started when any of the lightning bolt lines get activity, unless you adjust the TCP policies as suggested above. For something like a motion sensor delay, this design works great. For your case, you might have better luck coding a bit different.
I think this might work, and wouldn’t require changing the task control.
Logs from my test:
2/1/2020, 6:51:52 PM +220ms +1ms ╔Received event [Front Door Contact].contact = closed with a delay of 86ms +137ms ║Setting up scheduled job for Sat, Feb 1 2020 @ 6:53:46 PM CST (in 114.278s) +148ms ╚Event processed successfully (148ms) 2/1/2020, 6:51:46 PM +519ms +1ms ╔Received event [Front Door Contact].contact = open with a delay of 81ms +120ms ║Setting up scheduled job for Sat, Feb 1 2020 @ 6:53:46 PM CST (in 119.997s) +127ms ╚Event processed successfully (127ms)
I was trying to do something like that and just got lost in variable definitions. Does a defined boolean variable default to “false” if not assigned when defined? Does it get re-assigned to “false” each time the piston runs, or does it stay any value that is assigned in the code?
Does it get re-assigned to “false” each time the piston runs, or does it stay any value that is assigned in the code?
If you set it in the program definition, then yes, it does get reset each time through. If you adjust it on the trace screen, then it only changes when you change it. So, I’d suggest not setting the default (unless you want it reset each time).
OK, I tested my ‘m0co’ piston and it works as desired once I changed the first condition to a trigger (changes to open). It triggers on the first door opening and not again until after 2 minutes.
Did you change TCP to NEVER anywhere?
Worked like a champ!
I have a couple questions about the logic.
- Is the “Location” command just a place holder to allow for the TCP?
- I assume since the variables are defined within the Piston they only apply to this Piston and the name can be reused in another Piston without interfering with it. On that note, I assume the Global variables are for use across Pistons?
Thanks to all for responding, I’ll look at all the options to get ideas for other Pistons.
I started with your 0j8x so already had TCP set to never for the wait.
- location is a placeholder for tasks that don’t have (or require) an associated device.
- Right on both counts. Variable defined within a piston are only seen by that piston but the values are saved from run to run as long as they are not fixed in the define section. Global variables can be used across pistons but have some limitations like the value isn’t written until the piston finishes execution.
OK, using WAIT in my pistons has caused me distress. They are incredibly useful but somewhat difficult to understand. This is probably covered somewhere else, but I did not find an explanation that cleared it up for me. The following information may not be completely accurate, so any additions/corrections are appreciated. Consider the following piston:
Boolean Door_Closed = false;
execute IF Door_Sensor contact changes to open (Trigger) Then While Door_Closed is false Do SMS “The door is open” Wait 2 minutes; (TCP set to NEVER) IF Door_Sensor contact is closed Then Set Door_Closed = true; END IF END While END IF Do other stuff…… END execute;
TCP set to NEVER
If my wife opens the door and is bringing groceries in and out (opening and closing the door), then no matter how many times the door is opened or closed, the boolean Door_Closed will not be changed until AFTER the WAIT (when she is finished and the door is closed). Meaning that she can open and close the door many times during the WAIT without breaking out of the WHILE statement.
BUT during the WAIT, each time the door is opened, the SMS is executed. And each time the door is closed, DO OTHER STUFF is executed. This did not make sense to me.
Once the WAIT is complete, if the Door_Sensor contact is closed, then Door_Closed is changed to true and the WHILE is exited. Then, DO OTHER STUFF is executed and the piston finishes.
What surprised me the most is that the SMS is sent each time the door is opened during the WAIT. This behavior gave me the impression that each time the door opened (the trigger fired and the piston started from the top again) that a NEW WAIT was started and stacked on the old. I anticipated that the old WAITS would be completed in sequence. That does not appear to be the case. Once the first WAIT is completed, if the correct programmatic conditions are met, the piston continues/completes. The first WAIT completes regardless of how many times the door is opened/closed. I THOUGHT that execution would pause at the WAIT, and no other instructions would be executed until the WAIT was completed. Not so.
TCP set to DEFAULT
The difference here is that if the Door_Sensor contact (trigger) changes state during the WAIT, the WAIT is cancelled, and the piston executes from top to bottom again. SO, instructions after the WAIT (in the WHILE loop) do not get executed if the WAIT is cancelled by a trigger state change. If the WAIT does not get cancelled, then the instructions following it will be executed.
In essence, this logic did not come naturally to me. This is why I continue to have difficulties using WAIT statements.
This makes sense to me… (shown abbreviated below)
define Boolean Door_Closed = false; end define; execute IF Door_Sensor contact changes to open (Trigger) Then While Door_Closed is false Do SMS “The door is open”
Every single time the door opens, the
variable will be ‘false’, so a SMS will be sent…
This also makes sense to me… (shown abbreviated below)
execute IF Door_Sensor contact changes to open (Trigger) Then Do *some* stuff END IF Do "other" stuff... END execute;
The "other stuff is outside of the IF, so “other” stuff should execute when the sensor changes to open or close. (even though it will be delayed when first opened due to your loop)
OK so I thought a notification when the door was opened and not notifying again for 2 minutes was enough. However, I quickly realized this does nothing if the door is left open!
Here’s what I have, what changes do I need to make in order to get alerted if the door is left open. Also after the 2 minute delay?
Welcome to the nuances/fun of webcore. You think you have a piston the way that you want it and then you realize how much more you can do with it. It’s a never-ending cycle for me.
You could just add another IF statement at the bottom of your piston…
IF Contact Sensor 1 stays open for X minutes Then SMS "Door is open"
X minutes could be as long as you like.
Yes, because I made the false assumption that the piston would stop at the wait, not running again until it awakened from the wait. But even with TCP set to Never, the piston will still run from the top if the trigger state changes. That’s the part that I had to learn and is part of the bigger struggle that I have with completely understanding the nuances of WAITS.
That worked. However I had to keep in mind that it counts down the first 2 minutes then moves to the next if statement so I only put 1 minute for the stay open, for a total of 3 minutes.
You may be served better by a slight variation like the following. The above gives you one more warning but then stops sending messages. This will send a message every 2 minutes until the door is closed.
if contact sensor is open and door_open is false then set door_open=true while contact sensor is open <-- TCP set to never send push notification wait 2 minutes end while set door_open=false end if