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 true
or false
.
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 Devicename
’s 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 on
.
- 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 false
.
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 false
.
- 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 switch
is 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:
then
wait one hour
<the contents of the then block>
endif
- 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 then
block.
As with other triggers, there is a gotcha if the switch
turns off
and the piston doesn’t reach the stays
trigger when it executes.