For multiple devices, is an array created

THis is mainly a problem of documentation, or lack there of.

I started with Let There Be Light, and changed it so there can be multiple contact devices. So far so good. I want the contacts to act as a perimeter, so that if any of them are opened the light goes on. The problem is when I open two contacts and then close one of them, the light goes off.

I can visualize the solution. When I get a close contact event, I need to check the state of the other contacts before I turn the light off. How can I check the open/close status of contact devices that are defined as multiple: true?

This seems to be a problem similar to there being multiple presence sensors and determining if everyone is gone.

Yup, you need to iterate through the collection:

objects.each { object ->
        	if (object.currentValue("foo") == "bar"  {
        		doSomethingImportant()
             }
}

Another favorite to see what’s inside anything is log.debug wthIsThis.inspect()…

1 Like

You give me too much credit. I can read and tweak code, not write it. And I’m still flying with out documentation. What would “foo” and “bar” be for an array of contact switch objects? …“status” and “open”?

They would be the values in the third column here:
https://graph.api.smartthings.com/ide/doc/capabilities
So for contact sensors you have “open” and “closed”

OK, after a lot of trial and error, this code works (but could probably be cleaner):

def contactHandler(evt) {
log.debug "$evt.value"
if (evt.value == “open”) {
switch1.on()
} else if (allClosed(contact1)) {
switch1.off()
}
}

def allClosed(obj) {
def found = true;
obj.each {n -> if (n.currentValue(“contact”) != “closed”) found = false }
return found
}

With this code I can open multiple contacts and the light will come on. The light will not go out until all the contacts are closed. The perimeter is secure!

I bet some of you can make that function work with one line…

Writing code isn’t about being crafty or stupidly compact, I’ve written plenty of “cute” stuff that took forever to figure out years later…
The only thing I can think of here would be looking at the state from the other direction, maybe think of it this way.
If they are not all closed, then at least one must be open right?, so you could get away with only one if, with the else being on().
Fun stuff.

Just for fun:

def anyOpen(obj) {
obj.each {n->if (n.currentValue(“contact”)==“open”) return true}
return false
}

Marginally faster, because it returns true upon finding the first open contact rather than looking at all of them every time.

Well now you’ve done spoiled part of the OP’s adventure!!!, he was supposed to come up with that after looking at it “backwards”…

Nice try, but your code doesn’t work, storageanarchy!

This was my first pass at the function:
def allClosed(obj) {
obj.each {n->if (n.currentValue(“contact”)==“open”) return false}
return true
}

Here’s your code:
def anyOpen(obj) {
obj.each {n->if (n.currentValue(“contact”)==“open”) return true}
return false
}

Neither of the functions work! The return statement seems to only exit the obj.each loop, and not the function itself. Your function always returns true, mine always returns false.

Either we don’t understand what return does or it’s a bug! (My programming skills are really rusty, so I’d bet on option “A”)

Boom:
return contact1.currentValue(“contact”).toString().contains(“open”)
No loop (contains works on sets), no if (since it returns a Boolean), all in one…

This is all groovy stuff btw, nothing ST…

Bingo!

Here’s your idea implemented in my function:

def contactHandler(evt) {
log.debug "$evt.value"
if (evt.value == “open”) {
switch1.on()
} else if ( ! anyOpen(contact1) ) {
switch1.off()
}
}

def anyOpen(obj) {
return obj.currentValue(“contact”).toString().contains(“open”)
}

Tested and confirmed to work! Thanks!

C’mon now, you’re only a few short steps away from a one liner!!!