/* groovylint-disable LineLength, DuplicateNumberLiteral, DuplicateStringLiteral, ImplementationAsType, ImplicitClosureParameter, InvertedCondition, LineLength, MethodReturnTypeRequired, MethodSize, NestedBlockDepth, NglParseError, NoDef, NoJavaUtilDate, NoWildcardImports, ParameterReassignment, UnnecessaryGString, UnnecessaryObjectReferences, UnnecessaryToString, UnusedImport, VariableTypeRequired */
/**
* Govee LightEffects Grouping
*
* Copyright 2018 CRAIG KING
*
* 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: "Light Effects Grouping",
namespace: "Mavrrick",
author: "Craig King",
description: "Group Devices together to Standardize Scenes with a single list",
category: "lighting",
parent: "Mavrrick:Light Effects Tools",
importUrl: "https://raw.githubusercontent.com/Mavrrick/Hubitat-by-Mavrrick/refs/heads/main/Govee/show/GoveeLightEffectsShow",
iconUrl: "",
iconX2Url: ""
)
import groovy.json.JsonSlurper
// ======== Preferences ========
preferences {
page(name: "setupPage")
page(name: "commandConfigPage")
page(name: "intervalConfigPage")
page(name: "deviceConfigPage")
}
commandConfigPage
// ======== Page 1 – Setup ========
def setupPage() {
dynamicPage(name: "setupPage", uninstall: true, install: true) {
section("Give this app a name?") {
label(name: "label",
title: "Give this app a name?",
required: true,
multiple: false)
}
section("Pick Devices to set standard Settings") {
// Pick any device that has the "switch" capability (you can change to the cap you need)
input "selectedDevices", "capability.lightEffects",
title: "Choose Devices",
multiple: true,
required: true,
showFilter: true,
submitOnChange: true
/* input "standardBrightness", "number",
title: "Enter brightness level to be used across all selected Devices",
defaultValue: 80,
required: true,
range: "1..100",
submitOnChange: true */
}
section("Number of different scene effect groups") {
input "numGroups", "number",
title: "",
required: true,
defaultValue: 2,
submitOnChange: true
}
section ("Configure Light Effect Groups"){
href name: "commandConfigPage",
title: "Configure Light Effect Groups",
description: "${settings?.numGroups ?: 'Choose a number'} scene groups",
page: "commandConfigPage",
submitOnChange: true
}
section("Select Button Below to create Control device") {
input "createDevice" , "button", title: "Create Virtial control device"
}
section ("Overrides"){
paragraph "Use these buttons to activate or stop the Effect processing at any time."
input "startcycle" , "button", title: "Override - Activate effects Now"
input "stopcycle" , "button", title: "Override - Stop effects Now"
}
section {
// Next button – goes to the second page
input("debugEnable", "bool",title:"Enable Debug Logging",width:4,submitOnChange:true)
}
}
}
// ======== Page 2 – Command by Device Selection ========
def commandConfigPage() {
// Pull the number of intervals & selected devices from settings
int numGroups = (settings?.numGroups?.toInteger() ?: 1)
List devices = (settings?.selectedDevices ?: []) as List
dynamicPage(name: "commandConfigPage", uninstall: false, install: false, nextPage: "setupPage") {
section("Command Selection Page") {
(1..numGroups).each { i ->
// Pick any device that has the "switch" capability (you can change to the cap you need)
input "sceneName_group_${i}", "text",
title: "Group ${i} scene name",
// multiple: true,
required: true
paragraph "Device Command selection in Group ${i}"
devices.each { dev ->
input "command_${dev.id}_group_${i}", 'enum',
title: "${dev.displayName} – Command",
options: [0:'setEffect',
1:'colorTemperature',
2:'color' ],
multiple: false,
required: true,
submitOnChange: true
if (settings."command_${dev.id}_group_${i}" == '0') {
if(debugEnable) log.debug "Scenes for device are ${dev.currentValue("lightEffects")}"
def jsonSlurper = new JsonSlurper()
def lightEffects = jsonSlurper.parseText(dev.currentValue("lightEffects")).sort { it.value }
if(debugEnable) log.debug "Scenes for device are ${lightEffects}"
// Scene selection
input "scene_${dev.id}_group_${i}",
"enum",
title: "${dev.displayName} – Scene",
options: lightEffects,
required: false,
defaultValue: '0' // “None”
} else if (settings."command_${dev.id}_group_${i}" == '1') {
input "colorTemperature_${dev.id}_group_${i}", "number",
title: "Enter Color Temperature to be used for device in grouping action 2000-6500",
defaultValue: 2000,
required: true,
range: "2000..6500",
submitOnChange: false
} else if (settings."command_${dev.id}_group_${i}" == '2') {
input "color_${dev.id}_group_${i}", "color",
title: "Select Color to apply on device in group action",
// defaultValue: 80,
required: true,
// range: "2000..6500",
submitOnChange: false
}
}
}
}
}
}
// ======== SmartApp Lifecycle ========
def installed() {
log.debug "installed() called"
initialize()
}
def updated() {
log.debug "updated() called"
initialize()
buildLightEffectJson ()
}
def initialize() {
unsubscribe()
unschedule()
settingsCleanup()
if (triggerSwitch) {
subscribe(triggerSwitch, "switch", switchAction)
}
}
/**
* Control Helpers
*/
def on() {
if(debugEnable) log.debug "on(): Automation."
List devices = (settings?.selectedDevices ?: []) as List
devices.each { dev ->
List scenes = settings."scene_${dev.id}" as List
if(debugEnable) log.debug "on(): Processing on for ${dev}."
dev.on()
}
}
def off() {
if(debugEnable) log.debug "off(): Automation."
List devices = (settings?.selectedDevices ?: []) as List
devices.each { dev ->
List scenes = settings."scene_${dev.id}" as List
if(debugEnable) log.debug "off(): Processing off for ${dev}."
dev.off()
}
}
def setColorTemperature(value,level = null,transitionTime = null) {
if(debugEnable) log.debug "setColorTemperature(): Automation."
List devices = (settings?.selectedDevices ?: []) as List
devices.each { dev ->
// List scenes = settings."scene_${dev.id}" as List
// if(debugEnable) log.debug "setColorTemperature(): Processing effect for ${dev} with ${sceneCount} ${scenes}scenes selected. scene number ${scenes.get(scenePos)}."
dev.setColorTemperature(value, level, transitionTime)
}
}
def setLevel(brightness, transitiontime = 0) {
if(debugEnable) log.debug "setLevel(): Automation."
List devices = (settings?.selectedDevices ?: []) as List
devices.each { dev ->
// List scenes = settings."scene_${dev.id}" as List
// if(debugEnable) log.debug "setColorTemperature(): Processing effect for ${dev} with ${sceneCount} ${scenes}scenes selected. scene number ${scenes.get(scenePos)}."
dev.setLevel(brightness, 0)
}
}
def setColor(colorMap) {
if(debugEnable) log.debug "setColor(): Automation. with value ${colorMap}"
List devices = (settings?.selectedDevices ?: []) as List
devices.each { dev ->
// List scenes = settings."scene_${dev.id}" as List
// if(debugEnable) log.debug "setColorTemperature(): Processing effect for ${dev} with ${sceneCount} ${scenes}scenes selected. scene number ${scenes.get(scenePos)}."
dev.setColor(colorMap)
}
}
def setEffect(effectNo) {
if(debugEnable) log.debug "setEffect(): Automation."
List devices = (settings?.selectedDevices ?: []) as List
devices.each { dev ->
def cKey = "command_${dev.id}_group_${effectNo}" // command_3428_group_1
def command = (settings[cKey]?.toInteger() ?: 0)
if (command == 0) {
def sKey = "scene_${dev.id}_group_${effectNo}"
def sceneId = (settings[sKey]?.toInteger() ?: 0)
if(debugEnable) log.debug "startSequenceAdv(): Processing effect for ${dev} scene number ${sceneId}."
dev.setEffect(sceneId)
} else if (command == 1) {
def sKey = "colorTemperature_${dev.id}_group_${effectNo}" // colorTemperature_3428_group_1
def ctvalue = (settings[sKey]?.toInteger() ?: 0)
dev.setColorTemperature(ctvalue,level = null,transitionTime = null)
} else if (command == 2) {
def sKey = "color_${dev.id}_group_${effectNo}" // color_3428_group_1
colorHexValue = (settings[sKey]?.toString() ?: 0)
if(debugEnable) log.debug "startSequenceAdv(): Hex Value is ${colorHexValue}."
def rgb = hubitat.helper.ColorUtils.hexToRGB(colorHexValue)
def hsv = hubitat.helper.ColorUtils.rgbToHSV(rgb) // Converts RGB to HSV
def hslmap = [:]
hslmap.hue = hsv[0]
hslmap.level = hsv[1]
hslmap.saturation = hsv[2]
if(debugEnable) log.debug "startSequenceAdv(): Processing effect ${effectNo} for ${dev} HSB ${hsv} HSLMap ${hslmap}."
dev.setColor(hslmap)
}
}
}
def switchAction(evt) {
if(debugEnable) log.debug "switchAction(): Event is ${evt.value}"
if (evt.value == "on") {
startSequence()
} else {
endAction()
}
}
private def appButtonHandler(button) {
if(debugEnable) log.debug "appButtonHandler() ${button}"
if (button == "startcycle") {
startSequence()
} else if (button == "stopcycle") {
endAction()
} else if (button == "createDevice") {
childCount = getChildDevices().size()
if(debugEnable) log.debug "Child count is ${childCount}."
if (childCount == 0) {
addChildDevice('Mavrrick', 'LightEffect Group', app.getLabel()+'_Device' , location.hubs[0].id, [
'name': 'LightEffect Group Device ',
'label': app.getLabel()+'_Device',
'data': [
],
'completedSetup': true,
])
} else {
if(debugEnable) log.debug "Child Device already created."
}
}
}
def buildLightEffectJson () {
scenes = [:]
(1..numGroups).each { i ->
scenes[i] = settings."sceneName_group_${i}"
}
if(debugEnable) log.debug "buildLightEffectJson(): LightEffect map is ${scenes}"
return scenes
}
private def settingsCleanup(){
int nGroups = (settings?.numGroups?.toInteger() ?: 1)
List devices = (settings?.selectedDevices ?: []) as List
if(debugEnable) log.debug "settingsCleanup() ${settings}"
if(debugEnable) log.debug "settingsCleanup() Current list of settings: ${settings.keySet()}"
curSettingList = settings.keySet() // list of settings as currently in app
/// Build list of valid settings based on how the app is running
validSettingList = ["standardBrightness", "numGroups", "debugEnable", "selectedDevices"]
(1..nGroups).each { i ->
validSettingList.add("sceneName_group_${i}")
devices.each { dev ->
validSettingList.add("command_${dev.id}_group_${i}")
if (settings."command_${dev.id}_group_${i}" == '0') {
validSettingList.add("scene_${dev.id}_group_${i}")
}
if (settings."command_${dev.id}_group_${i}" == '1') {
validSettingList.add("colorTemperature_${dev.id}_group_${i}")
}
if (settings."command_${dev.id}_group_${i}" == '2') {
validSettingList.add("color_${dev.id}_group_${i}")
}
}
}
if(debugEnable) log.debug "settingsCleanup() Valid settings are: ${validSettingList}"
listToRemove = curSettingList - validSettingList
if(debugEnable) log.debug "settingsCleanup() List to be removed: ${listToRemove}"
listToRemove.each {
if(debugEnable) log.debug "settingsCleanup() removing setting: ${it}"
app.removeSetting(it)
}
}