2 * Smart Bulb Notifier/Flasher
4 * Copyright 2015 Scott Gibson
6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7 * in compliance with the License. You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
12 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
13 * for the specific language governing permissions and limitations under the License.
15 * Many thanks to Eric Roberts for his virtual switch creator, which served as the template for creating child switch devices!
19 name: "Smart Bulb Alert (Blink/Flash)",
20 namespace: "sticks18",
21 author: "Scott Gibson",
22 description: "Creates a virtual switch button that when turned on will trigger selected smart bulbs to blink or flash",
24 iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
25 iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
29 page(name: "basicInfo")
30 page(name: "configureBulbs")
34 dynamicPage(name: "basicInfo", title: "First, name your trigger and select smart bulb types", nextPage: "configureBulbs", uninstall: true){
35 section("Create Virtual Momentary Button as Trigger") {
36 input "switchLabel", "text", title: "Switch Button Label", multiple: false, required: true
38 section("Choose your Smart Bulbs") {
39 paragraph "This SmartApp will work with most zigbee bulbs by directly calling the Identify function built into the hardware. This function is generally run when you first pair a bulb to the hub to let you know it was successful. Different bulbs have different capabilities and/or endpoints to address, so they must be selected separately in this SmartApp. If expanded functionality exists for a particular bulb type, you will be given additional options to select. Caveats: Non-Hue bulbs connected to the Hue Bridge, such as GE Link or Cree Connected, will not work because the Hue API is not designed for them.",
40 title: "How to select your bulbs...", required: true
41 input "geLinks", "capability.switch level", title: "Select GE Link Bulbs", required: false, multiple: true
42 //input "creeCons", "capability.switch level", title: "Select Cree Connected Bulbs", required: false, multiple: true
43 //input "hueHubs", "capability.switch level", title: "Select Hue Bulbs connected to Hue Hub", required: false, multiple: true
44 //input "hueDirs", "capability.switch level", title: "Select Hue Bulbs directly connected to ST Hub", required: false, multiple: true
45 //input "osramLs", "capability.switch level", title: "Select Osram Lightify Bulbs", required: false, multiple: true
51 dynamicPage(name: "configureBulbs", title: "Additional Configuration Options by Bulb Type", install: true, uninstall: true) {
52 section(title: "Auto-off for bulbs directly connected to SmartThings Hub") {
53 input "autoOff", "bool", title: "Automatically stop the alert", required: false, submitOnChange: true
54 input "offDelay", "number", title: "Turn off alert after X seconds (default = 5, max = 10)", required: false, submitOnChange: true
56 /*section(title: "Options for Hue Bulbs connected to Hue Bridge", hidden: hideHueHubBulbs(), hideable: true) {
57 input "hBlink", "enum", title: "Select Blink for single flash or Breathe for 15 seconds continuous (default = Breathe)", multiple: false, required: false,
58 options: ["Blink", "Breathe"]
60 section(title: "Options for Hue Bulbs connected directly to SmartThings Hub", hidden: hideHueDirBulbs(), hideable: true) {
61 input "hdStyle", "enum", title: "Select alert style: Normal = Bulb will blink until stopped via auto-off or trigger, Blink = Single flash, Breathe = Mult Flash for 15 seconds, Okay = Bulb turn green for 2 seconds",
62 multiple: false, required: false, options: ["Normal", "Blink", "Breathe", "Okay"]
64 section(title: "Options for Osram Lightify Bulbs", hidden: hideOsramBulbs(), hideable: true) {
65 input "osStyle", "enum", title: "Select alert style: Normal = Bulb will blink until stopped via auto-off or trigger",
66 multiple: false, required: false, options: ["Normal"]
74 log.debug "Installed with settings: ${settings}"
80 log.debug "Updated with settings: ${settings}"
88 state.autoOff = offDelay
89 // state.hueHubOption = getHueHubOption()
90 // state.hueDirOption = getHueDirOption()
91 // state.osramOption = getOsramOption()
92 // state.onlyHueHub = getHueHubOnly()
94 def deviceId = app.id + "SimulatedSwitch"
96 def existing = getChildDevice(deviceId)
100 def childDevice = addChildDevice("sticks18", "Smart Bulb Alert Switch", deviceId, null, [label: switchLabel])
106 removeChildDevices(getChildDevices())
109 private removeChildDevices(delete) {
111 deleteChildDevice(it.deviceNetworkId)
115 /* private getOffDelay() {
117 log.debug "autoOff is ${autoOff}"
120 log.debug "offDelay is ${offDelay}"
122 def offSec = Math.Min(offDelay, 10)
123 offSec = Math.Max(offSec, 1)
127 log.debug "off delay: ${result}"
131 private getHueDirOption() {
153 log.debug "hue dir option: ${result}"
157 private getHueHubOnly() {
158 (creeCons || geLinks || osramLs || hueDirs) ? false : true
161 private getHueHubOption() {
176 log.debug "hue hub option: ${result}"
180 private getOsramOption() {
201 log.debug "osram option: ${result}"
205 private hideHueHubBulbs() {
206 (hueHubs) ? false : true
209 private hideHueDirBulbs() {
210 (hueDirs) ? false : true
213 private hideOsramBulbs() {
214 (osramLs) ? false : true
217 private hex(value, width=4) {
218 def s = new BigInteger(Math.round(value).toString()).toString(16)
219 while (s.size() < width) {
225 private Integer convertHexToInt(hex) {
226 Integer.parseInt(hex,16)
229 private String swapEndianHex(String hex) {
230 reverseArray(hex.decodeHex()).encodeHex()
233 private byte[] reverseArray(byte[] array) {
235 int j = array.length - 1;
247 // Child device methods after this point. Instead of subscribing to child, have child directly call parent
249 def on(childDevice) {
250 log.debug "Start alert"
251 if(state.autoOff != null) {
252 log.debug "Only alert for ${state.autoOff} seconds"
253 if(geLinks != null) {
254 geLinks.each { bulb ->
255 // bulb.setLevel(99, 1800)
256 bulb.alert(state.autoOff)
257 // childDevice.attWrite(bulb.deviceNetworkId, 1, 3, 0, "0x21", state.autoOff)
258 // childDevice.zigbeeCmd(bulb.deviceNetworkId, 1, 3, 0, "")
261 /*if(creeCons != null) {
262 creeCons.each { bulb ->
263 childDevice.attWrite(bulb.deviceNetworkId, "10", "3", "0", "0x21", state.autoOff)
266 if(state.hueDirOption != null) {
267 if(state.hueDirOption == "") {
268 hueDirs.each { bulb ->
269 childDevice.attWrite(bulb.deviceNetworkId, "0B", "3", "0", "0x21", state.autoOff)
273 hueDirs.each { bulb ->
274 def payload = state.hueDirOption + " 00"
275 childDevice.zigbeeCmd(bulb.deviceNetworkId, "0B", "3", "0x40", payload)
279 if(state.osramOption != null) {
280 if(state.osramOption == "") {
281 osramLs.each { bulb ->
282 childDevice.attWrite(bulb.deviceNetworkId, "03", "3", "0", "0x21", state.autoOff)
286 osramLs.each { bulb ->
287 def payload = state.osramOption + " 00"
288 childDevice.zigbeeCmd(bulb.deviceNetworkId, "03", "3", "0x40", payload)
292 childDevice.justOff()
296 log.debug "Starting continous alert"
297 if(geLinks != null) {
298 geLinks.each { bulb ->
299 childDevice.zigbeeCmd(bulb.deviceNetworkId, "1", "3", "0", "")
302 if(creeCons != null) {
303 creeCons.each { bulb ->
304 childDevice.zigbeeCmd(bulb.deviceNetworkId, "10", "3", "0", "")
307 if(state.hueDirOption != null) {
308 if(state.hueDirOption == "") {
309 hueDirs.each { bulb ->
310 childDevice.zigbeeCmd(bulb.deviceNetworkId, "0B", "3", "0", "")
314 hueDirs.each { bulb ->
315 def payload = state.hueDirOption + " 00"
316 childDevice.zigbeeCmd(bulb.deviceNetworkId, "0B", "3", "0x40", payload)
320 if(state.osramOption != null) {
321 if(state.osramOption == "") {
322 osramLs.each { bulb ->
323 childDevice.zigbeeCmd(bulb.deviceNetworkId, "03", "3", "0", "")
327 osramLs.each { bulb ->
328 def payload = state.osramOption + " 00"
329 childDevice.zigbeeCmd(bulb.deviceNetworkId, "03", "3", "0x40", payload)
334 if(state.hueHubOption != null) {
335 log.debug "Send planned alert to Hue Bulbs via Hue Bridge"
336 hueHubs.each { bulb ->
337 def hue = bulb.currentValue("hue")
338 def sat = bulb.currentValue("saturation")
339 def alert = state.hueHubOption
340 def value = [hue: hue, saturation: sat, alert: alert]
343 if(state.hueHubOnly) { childDevice.justOff() }
348 def off(childDevice) {
349 log.debug "Stop Alert" /*
350 if(state.autoOff != null) {
351 childDevice.justOff()
354 log.debug "Stopping continous alert"
355 if(geLinks != null) {
356 geLinks.each { bulb ->
357 childDevice.zigbeeCmd(bulb.deviceNetworkId, "1", "3", "0", "")
360 if(creeCons != null) {
361 creeCons.each { bulb ->
362 childDevice.zigbeeCmd(bulb.deviceNetworkId, "10", "3", "0", "")
365 if(state.hueDirOption != null) {
366 if(state.hueDirOption == "") {
367 hueDirs.each { bulb ->
368 childDevice.zigbeeCmd(bulb.deviceNetworkId, "0B", "3", "0", "")
372 if(state.osramOption != null) {
373 if(state.osramOption == "") {
374 osramLs.each { bulb ->
375 childDevice.zigbeeCmd(bulb.deviceNetworkId, "03", "3", "0", "")
383 def allOff(childDevice) {
384 log.debug "Stopping alerts" /*
385 if(geLinks != null) {
386 geLinks.each { bulb ->
387 childDevice.attWrite(bulb.deviceNetworkId, "1", "3", "0", "0x21", "0100")
390 if(creeCons != null) {
391 creeCons.each { bulb ->
392 childDevice.attWrite(bulb.deviceNetworkId, "10", "3", "0", "0x21", "0100")
395 if(hueDirs != null) {
396 hueDirs.each { bulb ->
397 childDevice.attWrite(bulb.deviceNetworkId, "0B", "3", "0", "0x21", "0100")
400 if(osramLs != null) {
401 osramLs.each { bulb ->
402 childDevice.attWrite(bulb.deviceNetworkId, "03", "3", "0", "0x21", "0100")