The automated home has not yet reached ubiquity, but systems like SmartThings are certainly making it easier to jump into the fun of controlling the phsyical world; even more so when Google Home and Alexa all come with SmartThings integrations.

As a dad to 5 and 7 year old boys I often find lights left on around the house and when those lights are upstairs there was a time I’d have mumbled a few choice words and thudded my way up the stairs to turn it off (surely children should have evolved to understand how high energy prices are now?). But no longer! I have replaced their lightswitch with a z-wave wall switch which means I can ask Google Home to do it; “Hey Google; Turn the Boys’ light off”. smile

The main problem is that my two monsters are currently still sleeping in the same room. The 7 year old is channelling vibes from a teen and would rather sleep late; but my five year old is a dawn chaser with a five year old’s lack of empathy. So, I often wake to find the light’s been on since the crack of dawn and they’ve been playing together and losing sleep. That makes them grumpy; and grumpy children are like mini Satans.

So, it was time to install into my SmartThings Hub the same app I used to run on my OpenHAB setup. This app used to ensure the light stayed off at night.

Now, there’s no way to physically stop the light being turned on; the switches are designed to switch the light directly so that they work even if there’s a network failure. So the only option is to detect it being switched on then switch it off again as quickly as possible. Turns out that’s quite easy with SmartThings.

SmartThings has an online IDE at http://graph.api.smartthings.com which is pretty basic. But it has a simulator so you can try the app before you publish it to your hub.

However, there is one massive caveat that had me stumped for some time. Apparently, the SmartThings guys have moved their systems to location-specific servers and the graph.api server will not actually publish your app to your hub (if it can even see your hub). For the UK you have to go to https://graph-eu01-euwest1.api.smartthings.com/ which works.

Once on the right server, in the My SmartApps section of the developer page, you can scaffold a new blank app by filling in the form. The form simply fills in an initialisation call at the top of your code, so you can change it later. Apps you add should be put in the My Apps category.

definition(
    name: "Ensure Lights Off",
    namespace: "uk.me.dupplaw.david.st",
    author: "David Dupplaw",
    description: "If lights are turned on during certain time spans, they are automatically turned off again.  Useful for children who want to play toys all night.",
    category: "My Apps",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
    iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png") {
}

The preferences() method sets up the page which the user will see on their mobile for adding settings to your app. It’s a basic UI DSL that maps preferences to types of capability.

preferences {
    section("Light to check") {
    	input "theLight", "capability.switch", title: "Which light?", required: true
	}
    section("Times to check") {
    	input "startTime", "time", title: "From:", required: true
        input "endTime", "time", title: "To:", required: true
    }
}

The names in the first columns of the inputs are automagically converted into usable variables with the appropriate capabilities. So theLight has capability switch, so has the on() and off() methods.

This is how it ends up looking in the app:

Ensure Lights Off App

The scaffolding also adds some default implementations for some of the lifecycle methods in your app. They’re not too interesting, but means you can hook into initialisation or settings update lifecycle events. In the initialize() lifecycle callback we subscribe to events from theLight.

def initialize() {
	subscribe(theLight, "switch.on", lightOnHandler)
}

Here, lightOnHandler is a callback method that’s called when theLight emits switch.on event. We’ll get to that now.

startTime and endTime (from the preferences) are strings that resolve to the date the user sets their preferences. However, the SmartThings API has methods timeToday(string) and timeOfDayIsBetween(...) which returns the time on today’s date as a Date or a boolean from those strings.

So, it’s pretty easy to check whether we’re in the no-light time period and switch the light back off when the event fires. That’s what our lightOnHandler does:

def lightOnHandler(evt) {
    def startDate = timeToday(startTime)
    def endDate   = timeToday(endTime);
    def timeZone  = location.getTimeZone()
    
    def isTime = timeOfDayIsBetween(startDate, endDate, new Date(), timeZone )
    if( isTime ) {
	lightOff();
    	log.debug "Light was turned on at ${new Date()} - turned it off again";
    }
}

def lightOff() {
    theLight.off();
}

We can run the simulator to try it out, but I was getting a problem with the timeZone. The simulator does not appear to have a timezone associated with it, so I added a null check on the timezone:

    def timeZone  = location.getTimeZone()
    
    if( timeZone == null ) {
    	timeZone = TimeZone.getDefault();
    }

The other problem I had (with OpenHAB too) was that if my little monsters hammered on the light switch, it would miss switch on events and the light would stay on. They learned that pretty quickly. So with OpenHAB I ran some light-off events a few seconds after the light was initially switched off - just to make sure.

It’s easy to do the same in SmartThings as it has the runIn method, which sets a timer (in seconds) and runs a callback when the timer expires. So I added this inside the if clause to try to turn the light off again after 1, 2 and 3 seconds after the initial event:

    runIn( 1, lightOff );
    runIn( 2, lightOff );
    runIn( 3, lightOff );

You can see it running in the simulator in this screengrab:

Simulator

And here it is for real:

LightsOff working

So far, it’s back to doing it’s job. The light is never on in the morning. The only problem is, they also have a lamp in their room, so looks like I’m going to have to get a z-wave plug and disable it during the night!

If you have a need for a similar app, or just want a starter for 10, check out my code on GitLab.