OK. Let’s start with the basics. Pistons are actually Groovy SmartApps. Like any SmartApp they will subscribe to device events and/or schedule timer events and then sit around waiting for events to happen. So how does a piston know which events to subscribe to? The answer is that it looks through the code to see what events could possibly affect it, which mostly means looking at the various conditions/triggers.
Now you will have noticed that some conditions are just called conditions, and other ones are classed as triggers. If you look at them you will notice that those classed as triggers are associated with things that have recently happened: for example a switch has changed to on; or a temperature has risen above a certain amount. Those just classed as conditions are more about the state of something: a switch is off; or the temperature is greater than a certain amount.
The piston, by default, figures that by using triggers you are explicitly telling it when you want it to be executed. So it will only subscribe to or schedule the events that affect how triggers will be evaluated. If there aren’t any triggers it will subscribe to or schedule the events that affect the conditions instead. This is sometimes described as promoting them to triggers but I’ve never found that helpful. You can actually override the subscription mechanism for each condition/trigger.
When the piston executes it effectively behaves like a script executing from the top down. Triggers and conditions are now just comparisons that evaluate to
So let’s look in some more detail.
Devicename switch changes to on is a trigger which means by default the piston will subscribe to events from
switch attribute. When it comes to evaluation the effective behaviour can be thought of as follows:
- The piston checks if the current event device is
Devicename and the current event attribute is
switch. If they aren’t then the result is
false as activity on the
Devicename switch isn’t the reason the piston is running. It hasn’t changed in the sense that the piston uses the word.
- The next check is if the current event value is
on. If it isn’t then the result is again
false as the switch can’t have changed to
- The next check is what the current event value was the last time this trigger was evaluated and the event was for
Devicename switch. If it wasn’t
on (i.e. it was
off), then the
switch has changed to
on and the result is
true, otherwise it is
Note the two gotchas here. Firsly the result of the trigger is based on a comparison between the events as seen when the trigger is evaluated so it is important that the trigger is evaluated every time the piston is executed in response to a
Devicename switch event. If it isn’t then
changes can’t be determined reliably. Secondly, only the event matters. It doesn’t matter if the
switch is actually now
off, if the event says it is
on it is
on. So delayed events can confuse things.
Devicename switch is on is a condition so the
Devicename switch attribute is only subscribed to if there aren’t any triggers or the defaults are overridden. When evaluated this is basically what happens:
- The piston checks if the current event is for the
Devicename switch attribute. If it is then the current event value is used as the
switch status. If it is
on the condition is
true. If it is
off then it is
- Otherwise the device object on SmartThings is queried for the current value of the
switch. If it is
on the condition is true. If it is
off then it is false.
Note the gotcha here. If the piston was fired because of a
Devicename switch event then that is what counts. It doesn’t matter if the piston instance has been running for hours and the switch has actually toggled eleventy billion times, it is still handling an event that says the
on and that is what counts.
Devicename switch was on for at least one hour (I may have got the wording slightly wrong) is a condition. As long as the piston wasn’t fired by a
Devicename switch event what it means is that the
Devicename switch has been set to
on continuously for at least one hour and it still is
on. It is determined by looking back through the device event history on SmartThings.
If the piston is handling a
Devicename switch event then the very last event in the history is ignored, so it would mean it was
on continuously for an hour prior to the event the the piston is currently handling. There is a gotcha here if events get so delayed that the event isn’t actually the last one in the history.
Devicename switch stays on for one hour is classed a trigger but is a bit quirky. When evaluated it does two things which can be thought of like this:
- It evaluates the equivalent of
Devicename switch is on and if that is
true then does the equivalent of:
wait one hour
<the contents of the then block>
- As well as the above, the trigger always returns
false and just continues on with any
else block and the rest of the piston. That can catch you out if you aren’t expecting it.
So what happens then? Well if the piston fires during the next hour and the
stays is evaluated again and the
switch is now
off the ‘wait’ will be ‘cancelled’. The
switch hasn’t stayed
on for an hour. Otherwise the
switch has stayed
on for an hour and the piston fires and continues with the
As with other triggers, there is a gotcha if the
off and the piston doesn’t reach the
stays trigger when it executes.