Subscription and Global Variable set problems

variables
triggers

#1

1) Give a description of the problem
The piston is only subscribing to 1 of the triggers in the IF.

2) What is the expected behavior?
This piston sets a global variable based on what mode Smartthings Location Mode is set to. I use the variables for diagnosing problems with pistons in web core, of which I have a few. I have just added a timer as a failsafe to run the statement every hour to ensure the location mode variable reflects the correct status of location mode. Basically If location mode changes, set a variable to reflect what it changed to and send a notification to say it changed.

3) What is happening/not happening?
It is subscribing to location mode changes and that is working perfectly however, the local variable ‘PistonRun’ that is set to true by the timer won’t subscribe in the IF. I’ve tried swapping the two IF’s but no difference.

**4) Post a Green Snapshot of the piston![image|45x37]


#2

I’ve also tried setting it to always subscribe but that still didn’t put the lightning bolt on the side.


#3

Untested, but it makes sense to me…

For a local variable to change, the piston must be executing…
and if a piston is executing, then the trigger has already happened.

My educated guess is a trigger has to be an event from outside the piston…


…and if a local variable cannot be a trigger, then my recommendation is to change line 25 to a condition.
IE: {PistonRun} IS true


#4

Right. Makes sense. Would I need to set the condition (PistonRun is True) to always subscribe to run the statement or when the timer finishes and sets the local variable does the piston re-run from top to bottom?

The other alternative could be using a global variable I imagine? but it would just be a waste of processing power.


#5

Unfortunately, changes to a Global Variable are only seen on subsequent executions of the piston. Not the current top to bottom execution.


To get near instant feedback, local variables are the way to go.
Maybe something like:

Every hour...
    Set variable {PistonRun} = true
    Wait 1 second
END EVERY

IF Location changes
   or
   {PistonRun} is true
Then
    IF Home
        Then Do Stuff
    END IF
    IF Away
        Then Do Stuff
    END IF
    IF Bundy
        Then Do Stuff
    END IF
END IF

This yields one trigger every hour, and one trigger when the location changes…

(Note: I moved the hourly timer to the top, since pistons run thru code from top to bottom each trigger)


#6

Thanks but wouldn’t that only run the statement once the timer finishes? I would need it to trigger every x minutes OR when location mode changes. As a location mode change may come right after the timer has ended.

I tried setting it to PistonRun is True. It runs once from the timer, on the second run the timer sets the variable back to to True but it doesn’t execute the IF again. Always subscribe/Auto made no difference.

I KNOW this isn’t the same piston but it is structured the same. I’m testing on this one ATM.


#7

Ooops, good call. They both need to be top level.

I made a few tweaks to that post that should do the trick.


#8

Testing…

Hmm okay, I think this now creates another problem that I have experienced before. The timer runs, finishes, changes the variable, then re loops. I remember one of the Webcore minions telling me that any statement that loops should be the only statement in that piston as it won’t run anything after it as only 1 statement can run at a time and loops take priority.


#9

I added a 1 second WAIT above, that might not be necessary


#10

Yeah now i’m having a bit of Deja Vu when it comes to timers.

Using the same method I used in post #13 on the above topic I just threw together this. It’s VERY ugly but I can’t see any other way of doing it at the moment.

IF

Location Mode changes
OR
Location Mode is any of 'Home, Away, Bundy'

THEN
Repeat
do
    with

    only when Location Mode is 'Home'
    Set Variable to 'Home'

    only when Location Mode is 'Away'
    Set Variable to 'Away'

    only when Location Mode is 'Bundy'
    Set Variable to 'Bundy'

    WAIT 1 hour?

Until
Forever?

That would only work if when Location mode changes it resets the 1 hour wait. I don’t know if webcore does that but I’ll try it.


#11

^^^
Wow okay I was certain what I scribbled together above wouldn’t work but it works beautifully. :face_with_raised_eyebrow:

It resets the wait and changes the variable when Location Mode changes and if I set the variable to a random value, once the wait counts down it sets the variable to mirror the current Location Mode. Perfect. Thank you very much for your help. :+1:

If someone else discovers a cleaner way of doing what I want let me know please. What I’ve got is messy and redundant but it does the job.

Make sure you keep something that never evaluates true in Until, otherwise it only runs once.


#12

Why not just:

set variable @Z_Locationmode = Location mode

Seems like that would accomplish what you want without all the only when’s. Also, not sure why you need the loop at all. Every time location mode changes, this should trigger and update your variable. Why would you need to do it more than once?


#13

Something is off with this. Your piston “ksyqz” does everything possible to STOP a loop from happening… (Well, other than the set variable every two minutes)

Personally, I see no reason to loop or repeat this at all. It should run top to bottom once, and only once per trigger.


#14

I just noticed that in “ksyqz” you forced a subscription. That is why it looped.

Basically, whenever any subscribed “device” changes at all, in either direction, the piston runs top to bottom. Unsubscribing from line 23 should do the trick…


#15

I tried it with and without the subscription. I just took the screenshot after I tried it with but it still kept looping only the loop.

To answer the questions about why the loop, well,

It goes back to what I mentioned in my first post. I have been having some issues with pistons firing in WebCoRE. I agree, guxdudes idea of " set variable @Z_Locationmode = Location mode" is brilliant and should change the variable to directly reflect the current status of location mode. But, from all of my testing and going about my day to day life with these pistons running automation’s to make my life a bit easier, for some reason, sometimes, pistons just don’t function as expected.

For instance, I have had problems with WebCoRE;
Skipping statements (Real Examples)
IF
Time between 8pm - 3:00am
&
Goodnight button is pushed
THEN
Set variable GoodnightRunning to True.
Set variable GoodnightBedroomLight to True.
Send PUSH notification - “Goodnight” - Store in messages = True
Set SHM to Stay
Turn off (all devices incept bedroom light.)

Without any apparent reason setting GoodnightBedroomLight to True sometimes just skips completely. So I now have another piston that after GoodnightRunning changes to false, it checks to see if GoodnightBedroomLight is True and sets it if it isn’t.

Sometimes Global variables just fail to set for me. In the below I have a local variable to reflect the change purely for fault finding, like this, and a global variable to reflect the change but it’s the one I actually need to change. You can see the 2 statuses are different, even though the triggers are the same.

Hence the timer loop, so after an hour I ‘know’ that the variable will be changed to the correct value if this set variable failure happens again.

This incredibly simple piston that turns on the bedroom light on Bedroom motion, only when someone is not asleep will sometimes randomly turn on the Bedroom Light when the variable is True and no motion occurred according the smart-things. Also going into smart-things Bedroom Light activity it shows “@ Bedroom Motion Light Sent on command to Bedroom Light.”

Literally as I was just typing this, my microwave just turned on when it shouldn’t have. So lets work this out together, Here is the piston;


Okay so the microwave turned on so Kitchen’s Motion must have changed to active. Go into smart-things;

Hmm, that’s strange, last motion recorded by Kitchen motion was last night, 7 hours ago. Maybe it wasn’t this piston that turned it on?

And these are the problems I have with WebCoRE, roughly once a week. Last week it was the bedroom light just turning on for no reason. Week before it was WebCoRE running goodbye when me and my wife were both at home. I did find out later that both of our GPS’s had for 13 seconds shown us as being in California, but we live in Australia. Fair enough, but smart-things has a setting that doesn’t actually change your location mode (Home, Away) until you have been outside of the set geofence for a set amount of time (2 minutes), but the piston ran anyway.

Basically I am trying to create reliable pistons. I know there are a lot simpler ways of doing what I want to do but for some reason I just don’t get consistent results even if the conditions haven’t changed. I’ve completely reworked all my pistons twice now, as when I started I decided to code by mode. So if someone is home, do this, that, when this, do that, send that, turn this off after x minutes etc, but my pistons became too massive (Mem used 76%, 37 chunks) and sometimes pistons would freeze. So with some help from the community I rewrote every piston based on it’s sole function/device it controlled. The outcome was improved reliability however by splitting the pistons up I had to use global variables, and that’s where these problems started. I have been soo frustrated with these issues I was at one point willing to pay someone to write my pistons for me as long as they worked reliably.

I’m not saying i’m ungrateful, any and all help is appreciated, thank you, but I know all software has bugs. Using WebCoRE for a year now, I figured that these issues I have been having with global variables was just limitations in the engine, so instead of going to the community and constantly asking for help with all my pistons with global variables (12 pistons, 4 total variables), I would rather create work around’s and fail-safes to limit the possibility of a malfunction. That way I know my chances of getting woken up again at 1:20 am by the Bedroom Light deciding it want’s to turn on, is reduced. :wink:


#16

Yeah I just tried it without the subscription, same result. I took a video for you you can watch if you want.
I’ll only leave it there for a hour.
-Link Removed-


#17

I have a lot on my plate at the moment, but I did watch the video, and it is acting as expected. A few observations:

The every 2 minutes block needs to be ABOVE the larger block, since code runs top to bottom

Global variables are not written until after the very last line of code has been executed. Your 10 second WAITS prevent that from happening in a timely fashion. (local variables happen within a few milliseconds)


#18

Personally, in tens of thousands of pistons, and hundreds of thousands of executions, I have never once seen a variable not written due to a software error.

Now what I have seen many many times is too many pistons triggering at one event, which spams the network, and not all commands will get executed 100% of the time. In our short dialog, I have seen a few of your pistons that have “location mode” as a trigger. This means that no matter what mode you are changing to, you have multiple pistons trying to do stuff simultaneously. This practically guarantees unreliability.

Ideally, what I aim for is each device/event should only trigger a single piston, and that piston should use IF’s below the trigger to do different things based on conditions. It is not always possible, but it is always my goal for reliability.


#19

Thank you very much for the information. After reading through what you answered multiple times, I now think I completely understand what you mean.

So, if you have two different pistons but with the same trigger (If ‘C’ contact changes to active), both pistons would “run” to evaluate the trigger even if there is also a condition in the IF halting it’s execution, correct?

Like you mentioned, looking through I do have quite a few pistons that are triggering on one motion sensor change. It does sound inefficient. So I’m going to work on fixing this today.

In relation to this, I was wondering if you knew when restrictions are evaluated in a pistons execution?
Could it limit unwanted pistons from attempting to evaluate or are restrictions only applied after the IF is evaluated?

Basically, say I have this piston:

IF
Location Mode is 'Bundy'
&
**Bedroom Motion changes to 'Active'**

THEN
Do this

And that’s what I have as a motion detector, but then I also have this piston that doesn’t need to evaluate:

IF
Wife's iPhone is 'Present'
&
**Bedroom Motion changes to 'Active'**

THEN
Do this

Would a top level restriction stop the piston from evaluating?

**ONLY WHEN**
**Location Mode is not 'Bundy'**

IF
Wife's iPhone is 'Present'
&
Bedroom Motion changes to 'Active'

THEN
Do this

I like to keep unrelated pistons separate when it comes to their function but if the above won’t work I may have to look at changing the way I program.
Thanks.


#20

Yes. But it even goes a step farther. With a single trigger (If ‘C’ contact changes to active), each time the Contact changes to active AND each time the Contact changes to inactive, both pistons will run top to bottom. When it gets to an IF block, it might skip that block, but it will continue on down the entire code.


I believe every lightning bolt in the left margin will run thru the entire code.
(and also the opposite of the lightning bolt, as mentioned above)

That being said, IF blocks can definitely stop certain blocks from executing.

I tend to put my precise triggers first(since that is what initiates the piston)
…and then conditional IFs next(to selectively choose what actions to take)


I understand this, and sometimes we can get away with it on simple pistons. Personally, I aim for 100% reliability, which is why I program based around triggers

For example, your two pistons above I would do something like this:

IF Bedroom motion changes to active
Then
    IF Location Mode is 'Bundy'
    Then 
        Do stuff
    ELSE
        IF Wife's iPhone is present
        Then
            Do other stuff
        END IF
    END IF
END IF

This way, one trigger can react differently depending on the other circumstances, and yet, only one piston is executing when someone walks in the room.