Explanation of each function?

Im wondering if there is a description of what each function does. I’ve been using it for about a year and some of them I just don’t really understand what they might do different (or why they exist). I’m thinking is there a list that would do this:

Is (are): compares thing against the defined state, is true for as long as that thing is in the state. Will not trigger piston.
Is any of (are any of): compares the thing against multiple defined states.
Is not (are not): same as above but…
Is not any of (are not any of): xxxxxxx
Changed…
Did not change…

Hope this makes sense. I am surprised I’ve never seen it. Sometimes when building or trouble shooting a piston I just can’t tell if it is doing the correct thing. I.E. biggest for me is usually the ‘was’ state. I always get the ‘was’ open for 15 seconds confused with ‘stay’ in the last 15 seconds and sometimes have issues getting the piston to work properly.

1 Like

start with the webCoRE wiki page

if you have any questions, check out the webCoRE community forum https://community.webcore.co

My bad, wrong forum. Didn’t realize there was a dedicated one for Webcore now. I was thinking it was the sub-forum. I’ll check it out.

I’ve tried searching and have never found a true list. Any code engine comes with a manual that explains all the functions in it, I wonder if there is the same. The Wiki does explain the boolean and other logic but doesn’t explain what gates these commands are trying to mimic.

Sorry to revive such an old thread, but were you ever able to find such a list?

I’ve been looking everywhere for some simple definitions or “use cases” for each of the specific Triggers and Conditions since I first started using WebCore like 2+ years ago…

I’m looking for the same thing. If I come across anything this week, I’ll cross-link it here. “was” vs “stays” and “is” vs “changes” are tricky for me. I also haven’t figured out what is a “trigger” vs not.

tagging @orangebucket as he was just commenting on “was” and “stays” on the webcore community forum.

I just want to point out that webcore is a legacy app and will cease when ST ends support for groovy on the platform. Any use of it would be short-term at this point and you will need to move to another tool such as Routines in the app or Rules API.

1 Like

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.

Super helpful, thank you!
Using your inputs, I went and changed some of my “conditions” to “triggers” like “is active” to “changes to active” for motion sensors. I also changed some “stays off for” to “was off for” since I wanted those as conditions.
I did not understand this part of your explanation:

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.

Do you mean do say that if I have a trigger on “changes to active” but the sensor has already changed back to “inactive” after “active”, but webcore is processing the earlier event, I might see a delayed action?

Also, is my understanding of the “stays” correct that there is a bug and the piston always executes the “else” conditions when we use a “stays” trigger?

Thanks for pointing that out. I could not figure out how to start using Rules API though. Is it open for everyone? The 200 routines limit in the app is pretty limiting and I couldn’t find how to get started with Rules API.

What I am saying is that if the event that fired a particular piston is Myswitch's switch being on, then Myswitch switch is on will always evaluate as true in that instance of the piston. The actual current state of the switch isn’t considered. Even if the piston encounters a wait one hour, exits and starts up again to continue after the wait, it is still processing that event.

So when you see code like …

if Myswitch1 changes to on
   and
   Myswitch1 is on

… the second condition is actually redundant.

There isn’t a bug. That is how it is supposed to work. The piston doesn’t pause its execution on the chance that stays might turn out to be true, it sets a timer to deal with that possibility when it happens and assumes it is false.

thank you, that helps me understand things better