From b23d7ccf2e854eb6e31943cb9469d21b19f91e61 Mon Sep 17 00:00:00 2001 From: Kyle LeNeau Date: Tue, 5 Apr 2016 23:30:42 -0700 Subject: [PATCH] Adding a SmartApp and stubs for all the device type tiles --- .../tile-basic-carousel.groovy | 225 ++++++++++++ .../tile-basic-colorwheel.groovy | 52 +++ .../tile-basic-presence.groovy | 63 ++++ .../tile-basic-slider.groovy | 75 ++++ .../tile-basic-standard.groovy | 109 ++++++ .../tile-basic-value.groovy | 96 +++++ .../tile-multiattribute-generic.groovy | 118 ++++++ .../tile-multiattribute-lighting.groovy | 211 +++++++++++ .../tile-multiattribute-mediaplayer.groovy | 122 +++++++ .../tile-multiattribute-thermostat.groovy | 341 ++++++++++++++++++ .../tile-multiattribute-videoplayer.groovy | 169 +++++++++ .../device-tile-controller.groovy | 107 ++++++ 12 files changed, 1688 insertions(+) create mode 100644 devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy create mode 100644 devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy create mode 100644 smartapps/smartthings/tile-ux/device-tile-controller.src/device-tile-controller.groovy diff --git a/devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy b/devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy new file mode 100644 index 0000000..19a9d91 --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-basic-carousel.src/tile-basic-carousel.groovy @@ -0,0 +1,225 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "carouselDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Thermostat" + capability "Relative Humidity Measurement" + + command "tempUp" + command "tempDown" + command "heatUp" + command "heatDown" + command "coolUp" + command "coolDown" + command "setTemperature", ["number"] + } + + tiles(scale: 2) { + multiAttributeTile(name:"thermostatMulti", type:"thermostat", width:6, height:4) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + tileAttribute("device.temperature", key: "VALUE_CONTROL") { + attributeState("default", action: "setTemperature") + } + tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { + attributeState("default", label:'${currentValue}%', unit:"%") + } + tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { + attributeState("idle", backgroundColor:"#44b621") + attributeState("heating", backgroundColor:"#ffa81e") + attributeState("cooling", backgroundColor:"#269bd2") + } + tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { + attributeState("off", label:'${name}') + attributeState("heat", label:'${name}') + attributeState("cool", label:'${name}') + attributeState("auto", label:'${name}') + } + tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + } + + main("thermostatMulti") + details([ + "thermostatMulti" + ]) + } +} + +def installed() { + sendEvent(name: "temperature", value: 72, unit: "F") + sendEvent(name: "heatingSetpoint", value: 70, unit: "F") + sendEvent(name: "thermostatSetpoint", value: 70, unit: "F") + sendEvent(name: "coolingSetpoint", value: 76, unit: "F") + sendEvent(name: "thermostatMode", value: "off") + sendEvent(name: "thermostatFanMode", value: "fanAuto") + sendEvent(name: "thermostatOperatingState", value: "idle") + sendEvent(name: "humidity", value: 53, unit: "%") +} + +def parse(String description) { +} + +def evaluate(temp, heatingSetpoint, coolingSetpoint) { + log.debug "evaluate($temp, $heatingSetpoint, $coolingSetpoint" + def threshold = 1.0 + def current = device.currentValue("thermostatOperatingState") + def mode = device.currentValue("thermostatMode") + + def heating = false + def cooling = false + def idle = false + if (mode in ["heat","emergency heat","auto"]) { + if (heatingSetpoint - temp >= threshold) { + heating = true + sendEvent(name: "thermostatOperatingState", value: "heating") + } + else if (temp - heatingSetpoint >= threshold) { + idle = true + } + sendEvent(name: "thermostatSetpoint", value: heatingSetpoint) + } + if (mode in ["cool","auto"]) { + if (temp - coolingSetpoint >= threshold) { + cooling = true + sendEvent(name: "thermostatOperatingState", value: "cooling") + } + else if (coolingSetpoint - temp >= threshold && !heating) { + idle = true + } + sendEvent(name: "thermostatSetpoint", value: coolingSetpoint) + } + else { + sendEvent(name: "thermostatSetpoint", value: heatingSetpoint) + } + if (idle && !heating && !cooling) { + sendEvent(name: "thermostatOperatingState", value: "idle") + } +} + +def setHeatingSetpoint(Double degreesF) { + log.debug "setHeatingSetpoint($degreesF)" + sendEvent(name: "heatingSetpoint", value: degreesF) + evaluate(device.currentValue("temperature"), degreesF, device.currentValue("coolingSetpoint")) +} + +def setCoolingSetpoint(Double degreesF) { + log.debug "setCoolingSetpoint($degreesF)" + sendEvent(name: "coolingSetpoint", value: degreesF) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), degreesF) +} + +def setThermostatMode(String value) { + sendEvent(name: "thermostatMode", value: value) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def setThermostatFanMode(String value) { + sendEvent(name: "thermostatFanMode", value: value) +} + +def off() { + sendEvent(name: "thermostatMode", value: "off") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def heat() { + sendEvent(name: "thermostatMode", value: "heat") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def auto() { + sendEvent(name: "thermostatMode", value: "auto") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def emergencyHeat() { + sendEvent(name: "thermostatMode", value: "emergency heat") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def cool() { + sendEvent(name: "thermostatMode", value: "cool") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def fanOn() { + sendEvent(name: "thermostatFanMode", value: "fanOn") +} + +def fanAuto() { + sendEvent(name: "thermostatFanMode", value: "fanAuto") +} + +def fanCirculate() { + sendEvent(name: "thermostatFanMode", value: "fanCirculate") +} + +def tempUp() { + def ts = device.currentState("temperature") + def value = ts ? ts.integerValue + 1 : 72 + sendEvent(name:"temperature", value: value) + evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def tempDown() { + def ts = device.currentState("temperature") + def value = ts ? ts.integerValue - 1 : 72 + sendEvent(name:"temperature", value: value) + evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def setTemperature(value) { + def ts = device.currentState("temperature") + sendEvent(name:"temperature", value: value) + evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def heatUp() { + def ts = device.currentState("heatingSetpoint") + def value = ts ? ts.integerValue + 1 : 68 + sendEvent(name:"heatingSetpoint", value: value) + evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint")) +} + +def heatDown() { + def ts = device.currentState("heatingSetpoint") + def value = ts ? ts.integerValue - 1 : 68 + sendEvent(name:"heatingSetpoint", value: value) + evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint")) +} + + +def coolUp() { + def ts = device.currentState("coolingSetpoint") + def value = ts ? ts.integerValue + 1 : 76 + sendEvent(name:"coolingSetpoint", value: value) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value) +} + +def coolDown() { + def ts = device.currentState("coolingSetpoint") + def value = ts ? ts.integerValue - 1 : 76 + sendEvent(name:"coolingSetpoint", value: value) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value) +} diff --git a/devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy b/devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy new file mode 100644 index 0000000..8086c2c --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-basic-colorwheel.src/tile-basic-colorwheel.groovy @@ -0,0 +1,52 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "colorWheelDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Color Control" + } + + tiles(scale: 2) { + valueTile("currentColor", "device.color") { + state "default", label: '${currentValue}' + } + + controlTile("rgbSelector", "device.color", "color", height: 6, width: 6, inactiveLabel: false) { + state "color", action: "color control.setColor" + } + + main("currentColor") + details([ + "rgbSelector" + ]) + } +} + +// parse events into attributes +def parse(String description) { + log.debug "Parsing '${description}'" +} + +def setSaturation(percent) { + log.debug "Executing 'setSaturation'" + sendEvent(name: "saturation", value: percent) +} + +def setHue(percent) { + log.debug "Executing 'setHue'" + sendEvent(name: "hue", value: percent) +} diff --git a/devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy b/devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy new file mode 100644 index 0000000..968fc08 --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-basic-presence.src/tile-basic-presence.groovy @@ -0,0 +1,63 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "presenceDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Presence Sensor" + + command "arrived" + command "departed" + } + + tiles(scale: 2) { + // You only get a presence tile view when the size is 3x3 otherwise it's a value tile + standardTile("presence", "device.presence", width: 3, height: 3, canChangeBackground: true) { + state("present", labelIcon:"st.presence.tile.mobile-present", backgroundColor:"#53a7c0") + state("not present", labelIcon:"st.presence.tile.mobile-not-present", backgroundColor:"#ebeef2") + } + + standardTile("notPresentBtn", "device.fake", width: 3, height: 3, decoration: "flat") { + state("not present", label:'not present', backgroundColor:"#ffffff", action:"departed") + } + + standardTile("presentBtn", "device.fake", width: 3, height: 3, decoration: "flat") { + state("present", label:'present', backgroundColor:"#53a7c0", action:"arrived") + } + + main("presence") + details([ + "presence", "presenceControl", "notPresentBtn", "presentBtn" + ]) + } +} + +def installed() { + sendEvent(name: "presence", value: "present") +} + +def parse(String description) { +} + +def arrived() { + log.trace "Executing 'arrived'" + sendEvent(name: "presence", value: "present") +} + +def departed() { + log.trace "Executing 'arrived'" + sendEvent(name: "presence", value: "not present") +} diff --git a/devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy b/devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy new file mode 100644 index 0000000..12e30be --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-basic-slider.src/tile-basic-slider.groovy @@ -0,0 +1,75 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "sliderDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Switch Level" + command "setRangedLevel", ["number"] + } + + tiles(scale: 2) { + controlTile("tinySlider", "device.level", "slider", height: 2, width: 2, inactiveLabel: false) { + state "level", action:"switch level.setLevel" + } + + controlTile("mediumSlider", "device.level", "slider", height: 2, width: 4, inactiveLabel: false) { + state "level", action:"switch level.setLevel" + } + + controlTile("largeSlider", "device.level", "slider", decoration: "flat", height: 2, width: 6, inactiveLabel: false) { + state "level", action:"switch level.setLevel" + } + + controlTile("rangeSlider", "device.rangedLevel", "slider", height: 2, width: 4, range: "(20..80)") { + state "level", action:"setRangedLevel" + } + + valueTile("rangeValue", "device.rangedLevel", height: 2, width: 2) { + state "default", label:'${currentValue}' + } + + controlTile("rangeSliderConstrained", "device.rangedLevel", "slider", height: 2, width: 4, range: "(40..60)") { + state "level", action:"setRangedLevel" + } + + main("rangeValue") + details([ + "tinySlider", "mediumSlider", + "largeSlider", + "rangeSlider", "rangeValue", + "rangeSliderConstrained" + ]) + } +} + +def installed() { + sendEvent(name: "level", value: 63) + sendEvent(name: "rangedLevel", value: 47) +} + +def parse(String description) { +} + +def setLevel(value) { + log.debug "setting level to $value" + sendEvent(name:"level", value:value) +} + +def setRangedLevel(value) { + log.debug "setting ranged level to $value" + sendEvent(name:"rangedLevel", value:value) +} diff --git a/devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy b/devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy new file mode 100644 index 0000000..3999313 --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-basic-standard.src/tile-basic-standard.groovy @@ -0,0 +1,109 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "standardDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Switch" + } + + tiles(scale: 2) { + // standard tile with actions + standardTile("actionRings", "device.switch", width: 2, height: 2, canChangeIcon: true) { + state "off", label: '${currentValue}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" + state "on", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" + } + + // standard flat tile with actions + standardTile("actionFlat", "device.switch", width: 2, height: 2, canChangeIcon: true, decoration: "flat") { + state "off", label: '${currentValue}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" + state "on", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" + } + + // standard flat tile without actions + standardTile("noActionFlat", "device.switch", width: 2, height: 2, canChangeIcon: true) { + state "off", label: '${currentValue}',icon: "st.switches.switch.off", backgroundColor: "#ffffff" + state "on", label: '${currentValue}', icon: "st.switches.switch.on", backgroundColor: "#79b821" + } + + // standard flat tile with only a label + standardTile("flatLabel", "device.switch", width: 2, height: 2, decoration: "flat") { + state "default", label: 'On Action', action: "switch.on", backgroundColor: "#ffffff" + } + + // standard flat tile with icon and label + standardTile("flatIconLabel", "device.switch", width: 2, height: 2, decoration: "flat") { + state "default", label: 'Off Action', action: "switch.off", icon:"st.switches.switch.off", backgroundColor: "#ffffff" + } + + // standard flat tile with only icon (Refreh text is IN the icon file) + standardTile("flatIcon", "device.switch", width: 2, height: 2, decoration: "flat") { + state "default", action:"refresh.refresh", icon:"st.secondary.refresh" + } + + // standard with defaultState = true + standardTile("flatDefaultState", "null", width: 2, height: 2, decoration: "flat") { + state "off", label: 'Fail!', icon: "st.switches.switch.off" + state "on", label: 'Pass!', icon: "st.switches.switch.on", defaultState: true + } + + // standard with implicit defaultState based on order (0 index is selected) + standardTile("flatImplicitDefaultState1", "null", width: 2, height: 2, decoration: "flat") { + state "on", label: 'Pass!', icon: "st.switches.switch.on" + state "off", label: 'Fail!', icon: "st.switches.switch.off" + } + + // standard with implicit defaultState based on state.name == default + standardTile("flatImplicitDefaultState2", "null", width: 2, height: 2, decoration: "flat") { + state "off", label: 'Fail!', icon: "st.switches.switch.off" + state "default", label: 'Pass!', icon: "st.switches.switch.on" + } + + // utility tiles to fill the spaces + standardTile("empty2x2", "null", width: 2, height: 2, decoration: "flat") { + state "default", label:'' + } + standardTile("empty4x2", "null", width: 4, height: 2, decoration: "flat") { + state "default", label:'' + } + + main("standard1") + details([ + "actionRings", "actionFlat", "noActionFlat", + + "flatLabel", "flatIconLabel", "flatIcon", + + "flatDefaultState", "flatImplicitDefaultState1", "flatImplicitDefaultState2", + ]) + } +} + +def installed() { + sendEvent(name: "switch", value: "off") +} + +def parse(String description) { +} + +def on() { + log.debug "on()" + sendEvent(name: "switch", value: "on") +} + +def off() { + log.debug "off()" + sendEvent(name: "switch", value: "off") +} diff --git a/devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy b/devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy new file mode 100644 index 0000000..cc79f11 --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-basic-value.src/tile-basic-value.groovy @@ -0,0 +1,96 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "valueDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Sensor" + } + + tiles(scale: 2) { + valueTile("text", "device.text", width: 2, height: 2) { + state "default", label:'${currentValue}' + } + + valueTile("longText", "device.longText", width: 2, height: 2) { + state "default", label:'${currentValue}' + } + + valueTile("integer", "device.integer", width: 2, height: 2) { + state "default", label:'${currentValue}' + } + + valueTile("integerFloat", "device.integerFloat", width: 2, height: 2) { + state "default", label:'${currentValue}' + } + + valueTile("pi", "device.pi", width: 2, height: 2) { + state "default", label:'${currentValue}' + } + + valueTile("floatAsText", "device.floatAsText", width: 2, height: 2) { + state "default", label:'${currentValue}' + } + + valueTile("bgColor", "device.integer", width: 2, height: 2) { + state "default", label:'${currentValue}', backgroundColor: "#e86d13" + } + + valueTile("bgColorRange", "device.integer", width: 2, height: 2) { + state "default", label:'${currentValue}', backgroundColors: [ + [value: 10, color: "#ff0000"], + [value: 90, color: "#0000ff"] + ] + } + + valueTile("bgColorRangeSingleItem", "device.integer", width: 2, height: 2) { + state "default", label:'${currentValue}', backgroundColors: [ + [value: 10, color: "#333333"] + ] + } + + valueTile("bgColorRangeConflict", "device.integer", width: 2, height: 2) { + state "default", label:'${currentValue}', backgroundColors: [ + [value: 10, color: "#990000"], + [value: 10, color: "#000099"] + ] + } + + valueTile("noValue", "device.nada", width: 2, height: 2) { + state "default", label:'${currentValue}' + } + + main("text") + details([ + "text", "longText", "integer", + "integerFloat", "pi", "floatAsText", + "bgColor", "bgColorRange", "bgColorRangeSingleItem", + "bgColorRangeConflict", "noValue" + ]) + } +} + +def installed() { + sendEvent(name: "text", value: "Test") + sendEvent(name: "longText", value: "The Longer The Text, The Better The Test") + sendEvent(name: "integer", value: 47) + sendEvent(name: "integerFloat", value: 47.0) + sendEvent(name: "pi", value: 3.14159) + sendEvent(name: "floatAsText", value: "3.14159") +} + +def parse(String description) { +} diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy new file mode 100644 index 0000000..4a63c6d --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-generic.src/tile-multiattribute-generic.groovy @@ -0,0 +1,118 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition (name: "genericDeviceTile", namespace: "smartthings/tile-ux", author: "SmartThings") { + capability "Actuator" + capability "Switch" + capability "Switch Level" + + command "levelUp" + command "levelDown" + command "randomizeLevel" + } + + tiles(scale: 2) { + multiAttributeTile(name:"basicTile", type:"generic", width:6, height:4) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" + } + } + multiAttributeTile(name:"sliderTile", type:"generic", width:6, height:4) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute("device.level", key: "SECONDARY_CONTROL") { + attributeState "default", icon: 'st.Weather.weather1', action:"randomizeLevel" + } + tileAttribute("device.level", key: "SLIDER_CONTROL") { + attributeState "default", action:"switch level.setLevel" + } + } + multiAttributeTile(name:"valueTile", type:"generic", width:6, height:4) { + tileAttribute("device.level", key: "PRIMARY_CONTROL") { + attributeState "default", label:'${currentValue}', backgroundColors:[ + [value: 0, color: "#ff0000"], + [value: 20, color: "#ffff00"], + [value: 40, color: "#00ff00"], + [value: 60, color: "#00ffff"], + [value: 80, color: "#0000ff"], + [value: 100, color: "#ff00ff"] + ] + } + tileAttribute("device.switch", key: "SECONDARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute("device.level", key: "VALUE_CONTROL") { + attributeState "VALUE_UP", action: "levelUp" + attributeState "VALUE_DOWN", action: "levelDown" + } + } + + main(["basicTile"]) + details(["basicTile", "sliderTile", "valueTile"]) + } +} + +def installed() { + +} + +def parse() { + // This is a simulated device. No incoming data to parse. +} + +def on() { + log.debug "turningOn" + sendEvent(name: "switch", value: "on") +} + +def off() { + log.debug "turningOff" + sendEvent(name: "switch", value: "off") +} + +def setLevel(percent) { + log.debug "setLevel: ${percent}, this" + sendEvent(name: "level", value: percent) +} + +def randomizeLevel() { + def level = Math.round(Math.random() * 100) + setLevel(level) +} + +def levelUp() { + def level = device.latestValue("level") as Integer ?: 0 + if (level < 100) { + level = level + 1 + } + setLevel(level) +} + +def levelDown() { + def level = device.latestValue("level") as Integer ?: 0 + if (level > 0) { + level = level - 1 + } + setLevel(level) +} diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy new file mode 100644 index 0000000..6ebbb3e --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-lighting.src/tile-multiattribute-lighting.groovy @@ -0,0 +1,211 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "lightingDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Switch Level" + capability "Actuator" + capability "Color Control" + capability "Power Meter" + capability "Switch" + capability "Refresh" + capability "Sensor" + + command "setAdjustedColor" + command "reset" + command "refresh" + } + + tiles(scale: 2) { + multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute ("device.power", key: "SECONDARY_CONTROL") { + attributeState "power", label:'Power level: ${currentValue}W', icon: "st.Appliances.appliances17" + } + tileAttribute ("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action:"switch level.setLevel" + } + tileAttribute ("device.color", key: "COLOR_CONTROL") { + attributeState "color", action:"setAdjustedColor" + } + } + + multiAttributeTile(name:"switchNoPower", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute ("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action:"switch level.setLevel" + } + tileAttribute ("device.color", key: "COLOR_CONTROL") { + attributeState "color", action:"setAdjustedColor" + } + } + + multiAttributeTile(name:"switchNoSlider", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute ("device.power", key: "SECONDARY_CONTROL") { + attributeState "power", label:'The power level is currently: ${currentValue}W', icon: "st.Appliances.appliances17" + } + tileAttribute ("device.color", key: "COLOR_CONTROL") { + attributeState "color", action:"setAdjustedColor" + } + } + + multiAttributeTile(name:"switchNoSliderOrColor", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute ("device.power", key: "SECONDARY_CONTROL") { + attributeState "power", label:'The light is currently consuming this amount of power: ${currentValue}W', icon: "st.Appliances.appliances17" + } + } + + valueTile("color", "device.color", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "color", label: '${currentValue}' + } + + standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single" + } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + + main(["switch"]) + details(["switch", "switchNoPower", "switchNoSlider", "switchNoSliderOrColor", "color", "refresh", "reset"]) + } +} + +// parse events into attributes +def parse(description) { + log.debug "parse() - $description" + def results = [] + def map = description + if (description instanceof String) { + log.debug "Hue Bulb stringToMap - ${map}" + map = stringToMap(description) + } + if (map?.name && map?.value) { + results << createEvent(name: "${map?.name}", value: "${map?.value}") + } + results +} + +// handle commands +def on() { + //log.trace parent.on(this) + sendEvent(name: "switch", value: "on") +} + +def off() { + //log.trace parent.off(this) + sendEvent(name: "switch", value: "off") +} + +def nextLevel() { + def level = device.latestValue("level") as Integer ?: 0 + if (level <= 100) { + level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer + } + else { + level = 25 + } + setLevel(level) +} + +def setLevel(percent) { + log.debug "setLevel: ${percent}, this" + sendEvent(name: "level", value: percent) + def power = Math.round(percent / 1.175) * 0.1 + sendEvent(name: "power", value: power) +} + +def setSaturation(percent) { + log.debug "setSaturation: ${percent}, $this" + sendEvent(name: "saturation", value: percent) +} + +def setHue(percent) { + log.debug "setHue: ${percent}, $this" + sendEvent(name: "hue", value: percent) +} + +def setColor(value) { + log.debug "setColor: ${value}, $this" + if (value.hue) { sendEvent(name: "hue", value: value.hue)} + if (value.saturation) { sendEvent(name: "saturation", value: value.saturation)} + if (value.hex) { sendEvent(name: "color", value: value.hex)} + if (value.level) { sendEvent(name: "level", value: value.level)} + if (value.switch) { sendEvent(name: "switch", value: value.switch)} +} + +def reset() { + log.debug "Executing 'reset'" + setAdjustedColor([level:100, hex:"#90C638", saturation:56, hue:23]) + //parent.poll() +} + +def setAdjustedColor(value) { + if (value) { + log.trace "setAdjustedColor: ${value}" + def adjusted = value + [:] + adjusted.hue = adjustOutgoingHue(value.hue) + // Needed because color picker always sends 100 + adjusted.level = null + setColor(adjusted) + } +} + +def refresh() { + log.debug "Executing 'refresh'" + //parent.manualRefresh() +} + +def adjustOutgoingHue(percent) { + def adjusted = percent + if (percent > 31) { + if (percent < 63.0) { + adjusted = percent + (7 * (percent -30 ) / 32) + } + else if (percent < 73.0) { + adjusted = 69 + (5 * (percent - 62) / 10) + } + else { + adjusted = percent + (2 * (100 - percent) / 28) + } + } + log.info "percent: $percent, adjusted: $adjusted" + adjusted +} + diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy new file mode 100644 index 0000000..b22c3f7 --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-mediaplayer.src/tile-multiattribute-mediaplayer.groovy @@ -0,0 +1,122 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "mediaPlayerDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Actuator" + capability "Switch" + capability "Refresh" + capability "Sensor" + capability "Music Player" + } + + tiles(scale: 2) { + multiAttributeTile(name: "mediaMulti", type:"mediaPlayer", width:6, height:4) { + tileAttribute("device.status", key: "PRIMARY_CONTROL") { + attributeState("paused", label:"Paused",) + attributeState("playing", label:"Playing") + attributeState("stopped", label:"Stopped") + } + tileAttribute("device.status", key: "MEDIA_STATUS") { + attributeState("paused", label:"Paused", action:"music Player.play", nextState: "playing") + attributeState("playing", label:"Playing", action:"music Player.pause", nextState: "paused") + attributeState("stopped", label:"Stopped", action:"music Player.play", nextState: "playing") + } + tileAttribute("device.status", key: "PREVIOUS_TRACK") { + attributeState("default", action:"music Player.previousTrack") + } + tileAttribute("device.status", key: "NEXT_TRACK") { + attributeState("default", action:"music Player.nextTrack") + } + tileAttribute ("device.level", key: "SLIDER_CONTROL") { + attributeState("level", action:"music Player.setLevel") + } + tileAttribute ("device.mute", key: "MEDIA_MUTED") { + attributeState("unmuted", action:"music Player.mute", nextState: "muted") + attributeState("muted", action:"music Player.unmute", nextState: "unmuted") + } + tileAttribute("device.trackDescription", key: "MARQUEE") { + attributeState("default", label:"${currentValue}") + } + } + + main "mediaMulti" + details(["mediaMulti"]) + } +} + +def installed() { + state.tracks = [ + "Gangnam Style (강남스타일)\nPSY\nPsy 6 (Six Rules), Part 1", + "Careless Whisper\nWham!\nMake It Big", + "Never Gonna Give You Up\nRick Astley\nWhenever You Need Somebody", + "Shake It Off\nTaylor Swift\n1989", + "Ironic\nAlanis Morissette\nJagged Little Pill", + "Hotline Bling\nDrake\nHotline Bling - Single" + ] + state.currentTrack = 0 + + sendEvent(name: "level", value: 72) + sendEvent(name: "mute", value: "unmuted") + sendEvent(name: "status", value: "stopped") +} + +def parse(description) { + // No parsing will happen with this simulated device. +} + +def play() { + sendEvent(name: "status", value: "playing") + sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack]) +} + +def pause() { + sendEvent(name: "status", value: "paused") + sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack]) +} + +def stop() { + sendEvent(name: "status", value: "stopped") +} + +def previousTrack() { + state.currentTrack = state.currentTrack - 1 + if (state.currentTrack < 0) + state.currentTrack = state.tracks.size()-1 + + sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack]) +} + +def nextTrack() { + state.currentTrack = state.currentTrack + 1 + if (state.currentTrack == state.tracks.size()) + state.currentTrack = 0 + + sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack]) +} + +def mute() { + sendEvent(name: "mute", value: "muted") +} + +def unmute() { + sendEvent(name: "mute", value: "unmuted") +} + +def setLevel(level) { + sendEvent(name: "level", value: level) +} diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy new file mode 100644 index 0000000..93c7c75 --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-thermostat.src/tile-multiattribute-thermostat.groovy @@ -0,0 +1,341 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "thermostatDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Thermostat" + capability "Relative Humidity Measurement" + + command "tempUp" + command "tempDown" + command "heatUp" + command "heatDown" + command "coolUp" + command "coolDown" + command "setTemperature", ["number"] + } + + tiles(scale: 2) { + multiAttributeTile(name:"thermostatFull", type:"thermostat", width:6, height:4) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + tileAttribute("device.temperature", key: "VALUE_CONTROL") { + attributeState("VALUE_UP", action: "tempUp") + attributeState("VALUE_DOWN", action: "tempDown") + } + tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { + attributeState("default", label:'${currentValue}%', unit:"%") + } + tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { + attributeState("idle", backgroundColor:"#44b621") + attributeState("heating", backgroundColor:"#ffa81e") + attributeState("cooling", backgroundColor:"#269bd2") + } + tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { + attributeState("off", label:'${name}') + attributeState("heat", label:'${name}') + attributeState("cool", label:'${name}') + attributeState("auto", label:'${name}') + } + tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + } + multiAttributeTile(name:"thermostatNoHumidity", type:"thermostat", width:6, height:4) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + tileAttribute("device.temperature", key: "VALUE_CONTROL") { + attributeState("VALUE_UP", action: "tempUp") + attributeState("VALUE_DOWN", action: "tempDown") + } + tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { + attributeState("idle", backgroundColor:"#44b621") + attributeState("heating", backgroundColor:"#ffa81e") + attributeState("cooling", backgroundColor:"#269bd2") + } + tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { + attributeState("off", label:'${name}') + attributeState("heat", label:'${name}') + attributeState("cool", label:'${name}') + attributeState("auto", label:'${name}') + } + tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") { + attributeState("default", label:'${currentValue}', unit:"dF") + } + } + multiAttributeTile(name:"thermostatBasic", type:"thermostat", width:6, height:4) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState("default", label:'${currentValue}', unit:"dF", + backgroundColors:[ + [value: 31, color: "#153591"], + [value: 44, color: "#1e9cbb"], + [value: 59, color: "#90d2a7"], + [value: 74, color: "#44b621"], + [value: 84, color: "#f1d801"], + [value: 95, color: "#d04e00"], + [value: 96, color: "#bc2323"] + ]) + } + tileAttribute("device.temperature", key: "VALUE_CONTROL") { + attributeState("VALUE_UP", action: "tempUp") + attributeState("VALUE_DOWN", action: "tempDown") + } + } + + valueTile("temperature", "device.temperature", width: 2, height: 2) { + state("temperature", label:'${currentValue}', unit:"dF", + backgroundColors:[ + [value: 31, color: "#153591"], + [value: 44, color: "#1e9cbb"], + [value: 59, color: "#90d2a7"], + [value: 74, color: "#44b621"], + [value: 84, color: "#f1d801"], + [value: 95, color: "#d04e00"], + [value: 96, color: "#bc2323"] + ] + ) + } + standardTile("tempDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label:'down', action:"tempDown" + } + standardTile("tempUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label:'up', action:"tempUp" + } + + valueTile("heatingSetpoint", "device.heatingSetpoint", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "heat", label:'${currentValue} heat', unit: "F", backgroundColor:"#ffffff" + } + standardTile("heatDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label:'down', action:"heatDown" + } + standardTile("heatUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label:'up', action:"heatUp" + } + + valueTile("coolingSetpoint", "device.coolingSetpoint", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "cool", label:'${currentValue} cool', unit:"F", backgroundColor:"#ffffff" + } + standardTile("coolDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label:'down', action:"coolDown" + } + standardTile("coolUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label:'up', action:"coolUp" + } + + standardTile("mode", "device.thermostatMode", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "off", label:'${name}', action:"thermostat.heat", backgroundColor:"#ffffff" + state "heat", label:'${name}', action:"thermostat.cool", backgroundColor:"#ffa81e" + state "cool", label:'${name}', action:"thermostat.auto", backgroundColor:"#269bd2" + state "auto", label:'${name}', action:"thermostat.off", backgroundColor:"#79b821" + } + standardTile("fanMode", "device.thermostatFanMode", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "fanAuto", label:'${name}', action:"thermostat.fanOn", backgroundColor:"#ffffff" + state "fanOn", label:'${name}', action:"thermostat.fanCirculate", backgroundColor:"#ffffff" + state "fanCirculate", label:'${name}', action:"thermostat.fanAuto", backgroundColor:"#ffffff" + } + standardTile("operatingState", "device.thermostatOperatingState", width: 2, height: 2) { + state "idle", label:'${name}', backgroundColor:"#ffffff" + state "heating", label:'${name}', backgroundColor:"#ffa81e" + state "cooling", label:'${name}', backgroundColor:"#269bd2" + } + + + main("thermostatFull") + details([ + "thermostatFull", "thermostatNoHumidity", "thermostatBasic" + "temperature","tempDown","tempUp", + "mode", "fanMode", "operatingState", + "heatingSetpoint", "heatDown", "heatUp", + "coolingSetpoint", "coolDown", "coolUp" + ]) + } +} + +def installed() { + sendEvent(name: "temperature", value: 72, unit: "F") + sendEvent(name: "heatingSetpoint", value: 70, unit: "F") + sendEvent(name: "thermostatSetpoint", value: 70, unit: "F") + sendEvent(name: "coolingSetpoint", value: 76, unit: "F") + sendEvent(name: "thermostatMode", value: "off") + sendEvent(name: "thermostatFanMode", value: "fanAuto") + sendEvent(name: "thermostatOperatingState", value: "idle") + sendEvent(name: "humidity", value: 53, unit: "%") +} + +def parse(String description) { +} + +def evaluate(temp, heatingSetpoint, coolingSetpoint) { + log.debug "evaluate($temp, $heatingSetpoint, $coolingSetpoint" + def threshold = 1.0 + def current = device.currentValue("thermostatOperatingState") + def mode = device.currentValue("thermostatMode") + + def heating = false + def cooling = false + def idle = false + if (mode in ["heat","emergency heat","auto"]) { + if (heatingSetpoint - temp >= threshold) { + heating = true + sendEvent(name: "thermostatOperatingState", value: "heating") + } + else if (temp - heatingSetpoint >= threshold) { + idle = true + } + sendEvent(name: "thermostatSetpoint", value: heatingSetpoint) + } + if (mode in ["cool","auto"]) { + if (temp - coolingSetpoint >= threshold) { + cooling = true + sendEvent(name: "thermostatOperatingState", value: "cooling") + } + else if (coolingSetpoint - temp >= threshold && !heating) { + idle = true + } + sendEvent(name: "thermostatSetpoint", value: coolingSetpoint) + } + else { + sendEvent(name: "thermostatSetpoint", value: heatingSetpoint) + } + + if (mode == "off") { + idle = true + } + + if (idle && !heating && !cooling) { + sendEvent(name: "thermostatOperatingState", value: "idle") + } +} + +def setHeatingSetpoint(Double degreesF) { + log.debug "setHeatingSetpoint($degreesF)" + sendEvent(name: "heatingSetpoint", value: degreesF) + evaluate(device.currentValue("temperature"), degreesF, device.currentValue("coolingSetpoint")) +} + +def setCoolingSetpoint(Double degreesF) { + log.debug "setCoolingSetpoint($degreesF)" + sendEvent(name: "coolingSetpoint", value: degreesF) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), degreesF) +} + +def setThermostatMode(String value) { + sendEvent(name: "thermostatMode", value: value) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def setThermostatFanMode(String value) { + sendEvent(name: "thermostatFanMode", value: value) +} + +def off() { + sendEvent(name: "thermostatMode", value: "off") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def heat() { + sendEvent(name: "thermostatMode", value: "heat") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def auto() { + sendEvent(name: "thermostatMode", value: "auto") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def emergencyHeat() { + sendEvent(name: "thermostatMode", value: "emergency heat") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def cool() { + sendEvent(name: "thermostatMode", value: "cool") + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def fanOn() { + sendEvent(name: "thermostatFanMode", value: "fanOn") +} + +def fanAuto() { + sendEvent(name: "thermostatFanMode", value: "fanAuto") +} + +def fanCirculate() { + sendEvent(name: "thermostatFanMode", value: "fanCirculate") +} + +def poll() { + null +} + +def tempUp() { + def ts = device.currentState("temperature") + def value = ts ? ts.integerValue + 1 : 72 + sendEvent(name:"temperature", value: value) + evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def tempDown() { + def ts = device.currentState("temperature") + def value = ts ? ts.integerValue - 1 : 72 + sendEvent(name:"temperature", value: value) + evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def setTemperature(value) { + def ts = device.currentState("temperature") + sendEvent(name:"temperature", value: value) + evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint")) +} + +def heatUp() { + def ts = device.currentState("heatingSetpoint") + def value = ts ? ts.integerValue + 1 : 68 + sendEvent(name:"heatingSetpoint", value: value) + evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint")) +} + +def heatDown() { + def ts = device.currentState("heatingSetpoint") + def value = ts ? ts.integerValue - 1 : 68 + sendEvent(name:"heatingSetpoint", value: value) + evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint")) +} + + +def coolUp() { + def ts = device.currentState("coolingSetpoint") + def value = ts ? ts.integerValue + 1 : 76 + sendEvent(name:"coolingSetpoint", value: value) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value) +} + +def coolDown() { + def ts = device.currentState("coolingSetpoint") + def value = ts ? ts.integerValue - 1 : 76 + sendEvent(name:"coolingSetpoint", value: value) + evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value) +} diff --git a/devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy b/devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy new file mode 100644 index 0000000..792b458 --- /dev/null +++ b/devicetypes/smartthings/tile-ux/tile-multiattribute-videoplayer.src/tile-multiattribute-videoplayer.groovy @@ -0,0 +1,169 @@ +/** + * Copyright 2016 SmartThings, Inc. + * + * 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. + * + */ +metadata { + definition ( + name: "videoPlayerDeviceTile", + namespace: "smartthings/tile-ux", + author: "SmartThings") { + + capability "Configuration" + capability "Video Camera" + capability "Video Capture" + capability "Refresh" + capability "Switch" + + // custom commands + command "start" + command "stop" + command "setProfileHD" + command "setProfileSDH" + command "setProfileSDL" + } + + tiles(scale: 2) { + multiAttributeTile(name: "videoPlayer", type: "videoPlayer", width: 6, height: 4) { + tileAttribute("device.switch", key: "CAMERA_STATUS") { + attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", action: "switch.off", backgroundColor: "#79b821", defaultState: true) + attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", action: "switch.on", backgroundColor: "#ffffff") + attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0") + attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", action: "refresh.refresh", backgroundColor: "#F22000") + } + + tileAttribute("device.errorMessage", key: "CAMERA_ERROR_MESSAGE") { + attributeState("errorMessage", label: "", value: "", defaultState: true) + } + + tileAttribute("device.camera", key: "PRIMARY_CONTROL") { + attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", backgroundColor: "#79b821", defaultState: true) + attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", backgroundColor: "#ffffff") + attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0") + attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", backgroundColor: "#F22000") + } + + tileAttribute("device.startLive", key: "START_LIVE") { + attributeState("live", action: "start", defaultState: true) + } + + tileAttribute("device.stream", key: "STREAM_URL") { + attributeState("activeURL", defaultState: true) + } + + tileAttribute("device.profile", key: "STREAM_QUALITY") { + attributeState("1", label: "720p", action: "setProfileHD", defaultState: true) + attributeState("2", label: "h360p", action: "setProfileSDH", defaultState: true) + attributeState("3", label: "l360p", action: "setProfileSDL", defaultState: true) + } + + tileAttribute("device.betaLogo", key: "BETA_LOGO") { + attributeState("betaLogo", label: "", value: "", defaultState: true) + } + } + + multiAttributeTile(name: "videoPlayerMin", type: "videoPlayer", width: 6, height: 4) { + tileAttribute("device.switch", key: "CAMERA_STATUS") { + attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", action: "switch.off", backgroundColor: "#79b821", defaultState: true) + attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", action: "switch.on", backgroundColor: "#ffffff") + attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0") + attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", action: "refresh.refresh", backgroundColor: "#F22000") + } + + tileAttribute("device.errorMessage", key: "CAMERA_ERROR_MESSAGE") { + attributeState("errorMessage", label: "", value: "", defaultState: true) + } + + tileAttribute("device.camera", key: "PRIMARY_CONTROL") { + attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", backgroundColor: "#79b821", defaultState: true) + attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", backgroundColor: "#ffffff") + attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0") + attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", backgroundColor: "#F22000") + } + + tileAttribute("device.startLive", key: "START_LIVE") { + attributeState("live", action: "start", defaultState: true) + } + + tileAttribute("device.stream", key: "STREAM_URL") { + attributeState("activeURL", defaultState: true) + } + } + + main("videoPlayer") + details([ + "videoPlayer", "videoPlayerMin" + ]) + } +} + +def installed() { +} + +def parse(String description) { +} + +def refresh() { + log.trace "refresh()" + // no-op +} + +def on() { + log.trace "on()" + // no-op +} + +def off() { + log.trace "off()" + // no-op +} + +def setProfile(profile) { + log.trace "setProfile(): ${profile}" + sendEvent(name: "profile", value: profile, displayed: false) +} + +def setProfileHD() { + setProfile(1) +} + +def setProfileSDH() { + setProfile(2) +} + +def setProfileSDL() { + setProfile(3) +} + +def start() { + log.trace "start()" + def dataLiveVideo = [ + OutHomeURL : "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8", + InHomeURL : "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8", + ThumbnailURL: "http://cdn.device-icons.smartthings.com/camera/dlink-indoor@2x.png", + cookie : [key: "key", value: "value"] + ] + + def event = [ + name : "stream", + value : groovy.json.JsonOutput.toJson(dataLiveVideo).toString(), + data : groovy.json.JsonOutput.toJson(dataLiveVideo), + descriptionText: "Starting the livestream", + eventType : "VIDEO", + displayed : false, + isStateChange : true + ] + sendEvent(event) +} + +def stop() { + log.trace "stop()" +} \ No newline at end of file diff --git a/smartapps/smartthings/tile-ux/device-tile-controller.src/device-tile-controller.groovy b/smartapps/smartthings/tile-ux/device-tile-controller.src/device-tile-controller.groovy new file mode 100644 index 0000000..fbc7195 --- /dev/null +++ b/smartapps/smartthings/tile-ux/device-tile-controller.src/device-tile-controller.groovy @@ -0,0 +1,107 @@ +/** + * Device Tile Controller + * + * Copyright 2016 SmartThings + * + * 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: "Device Tile Controller", + namespace: "smartthings/tile-ux", + author: "SmartThings", + description: "A controller SmartApp to install virtual devices into your location in order to simulate various native Device Tiles.", + category: "SmartThings Internal", + iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png", + iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png", + iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png", + singleInstance: true) + + +preferences { + // landing page + page(name: "defaultPage") +} + +def defaultPage() { + dynamicPage(name: "defaultPage", install: true, uninstall: true) { + section { + paragraph "Select on Unselect the devices that you want to install" + } + section(title: "Multi Attribute Tile Types") { + input(type: "bool", name: "genericDeviceTile", title: "generic", description: "A device that showcases the various use of generic multi-attribute-tiles.", defaultValue: "false") + input(type: "bool", name: "lightingDeviceTile", title: "lighting", description: "A device that showcases the various use of lighting multi-attribute-tiles.", defaultValue: "false") + input(type: "bool", name: "thermostatDeviceTile", title: "thermostat", description: "A device that showcases the various use of thermostat multi-attribute-tiles.", defaultValue: "true") + input(type: "bool", name: "mediaPlayerDeviceTile", title: "media player", description: "A device that showcases the various use of mediaPlayer multi-attribute-tiles.", defaultValue: "false") + input(type: "bool", name: "videoPlayerDeviceTile", title: "video player", description: "A device that showcases the various use of videoPlayer multi-attribute-tiles.", defaultValue: "false") + } + section(title: "Device Tile Types") { + input(type: "bool", name: "standardDeviceTile", title: "standard device tiles", description: "A device that showcases the various use of standard device tiles.", defaultValue: "false") + input(type: "bool", name: "valueDeviceTile", title: "value device tiles", description: "A device that showcases the various use of value device tiles.", defaultValue: "false") + input(type: "bool", name: "presenceDeviceTile", title: "presence device tiles", description: "A device that showcases the various use of color control device tile.", defaultValue: "false") + } + section(title: "Other Tile Types") { + input(type: "bool", name: "carouselDeviceTile", title: "image carousel", description: "A device that showcases the various use of carousel device tile.", defaultValue: "false") + input(type: "bool", name: "sliderDeviceTile", title: "slider", description: "A device that showcases the various use of slider device tile.", defaultValue: "false") + input(type: "bool", name: "colorWheelDeviceTile", title: "color wheel", description: "A device that showcases the various use of color wheel device tile.", defaultValue: "false") + } + } +} + +def installed() { + log.debug "Installed with settings: ${settings}" +} + +def uninstalled() { + getChildDevices().each { + deleteChildDevice(it.deviceNetworkId) + } +} + +def updated() { + log.debug "Updated with settings: ${settings}" + unsubscribe() + initializeDevices() +} + +def initializeDevices() { + settings.each { key, value -> + log.debug "$key : $value" + def existingDevice = getChildDevices().find { it.name == key } + log.debug "$existingDevice" + if (existingDevice && !value) { + deleteChildDevice(existingDevice.deviceNetworkId) + } else if (!existingDevice && value) { + String dni = UUID.randomUUID() + log.debug "$dni" + addChildDevice(app.namespace, key, dni, null, [ + label: labelMap()[key] ?: key, + completedSetup: true + ]) + } + } +} + +// Map the name of the Device to a proper Label +def labelMap() { + [ + genericDeviceTile: "Tile Multiattribute Generic", + lightingDeviceTile: "Tile Multiattribute Lighting", + thermostatDeviceTile: "Tile Multiattribute Thermostat", + mediaPlayerDeviceTile: "Tile Multiattribute Media Player", + videoPlayerDeviceTile: "Tile Multiattribute Video Player", + standardDeviceTile: "Tile Device Standard", + valueDeviceTile: "Tile Device Value", + presenceDeviceTile: "Tile Device Presence", + carouselDeviceTile: "Tile Device Carousel", + sliderDeviceTile: "Tile Device Slider", + colorWheelDeviceTile: "Tile Device Color Wheel" + ] +}