Cobra:
I’ve finally managed to solve the issue with state variable.
and added switch to enable/disable
they all work fine.
But , the loop does not continue forever.
For example , I set 5 actions. after the 5th action, it goes back to the first one.
But does not go the the 2nd.
here’s the full code :
definition(
name: "Color Changing Bulbs",
namespace: "smartthings",
author: "SmartThings",
description: "Change color of bulbs in a defined pattern",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos@2x.png"
)
preferences {
page(name: "mainPage", title: "Color Changing Bulbs", install: true, uninstall: true)
page(name: "configureAction")
page(name: "timeIntervalInput", title: "Only during a certain time") {
section {
input "starting", "time", title: "Starting", required: false
input "ending", "time", title: "Ending", required: false
}
}
}
def mainPage() {
dynamicPage(name: "mainPage") {
section("Control these bulbs...") {
input "hues", "capability.colorControl", title: "Which Hue Bulbs?", required:false, multiple:true
}
section("enable/disable switch") {
input "switch1", "capability.switch", title: "Select switch to enable/disable app (Optional)", required: false, multiple: false
}
section("Actions") {
input "numberOfActions", "enum", title: "Number of Actions?", required: true, submitOnChange: true, options: [
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
def configDescription = ""
for (int i = 1; i <= (settings["numberOfActions"] as Integer); i++){
configDescription = ""
if (settings["p_${i}_color"] != null) {
configDescription = configDescription + "p_${i}_color" +":"
}
if (settings["p_${i}_lightLevel"] != null) {
configDescription = configDescription + "p_${i}_lightLevel" +":"
}
if (settings["p_${i}_duration"] != null) {
configDescription = configDescription + "p_${i}_duration" +":"
}
if (configDescription == ""){
configDescription = "Click to configure"
}
href "configureAction", title:"Configure Action", description:"$configDescription", params: [paction: i]
}
}
def anythingSet = anythingSet()
if (anythingSet) {
section("Play weather report when"){
ifSet "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
ifSet "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
ifSet "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
ifSet "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
ifSet "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
ifSet "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
ifSet "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
ifSet "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
ifSet "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
ifSet "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
ifSet "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
ifSet "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
ifSet "timeOfDay", "time", title: "At a Scheduled Time", required: false
}
}
def hideable = anythingSet || app.installationState == "COMPLETE"
def sectionTitle = anythingSet ? "Select additional triggers" : "Play weather report when..."
section(sectionTitle, hideable: hideable, hidden: true){
ifUnset "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
ifUnset "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
ifUnset "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
ifUnset "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
ifUnset "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
ifUnset "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
ifUnset "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
ifUnset "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
ifUnset "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
ifUnset "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
ifUnset "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
ifUnset "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
}
section("More options", hideable: true, hidden: true) {
input "frequency", "decimal", title: "Minimum time between actions (defaults to every event)", description: "Minutes", required: false
href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : "incomplete"
input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
if (settings.modes) {
input "modes", "mode", title: "Only when mode is", multiple: true, required: false
}
input "oncePerDay", "bool", title: "Only once per day", required: false, defaultValue: false
}
section([mobileOnly:true]) {
label title: "Assign a name", required: false
mode title: "Set for specific mode(s)"
}
}
}
def configureAction(params) {
if (params.paction != null) state.currentAction = params.paction.toInteger() //log.debug "$params.pbutton"
dynamicPage(name: "configureAction", title: "Choose the actions for Program${state.currentAction}.",
getActionSections(state.currentAction))
}
def getActionSections(actionNumber) {
return {
section("Color") {
input "p_${actionNumber}_color", "enum", title: "Light Strip Color?", required: false, multiple:false, submitOnChange: true, options: [
["Soft White":"Soft White - Default"],
["White":"White - Concentrate"],
["Daylight":"Daylight - Energize"],
["Warm White":"Warm White - Relax"],
"Red","Green","Blue","Yellow","Orange","Purple","Pink","Cyan","W1","W2","Random","Custom","Off"]
if (settings["p_${actionNumber}_color"] == "Custom"){
input "p_${actionNumber}_custom", "text", title: "Custom Color in Hex (ie ffffff)", submitOnChange: false, required: false
}
}
section("Level"){
input "p_${actionNumber}_lightLevel", "number", title: "Light Level?", required: false, range: "1..100"
}
section ("Duration"){
input "p_${actionNumber}_duration", "number", title: "Duration (milliseconds)", range: "100..1000000", submitOnChange: false, required: false
}
}
}
private anythingSet() {
for (name in ["hues","motion","contact","contactClosed","acceleration","mySwitch","mySwitchOff","arrivalPresence","departurePresence","smoke","water","button1","timeOfDay","triggerModes"]) {
if (settings[name]) {
return true
}
}
return false
}
private ifUnset(Map options, String name, String capability) {
if (!settings[name]) {
input(options, name, capability)
}
}
private ifSet(Map options, String name, String capability) {
if (settings[name]) {
input(options, name, capability)
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
subscribeToEvents()
}
def updated() {
def colors = []
def levels = []
def durations = []
state.noa=settings["numberOfActions"] as Integer
for (int i = 1; i <= (settings["numberOfActions"] as Integer); i++) {
colors << settings["p_${i}_color"]
levels << settings["p_${i}_lightLevel"]
durations << settings["p_${i}_duration"]
}
state.colors = colors
state.levels = levels
state.durations = durations
state.where = 0 as Integer
//log.debug "$state.colors $state.levels $state.durations"
log.debug "Updated with settings: ${settings}"
unsubscribe()
unschedule()
subscribeToEvents()
}
def subscribeToEvents() {
subscribe(switch1, "switch", switchEnableNow) // Default - Enable/Disable switch
subscribe(app, appTouchHandler)
subscribe(contact, "contact.open", eventHandler)
subscribe(contactClosed, "contact.closed", eventHandler)
subscribe(acceleration, "acceleration.active", eventHandler)
subscribe(motion, "motion.active", eventHandler)
subscribe(mySwitch, "switch.on", eventHandler)
subscribe(mySwitchOff, "switch.off", eventHandler)
subscribe(arrivalPresence, "presence.present", eventHandler)
subscribe(departurePresence, "presence.not present", eventHandler)
subscribe(smoke, "smoke.detected", eventHandler)
subscribe(smoke, "smoke.tested", eventHandler)
subscribe(smoke, "carbonMonoxide.detected", eventHandler)
subscribe(water, "water.wet", eventHandler)
subscribe(button1, "button.pushed", eventHandler)
if (triggerModes) {
subscribe(location,modeChangeHandler)
}
if (timeOfDay) {
schedule(timeOfDay, scheduledTimeHandler)
}
if (song) {
saveSelectedSong()
}
}
// Enable Switch Handler *********
// disable/enable switch
def switchEnableNow(evt){
state.enable = evt.value
}
private getenableOk(){
def result = true
if(state.enable == 'on'){
result = true }
else if(state.enable == 'off'){
result = false }
result
}
def eventHandler(evt) {
if (allOk) {
log.trace "allOk"
def lastTime = state[frequencyKey(evt)]
if (oncePerDayOk(lastTime)) {
if (frequency) {
if (lastTime == null || now() - lastTime >= frequency * 60000) {
takeAction(evt)
}
else {
log.debug "Not taking action because $frequency minutes have not elapsed since last action"
}
}
else {
takeAction(evt)
}
}
else {
log.debug "Not taking action because it was already taken today"
}
}
}
def modeChangeHandler(evt) {
if (evt.value in triggerModes) {
eventHandler(evt)
}
}
def scheduledTimeHandler() {
eventHandler(null)
}
def appTouchHandler(evt) {
takeAction(evt)
}
private takeAction(evt) {
loadText()
if (frequency || oncePerDay) {
state[frequencyKey(evt)] = now()
}
}
private frequencyKey(evt) {
"lastActionTimeStamp"
}
private dayString(Date date) {
def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
if (location.timeZone) {
df.setTimeZone(location.timeZone)
}
else {
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
}
df.format(date)
}
private oncePerDayOk(Long lastTime) {
def result = true
if (oncePerDay) {
result = lastTime ? dayString(new Date()) != dayString(new Date(lastTime)) : true
log.trace "oncePerDayOk = $result"
}
result
}
// TODO - centralize somehow
private getAllOk() {
modeOk && daysOk && timeOk
}
private getModeOk() {
def result = !modes || modes.contains(location.mode)
log.trace "modeOk = $result"
result
}
private getDaysOk() {
def result = true
if (days) {
def df = new java.text.SimpleDateFormat("EEEE")
if (location.timeZone) {
df.setTimeZone(location.timeZone)
}
else {
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
}
def day = df.format(new Date())
result = days.contains(day)
}
log.trace "daysOk = $result"
result
}
private getTimeOk() {
def result = true
if (starting && ending) {
def currTime = now()
def start = timeToday(starting, location?.timeZone).time
def stop = timeToday(ending, location?.timeZone).time
result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
}
log.trace "timeOk = $result"
result
}
private hhmm(time, fmt = "h:mm a")
{
def t = timeToday(time, location.timeZone)
def f = new java.text.SimpleDateFormat(fmt)
f.setTimeZone(location.timeZone ?: timeZone(time))
f.format(t)
}
private getTimeLabel()
{
(starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
}
private loadText() {
int i = state.where
int j = state.noa
//log.debug "$state.where"
//log.debug "$state.where ${state.colors[i]}"
hues.each {
sendcolor(state.colors[i],state.levels[i],it)
pause(200)
}
pause(state.durations[i])
i++
state.where=i
//if (state.where < state.noa) {
if (enableOk) {goagain()}
//}
}
private goagain() {
if (state.where >= state.noa) {
state.where=0 as Integer
}
log.debug "$state.where"
loadText()
}
def sendcolor(color,level,bulb) {
def hueColor = 0
def saturation = 100
switch(color) {
case "White":
hueColor = 52
saturation = 19
break;
case "Daylight":
hueColor = 53
saturation = 91
break;
case "Soft White":
hueColor = 23
saturation = 56
break;
case "Warm White":
hueColor = 20
saturation = 80 //83
break;
case "Blue":
hueColor = 69
saturation = 95
break;
case "DarkBlue":
hueColor = 70
break;
case "Green":
hueColor = 39
break;
case "Yellow":
hueColor = 25
break;
case "Orange":
hueColor = 10
break;
case "Purple":
hueColor = 75
break;
case "Pink":
hueColor = 83
break;
case "Red":
hueColor = 100
break;
}
// state.previous = [:]
/*
hues.each {
state.previous[it.id] = [
"switch": it.currentValue("switch"),
"level" : it.currentValue("level"),
"hue": it.currentValue("hue"),
"saturation": it.currentValue("saturation")
]
}
*/
def newValue = [hue: hueColor, saturation: saturation, level:level]
bulb.setColor(newValue)
//hues*.setColor(newValue)
}