How to schedule a start and end time for mode changes when presence detected


(Emerson) #1

Ok, so what I’m trying to do is set up a start and end time for a presence tag to be “listened” to. Say, for instance, I want a light to switch on when I come home but only when it’s between the hours of sunset and 4 am. I’ve read most of the documentation but I see nothing that is quite like what I’m looking for. Here is what I have so far- not sure if it’s correct or not… all a learning process for me. Almost all of the code is SmartThing’s work but blending two examples.

preferences {

 

section("When one of these people arrive at home") {

input "people", "capability.presenceSensor", multiple: true

}

section("Starting at the time"){

input "time", "time", title: "Start Time of Day"

}

section("Change to this mode") {

input "newMode", "text", title: "Mode?"

}

section("And text me at (optional)") {

input "phone", "phone", title: "Phone number?", required: false

}

section("False alarm threshold (defaults to 10 min)") {

input "falseAlarmThreshold", "decimal", title: "Number of minutes", required: false

}

}

 

def installed() {

initialize()

log.debug "Installed with settings: ${settings}"

log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"

people.each {

subscribe(it.presence)

}

}

 

def updated() {

initialize()

unschedule()

log.debug "Updated with settings: ${settings}"

log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"

unsubscribe()

subscribe(people, "presence", presence)

}

 

def initialize() {

schedule(time, newMode)

}

 

def presence(evt)

{

log.debug "evt.name: $evt.value"

def threshold = falseAlarmThreshold != null ? (falseAlarmThreshold * 60 * 1000) as Long : 10 * 60 * 1000L

 

if (location.mode != newMode) {

 

def t0 = new Date(now() - threshold)

if (evt.value == "present") {

 

def person = getPerson(evt)

def recentNotPresent = person.statesSince("presence", t0).find{it.value == "not present"}

if (recentNotPresent) {

log.debug "skipping notification of arrival of ${person.displayName} because last departure was only ${now() - recentNotPresent.date.time} msec ago"

}

else {

def message = "${person.displayName} arrived at home, changing mode to '${newMode}'"

log.info message

sendPush(message)

if (phone) {

sendSms(phone, message)

}

setLocationMode(newMode)

}

}

}

else {

log.debug "mode is the same, not evaluating"

}

}

 

private getPerson(evt)

{

people.find{evt.deviceId == it.id}

}

(Love And Laughter Farm) #2

Sounds like you want to use a combination of two SmartApps already available:

Scheduled Mode Change
Light Follows Me

Create a new mode for your specified time and create a SmartApp to respond to your presence sensor when in that new Mode.

 


(Emerson) #3

Thanks for the help. I was trying to go for something a little more like what I assume the sunrise/sunset app does yet they don’t have that available as an example. It seems a little more involved than it needs to be on the user side.


(Freetobelee) #4

I’m trying to do a similar thing, basically trying to avoid changing modes. I feel like the app itself can check if it is after sunset (dang, I WISH that sunrise/sunset app was example code we could see!) and before a certain time, and only turn on the light when motion is sensed in that range.


(Freetobelee) #5

excuse me, I meant when you get home in that range of time (motion is what I am trying to accomplish…)


(Egarl005) #6

Emerson here, SmartThings login has been acting off for the past week for me so I re registered :/. I fee what you’re saying. I’ve been learning a lot though- through this forum and elsewhere. I for one can’t wait until the documentation becomes more complete. Especially the OAUTH sections.


(Dan Lieberman) #7

@egarl005 / @freetobelee - We’re working on getting the documentation together on exposing web services and the OAUTH2 flow and hope to have that complete soon.

As for consuming web services (the Weather Underground Astronomy Web Service API for getting sunrise/sunset, for example), you can use the HTTP methods from within your SmartApp. See the documentation here: http://support.smartthings.com/entries/21775510-HTTP-Methods

Like many Web Service APIs, Weather Underground requires an API Key which you can obtain for free by registering on their developer website.


(James) #8

@freetobelee, did you ever figure out how to make an app that does this? I’m trying to do the exact same thing: Turn on a light when motion is sensed, but only after sunset and before my bedtime. Seems like it should be easy enough, but I can’t get it working to save my life.


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #9

Hmmm… I thought Sunrise/Sunset was published; regardless, here is my copy with very minor mods.

/**
 *  Sunrise, Sunset
 *
 *  Author: SmartThings
 *
 *  Date: 2013-04-30
 */
preferences {
	section ("At sunrise...") {
		input "sunriseMode", "mode", title: "Change mode to?", required: false
	    input "sunriseButton", "capability.momentary", title: "Tap Scene Buttons?", required: false, multiple: true
		input "sunriseOn", "capability.switch", title: "Turn on?", required: false, multiple: true
        input "sunriseOff", "capability.switch", title: "Turn off?", required: false, multiple: true
	}
	section ("At sunset...") {
		input "sunsetMode", "mode", title: "Change mode to?", required: false
	    input "sunsetButton", "capability.momentary", title: "Tap Scene Buttons?", required: false, multiple: true        
		input "sunsetOn", "capability.switch", title: "Turn on?", required: false, multiple: true
		input "sunsetOff", "capability.switch", title: "Turn off?", required: false, multiple: true
	}
	section ("Sunrise offset (optional)...") {
		input "sunriseOffsetValue", "text", title: "HH:MM", required: false
		input "sunriseOffsetDir", "enum", title: "Before or After", required: false, metadata: [values: ["Before","After"]]
	}
	section ("Sunset offset (optional)...") {
		input "sunsetOffsetValue", "text", title: "HH:MM", required: false
		input "sunsetOffsetDir", "enum", title: "Before or After", required: false, metadata: [values: ["Before","After"]]
	}
	section ("Zip code (optional, defaults to location coordinates)...") {
		input "zipCode", "text", required: false
	}
}

def installed() {
	initialize()
}

def updated() {
	unschedule()
	initialize()
}

def initialize() {
	astroCheck()
	schedule("0 1 * * * ?", astroCheck) // check every hour since location can change without event?
}

def astroCheck() {
	def s = getSunriseAndSunset(zipCode: zipCode, sunriseOffset: sunriseOffset, sunsetOffset: sunsetOffset)

	def now = new Date()
	def riseTime = s.sunrise
	def setTime = s.sunset
	log.debug "riseTime: $riseTime"
	log.debug "setTime: $setTime"
	if (state.riseTime != riseTime.time || state.setTime != setTime.time) {
		state.riseTime = riseTime.time
		state.setTime = setTime.time

		unschedule("sunriseHandler")
		unschedule("sunsetHandler")

		if (riseTime.after(now)) {
			log.info "scheduling sunrise handler for $riseTime"
			runOnce(riseTime, sunriseHandler)
		}

		if (setTime.after(now)) {
			log.info "scheduling sunset handler for $setTime"
			runOnce(setTime, sunsetHandler)
		}
	}
}

def sunriseHandler() {
	log.info "Executing sunrise handler"
    sunriseButton?.push()
	sunriseOn?.on()
	sunriseOff?.off()
	changeMode(sunriseMode)
	unschedule("sunriseHandler") // Temporary work-around for scheduling bug
}

def sunsetHandler() {
	log.info "Executing sunset handler"
    setsetButton?.push()
	sunsetOn?.on()
	sunsetOff?.off()
	changeMode(sunsetMode)
	unschedule("sunsetHandler") // Temporary work-around for scheduling bug
}

def changeMode(newMode) {
	if (newMode && location.mode != newMode) {
		if (location.modes?.find{it.name == newMode}) {
			setLocationMode(newMode)
			send "${label} has changed the mode to '${newMode}'"
		}
		else {
			send "${label} tried to change to undefined mode '${newMode}'"
		}
	}
}

private send(msg) {
	sendPush msg
	log.debug msg
}

private getLabel() {
	app.label ?: "SmartThings"
}

private getSunriseOffset() {
	sunriseOffsetValue ? (sunriseOffsetDir == "Before" ? "-$sunriseOffsetValue" : sunriseOffsetValue) : null
}

private getSunsetOffset() {
	sunsetOffsetValue ? (sunsetOffsetDir == "Before" ? "-$sunsetOffsetValue" : sunsetOffsetValue) : null
}