Subscribe to multiple devices perform action on one


(Eric M) #1

So, I have a SmartApp that I am working on. In this app, the user selects a set of switches to monitor for events. When one of these switches is activated, the app performs an action at that same switch. The problem I am having is how do I perform an action on a single switch and not all of the switches?

Here is my code so far:

    preferences {
    section("When any of these switches is toggled...") {
        input "switches", "capability.switchLevel", title: "Which Switch", multiple: true
    }
    section( "Notifications" ) {
        input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes", "No"]], required: false
        input "phoneNumber", "phone", title: "Send a text message?", required: false
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    subscribe(switches, "switch", switchHandler, [filterEvents: false])
}

def updated() {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    subscribe(switches, "switch", switchHandler, [filterEvents: false])
}

def switchHandler(evt) {
    
    def toggledSwitch = switches.findAll{it.id == evt.deviceId}
    def recentStates2 = toggledSwitch.eventsSince(new Date(now() - 30000), [all:true, max: 200])
}

This seems to work except I am getting the following error when searching for events:

c4bf7f95-9ce4-4b23-a1d2-b4b0411beb81 12:35:26 PM: error groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.eventsSince() is applicable for argument types: (java.util.Date, java.util.LinkedHashMap) values: [Mon Jun 30 18:34:56 UTC 2014, [all:true, …]] @ line 54

I believe because toggledSwitch is an ArrayList and the method I am using (eventsSince) is intended for a single device.

Is there any way to convert it to a single device or is there a better way of accomplishing this?


(Gabriele Nizzoli) #2

Probably this is what you want: calling eventsSince on every element of the list, then flattening everything to avoid having a list of lists of events but simply a list of events.

def toggledSwitch = switches.findAll{it.id == evt.deviceId}

def recentStates2 = toggledSwitch
   .collect{ it.eventsSince(new Date(now() - 30000), [all:true, max: 200]) }
   .flatten()

(Eric M) #3

Thank you for your response. I was actually able to find a solution last night and just did some final testing on it this afternoon and it seems to be working great. This pulls a single device object from a devices object, which is exactly what I need. There may be a better way to do this, but this is what I have:

def toggledSwitch
switches.each { eswitch ->
        if ( evt.deviceId == eswitch.id ) {
           toggledSwitch = eswitch
           log.debug "Found the device that triggered the event: ${toggledSwitch.displayName}"
        }
    }

You can then go on to retrieve events from toggledSwitch or adjust its level or turn it on/off, etc.

Thanks again for your response.


Can SmartThings generate a https request?
(Gabriele Nizzoli) #4

If you just need to get one, try this:

def toggledSwitch = switches.find{it.id == evt.deviceId}

notice the find instead of findAll: findAll gets all of them, find only gets the first one. Actually, since we are filtering the collection by device id, you wil only get back at most one device, so findAll returns an array ( that is or an empty array [] or [toggledSwitch] ), while find retuns the object itself (toggledSwitch).