diff --git a/Improved OSRAM Lightify Gardenspot RGB MA.groovy b/Improved OSRAM Lightify Gardenspot RGB MA.groovy index 8535b3b..212b084 100644 --- a/Improved OSRAM Lightify Gardenspot RGB MA.groovy +++ b/Improved OSRAM Lightify Gardenspot RGB MA.groovy @@ -19,8 +19,15 @@ metadata { attribute "colorName", "string" attribute "switchColor", "string" + attribute "loopActive", "string" + attribute "loopDirection", "string" + attribute "loopTime", "number" command "setAdjustedColor" + command "startLoop" + command "stopLoop" + command "setLoopTime" + command "setDirection" fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenspot RGB" @@ -71,6 +78,7 @@ tiles (scale: 2){ attributeState "Deep Pink", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#ff007b" attributeState "Raspberry", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#ff0061" attributeState "Crimson", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#ff003b" + attributeState "Color Loop", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" } tileAttribute ("device.color", key: "COLOR_CONTROL") { attributeState "color", action: "setAdjustedColor" @@ -80,24 +88,37 @@ tiles (scale: 2){ } } standardTile("refresh", "device.switch", height: 2, width: 2, inactiveLabel: false, decoration: "flat") { - state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" - } - controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 6, inactiveLabel: false) { - state "level", action:"switch level.setLevel" - } + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + standardTile("loop", "device.loopActive", height: 2, width: 2, inactiveLabel: false, decoration: "flat") { + state "Active", label:'${currentValue}', action: "stopLoop" + state "Inactive", label:'${currentValue}', action: "startLoop" + } + controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 6, inactiveLabel: false) { + state "level", action:"switch level.setLevel" + } valueTile("colorName", "device.colorName", height: 2, width: 2, inactiveLabel: false, decoration: "flat") { - state "colorName", label: '${currentValue}' + state "colorName", label: '${currentValue}' + } + controlTile("loopTimeControl", "device.loopTime", "slider", height: 2, width: 4, range: "(1..60)", inactiveLabel: false) { + state "loopTime", action: "setLoopTime" + } + standardTile("loopDir", "device.loopDirection", height: 2, width: 2, inactiveLabel: false, decoration: "flat") { + state "default", label: '${currentValue}', action: "setDirection" } main(["switch"]) - details(["switch", "levelSliderControl", "colorName", "refresh"]) + details(["switch", "levelSliderControl", "colorName", "loop", "refresh", "loopTimeControl", "loopDir"]) } } // Parse incoming device messages to generate events def parse(String description) { //log.info "description is $description" - if (description?.startsWith("catchall:")) { + if (device.currentValue("loopActive") == "Active") { + + } + else if (description?.startsWith("catchall:")) { if(description?.endsWith("0100") ||description?.endsWith("1001") || description?.matches("on/off\\s*:\\s*1")) { def result = createEvent(name: "switch", value: "on") @@ -121,7 +142,7 @@ def parse(String description) { if (descMap.cluster == "0300") { if(descMap.attrId == "0000"){ //Hue Attribute - def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 360) + def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 100) log.debug "Hue value returned is $hueValue" def colorName = getColorName(hueValue) sendEvent(name: "colorName", value: colorName) @@ -156,6 +177,87 @@ def parse(String description) { } +def setDirection() { + def direction = (device.currentValue("loopDirection") == "Down" ? "Up" : "Down") + log.trace direction + sendEvent(name: "loopDirection", value: direction) + if (device.currentValue("loopActive") == "Active") { + def dirHex = (direction == "Down" ? "00" : "01") + log.trace dirHex + "st cmd 0x${device.deviceNetworkId} ${endpointId} 0x300 0x44 {02 01 ${dirHex} 0000 0000}" + } +} + +def setLoopTime(value) { + sendEvent(name:"loopTime", value: value) + if (device.currentValue("loopActive") == "Active") { + def finTime = swapEndianHex(hexF(value, 4)) + "st cmd 0x${device.deviceNetworkId} ${endpointId} 0x300 0x44 {04 01 00 ${finTime} 0000}" + } +} + +def startLoop(Map params) { + // direction either increments or decrements the hue value: "Up" will increment, "Down" will decrement + def direction = (device.currentValue("loopDirection") != null ? (device.currentValue("loopDirection") == "Down" ? "00" : "01") : "00") + log.trace direction + if (params?.direction != null) { + direction = (params.direction == "Down" ? "00" : "01") + sendEvent(name: "loopDirection", value: params.direction ) + } + log.trace direction + + // time parameter is the time in seconds for a full loop + def cycle = (device.currentValue("loopTime") != null ? device.currentValue("loopTime") : 2) + log.trace cycle + if (params?.time != null) { + cycle = params.time + sendEvent(name:"loopTime", value: cycle) + } + log.trace cycle + def finTime = swapEndianHex(hexF(cycle, 4)) + log.trace finTime + + def cmds = [] + cmds << "st cmd 0x${device.deviceNetworkId} ${endpointId} 6 1 {}" + cmds << "delay 200" + + sendEvent(name: "switchColor", value: "Color Loop", displayed: false) + sendEvent(name: "loopActive", value: "Active") + + if (params?.hue != null) { + + // start hue was specified, so convert to enhanced hue and start loop from there + def sHue = Math.min(Math.round(params.hue * 255 / 100), 255) + finHue = swapEndianHex(hexF(sHue, 4)) + log.debug "activating color loop from specified hue" + cmds << "st cmd 0x${device.deviceNetworkId} ${endpointId} 0x300 0x44 {0F 01 ${direction} ${finTime} ${sHue}}" + + } + else { + + // start hue was not specified, so start loop from current hue updating direction and time + log.debug "activating color loop from current hue" + cmds << "st cmd 0x${device.deviceNetworkId} ${endpointId} 0x300 0x44 {07 02 ${direction} ${finTime} 0000}" + + } + cmds +} + +def stopLoop() { + + log.debug "deactivating color loop" + def cmds = [ + "st cmd 0x${device.deviceNetworkId} ${endpointId} 0x300 0x44 {01 00 00 0000 0000}", "delay 200", + "st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0300 0", "delay 200", + "st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0300 1", "delay 200", + "st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0" + ] + sendEvent(name: "loopActive", value: "Inactive") + + cmds + +} + def on() { log.debug "on()" setLevel(state?.levelValue) @@ -352,6 +454,14 @@ private hex(value, width=2) { s } +private hexF(value, width) { + def s = new BigInteger(Math.round(value).toString()).toString(16) + while (s.size() < width) { + s = "0" + s + } + s +} + private evenHex(value){ def s = new BigInteger(Math.round(value).toString()).toString(16) while (s.size() % 2 != 0) {