Hello, Home Phrase Director - Control modes (through hello home phrases) based on occupancy and "sun state"

A lot of peope have had interest in this app over the last few weeks. Setting up a dedicated thread for it.

Magic home allows for four hello home scenes to be run based on 2 conditions. 1) Occupancy of your home 2) the current “sun state”.

This allows for you to have a sunrise and sunset mode for when your home is occupied and not occupied. I currently have mine setup like this.

  1. Away Day - Will trigger when everyone is away and the sun is up
  2. Away Night - Will trigger when everyone is away and the sun is down
  3. Home Day - Will trigger when someone is home and the sun is up
  4. Home Night - Will trigger when someone is home and the sun is down

Everything is automated and it will trigger on each event. So everytime the “sun state” changes it will check to see if anyone is home as well as everytime the presence changes it will check to see if the sun is up. This has become a integral part in my automation.

I hope this helps people :smile:

I have submitted this for official SmartThings integration but it has not begun review yet. Its been in queue for 2 weeks or so. Hoping it will be looked at soon.

EDIT: You can find the code on my GitHub now. Trying to keep versions the same for everyone.

@mxrugg made this writeup to configure the app. Thanks man!!!

18 Likes

Awesome! I will be sure to “watch” this new string to see the updates about its acceptance aas an official SmartApp.

Thanks Tim!

This is great - but to be useful for me, I just need to ask for FOUR more states :o):

  1. Home and Asleep (HVAC settings change for cooler/warmer sleeping, Smart Alarm sets for increased detection while I’m sleeping, all internal lights turn off no matter when I turned them on, etc.) Sunrise/Sunset doesn’t matter
  2. Home and Awake (HVAC warrms up the house, HW recirculator warms up the water, coffee maker starts, morning light scene turns on for coffee & reading the paper, TV turns on, etc.
  3. Home and Working (everything but my office pretty much shut down)
  4. Home and Watching Football (OK, so I’ve probably over done it a bit… you probably get the point I’m trying to make)

I totally appreciate that not everyone thinks this way, but for me, modes are really about the activities I do when I’m home (or not). If I need some things to happen at sunrise/sunset, they generally aren’t related to whether I am home or not (e.g., turn on the driveway lights when it gets dark, off at midnight, on at 5am for the snow plow guy, off at sunrise - all whether I am home or not). Trying to merge solar cycles and my daily routine cycles is stretching things beyond practical, IMHO.

I’m glad it works for you, and thank you for sharing!

1 Like

I do these types of things outside of the app using additional home phrases. This is just re foundation that I build upon. For instance I have a home - Work phrase the triggers at 8Am if I am home that boots up my PC and turns on my office heater.

This app shouldn’t be considered a end all be all but foundational for other things:)

Hope this makes sense.

Does this require an additional Mode as well as Hello Home Action?
Thx

You’ll need. Mode for each hello home action if you want different modes to control different things

Tim thanks again. This app is a great solution to automatic mode switching with sunrise/sunset.
Is there any probability of a sunrise/sunset offset option in a future release just to avoid having to stack multiple hello home routines in front of it to account for those of us up and moving well before the sunrise?

No. My version with an offset was rejected by STs.

The beauty of STs is that the apps are “simple” this allows for more granularity. Once you start making a “one size fits all” app you slow down creativity.

Plus with a sunset offset it wouldn’t really help in most cases. For instance if there was an offset here it will change you mode to Home Day right? If you want lights to turn on during early morning hours then lights will forever turn on by motion in home day mode. Doesn’t really make sense for 2 hours of darkness. You should create a “Getting Ready for work mode” that runs when motion is detected between x and y times.

IMO less is not more when it comes to modes. More is more. One mode for every single thing you need done. My app will just take care of you coming and going:) and making sure your house is setup for you at sunrise and sunset:)

Last I counted I have 30 or so modes. Very few which I ever have to interact with. It’s all automated for the most part through hello home. One for every situation.

1 Like

Hope it gets approved an on the ST list - I sure could use it!

This is an awesome app idea. I wanted this exact setup; I did it manually with 6 separate smartapps in Mode Magic, which was a hassle. An off-the-shelf solution would have been easier. Although I do use the offset.

@storageanarchy - I wrote a similar app that can use a variable number of modes. I’ve been testing it to make sure it works before I posted the code. Here’s my code:

/**
 *  Better Sunrise/Sunset
 *
 *  Copyright 2014 Eric Roberts
 *
 *  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.
 *
 */
definition(
    name: "Better Sunrise/Sunset",
    namespace: "baldeagle072",
    author: "Eric Roberts",
    description: "Better sunrise/sunset with more options",
    category: "Mode Magic",
    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")

//setup

preferences {
	page name:"setupInit"
	page name:"setupConfigure"
	page name:"setupModeTypes"
}

def setupInit() {
	TRACE("setupInit()")
	if (state.installed) {
		//return setupModeTypes()
        return setupConfigure()
	} else {
		return setupConfigure()
	}
}

def setupConfigure() {
	TRACE("setupConfigure()")

	def textNumOfHelp = 
		"You can switch between two modes for each type. How many types " +
		"do you have?"

	def inputNumModeTypes = [
		name: 			"numModeTypes",
		type: 			"number",
		title: 			"How many mode types?",
		defaultValue: 	"3",
		required: 		true
	]


	def pageProperties = [
		name: 			"setupConfigure",
		title: 			"Number of Mode Types",
		nextPage: 		"setupModeTypes",
		uninstall: 		true
	]

/*
	def pageProperties = [
		name: 			"setupConfigure",
		title: 			"Number of Mode Types",
        install: 		true,
		uninstall: 		false
	]
    */
	return dynamicPage(pageProperties) {
		section("Number of Mode Types") {
			paragraph textNumOfHelp
			input inputNumModeTypes
		}

		section ("Sunrise offset (optional)...") {
			input "sunriseOffsetValue", "text", title: "HH:MM", required: false
			input "sunriseOffsetDir", "enum", title: "Before or After", required: false, options: ["Before","After"]
		}
		section ("Sunset offset (optional)...") {
			input "sunsetOffsetValue", "text", title: "HH:MM", required: false
			input "sunsetOffsetDir", "enum", title: "Before or After", required: false, options: ["Before","After"]
		}
		section ("Zip code (optional, defaults to location coordinates)...") {
			input "zipCode", "text", required: false
		}
        /*
		section( "Notifications" ) {
			input "sendPushMessage", "enum", title: "Send a push notification?", options: ["Yes", "No"], required: false
			input "phoneNumber", "phone", title: "Send a text message?", required: false
		}
        */
	}
}

def setupModeTypes() {
	TRACE("setupModeTypes()")

	def textDayHelp =
		"This mode will be active during the day"

	def textNightHelp =
		"This mode will be active at night"

	def textOnSunriseHelp =
		"These switches will turn on at sunrise"

	def textOffSunriseHelp =
		"These switches will turn off at sunrise"

	def textOnSunsetHelp =
		"These switches will turn on at sunset"

	def textOffSunsetHelp =
		"These switches will turn off at sunset"
	
	def pageProperties = [
		name: 		"setupModeTypes",
		title: 		"Configure Mode Types",
		install: 	true,
		uninstall: 	state.installed
	]

	return dynamicPage(pageProperties) {
		for (int n = 1; n <= numModeTypes; n++) {
			section("Mode Type ${n}", hideable:true, hidden:true) {
				paragraph textDayHelp
				input "m${n}_dayMode", "mode", title: "Day Mode", required: true
				paragraph textNightHelp
				input "m${n}_nightMode", "mode", title: "Night Mode", required: true
				paragraph textOnSunriseHelp
				input "m${n}_sunriseOnSwitches", "capability.switch", title: "Sunrise On Switches", multiple: true, required: false
				paragraph textOffSunriseHelp
				input "m${n}_sunriseOffSwitches", "capability.switch", title: "Sunrise Off Switches", multiple: true, required: false
				paragraph textOnSunsetHelp
				input "m${n}_sunsetOnSwitches", "capability.switch", title: "Sunset On Switches", multiple: true, required: false
				paragraph textOffSunsetHelp
				input "m${n}_sunsetOffSwitches", "capability.switch", title: "Sunset Off Switches", multiple: true, required: false
			}
		}
	}
}

// installed/updated/init

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

	initialize()
}

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

	unsubscribe()
	initialize()
}

def initialize() {
	// TODO: subscribe to attributes, devices, locations, etc.
	TRACE("initialize()")
    
    state.installed = true
    
    if (settings.zipCode == null) {
    	settings.zipCode = location.zipCode
    }
    
    state.numModeTypes = numModeTypes
    
    state.sunriseArray = []
	state.sunsetArray = []
    state.modeTypes = []
    
    for (int n = 1; n <= numModeTypes; n++) {
    	setupModeType(n)
    }
    
    //log.debug("init modeTypes ${state.modeTypes}")

    scheduleSunriseSunset()
    TRACE("End init")
}

def setupModeType(n) {
	TRACE("setupModeType($n)")
	def modeType = [:]
	modeType.dayMode = settings."m${n}_dayMode"
	modeType.nightMode = settings."m${n}_nightMode"
    
	state.modeTypes.push(modeType)
    state.sunriseArray.push(modeType.nightMode)
    state.sunsetArray.push(modeType.dayMode)
}

def getModeTypeDevices(n) {
	if (n >= state.numModeTypes) {
    	return null
    }
    n++
    
    def devices = [:]
    
	devices.sunriseOnSwitches = settings."m${n}_sunriseOnSwitches"
	devices.sunriseOffSwitches = settings."m${n}_sunriseOffSwitches"
	devices.sunsetOnSwitches = settings."m${n}_sunsetOnSwitches"
	devices.sunsetOffSwitches = settings."m${n}_sunsetOffSwitches"
    
    return devices
}

// schedule

def scheduleSunriseSunset() {
	TRACE("scheduleSunriseSunset()")
    def srOff = sunriseOffset()
    def ssOff = sunsetOffset()
    log.debug("srOff: $srOff , ssOff: $ssOff")
	
	def sunriseSunset = getSunriseAndSunset(zipCode: settings.zipCode)
    
	def sunriseTime = sunriseSunset.sunrise
	def sunsetTime = sunriseSunset.sunset

	def sunriseScheduleTime = getSunriseWithOffset(srOff)
	def sunsetScheduleTime = getSunsetWithOffset(ssOff)

	log.debug("sunriseScheduleTime $sunriseScheduleTime , sunsetScheduleTime $sunsetScheduleTime")
    
    def localData = getWeatherFeature('geolookup', settings.zipCode as String)
    
    def timezone = TimeZone.getTimeZone(localData.location.tz_long)
    
    log.debug( "Sunset today is at $sunsetTime" )
    log.debug( "Sunrise today is at $sunriseTime" )
    
    unschedule()    
    schedule(sunriseScheduleTime, sunrise)
    schedule(sunsetScheduleTime, sunset)
    schedule(timeTodayAfter(new Date(), '01:00', timezone), scheduleSunriseSunset)
}

def getSunriseWithOffset(srOff) {
	def srOffTime = getSunriseAndSunset(zipCode: settings.zipCode, sunriseOffset:srOff)
    //log.debug(srOffTime)
    return srOffTime.sunrise
}

def getSunsetWithOffset(ssOff) {
	def ssOffTime = getSunriseAndSunset(zipCode: settings.zipCode, sunsetOffset:ssOff)
	return ssOffTime.sunset
}

def sunriseOffset() {
	//log.debug("settings.sunriseOffsetValue ${settings.sunriseOffsetValue}")
    //log.debug("settings.sunriseOffsetDir ${settings.sunriseOffsetDir}")
	if ((settings.sunriseOffsetValue != null) && (settings.sunriseOffsetDir != null)) {
		def offsetString = ""
		if (settings.sunriseOffsetDir == 'Before') {
			offsetString = "-"
		}
		offsetString += settings.sunriseOffsetValue
		return offsetString
	} else {
		return "00:00"
	}
}

def sunsetOffset() {
	//log.debug("settings.sunsetOffsetValue ${settings.sunsetOffsetValue}")
    //log.debug("settings.sunsetOffsetDir ${settings.sunsetOffsetDir}")
    //log.debug((settings.sunsetOffsetValue != null) && (settings.sunsetOffsetDir != null))
	if ((settings.sunsetOffsetValue != null) && (settings.sunsetOffsetDir != null)) {
		def offsetString = ""
		if (settings.sunsetOffsetDir == 'Before') {
			offsetString = "-"
		}
		offsetString += settings.sunsetOffsetValue
		return offsetString
	} else {
		return "00:00"
	}
}

// events

def sunrise() {
	TRACE("sunrise()")
	def currentMode = location.mode
	def n = state.sunriseArray.indexOf(currentMode)
    log.debug("currentMode $currentMode sunriseArray ${state.sunriseArray}")
	if (n >= 0) {
		def modeType = state.modeTypes[n]
        log.debug("sunrise modeType $modeType")
        def devices = getModeTypeDevices(n)
        def onSwitches = devices.sunriseOnSwitches
        def offSwitches = devices.sunriseOffSwitches
		if (onSwitches != null) {
        	onSwitches.on()
        }
        if (offSwitches != null) {
        	offSwitches.off()
        }
		changeMode(modeType.dayMode)
	}
}

def sunset() {
	TRACE("sunset()")
	def currentMode = location.mode
	def n = state.sunsetArray.indexOf(currentMode)
	if (n >= 0) {
		def modeType = state.modeTypes[n]
        def devices = getModeTypeDevices(n)
        def onSwitches = devices.sunsetOnSwitches
        def offSwitches = devices.sunsetOffSwitches
		if (onSwitches != null) {
        	onSwitches.on()
        }
        if (offSwitches != null) {
        	offSwitches.off()
        }
		changeMode(modeType.nightMode)
	}
}

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

// debug

def TRACE(msg) {
	log.debug msg
    //log.debug("state $state")
}

Just so no one gets confused. @baldeagle072’s app will not change mode based on presence. Only at sunrise/sunset.

Two different but very useful apps depending on the application. Thanks for sharing @baldeagle072!!!

Tim,

Any idea why my Modes switched from Away Day to Home Night and skipped Away Night? Returned home to close to sunset maybe? Some kind of delay?
When using Magic Home is it normal to get the “Setting Sunset Mode” notification twice? Thanks!

Are your settings correct in the app? If they are I’m guessing you just returned home right around sunset. What time was sunset in your area today? If it was around 5:36 then that would be the correct assumption.

Used for debugging and has since been removed.

Sunset was at 5:27pm.
Some settings in my Magic Home:


What’s the false alarm threshold? Mode does not change to Away mode for X of minutes until after I leave home? Is this all it does?

Yep. Its meant to keep presence sensors from running amok.

Looks good. Guessing it was just a coincidence

How about this one?
Two Sunrise messages 3hrs apart? East Coast / West Coast maybe?

I think I had the same last night with Sunset.

@Dave Did you update to the latest code above? I get zero of these messages.

@tslagle13
Time, your Github says the last update was 14days ago, is the code in post #1 above more recent?

I just downloaded the code 3 or 4 days ago.
Thx

Yeah, i have not updated my github yet. #timfail

1 Like