Multiple instances of same app running?


#1

I can not for the likes of me figure out how the following piece of code actually executes twice.

if (state.atHome=="true" && state.hasLeft=="true") {  // All sensors have once left home but now have returned.
   	def msg="Arriving Home App: All sensors are accounted for"
	log.debug "$msg"
    sendPush(msg)
    state.hasLeft="false"
    state.setToAway="false"

}

At times (yup, only sometimes) I will get two or more entries in my “Hello Home” log with the $msg defined within the block of code above. The state.hasLeft has been set to false within this same block of code and can only be reset to true when other conditions occur. If that were to happen another “SendPush()” would be sent to my log with a msg something like " Alll sensors have left". This never happens. I got to assume two or more instancs are running at once. Is this possible??

Complete source code for app is here


(Johnathan Fullman) #2

Couldn’t access your source, but yes, the engine runs an instance of your app every time a sensor/schedule subscription is triggered. And yes, these instances can compete with each other. If you have multiple presence sensors that come and go at the same time, that may cause your issue. You may try using atomic state to correct the race condition:
atomic state docs


(Barry) #3

I also suggest that you reset the state.variables (or atomicState.variables) as the FIRST thing you do in your if condition, rather than the last. THEN do your msg stuff. That’s probably enough to stop a second occurrence getting past your if test…


#4

:confused: That’s odd.

Another thing thats is odd is when I test this app, I use to virtual presence sensors. From the app, I turn both on/off and watch the log. Every thing works as I hoped it would. Then I leave home and/or return and everything falls apart. I am guessing it because the sensors (android phone and Life360) trigger “Present” while still on the cell network whereas the virtual sensors trigger while on wifi.

Regardless, I will try using atomicState and see how this works out.


(Johnathan Fullman) #5

I think I can’t access your source because I am on my work network and they lock outbound ports pretty heavily. :slight_smile: Probably not you.


#6

Well I figured out how to duplicate this error with my virtual sensors. Touching both at the exact same time I end up with 2 identical log entries. Now all I have to do is fix it :smile:


#7

So I have tried your suggestion (re:Resetting the vars) as well as Johnathan by using atomicState. Alas, no luck… :disappointed_relieved:
I even went as far as putting a condition at the very top of the function to avoid duplicate execution.
i.e

if (atomicState.isRunning !=“true”) { // yup, go ahead and execute block below
atomicState.isRunning =“true”
.
.
.
.
.
atomicState.isRunning !=“false”
}

No luck… In my opinion this confirms that there are two instances running. Going to have to review my approach and redesign :frowning: Back to the drawingboard


(Barry) #8

I’m sure that you’re just using an example, but I use this approach in a number of SmartApps to successfully single-thread parts of my code.

Just to be sure that it isn’t a typo in your example, try using this approach - if only because logical compares are faster than string compares:

def someMethod() {
    if ((atomicState.isRunning != null) && (atomicState.isRunning == true)) {
        return
    }
    atomicState.isRunning = true as Boolean
    .
    .
    .
    atomicState.isRunning = false
}

Of course, YMMV - but this approach works for me.

You might also try creating a NEW SmartApp (from scratch, not just renaming this one), and then install an instance of it. If you use a slightly different string for your msg, you might prove to yourself whether you have 2 Apps running with the same parameters, or 2 instances of the same single app…

Good luck!


#9

The multiple sendPush() I use are for debugging purposes but it occurred to me after reading your post that maybe they are slowing thing down. Then I looked at my code a little closer :blush:

The problem is here

prefpresence.each { 
    def pValue = prefpresence[n].currentValue("presence")
    def pName=prefpresence[n].displayName
    if (pValue=="not present") {
        devicesAway++
    }
    log.debug "Current state of $pName is: $pValue"
    n++

}

If I have selected 2 presence sensors and both become (not)present the presenceHandler() get called twice. and so it should. However, the first time the above loop is executed (called from presenceHandler) it will determine that in fact both sensors are (not)present and execute the remaining code accordingly. That code should only be executed after the 2nd sensor event occurred. Does that make sense??


#10

I “solved” the problem by adding code to the presenceHandler() that counts the how many presences have triggered an event. Once the total number of events equals the total # of presences defined in the Prefs, the above function is called.

I have a question or two however.
Where do I find a list of attributes contained in the object (i.e. “evt”) that is passed to the presenceHandler(evt)?
Instead of looping thru the array (i.e. presences.each { count++ } ) is there an easier way to determine how many presences were defined in the Prefs? i.e totalCount=presences.count
Why does atomicState.currentCount++ not work yet count++ does. I had to increment as follows atomicState.currentCount=atomicState.currentCount+1

Thanks in advance :grinning:


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #11

Perhaps “evt” is an object of type Event?

http://docs.smartthings.com/en/latest/ref-docs/event-ref.html


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #12

Does presences.size() work?

I think that’s the available method in the List Type.


#13

Exactly what I was looking for :grin:


#14

It does if you first change presences. to what you actually called it in preferences. :blush: