Multiple ways to restrict the execution of a piston

variables
conditions
execution
triggers

#1

As we all know, there are many built-in ways in webCoRE to restrict either the full or partial execution of a piston. You can select things like time of day, days of the week, whether it’s before or after sunset, location mode, presence status and many more. However, there are times when even all of those options are not enough. Below I will explain multiple different methods that you can use to restrict either the full or partial execution of a piston. These are not intended to be examples on how to perform a specific task, but rather they are designed to be a framework from which you can build your own full solutions.

1. Using a Boolean variable
Boolean variables are very much like a standard light switch. They can hold a value of either True or False which is very much like On or Off. To use a boolean variable you define it at the top of the piston. It is important when using a boolean in this manner to not define a value for it at the beginning of the piston. We want the conditions that happen in the piston to change the variable as needed. So we purposely leave the value blank initially. Likewise, when we have used the boolean variable to do what we wanted it’s important to set the value it has back to the normal state we want it to have.

In the example below, I’m setting a boolean variable to be equal to true when a presence sensor is detected to have just changed to be present. This way any future triggers in this same piston will only execute if the boolean variable is true, meaning they will only execute just after the person got home.

So in this example we’re restricting the piston to only trigger when the person just gets home. Opening the contact sensor at any other time while the person is home will do nothing.

2. Using a Counter
There may be times when you only want to perform the actions in a piston after a certain number of times an event or device is triggered. In this example I’m showing how to use a motion sensor and an Integer variable to hold the value of the number of times the motion sensor is triggered to Active. When the counter reaches the desired number, the rest of the piston will execute. A motion sensor is just one example. But you could have a piston based on any event and have it count up to your desired value before proceeding with the rest of the actions. Counters can be very powerful resource to have if you want to restrict a piston to only run after a specific number of events have happened.

3. Followed by
This is a built-in function of webCoRE but since many people do not now that it exists I will include it here. Followed by is a great way to restrict a piston to only execute when multiple events/triggers happen in sequence. Pistons generally fire off based on certain event triggers. The nature of triggers means that two of them can never be true simultaneously. One of them will always report that it happened first (down to the millisecond level) therefore using two triggers to initiate a piston to start will fail…unless you use “followed by”. This example shows a motion sensor changing to active followed by a contact sensor opening. So if you had a motion sensor in your garage and and within two minutes your back door opened you could likely deduce that you’re coming in from outside. However if hose triggers happened in the opposite order then you’re likely going out instead. Different things could then be slated to happen based on that calculation.

4. Using time as a "lockout"
This is a great method to restrict a piston so that it only executes once within a specified time period. To do this I’m using a datetime variable and setting the value that it has to a point in time in the future. The addMinutes function is used in an expression to set the value stored in the Lockout variable. There are of course other functions for addHours, addDays, etc. So you can set the future time to be whatever you desire. The way this restriction works is to compare the value of the system variable for the current time, which is $now, to the value that is stored in the Lockout variable. Since we are specifying that $now must be after the value in Lockout we are, in this example, saying that this piston will only run once every 10 minutes. Or said differently, this piston will only run again when both the switch changes to On and the time is 10 minutes later than the last time it successfully ran. ff the switch changes back to on in 5 minutes, that will be ignored by this piston as the time condition is not met.

5. Using previousAge
Technically previousAge is also a built in feature of webCoRE, however, we’re getting into some advanced territory here so I saved this one for later. Devices do store a datetime value of the last time that they processed an event. So in the example below I am showing how to do something very similar to the lockout example above by testing for the last time that a contact sensor opened and only proceeding if it was more than 30 seconds ago. However, the important thing to note here is that you can use the previousAge value from any device and not necessarily the one that just triggered the piston. So if you wanted to test for the previousAge of a presence sensor after a contact sensor has been tripped you could do that. When using previousAge you must ensure that you get the name of the device in the expression spelled and formatted correctly. I find it easier to use a device variable in these cases so that you don’t have to change several expressions if you make a modification to the devices used in the piston. Also note that the value stored in previousAge is stored in milliseconds, so you have to account for that in your comparisons. I pulled out all the stops in this last example piston, also showing the use of a boolean and even including a While Loop which will continue to run until the contact sensor is closed again.

One little caveat to this example, webCoRE is a cloud based rules engine, so the actions that you’re telling the system to perform have to go out to the cloud and come back again. So this specific piston example which flashes a light may take some time to notice that the contact sensor has gone back to closed. Meaning it may still flash several more times after the contact is closed. Your own environment (connection speed to the Internet and such) should be taken into consideration before using something like this one. But it’s still a good example of the type of restrictions that are possible within a piston.

6. Using a “Flag” and Location Modes
In this example I’m showing the classic “restriction” on a piston that is available in the the editor. This is the simplest way that you can restrict the execution of a piston (by wrapping the entire thing with an actual restriction). However, I’m introducing a couple more concepts here. First, there’s the concept of a “master flag” switch that you can setup so that you can disable all of your pistons at once with the flip of a “simulated switch”. See the article below on how to create a simulated switch (also known as a “virtual switch”) in the IDE.

As I’ve said, many people use this concept to turn off the execution of all of their pistons (say if they want to do maintenance on things or perhaps if they go on vacation). In the example below, nothing in the piston will execute unless the “MasterFlag” switch is in the OFF position. If the Flag is set in the ON position then essentially nothing in this piston will happen. A flag is very similar to a Boolean variable, but by popular demand I’m showing it in its own section.

Additionally I’m also showing how to use a location mode as a restriction. Location modes are very powerful as restrictions as they can be set on the entire piston (as shown in the example below) or they can even be setup on each command.

Please note, this example uses “Time” for the trigger to start the piston. Restrictions on the outside of a piston can be used when you are using Time as the trigger…however, DO NOT use restrictions on the outside of a piston when using a Timer. I’ll cover restrictions on timers in the next example.

Also of note in this example is that I"m showing how to call a different piston and pass Arguments to it. Calling other pistons is a good way to reuse code that you write and to consolidate things.

7. Restrictions on a Timer
One of the things that took me a while to realize in webCoRE is that different rules apply to restrictions on Time versus a Timer. When you configure a piston to have a Timer in it, the outside restrictions on the Timer are evaluated when the piston starts, not when the piston wakes up to execute the Timer. Read that again if you need to as that is an important concept to grasp.

What that basically means then, is that if you want to place any restrictions on a Timer that might change while the timer is counting down then those restrictions need to be on the INSIDE of the Timer and not on the outside of it. (Technically there is a way to use restrictions on the outside of a Timer, but that requires putting in additional Triggers for each restriction that might change…suffice to say, putting them on the inside of the Timer is easier and looks much cleaner). Examples of restrictions that might change include Location Mode, Presence and the state of device such as real or simulated switches.

In the example below, I’m showing a Wake up routine that I use. This one actually has two triggers in it as sometimes I get up early and start the routine by turning on a virtual switch with the Echo The piston still runs at 6:30, but instead of executing fully it just turns off the virtual switch so that it can be used again the next day. Again note that these restrictions are all on the inside of the Timer and therefore they will all be properly evaluated when the Timer executes.

Well, there you have it. Several ways that you can restrict all or parts of a piston from running using various methods that are possible in webCoRE. My hope is that these examples demonstrate a little more about what you can do with this platform and further that they inspire an idea that you can eventually share with everyone else.

See one, do one, teach one…


Sequence of events
How to Limit Automations to Once-Per-Period-Of-Time? (when the start-time for the period is dynamic; i.e. based on an event)
Conditions and Triggers: The difference?
Trying to figure out how to override a scheduled rule in ST using a virtual switch
Restricting a trigger to run only once per mode change?
Turn on Lights on Motion when moving from one room to another (motion detected within x seconds of preceding motion sensor)
Help with timing of a piston
Still unclear how commands AND, OR, BUT are created when building piston
Override Automatic Mode Using Presence Sensor
Making harmony hub action work once per day
Door sensor to trigger Aeotec doorbell and send SMS
Disarm the house
Master virtual dimmer w/ maintained state when externally controlled
Simplify an arrive/ leave piston
Help with a gradual siren behavior
#2

Thanks a lot for this thread!
I really appreciate your willingness to share what you’ve gathered on your own thus far with others. This will come in VERY handy for those of us getting over here kinda late in the game. :slight_smile:

I haven’t actually read it all yet (so, I’m sorry if this is already covered, but I just didn’t see it, specifically, on my first quick glance), but I wonder if you may want to consider adding the option of using either internal or external ‘flags’ (such as a virtual/simulated switch, etc) as another option for restricting the execution of a piston.

I have a few things set up like this. In fact, I have a mildly complex subset of virtual switches that help with this throughout my rules engines (formerly for controlling RuleMahcine, then CoRE, and now for webCoRE)…

…mildly complex in that there is one main ‘Enable/Disable’ switch for EVERYTHING (any and all rules, SmartApps, and webCoRE pistons), and then each ‘section’ of my system (e.g. things in the kitchen, or things in the master bedroom) has such a switch for it.

When any section’s ‘Rules’ virtual switch is ‘ON’, the rules related to that section are enabled. When it’s OFF, they are disabled. Then, the Master ‘Rules’ virtual switch controls all of those section switches. So, I can either disable just one section of rules, or all of them throughout the entire system.


#3

Although I haven’t done the ‘Flag’ option to the same extent as @sgnihttrams, I also use ‘flags’ via simulated switches so that I can, when needed or desired, have additional control over some pistons. It also allows their use via my Echo devices. This in no way, diminishes the great information contained in your post, it’s just a number 6 option. :wink:


#4

Method 6: restrict by modes

Only when Mode is away; only when Mode is home; etc.

Good write up, should be included on the wiki


#5

Yep. This would fit as another example in the ‘flags’ option, I think.


Help with Disabling a Piston but not the switch
#6

Done, done and done. :slight_smile:

I also added a section showing the proper way to put restrictions on a Timer as those follow a different set of rules than if you were to use Time as a trigger. So now I’m up to 7 examples (and so I changed the title of the post as well). Thanks for the feedback guys.


#7

Since you just helped me with this yesterday, I agree it’s a valuable addition. :+1:


#8

Great write-up!

I’m curious about restricting writing variables? Specifically only allowing a variable to be written once every x minutes.

I have a garage door that I want to turn some inside and outside lights on both when it opens and closes. And then after several minutes of inactivity, turn those lights off, but only if they weren’t on to begin with. This is easy enough, the issue is, most normal human beings open the garage door, drive in, then close the garage door, usually in only a couple minutes. My problem is when anyone closes the door shortly after opening (which is most of the time in my house) it overwrites the variable and neither of the lights that came on, get turned off.

I hoping there is a way to tell the piston to only write the variable once every x minutes, where x is also equal to the amount of time the door has to remain unchanged for the lights to turn off. This basically creates a timer that resets every time the door is operated. Any ideas?


#9

That sounds like it might be something where you could use the time based lockout that I show above. You can lockout a piston from running any command that way. Just wrap the overwrite in an IF block:

IF $now is after VariableResetTime
then set your variable
otherwise skip the reset.

You could also capture the Time when the door opened to a variable, then the time when the door closed to a different variable and determine the duration of time it was open and proceed based on that info.

I would suggest you post a green snapshot in the Design Help section of what you’ve got now and I’ll take a look at it. Seeing the real thing will help me.


#10

Ya this topic is getting moved to “Instructions and Turorials”

It’s too good to just be in the examples category :upside_down_face:


#12

Please help. I’m trying to do exactly that from your first example. I’m still new to programming but how or why did you define your presence sensor. Could we not have just said.

If my presence sensor has changed to present
myWifePresence sensor is not present
and garage contact changed to open
And garage status changes in the last to 2 minute.

Would that not say you have just arrived.
Forgive my ignorance.


#13

Not reading this whole thread, but just reading your example I can say this. The biggest reason for defining anything in code is simplistic changes. If you have code that has my presence sensor threw out and you want to change this to a new presences sensor it very time consuming to look at every bit of code to make the change. If you define it in the beginning then you only need to change it in one place and your done.