[BETA] Energy Allowance with shut-off

I ended up writing this (my very first SmartApp ever!) because I couldn’t find similar functionality anywhere else, or make other modules like Smart Lighting, operate the way I intended.

My problem statement:
Occasionally, family members forget to turn off the toaster oven, and as a result it has been left on for hours accidentally.

Solution:
Put it on a Samsung Smart Outlet and figure out how to get SmartThings to turn it off when it’s been left on too long!

Details:
The application I wrote looks for continuous usage over a pre-set time interval. With a toaster oven (my specific use case), when on, it consumes >400W, but when it’s on but idle (at temperature) it drops to 0.1W (but still above 0W!). I am looking to shut off the outlet if the continuous usage exceeds 20 minutes. Since that’s my specific case, I actually made these the default values in my code, but they’re customizable.

Like I said, this is the first SmartApp code I’ve ever written, so be gentle. :slight_smile:

/**
 *  Copyright 2019
 *
 *  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.
 *
 *  Energy Allowance
 *
 *  Author: Dan Jeuch
 */
definition(
    name: "Energy Allowance",
    namespace: "djeuch",
    author: "Dan Jeuch",
    description: "Shut off an outlet based on continuous power draw over a pre-determined time interval. Example: Shut off a toaster connected to an outlet if left on for 20 continuous minutes using 0 watts or more",
    category: "Green Living",
    iconUrl: "http://cdn.device-icons.smartthings.com/Appliances/applicances15-icn@2x.png",
    iconX2Url: "http://cdn.device-icons.smartthings.com/Appliances/applicances15-icn.png"
)

preferences {
	section("When power is being used...") {
		input "theOutlet", "capability.powerMeter", required: true
	}
	section("Turn it off after how many minutes?") {
		input "minutesLater", "number", title: "How long?", required: true, defaultValue: 20
		input "usingWatts", "number", title: "How many Watts? (0=any power)", required: true, defaultValue: 0
	}
}

def installed() {
	log.debug "Installed with settings: ${settings}"
    state.InUse=false  // InUse is held static to keep track if power is being continuously drawn
	subscribe(theOutlet, "power", outletInUseHandler, [filterEvents: false])
}

def updated() {
	log.debug "Updated with settings: ${settings}"
    state.InUse=false
	unsubscribe()
	subscribe(theOutlet, "power", outletInUseHandler, [filterEvents: false])
}

def outletInUseHandler(evt) {
    def meter=evt.value as double
    if( meter > usingWatts )
    {
	    log.debug "Outlet ${theSwitch} power: ${meter}"
    	if (!state.InUse) { // if this is a new power draw
	    	state.InUse = true
	        state.StartTime = now()
            log.debug "Energy Allowance Timer starting"
		    runIn(minutesLater*60,"outletInUseTimer",[overwrite: true]) // need to schedule this in case power utilization doesn't change enough to trigger this particular routine
	    } else {
	    	def elapsed = now() - state.StartTime // in milliseconds
            def elapsedSeconds = elapsed / 1000   // in seconds
            log.debug "Energy Allowance Timer running at ${meter} watts, continuously running over ${usingWatts} watts for ${elapsedSeconds} seconds"
            if (elapsedSeconds > minutesLater*60) {
            	log.debug "Energy Allowance Maximum time reached - shutting off outlet"
				theOutlet.off()
            }
	    }
    } else { // if we are here, utilization dropped below the threshhold, so we reset back to the full time interval for the next time
    	state.InUse=false
        log.debug "Energy Allowance Timer stopped - below ${usingWatts} watts being used"
    }
}

def outletInUseTimer() {
	def meter=theOutlet.currentValue("power") as double
    log.debug "Energy Allowance Timer triggered, outlet ${state.Inuse} and using ${meter} watts"
	if (state.InUse && meter > usingWatts) {
        log.debug "Energy Allowance Maximum time reached - shutting off outlet"
    	theOutlet.off()
	    state.InUse=false
    }
}
1 Like

Sounds like a good use case!

These days, I think that most people who find the official features are lacking variables that they need just jump directly to Webcore. It’s essentially a scripting language for smartthings, and does a lot of the heavy lifting for you.

You might enjoy looking into it. It’s very popular for those with a technical background, and they even have their own forum. :sunglasses:

I have WebCoRE installed and looked at it, but wanted to see if I could go with a native solution! I may do something similar in WebCoRE as an exercise, but it wasn’t too difficult to pick up on the language/syntax/variables within SmartThings.