@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")
}