/** * SmartThings Lightify Dimmer Switch support * Copyright (C) 2016 Adam Outler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ /** * Command reference * on 'catchall: 0104 0006 01 01 0140 00 3A68 01 00 0000 01 00 ' * off 'catchall: 0104 0006 01 01 0140 00 3A68 01 00 0000 00 00 ' * held up 'catchall: 0104 0008 01 01 0140 00 3A68 01 00 0000 05 00 0032' * held down 'catchall: 0104 0008 01 01 0140 00 3A68 01 00 0000 01 00 0132' * released 'catchall: 0104 0008 01 01 0140 00 3A68 01 00 0000 03 00 ' */ /** *sets up fingerprint for autojoin *sets up commands for polling and others *sets up capabilities *sets up variables */ metadata { definition(name: "Lightify Dimming Switch- Zigbee", namespace: "adamoutler", author: "Adam Amber House") { capability "Battery" capability "Button" capability "Switch Level" attribute "State Array", "string" attribute 'Awesomeness Level', "string" attribute 'state', "string" command "refresh" command "poll" command "toggle" command "configure" command "installed" fingerprint profileId: "0104", deviceId: "0001", inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "OSRAM", model: "LIGHTIFY Dimming Switch", deviceJoinName: "OSRAM Lightify Dimming Switch" } simulator { // Simulations are for loosers, work in production :D } preferences { section("Device1") { } section("Device2") { } section("Device3") { } section("Device4") { } section("Device5") { } } /** *UI tile definitions */ tiles(scale: 2) { standardTile("button", "device.state", width: 6, height: 4) { state "off", label: 'Off', action: "toggle", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" state "on", label: "On", action: "toggle", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff" state "turningOn", label: 'Turning on', icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff" state "turningOff", label: 'Turning off', icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" } valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) { state "battery", label: 'battery ${currentValue}%' } valueTile("brightness", "device.level", decoration: "flat", inactiveLabel: false, width: 2, height: 2) { state "brightness", label: 'brightnessn${currentValue}%' } standardTile("refresh", "device.button", decoration: "flat", width: 2, height: 2) { state "default", label: "", action: "refresh", icon: "st.secondary.refresh" } controlTile("levelSliderControl", "device.level", "slider", height: 2, width: 6, inactiveLabel: false, range:"(1..100)") { state "level", action:"setLevel" } main "button" details(["button", "levelSliderControl", "switch", "battery", "brightness", "refresh"]) } } /** *returns a map representing important states */ brightness: state.brightness, battery: state.battery, value: state.value, level: state.level, lastAction: state.lastAction, on: state.on, data: '', descriptionText: "$device.displayName button $state.buttonNumber was $value" ] } /** *Gets a list of devices in [address,endpoint] format compiled from inputs above *returns: Arraylist<[address,endpoint]> */ list.add([devs[i], ends[i]]) } } return list } /** *Parse events into attributes. */ log.debug(msgFromST) fireCommands(value.command) log.error('unrecognized command:' + msgFromST) log.error('unrecognized command:' + msgFromST) } } /** *fire commands into the hub *commands - an array of string commands to be fired */ log.trace("Executing commands-- state:" + state + " commands:" + commands) }) } } } return returnval case 8: handleButtonHeld(msg) case 8021: log.info("Networking Bind Response received!!!") updateButtonState("Network binding complete!") return state case 8034: log.info("Network managment Leave Response!!!") return state log.error("Unhandled message: " + msg) } } /** * This is the handler for button presses. Map is routed here once a button press has been detected */ case "01": updateButtonState("on") return returnval case "03": bothButtonsPressed() case "00": updateButtonState("off") return returnval case "07": log.info("Button Press Bind Response!!!") return state log.error(getLinkText(device)+" got unknown button press command: " + msg.command) } } /** *this is the handler for button held events. Map is routed here once a button held event has been detected */ case 1: log.debug("Button held- Lowering brightness commanded") updateButtonState("lowering brightness") state.lastHeld = "down" case 3: log.debug("stop brightness commanded") updateButtonState(state.lastHeld + " released") return state case 5: log.debug("Button held- raising brightness commanded") state.lastHeld = "up" updateButtonState("raising brightness") case 7: log.info("Button Held Bind Response - 7!!!") return state case 8: log.info("Button Held Bind Response - 8!!!") return state log.error("Unhandled button held event: " + msg) } return msg } /** * adjusts brightness up/down depending on the value of the up boolean true is up, false is down * continues to adjust until state.dimming is changed * up- true if we are adjusting brightness up, false if down * level - first level commanded */ Map result log.debug("adjusting brightness" + (up?"up" : "down") + " from current " + state.brightness) //increase or decrease brightness } executeBrightnessAdjustmentUntilButtonReleased() log.debug("Final brightness adjusted to " + state.brightness) } sendEvent(name: "brightness", value: state.brightness) } /** * performs a recursive brightness adjustment based on state.brightening while state.dimming is true */ state.brightness = state.brightness + 20 state.brightness = state.brightness - 20 } state.brightness = 100 } state.brightness = 1 } runIn(1, executeBrightnessAdjustmentUntilButtonReleased) } } /** * gets the current brightness in hex format * length - the length of the number after leading 0's have been applied. This will likely be "2" */ sb.insert(0, '0') } } /** *formats a decimal value with leading 0's *value - the value to be formatted *length - the size of the number after leading 0's have been added */ } /** *performs configuration and bindings */ log.debug("configuration complete") sendEvent(name:"Configured", value:"true") } log.debug "Confuguring Reporting and Bindings." fireCommands(zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(0x0001, 0x0020)) configureDaemon() return configCmds } /* * handles binding if switch doesn't pay attention the first time. */ } } } /** *Refresh support. Causes battery status update and others */ fireCommands(zigbee.readAttribute(0x0001, 0x0020) +zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.readAttribute(0x0001, 0x0020) ) } /** *actions to be taken once the device is installed */ log.info(device.name + " installed!!!") sendEvent(name:"Configured", value:"false") state.lastAction = 0 state.brightness = 0 state.buttonNumber = 1 state.value = "unknown" state.lastHeld = "none" state.battery = 100 } log.info("updated") } /** *handles battery messages */ def descriptionText state.battery = "unknown" result.descriptionText = "${linkText} battery has too much power (${volts} volts)." state.battery = "overvoltage" result.battery = state.battery result.descriptionText = "${linkText} battery was ${result.value}%" } } sendEvent(name: 'battery', value: state.battery, units: "%") log.debug "${result?.descriptionText}" return result } /** * handle level commands, * level=desired level * duration=desired time-to-level */ log.debug("Maximum parameters (level 0-100, duration 0-9999)-- commanded level:" + level + " commanded duration:" + duration) } log.info("Brightness commanded to " + level + "%") fireCommands(result.command) //send it to the hub for processing } /** *sets level using a 1-second duration *level= percent */ setLevel(level, 1000) } /** * Returns true if the switch is on. false if off. */ } /** *poll support, forces an update of states */ sendEvent(name: 'brightness', value: state.brightness, units: "%") reportOnState(getOnState()) } /** *takes a command and data, generates an "st cmd" array *command- string representing the command and data to be send to the device *returns the command for all devices on the switch */ List<String> output = [] LinkedHashMap result = getStatus() output.add("st cmd 0x" + item[0] + " 0x" + item[1] + " " + command) } return result } /** * Handles event updates. All updates go here. */ sendEvent(name: 'state', type:"thing", value:onValue) sendEvent(name: 'battery', value: state.battery) sendEvent(name: 'level', value: state.brightness) sendEvent(name: 'button', value: state.value) sendEvent(name: 'numberOfButtons', value: 5) sendEvent(name: 'State Array', value: state) sendEvent(name: 'Awesomeness Level', value: "over 9000") state.on = onValue } state.value = value sendEvent(name: "button", value: value, unit: "") } /** *commands the opposite of the current state *if on, turn off, if off, turn on. */ Map command log.debug(device.displayName + " toggled on") command = off() command = on() log.debug(device.displayName + " toggled off") } log.debug(command) fireCommands(command.command) } /** *detects the current state versus commanded *if curret is off, and commanded is off, returns true and same for inverse */ } /** *This switch does not support pressing the same button in rapid sucession *this check finds out if user tapped one button and then the other within 1.5 seconds. */ } //TODO create a up-down tapped mechanism. /** *turns light on. *if already on, commands max */ log.debug(device.displayName + " commanded on" ) } state.lastAction=now() } /** *turns light off *if already off, commands on to minimum */ log.debug(device.displayName + " commanded off") } state.lastAction=now() setLevel(1, 1000) return value } } /** *Action to be taken when both buttons are pressed at the same time */ log.error("Both Buttons Pressed" + state) installed() state.lastAction = 100 updateButtonState("Initiating configuration routines. Please stand by.") configure() return state }