[OBSOLETE] SmartBulb Power Outage handler

I was tired of coming home or waking up to find all my smart bulbs turned on due to a power outage.
This app was inspired by the concept of a “Canary” bulb from @JDRoberts ( see Power Outage and Zigbee Bulbs)

Basically you set up a smart bulb that you never use. If this bulb is on, then the app turns it off and any bulbs that were off before the power outage occurred.

There is a lot of discussion on other posts about whether you should be changing the states of bulbs because you don’t know if anyone intended to change the states of the light while the power was out or after the power came back on and before the ST hub reconnects to the internet. This option works for my usage, hopefully it works for yours.

The code:

definition(
	name: "Smarter Bulbs",
	namespace: "nsweet68",
	author: "nick@sweet-stuff.cc",
	description: "Save the state of a bunch of bulbs and reset when 'Canary' bulb turns on",
	category: "My Apps",
	iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/App-LightUpMyWorld.png",
	iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/App-LightUpMyWorld@2x.png"
)
preferences {
    section("Canary Bulb") {
        input "canary", "capability.switch", title: "Who sings?"
    }
    section("Zigbee bulbs to monitor") {    
        input "slaves","capability.switch", multiple: true
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    initialize()
}

def updated() {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def initialize() {
    subscribe(slaves, "switch", saveStates)
    subscribe(canary,"switch.on", checkRestore)
    pollCanary()
    saveStates() 
	runEvery5Minutes(checkRestore)
    
}

def saveStates(evt) {
	log.debug "Checking States"
    if ("off" == canary.currentSwitch ) {
    	def lightsOff = [:]
    	slaves?.each {
			if (it.currentSwitch == "off"){
        	log.debug "${it.displayName} value ${it.currentSwitch}" 
        	lightsOff[it.id]="off"
        	}
		}
   	state.lOff = lightsOff
	}
}

def checkRestore(evt) {
    log.debug "Checking Restore"  
    pollCanary() 
    log.debug "Canary is ${canary.currentSwitch}"
    if ("on" == canary.currentSwitch) { 
    	log.debug "Turning stuff off"
        restoreState()
        canary.off()
        }
    pollSlaves()
    saveStates(evt)
}

private restoreState() {
  slaves?.each {
				if (state.lOff[it.id] == "off") {
                log.debug "turning $it.label off"
				it.off()
                }
			}
		}

private pollCanary() {
    def hasPoll = canary.hasCommand("poll")
    if (hasPoll) {
    	canary.poll()
        log.debug "Poll canary"
    }
    else
    {
    	canary.refresh()
        log.debug "Refresh canary"
    }
}

private pollSlaves() {

slaves.each {slave ->
def hasPoll = slave.hasCommand("poll")
    if (hasPoll) {
    	slave.poll()
        log.debug "Poll ${slave.displayName}"
    }
    else
    {
    	slave.refresh()
        log.debug "Refresh ${slave.displayName}"
    }
}
    
}
14 Likes

Good idea, I’ve been trying to think of a way to implement something like this.

The only catch is that the bulb being used as the “canary” has to be able to detect when it’s turned on by providing it power.

For example, if you use a dumb switch to turn on a GE Link Bulb, the Mobile App will show that the light was just turned on. If you do the same thing with a Cree Connect Bulb, the bulb will turn on, but the Mobile App will still think it’s off.

I haven’t tried this, but in theory, as long as you use the GE Link Bulb as the “canary”, the overall concept seems sound.

1 Like

In the original thread, you’ll see that my first thought was to put a Lux detector in the room, but the OP had a requirement that everything run locally And I wasn’t sure if there are any devices that measure Lux that run locally. The point being that you would get a Lux level and you wouldn’t have to worry about what the bulb reported. It would also be OK if there was a little bit of a delay while everything got synced up again because eventually the lux sensor would report “hey, there’s light in here!” And you’d catch it.

My second thought was to use a PIR motion sensor on the table underneath the Canary bulb because the heat of the bulb coming on will very likely trigger the motion sensor. That gives you a local device. The only problem with that is again you might miss the event, timing can get tricky. The lux sensor is easier because it’s just looking for a level, not a state change.

But eventually, I just got to “why not try it just with the bulb?” But I agree you need to do some testing to make sure it works with your particular set up. :sunglasses:

There are really two separate issues. First, is there something local you can test to see if the power came back on that wouldn’t be fooled by normal activity? That’s an obvious Canary test, and a bulb is an obvious canary.

Next, how are you going to measure the Canary’s change in state? As just discussed, there are multiple things you can check: Lux, heat, a bulb event, etc.

For this particular smartapp, The bulb event was chosen. But if that doesn’t work for somebody, there are other ways. :sunglasses:

2 Likes

Did you by any chance get this up in GitHub for us to retrieve?

Good Call! Luckily I did my testing with a GE bulb as the canary or it could have been very frustrating until I realized the issue with Cree bulb.
I just did some testing with the Cree bulb as the Canary and it failed most of the time. There would also be an issue with the app still recording the Cree bulb as off, if it was turn on by a dumb switch. This would result in the Cree bulb being turned off, even though it was on when the outage occurred.
I like the Cree bulbs better as a light bulb, but I guess I’ll be buying the GE Link Bulbs from now on.
Is this issue a Cree hardware issue or a Cree/Smarthings issue?

The bulb doesn’t send a message when it’s turned on so there’s nothing that can be done in SmartThings.

I created a DTH for the Cree Bulb that uses zigbee reporting to correct itself, but the reporting often stops when the bulb is manually turned off and then back on.

Polling the device will start the reporting again and correct the state, but SmartThings polls zigbee devices anywhere from multiple times within a few minutes to once every few days so you can’t rely on that.

I’ve also noticed that the bulbs will start displaying timeout exception if you manually poll them more than every few hours.

1 Like

The GE links have a known firmware problem: they can lose track of what network they’re connected to. It’s not every bulb every time, but it’s enough bulbs often enough that this is the reason they are not on the official “works with smartthings” list. They would probably be my least favorite as a canary for this reason. Unless of course you’re going to use a lux sensor or a motion sensor in which case the fact that that bulb can’t talk to smartthings won’t make any difference :wink:

I hear good things about the eco-smart bulbs but I haven’t tried one.

A Hue white is also $15. But I don’t know what reporting it does when it’s connected directly.

Maybe? I’m a GitHub newbie. Set up my account last year when I first got my ST hub and haven’t really used it since.
It’s here, not sure if that’s where it should be.

1 Like

Thanks! Well I am a GitHub newbie myself. This at least gets us to the code. The way you setup is a little bit off their ST recommended but the important pieces of the .src and .groovy is good enough to integrate to. I personally don’t like the way the method is described in the documentation because there is no easy way to determine whose github repo you are attached to when “Update from Repo” is clicked. ST directions will have everyone with SmartThingsPublic (master) {which is what yours says now} which is practically useless to know which repo has the latest code that needs updating. When they say to use a directory name for your smartapp or device handler as SmartThingsPublic I would change that to the app or device handler name. Then you can see from my highlights which repo I want to update.

1 Like

I noticed I had a bad routine name in
runEvery5Minutes(someEventHandler)

Should be
runEvery5Minutes(checkRestore)

Although I think it worked without it, but I’m not sure when I screwed that up.
This is commit to GitHub.

1 Like

Nick, thanks for putting this together. I set up a GE link bulb as a canary, and now the rest of my 12 smart bulbs behave well after a power outage. Waking up to a room full of lights, or coming home from 2 weeks of travel to find a ton of bulbs on is no longer a problem.

1 Like

I’m glad I could help!

1 Like

So I have something weird going on. I have a z-wave siren that, when turned on, is triggering the app as if the siren is a canary device. Debug logging shows “canary is on” when the siren is activated. I don’t have the siren device selected in the Smarter Bulbs app, so I’m not sure how it’s changing the state of the app’s canary device…

Here’s the debug entry when saving the app settings. The siren device isn’t here:

Updated with settings: [canary:Canary Bulb, slaves:[Bar Lamp, Desk Lamp, Left Couch Light, MBR Left Bed Light, MBR Left Closet Light, MBR Right Bed Light, MBR Right Closet Light, Right Couch Light, Side Yard Floodlight, Trash Area Floodlight]]

Nevermind all that. Apparently when I was creating the SmartApp, I installed an instance of it through the web IDE and set the siren device as the canary. I didn’t even know it was possible to activate a SmartApp thru the IDE and have it invisible from the mobile app…

Back to your usual scheduled programming.

1 Like

So, the power went off for a few minutes the other day. The power came back on, but smartthings didn’t pick up the canary bulb as on, so all the lights stayed on.
I had a prior power outage and things worked as expected, so I guess this is hit or miss.

At one point I tried using poll() and refresh() to try to get the status of CREE bulbs without any success. Anyone know if either works with the GE bulbs?

Any other suggestions?

Nevermind. Not sure what I was doing the last time I tested polling. I added polling to the canary bulb and it should now handle a missed “canary on” event. (also only turn the canary off, if I think it is on).
As an added bonus, you can use a Cree bulb as the canary and it should work without any issues.

This has been committed to GitHub.

1 Like

Updated the code to also poll the monitored light bulbs. This should now pick up bulbs that were turned on by the physical switch and smartthings didn’t pick up the change (mainly for CREE bulbs). This should avoid turning those lights off after a power outage.

/**
 *  Smarter Bulbs
 *
 *  Copyright 2016 Nick Sweet.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */

/************
 * Metadata *
 ************/
definition(
	name: "Smarter Bulbs",
	namespace: "nsweet68",
	author: "nick@sweet-stuff.cc",
	description: "Save the state of a bunch of bulbs and reset when 'Canary' bulb turns on",
	category: "My Apps",
	iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/App-LightUpMyWorld.png",
	iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/App-LightUpMyWorld@2x.png"
)
preferences {
    section("Canary Bulb") {
        input "canary", "capability.switch", title: "Who sings?"
    }
    section("Zigbee bulbs to monitor") {    
        input "slaves","capability.switch", multiple: true
    }
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    initialize()
}

def updated() {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    initialize()
}

def initialize() {
    subscribe(slaves, "switch", saveStates)
    subscribe(canary,"switch.on", checkRestore)
    pollCanary()
    saveStates() 
	runEvery5Minutes(checkRestore)
    
}

def saveStates(evt) {
	log.debug "Checking States"
    if ("off" == canary.currentSwitch ) {
    	def lightsOff = [:]
    	slaves?.each {
			if (it.currentSwitch == "off"){
        	log.debug "${it.displayName} value ${it.currentSwitch}" 
        	lightsOff[it.id]="off"
        	}
		}
   	state.lOff = lightsOff
	}
}

def checkRestore(evt) {
    log.debug "Checking Restore"  
    pollCanary() 
    log.debug "Canary is ${canary.currentSwitch}"
    if ("on" == canary.currentSwitch) { 
    	log.debug "Turning stuff off"
        restoreState()
        canary.off()
        }
    pollSlaves()
    saveStates(evt)
}

private restoreState() {
  slaves?.each {
				if (state.lOff[it.id] == "off") {
                log.debug "turning $it.label off"
				it.off()
                }
			}
		}

private pollCanary() {
    def hasPoll = canary.hasCommand("poll")
    if (hasPoll) {
    	canary.poll()
        log.debug "Poll canary"
    }
    else
    {
    	canary.refresh()
        log.debug "Refresh canary"
    }
}

private pollSlaves() {

slaves.each {slave ->
def hasPoll = slave.hasCommand("poll")
    if (hasPoll) {
    	slave.poll()
        log.debug "Poll ${slave.displayName}"
    }
    else
    {
    	slave.refresh()
        log.debug "Refresh ${slave.displayName}"
    }
}
    
}

1 Like

Power went out during our little mini heat wave today. Smart bulbs back to their intended states as soon as generator kicked in! App worked perfectly. There were a few utility recloser activations right as my evening light routines started turning some bulbs on. Even with the power going on and off, all the bulbs ended up in the correct state (minus a few GE Links, but that’s another story). Great app.

2 Likes

Great to hear! I haven’t had a power outage since I made the last updates so I really appreciate the feedback.
Thanks!

1 Like

My power went out last night (2nd time since I set up your app) worked great both times. Thank you!!!

1 Like