Compare commits

..

12 Commits

Author SHA1 Message Date
kathiresan
f3dbc37d96 Modifying 'NetworkScan' 2015-12-08 04:59:23 -06:00
kathiresan
48b5d0703e MSA-700: NetworkScanner Device Discovery 2015-11-24 03:43:53 -06:00
Yaima
8c6c68f102 Merge pull request #303 from Yaima/master
WeMo uninstall not available
2015-11-23 11:26:59 -08:00
Yaima Valdivia
661f8b3bc0 WeMo uninstall not available
https://smartthings.atlassian.net/browse/DVCSMP-1208
2015-11-23 11:22:57 -08:00
Mike Robinet
a62d825f69 Merge pull request #289 from mrobinet/dvcsmp-1262
DVCSMP-1262 Fix reference to Life360 User child device type
2015-11-20 13:52:29 -06:00
Vinay Rao
1890147221 Merge pull request #292 from workingmonk/fingerprint_changes
fingerprint spacing consistency, additional fingerprint color
2015-11-19 08:44:01 -08:00
Vinay Rao
2fb5f8c78c fingerprint spacing consistency, additional fingerprint color
removing sensor from zigbee white color temp, switch and dimmer
2015-11-19 08:41:44 -08:00
Vinay Rao
b44356248c Merge pull request #299 from juano2310/Harmony_Global
Updated - Device Type name
2015-11-19 06:28:00 -08:00
Juan Pablo Risso
c30af84d70 Updated - Device Type name 2015-11-19 09:23:08 -05:00
Yaima Valdivia
5cf72c644c Rename Sonos SmartApps
https://smartthings.atlassian.net/browse/DVCSMP-607
2015-11-18 14:00:57 -06:00
Warodom Khamphanchai
5e93bca030 LiFX - change shardUrl param to apiServerUrl 2015-11-16 16:33:07 -08:00
Mike Robinet
30dedde0df DVCSMP-1262 Fix reference to Life360 User child device type 2015-11-16 11:49:23 -06:00
18 changed files with 343 additions and 521 deletions

View File

@@ -1,294 +0,0 @@
// Express Controls EZMultiPli Multi-sensor
// Motion Sensor - Temperature - Light level - 8 Color Indicator LED - Z-Wave Range Extender - Wall Powered
// driver for SmartThings
// The EZMultiPli is also known as the HSM200 from HomeSeer.com
//
// v0.1.0 - DrZWave - chose better icons, Got color LED to work - first fully functional version
// v0.0.9 - jrs - got the temp and luminance to work. Motion works. Debugging the color wheel.
// v0.0.8 - DrZWave 2/25/2015 - change the color control to be tiles since there are only 8 colors.
// v0.0.7 - jrs - 02/23/2015 - Jim Sulin
metadata {
definition (name: "EZmultiPli", namespace: "DrZWave", author: "Eric Ryherd", oauth: true) {
capability "Motion Sensor"
capability "Temperature Measurement"
capability "Illuminance Measurement"
capability "Switch"
capability "Color Control"
capability "Configuration"
command "setColor"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x71, 0x31, 0x33, 0x72, 0x86, 0x59, 0x85, 0x70, 0x77, 0x5A, 0x7A, 0x73, 0xEF, 0x20"
} // end definition
simulator {
// messages the device returns in response to commands it receives
status "motion" : "command: 7105000000FF07, payload: 07"
status "no motion" : "command: 7105000000FF07, payload: 00"
for (int i = 0; i <= 100; i += 20) {
status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
}
for (int i = 0; i <= 100; i += 20) {
status "luminance ${i} %": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
scaledSensorValue: i, precision: 0, sensorType: 3).incomingMessage()
}
controlTile("rgbSelector", "device.color", "color", height: 3, width: 3, inactiveLabel: false) {
state "color", action:"setColor"
}
} //end simulator
tiles {
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
}
standardTile("switch", "device.switch", canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#79b821"
state "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
}
valueTile("temperature", "device.temperature") {
state "temperature", label:'${currentValue}°', unit:"F", icon:"st.Weather.weather2", // would be better if the units would switch to the desired units of the system (imperial or metric)
backgroundColors:[
[value: 0, color: "#1010ff"], // blue=cold
[value: 65, color: "#a0a0f0"],
[value: 70, color: "#e0e050"],
[value: 75, color: "#f0d030"], // yellow
[value: 80, color: "#fbf020"],
[value: 85, color: "#fbdc01"],
[value: 90, color: "#fb3a01"],
[value: 95, color: "#fb0801"] // red=hot
]
} // icons to use would be st.Weather.weather2 or st.alarm.temperature.normal - see http://scripts.3dgo.net/smartthings/icons/ for a list of icons
valueTile("illuminance", "device.illuminance", inactiveLabel: false) {
// jrs 4/7/2015 - Null on display
// state "luminosity", label:'${currentValue} ${unit}'
state "luminosity", label:'${currentValue}%', unit:"%", icon:"st.illuminance.illuminance.bright",
backgroundColors:[
[value: 25, color: "#404040"],
[value: 50, color: "#808080"],
[value: 75, color: "#a0a0a0"],
[value: 90, color: "#e0e0e0"]
]
}
// jrs 4/7/2015
controlTile("rgbSelector", "device.color", "color", height: 1, width: 1) {
state "color", action:"color control.setColor"
}
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
main ("motion")
details(["motion", "temperature", "illuminance", "configure", "switch", "rgbSelector"])
} // end tiles
preferences {
input "OnTime", "number", title: "No Motion Interval", description: "N minutes lights stay on after no motion detected [0, 1-127]", defaultValue: 10, displayDuringSetup: true, required: false
input "OnLevel", "number", title: "Dimmer Onlevel", description: "Dimmer OnLevel for associated node 2 lights [0, 1-99, -1]", defaultValue: -1, displayDuringSetup: true, required: false
input "LiteMin", "number", title: "Luminance Report Frequency", description: "Luminance report sent every N minutes", defaultValue: 60, displayDuringSetup: true, required: false
input "TempMin", "number", title: "Temperature Report Frequency", description: "Temperature report sent every N minutes", defaultValue: 60, displayDuringSetup: true, required: false
input "TempAdj", "number", title: "Temperature Calibration", description: "Adjust temperature up/down N tenths of a degree F [(-127)-(+128)]", defaultValue: 0, displayDuringSetup: true, required: false
}
} // end metadata
// Parse incoming device messages from device to generate events
def parse(String description){
def result = []
def cmd = zwave.parse(description, [0x31: 5]) // 0x31=SensorMultilevel which we force to be version 5
if (cmd) {
result << createEvent(zwaveEvent(cmd))
}
log.debug "Parse returned ${result}"
return result
}
// Event Generation
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){
def map = [:]
switch (cmd.sensorType) {
case 0x01: // SENSOR_TYPE_TEMPERATURE_VERSION_1
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
log.debug "Temperature report"
break;
case 0x03 : // SENSOR_TYPE_LUMINANCE_VERSION_1
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "%"
map.name = "illuminance"
log.debug "Luminance report"
break;
}
return map
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType==0x07) { // NOTIFICATION_TYPE_BURGLAR
if (cmd.event==0x07 || cmd.event==0x08) {
map.name = "motion"
map.value = "active"
map.descriptionText = "$device.displayName motion detected"
log.debug "motion recognized"
} else if (cmd.event==0) {
map.name = "motion"
map.value = "inactive"
map.descriptionText = "$device.displayName no motion detected"
log.debug "No motion recognized"
}
}
if (map.name != "motion") {
log.debug "unmatched parameters for cmd: ${cmd.toString()}}"
}
return map
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
[name: "switch", value: cmd.value ? "on" : "off", type: "digital"]
}
def on() {
log.debug "Turning Light 'on'"
delayBetween([
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.basicV1.basicGet().format()
], 500)
}
def off() {
log.debug "Turning Light 'off'"
delayBetween([
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.basicV1.basicGet().format()
], 500)
}
def setColor(value) {
log.debug "setColor() : ${value} and red value is= ${value.red}"
def cmds = []
def myred=value.red >128 ? 255 : 0 // the EZMultiPli has just on/off for each of the 3 channels RGB so convert the 0-255 value into 0 or 255.
def mygreen=value.green >128 ? 255 : 0
def myblue=value.blue>128 ? 255 : 0
// cmds << zwave.colorControlV1.stateSet(stateDataLength: 3, VariantGroup1: [0x02, myred], VariantGroup2:[ 0x03, mygreen], VariantGroup3:[0x04,myblue]).format() // ST support for this command as of 2015/02/23 does not support the color IDs so this command cannot be used.
// So instead we'll use these commands to hack around the lack of support of the above command
cmds << zwave.basicV1.basicSet(value: 0x00).format() // As of 2015/02/23 ST is not supporting stateSet properly but found this hack that works.
if (myred!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x02, startState: myred, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x02).format()
}
if (mygreen!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x03, startState: mygreen, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x03).format()
}
if (myblue!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x04, startState: myblue, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x04).format()
}
delayBetween(cmds, 100)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
[:]
}
// ensure we are passing acceptable param values for LiteMin & TempMin configs
def checkLiteTempInput(value) {
if (value == null) {
value=60
}
def liteTempVal = value.toInteger()
switch (liteTempVal) {
case { it < 0 }:
return 60 // bad value, set to default
break
case { it > 127 }:
return 127 // bad value, greater then MAX, set to MAX
break
default:
return liteTempVal // acceptable value
}
}
// ensure we are passing acceptable param value for OnTime config
def checkOnTimeInput(value) {
if (value == null) {
value=10
}
def onTimeVal = value.toInteger()
switch (onTimeVal) {
case { it < 0 }:
return 10 // bad value set to default
break
case { it > 127 }:
return 127 // bad value, greater then MAX, set to MAX
break
default:
return onTimeVal // acceptable value
}
}
// ensure we are passing acceptable param value for OnLevel config
def checkOnLevelInput(value) {
if (value == null) {
value=99
}
def onLevelVal = value.toInteger()
switch (onLevelVal) {
case { it < -1 }:
return -1 // bad value set to default
break
case { it > 99 }:
return 99 // bad value, greater then MAX, set to MAX
break
default:
return onLevelVal // acceptable value
}
}
// ensure we are passing an acceptable param value for TempAdj configs
def checkTempAdjInput(value) {
if (value == null) {
value=0
}
def tempAdjVal = value.toInteger()
switch (tempAdjVal) {
case { it < -127 }:
return 0 // bad value, set to default
break
case { it > 128 }:
return 128 // bad value, greater then MAX, set to MAX
break
default:
return tempAdjVal // acceptable value
}
}
def configure() {
log.debug "OnTime=${settings.OnTime} OnLevel=${settings.OnLevel}"
def cmd = delayBetween([
zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [checkOnTimeInput(settings.OnTime)]).format(),
zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, configurationValue: [checkOnLevelInput(settings.OnLevel)]).format(),
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, configurationValue: [checkLiteTempInput(settings.LiteMin)]).format(),
zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, configurationValue: [checkLiteTempInput(settings.TempMin)]).format(),
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, configurationValue: [checkTempAdjInput(settings.TempAdj)]).format()
], 100)
log.debug cmd
cmd
}

View File

@@ -15,6 +15,7 @@
* Author: SmartThings
* Date: 2013-12-04
*/
//DEPRECATED - Using the generic DTH for this device. Users need to be moved before deleting this DTH
metadata {
definition (name: "CentraLite Dimmer", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
@@ -25,7 +26,6 @@ metadata {
capability "Refresh"
capability "Sensor"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04,0B05", outClusters: "0019"
}
// simulator metadata

View File

@@ -14,7 +14,7 @@
*
*/
metadata {
definition (name: "Logitech Harmony Activity", namespace: "smartthings", author: "Juan Risso") {
definition (name: "Harmony Activity", namespace: "smartthings", author: "Juan Risso") {
capability "Switch"
capability "Actuator"
capability "Refresh"

View File

@@ -17,44 +17,50 @@ metadata {
}
simulator {
// TODO: define status and reply messages here
}
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "unreachable", label: "?", action:"refresh.refresh", icon:"st.switches.light.off", backgroundColor:"#666666"
state "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'Turning on', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'Turning off', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666"
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", 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:"setColor"
}
tileAttribute ("device.model", key: "SECONDARY_CONTROL") {
attributeState "model", label: '${currentValue}'
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
valueTile("null", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:''
}
controlTile("rgbSelector", "device.color", "color", height: 3, width: 3, inactiveLabel: false) {
state "color", action:"setColor"
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 3, inactiveLabel: false, range:"(0..100)") {
state "level", action:"switch level.setLevel"
}
valueTile("level", "device.level", inactiveLabel: false, icon: "st.illuminance.illuminance.light", decoration: "flat") {
state "level", label: '${currentValue}%'
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 1, width: 2, inactiveLabel: false, range:"(2700..9000)") {
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 2, width: 4, inactiveLabel: false, range:"(2700..9000)") {
state "colorTemp", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat") {
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", height: 2, width: 2) {
state "colorTemp", label: '${currentValue}K'
}
main(["switch"])
details(["switch", "refresh", "level", "levelSliderControl", "rgbSelector", "colorTempSliderControl", "colorTemp"])
main "switch"
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
@@ -70,7 +76,7 @@ def parse(String description) {
def setHue(percentage) {
log.debug "setHue ${percentage}"
parent.logErrors(logObject: log) {
def resp = parent.apiPUT("/lights/${device.deviceNetworkId}/color", [color: "hue:${percentage * 3.6}"])
def resp = parent.apiPUT("/lights/${selector()}/state", [color: "hue:${percentage * 3.6}", power: "on"])
if (resp.status < 300) {
sendEvent(name: "hue", value: percentage)
sendEvent(name: "switch", value: "on")
@@ -83,7 +89,7 @@ def setHue(percentage) {
def setSaturation(percentage) {
log.debug "setSaturation ${percentage}"
parent.logErrors(logObject: log) {
def resp = parent.apiPUT("/lights/${device.deviceNetworkId}/color", [color: "saturation:${percentage / 100}"])
def resp = parent.apiPUT("/lights/${selector()}/state", [color: "saturation:${percentage / 100}", power: "on"])
if (resp.status < 300) {
sendEvent(name: "saturation", value: percentage)
sendEvent(name: "switch", value: "on")
@@ -114,7 +120,7 @@ def setColor(Map color) {
}
}
parent.logErrors(logObject:log) {
def resp = parent.apiPUT("/lights/${device.deviceNetworkId}/color", [color: attrs.join(" ")])
def resp = parent.apiPUT("/lights/${selector()}/state", [color: attrs.join(" "), power: "on"])
if (resp.status < 300) {
sendEvent(name: "color", value: color.hex)
sendEvent(name: "switch", value: "on")
@@ -135,9 +141,10 @@ def setLevel(percentage) {
return off() // if the brightness is set to 0, just turn it off
}
parent.logErrors(logObject:log) {
def resp = parent.apiPUT("/lights/${device.deviceNetworkId}/color", ["color": "brightness:${percentage / 100}"])
def resp = parent.apiPUT("/lights/${selector()}/state", ["brightness": percentage / 100, "power": "on"])
if (resp.status < 300) {
sendEvent(name: "level", value: percentage)
sendEvent(name: "switch.setLevel", value: percentage)
sendEvent(name: "switch", value: "on")
} else {
log.error("Bad setLevel result: [${resp.status}] ${resp.data}")
@@ -148,7 +155,7 @@ def setLevel(percentage) {
def setColorTemperature(kelvin) {
log.debug "Executing 'setColorTemperature' to ${kelvin}"
parent.logErrors() {
def resp = parent.apiPUT("/lights/${device.deviceNetworkId}/color", [color: "kelvin:${kelvin}"])
def resp = parent.apiPUT("/lights/${selector()}/state", [color: "kelvin:${kelvin}", power: "on"])
if (resp.status < 300) {
sendEvent(name: "colorTemperature", value: kelvin)
sendEvent(name: "color", value: "#ffffff")
@@ -163,7 +170,7 @@ def setColorTemperature(kelvin) {
def on() {
log.debug "Device setOn"
parent.logErrors() {
if (parent.apiPUT("/lights/${device.deviceNetworkId}/power", [state: "on"]) != null) {
if (parent.apiPUT("/lights/${selector()}/state", [power: "on"]) != null) {
sendEvent(name: "switch", value: "on")
}
}
@@ -172,7 +179,7 @@ def on() {
def off() {
log.debug "Device setOff"
parent.logErrors() {
if (parent.apiPUT("/lights/${device.deviceNetworkId}/power", [state: "off"]) != null) {
if (parent.apiPUT("/lights/${selector()}/state", [power: "off"]) != null) {
sendEvent(name: "switch", value: "off")
}
}
@@ -180,19 +187,26 @@ def off() {
def poll() {
log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}"
def resp = parent.apiGET("/lights/${device.deviceNetworkId}")
if (resp.status != 200) {
def resp = parent.apiGET("/lights/${selector()}")
if (resp.status == 404) {
sendEvent(name: "switch", value: "unreachable")
return []
} else if (resp.status != 200) {
log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}")
return []
}
def data = resp.data
def data = resp.data[0]
log.debug("Data: ${data}")
sendEvent(name: "level", value: sprintf("%.1f", (data.brightness ?: 1) * 100))
sendEvent(name: "label", value: data.label)
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch", value: data.connected ? data.power : "unreachable")
sendEvent(name: "color", value: colorUtil.hslToHex((data.color.hue / 3.6) as int, (data.color.saturation * 100) as int))
sendEvent(name: "hue", value: data.color.hue / 3.6)
sendEvent(name: "hue", value: data.color.hue / 3.6)
sendEvent(name: "saturation", value: data.color.saturation * 100)
sendEvent(name: "colorTemperature", value: data.color.kelvin)
sendEvent(name: "model", value: "${data.product.company} ${data.product.name}")
return []
}
@@ -201,3 +215,11 @@ def refresh() {
log.debug "Executing 'refresh'"
poll()
}
def selector() {
if (device.deviceNetworkId.contains(":")) {
return device.deviceNetworkId
} else {
return "id:${device.deviceNetworkId}"
}
}

View File

@@ -16,41 +16,44 @@ metadata {
}
simulator {
// TODO: define status and reply messages here
}
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'Turning on', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'Turning off', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "unreachable", label: "?", action:"refresh.refresh", icon:"st.switches.light.off", backgroundColor:"#666666"
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "unreachable", label: "?", action:"refresh.refresh", icon:"http://hosted.lifx.co/smartthings/v1/196xUnreachable.png", backgroundColor:"#666666"
attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
valueTile("null", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:''
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 3, inactiveLabel: false, range:"(0..100)") {
state "level", action:"switch level.setLevel"
}
valueTile("level", "device.level", inactiveLabel: false, icon: "st.illuminance.illuminance.light", decoration: "flat") {
state "level", label: '${currentValue}%'
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 1, width: 2, inactiveLabel: false, range:"(2700..6500)") {
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 2, width: 4, inactiveLabel: false, range:"(2700..9000)") {
state "colorTemp", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat") {
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", height: 2, width: 2) {
state "colorTemp", label: '${currentValue}K'
}
main(["switch"])
details(["switch", "refresh", "level", "levelSliderControl", "colorTempSliderControl", "colorTemp"])
main "switch"
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
// parse events into attributes
@@ -72,9 +75,10 @@ def setLevel(percentage) {
return off() // if the brightness is set to 0, just turn it off
}
parent.logErrors(logObject:log) {
def resp = parent.apiPUT("/lights/${device.deviceNetworkId}/color", ["color": "brightness:${percentage / 100}"])
def resp = parent.apiPUT("/lights/${selector()}/state", [brightness: percentage / 100, power: "on"])
if (resp.status < 300) {
sendEvent(name: "level", value: percentage)
sendEvent(name: "switch.setLevel", value: percentage)
sendEvent(name: "switch", value: "on")
} else {
log.error("Bad setLevel result: [${resp.status}] ${resp.data}")
@@ -85,7 +89,7 @@ def setLevel(percentage) {
def setColorTemperature(kelvin) {
log.debug "Executing 'setColorTemperature' to ${kelvin}"
parent.logErrors() {
def resp = parent.apiPUT("/lights/${device.deviceNetworkId}/color", [color: "kelvin:${kelvin}"])
def resp = parent.apiPUT("/lights/${selector()}/state", [color: "kelvin:${kelvin}", power: "on"])
if (resp.status < 300) {
sendEvent(name: "colorTemperature", value: kelvin)
sendEvent(name: "color", value: "#ffffff")
@@ -100,7 +104,7 @@ def setColorTemperature(kelvin) {
def on() {
log.debug "Device setOn"
parent.logErrors() {
if (parent.apiPUT("/lights/${device.deviceNetworkId}/power", [state: "on"]) != null) {
if (parent.apiPUT("/lights/${selector()}/state", [power: "on"]) != null) {
sendEvent(name: "switch", value: "on")
}
}
@@ -109,7 +113,7 @@ def on() {
def off() {
log.debug "Device setOff"
parent.logErrors() {
if (parent.apiPUT("/lights/${device.deviceNetworkId}/power", [state: "off"]) != null) {
if (parent.apiPUT("/lights/${selector()}/state", [power: "off"]) != null) {
sendEvent(name: "switch", value: "off")
}
}
@@ -117,16 +121,22 @@ def off() {
def poll() {
log.debug "Executing 'poll' for ${device} ${this} ${device.deviceNetworkId}"
def resp = parent.apiGET("/lights/${device.deviceNetworkId}")
if (resp.status != 200) {
def resp = parent.apiGET("/lights/${selector()}")
if (resp.status == 404) {
sendEvent(name: "switch", value: "unreachable")
return []
} else if (resp.status != 200) {
log.error("Unexpected result in poll(): [${resp.status}] ${resp.data}")
return []
}
def data = resp.data
def data = resp.data[0]
sendEvent(name: "level", value: sprintf("%f", (data.brightness ?: 1) * 100))
sendEvent(name: "label", value: data.label)
sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100))
sendEvent(name: "switch", value: data.connected ? data.power : "unreachable")
sendEvent(name: "colorTemperature", value: data.color.kelvin)
sendEvent(name: "model", value: data.product.name)
return []
}
@@ -135,3 +145,11 @@ def refresh() {
log.debug "Executing 'refresh'"
poll()
}
def selector() {
if (device.deviceNetworkId.contains(":")) {
return device.deviceNetworkId
} else {
return "id:${device.deviceNetworkId}"
}
}

View File

@@ -25,8 +25,8 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-CIA19NAE26", deviceJoinName: "Sengled Element touch"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B05,0702", outClusters: "000A,0019", manufacturer: "Jasco Products", model: "45852", deviceJoinName: "GE Zigbee Plug-In Dimmer"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B05,0702", outClusters: "000A,0019", manufacturer: "Jasco Products", model: "45857", deviceJoinName: "GE Zigbee In-Wall Dimmer"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45852", deviceJoinName: "GE Zigbee Plug-In Dimmer"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45857", deviceJoinName: "GE Zigbee In-Wall Dimmer"
}
tiles(scale: 2) {

View File

@@ -17,15 +17,14 @@ metadata {
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Switch"
capability "Switch Level"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "OSRAM LIGHTIFY LED Smart Connected Light"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
}
tiles(scale: 2) {

View File

@@ -23,8 +23,8 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B05,0702", outClusters: "0003, 000A,0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B05,0702", outClusters: "000A,0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
}
tiles(scale: 2) {

View File

@@ -17,7 +17,6 @@ metadata {
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006"

View File

@@ -23,18 +23,18 @@ metadata {
capability "Color Temperature"
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Switch"
capability "Switch Level"
attribute "colorName", "string"
command "setGenericName"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04", outClusters: "0019"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Flood BR30 Tunable White"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Recessed Kit RT 5/6 Tunable White"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04", outClusters: "0019"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Flood BR30 Tunable White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Recessed Kit RT 5/6 Tunable White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "OSRAM LIGHTIFY LED Tunable White 60W"
}
// UI tile definitions

View File

@@ -0,0 +1,69 @@
/**
* SCANNER SMARTTHINGS APPS
*
* Copyright 2015 kathiresan
*
*/
definition(
name: "SCANNER SMARTTHINGS APPS",
namespace: "NetworkScanner",
author: "kathiresan",
description: "Network Scanner Smartthings Apps",
category: "My Apps",
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",
oauth: true)
preferences {
section("Title") {
// TODO: put inputs here
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
def hub = location.hubs[0]
initialize()
log.debug "id: ${hub.id}"
log.debug "zigbeeId: ${hub.zigbeeId}"
log.debug "zigbeeEui: ${hub.zigbeeEui}"
// PHYSICAL or VIRTUAL
log.debug "type: ${hub.type}"
log.debug "name: ${hub.name}"
log.debug "firmwareVersionString: ${hub.firmwareVersionString}"
log.debug "localIp: ${hub.localIP}"
log.debug "localSrvPortTCP: ${hub.localSrvPortTCP}"
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
// TODO: subscribe to attributes, devices, locations, etc.
}
mappings {
path("/HubInfo") {
action: [
GET: "hubInfo"
]
}
}
// returns a list like
// [[name: "kitchen lamp", value: "off"], [name: "bathroom", value: "on"]]
def hubInfo() {
def hub = location.hubs[0]
return "localIp: ${hub.localIP}"
}
// TODO: implement event handlers

View File

@@ -592,7 +592,7 @@ def updated() {
// log.debug "External Id=${app.id}:${member.id}"
// create the device
def childDevice = addChildDevice("smartthings", "life360-user", "${app.id}.${member.id}",null,[name:member.firstName, completedSetup: true])
def childDevice = addChildDevice("smartthings", "Life360 User", "${app.id}.${member.id}",null,[name:member.firstName, completedSetup: true])
// childDevice.setMemberId(member.id)
if (childDevice)

View File

@@ -5,23 +5,23 @@
*
*/
definition(
name: "LIFX (Connect)",
namespace: "smartthings",
author: "LIFX",
description: "Allows you to use LIFX smart light bulbs with SmartThings.",
category: "Convenience",
iconUrl: "https://cloud.lifx.com/images/lifx.png",
iconX2Url: "https://cloud.lifx.com/images/lifx.png",
iconX3Url: "https://cloud.lifx.com/images/lifx.png",
oauth: true,
singleInstance: true) {
appSetting "clientId"
appSetting "clientSecret"
}
name: "LIFX (Connect)",
namespace: "smartthings",
author: "LIFX",
description: "Allows you to use LIFX smart light bulbs with SmartThings.",
category: "Convenience",
iconUrl: "https://cloud.lifx.com/images/lifx.png",
iconX2Url: "https://cloud.lifx.com/images/lifx.png",
iconX3Url: "https://cloud.lifx.com/images/lifx.png",
oauth: true,
singleInstance: true) {
appSetting "clientId"
appSetting "clientSecret"
}
preferences {
page(name: "Credentials", title: "LIFX", content: "authPage", install: false)
page(name: "Credentials", title: "LIFX", content: "authPage", install: true)
}
mappings {
@@ -33,29 +33,29 @@ mappings {
path("/test") { action: [ GET: "oauthSuccess" ] }
}
def getServerUrl() { return "https://graph.api.smartthings.com" }
def apiURL(path = '/') { return "https://api.lifx.com/v1beta1${path}" }
def buildRedirectUrl(page) {
return "${serverUrl}/api/token/${state.accessToken}/smartapps/installations/${app.id}/${page}"
}
def getServerUrl() { return "https://graph.api.smartthings.com" }
def getCallbackUrl() { return "https://graph.api.smartthings.com/oauth/callback"}
def apiURL(path = '/') { return "https://api.lifx.com/v1${path}" }
def getSecretKey() { return appSettings.secretKey }
def getClientId() { return appSettings.clientId }
def authPage() {
log.debug "authPage"
log.debug "authPage test1"
if (!state.lifxAccessToken) {
log.debug "no LIFX access token"
// This is the SmartThings access token
if (!state.accessToken) {
log.debug "no access token, create access token"
createAccessToken() // predefined method
state.accessToken = createAccessToken() // predefined method
}
def description = "Tap to enter LIFX credentials"
def redirectUrl = "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}" // this triggers oauthInit() below
log.debug "app id: ${app.id}"
def redirectUrl = "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" // this triggers oauthInit() below
// def redirectUrl = "${apiServerUrl}"
log.debug "app id: ${app.id}"
log.debug "redirect url: ${redirectUrl}"
return dynamicPage(name: "Credentials", title: "Connect to LIFX", nextPage: null, uninstall: true, install:false) {
return dynamicPage(name: "Credentials", title: "Connect to LIFX", nextPage: null, uninstall: true, install:true) {
section {
href(url:redirectUrl, required:true, title:"Connect to LIFX", description:"Tap here to connect your LIFX account")
// href(url:buildRedirectUrl("test"), title: "Message test")
}
}
} else {
@@ -63,17 +63,15 @@ def authPage() {
def options = locationOptions() ?: []
def count = options.size()
def refreshInterval = 3
return dynamicPage(name:"Credentials", title:"Select devices...", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
return dynamicPage(name:"Credentials", title:"", nextPage:"", install:true, uninstall: true) {
section("Select your location") {
input "selectedLocationId", "enum", required:true, title:"Select location (${count} found)", multiple:false, options:options
input "selectedLocationId", "enum", required:true, title:"Select location (${count} found)", multiple:false, options:options, submitOnChange: true
}
}
}
}
// OAuth
def oauthInit() {
@@ -112,7 +110,7 @@ def oauthCallback() {
}
def oauthReceiveToken(redirectUrl = null) {
// Not sure what redirectUrl is for
log.debug "receiveToken - params: ${params}"
def oauthParams = [ client_id: "${appSettings.clientId}", client_secret: "${appSettings.clientSecret}", grant_type: "authorization_code", code: params.code, scope: params.scope ] // how is params.code valid here?
def params = [
@@ -135,25 +133,25 @@ def oauthReceiveToken(redirectUrl = null) {
def oauthSuccess() {
def message = """
<p>Your LIFX Account is now connected to SmartThings!</p>
<p>Click 'Done' to finish setup.</p>
"""
<p>Your LIFX Account is now connected to SmartThings!</p>
<p>Click 'Done' to finish setup.</p>
"""
oauthConnectionStatus(message)
}
def oauthFailure() {
def message = """
<p>The connection could not be established!</p>
<p>Click 'Done' to return to the menu.</p>
"""
<p>The connection could not be established!</p>
<p>Click 'Done' to return to the menu.</p>
"""
oauthConnectionStatus(message)
}
def oauthReceivedToken() {
def message = """
<p>Your LIFX Account is already connected to SmartThings!</p>
<p>Click 'Done' to finish setup.</p>
"""
<p>Your LIFX Account is already connected to SmartThings!</p>
<p>Click 'Done' to finish setup.</p>
"""
oauthConnectionStatus(message)
}
@@ -161,74 +159,74 @@ def oauthConnectionStatus(message, redirectUrl = null) {
def redirectHtml = ""
if (redirectUrl) {
redirectHtml = """
<meta http-equiv="refresh" content="3; url=${redirectUrl}" />
"""
<meta http-equiv="refresh" content="3; url=${redirectUrl}" />
"""
}
def html = """
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width">
<title>SmartThings Connection</title>
<style type="text/css">
@font-face {
font-family: 'Swiss 721 W01 Thin';
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot');
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot?#iefix') format('embedded-opentype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.woff') format('woff'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.ttf') format('truetype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.svg#swis721_th_btthin') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Swiss 721 W01 Light';
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot');
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot?#iefix') format('embedded-opentype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.woff') format('woff'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.ttf') format('truetype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.svg#swis721_lt_btlight') format('svg');
font-weight: normal;
font-style: normal;
}
.container {
width: 280;
padding: 20px;
text-align: center;
}
img {
vertical-align: middle;
}
img:nth-child(2) {
margin: 0 15px;
}
p {
font-size: 1.2em;
font-family: 'Swiss 721 W01 Thin';
text-align: center;
color: #666666;
padding: 0 20px;
margin-bottom: 0;
}
span {
font-family: 'Swiss 721 W01 Light';
}
</style>
${redirectHtml}
</head>
<body>
<div class="container">
<img src='https://cloud.lifx.com/images/lifx.png' alt='LIFX icon' width='100'/>
<img src='https://s3.amazonaws.com/smartapp-icons/Partner/support/connected-device-icn%402x.png' alt='connected device icon' width="40"/>
<img src='https://s3.amazonaws.com/smartapp-icons/Partner/support/st-logo%402x.png' alt='SmartThings logo' width="100"/>
<p>
${message}
</p>
</div>
</body>
</html>
"""
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width">
<title>SmartThings Connection</title>
<style type="text/css">
@font-face {
font-family: 'Swiss 721 W01 Thin';
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot');
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.eot?#iefix') format('embedded-opentype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.woff') format('woff'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.ttf') format('truetype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-thin-webfont.svg#swis721_th_btthin') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Swiss 721 W01 Light';
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot');
src: url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.eot?#iefix') format('embedded-opentype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.woff') format('woff'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.ttf') format('truetype'),
url('https://s3.amazonaws.com/smartapp-icons/Partner/fonts/swiss-721-light-webfont.svg#swis721_lt_btlight') format('svg');
font-weight: normal;
font-style: normal;
}
.container {
width: 280;
padding: 20px;
text-align: center;
}
img {
vertical-align: middle;
}
img:nth-child(2) {
margin: 0 15px;
}
p {
font-size: 1.2em;
font-family: 'Swiss 721 W01 Thin';
text-align: center;
color: #666666;
padding: 0 20px;
margin-bottom: 0;
}
span {
font-family: 'Swiss 721 W01 Light';
}
</style>
${redirectHtml}
</head>
<body>
<div class="container">
<img src='https://cloud.lifx.com/images/lifx.png' alt='LIFX icon' width='100'/>
<img src='https://s3.amazonaws.com/smartapp-icons/Partner/support/connected-device-icn%402x.png' alt='connected device icon' width="40"/>
<img src='https://s3.amazonaws.com/smartapp-icons/Partner/support/st-logo%402x.png' alt='SmartThings logo' width="100"/>
<p>
${message}
</p>
</div>
</body>
</html>
"""
render contentType: 'text/html', data: html
}
@@ -239,7 +237,6 @@ String toQueryString(Map m) {
// App lifecycle hooks
def installed() {
enableCallback() // wtf does this do?
if (!state.accessToken) {
createAccessToken()
} else {
@@ -251,7 +248,6 @@ def installed() {
// called after settings are changed
def updated() {
enableCallback() // not sure what this does
if (!state.accessToken) {
createAccessToken()
} else {
@@ -305,27 +301,36 @@ def logErrors(options = [errorReturn: null, logObject: log], Closure c) {
state.remove("lifxAccessToken")
options.logObject.warn "Access token is not valid"
}
return options.errerReturn
return options.errorReturn
} catch (java.net.SocketTimeoutException e) {
options.logObject.warn "Connection timed out, not much we can do here"
return options.errerReturn
return options.errorReturn
}
}
def apiGET(path) {
httpGet(uri: apiURL(path), headers: apiRequestHeaders()) {response ->
logResponse(response)
return response
try {
httpGet(uri: apiURL(path), headers: apiRequestHeaders()) {response ->
logResponse(response)
return response
}
} catch (groovyx.net.http.HttpResponseException e) {
logResponse(e.response)
return e.response
}
}
def apiPUT(path, body = [:]) {
log.debug("Beginning API PUT: ${path}, ${body}")
httpPutJson(uri: apiURL(path), body: new groovy.json.JsonBuilder(body).toString(), headers: apiRequestHeaders(), ) {response ->
logResponse(response)
return response
}
}
try {
log.debug("Beginning API PUT: ${path}, ${body}")
httpPutJson(uri: apiURL(path), body: new groovy.json.JsonBuilder(body).toString(), headers: apiRequestHeaders(), ) {response ->
logResponse(response)
return response
}
} catch (groovyx.net.http.HttpResponseException e) {
logResponse(e.response)
return e.response
}}
def devicesList(selector = '') {
logErrors([]) {
@@ -340,12 +345,12 @@ def devicesList(selector = '') {
}
Map locationOptions() {
def options = [:]
def devices = devicesList()
devices.each { device ->
options[device.location.id] = device.location.name
}
log.debug("Locations: ${options}")
return options
}
@@ -359,28 +364,32 @@ def updateDevices() {
state.devices = [:]
}
def devices = devicesInLocation()
def deviceIds = devices*.id
def selectors = []
log.debug("All selectors: ${selectors}")
devices.each { device ->
def childDevice = getChildDevice(device.id)
selectors.add("${device.id}")
if (!childDevice) {
log.info("Adding device ${device.id}: ${device.capabilities}")
log.info("Adding device ${device.id}: ${device.product}")
def data = [
label: device.label,
level: sprintf("%f", (device.brightness ?: 1) * 100),
level: Math.round((device.brightness ?: 1) * 100),
switch: device.connected ? device.power : "unreachable",
colorTemperature: device.color.kelvin
]
if (device.capabilities.has_color) {
if (device.product.capabilities.has_color) {
data["color"] = colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int)
data["hue"] = device.color.hue / 3.6
data["saturation"] = device.color.saturation * 100
childDevice = addChildDevice("smartthings", "LIFX Color Bulb", device.id, null, data)
childDevice = addChildDevice(app.namespace, "LIFX Color Bulb", device.id, null, data)
} else {
childDevice = addChildDevice("smartthings", "LIFX White Bulb", device.id, null, data)
childDevice = addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, data)
}
}
}
getChildDevices().findAll { !deviceIds.contains(it.deviceNetworkId) }.each {
getChildDevices().findAll { !selectors.contains("${it.deviceNetworkId}") }.each {
log.info("Deleting ${it.deviceNetworkId}")
deleteChildDevice(it.deviceNetworkId)
}
@@ -392,4 +401,4 @@ def refreshDevices() {
getChildDevices().each { device ->
device.refresh()
}
}
}

View File

@@ -10,24 +10,24 @@
* 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.
*
* Sonos Control
* Speaker Control
*
* Author: SmartThings
*
* Date: 2013-12-10
*/
definition(
name: "Sonos Control",
name: "Speaker Control",
namespace: "smartthings",
author: "SmartThings",
description: "Play or pause your Sonos when certain actions take place in your home.",
description: "Play or pause your Speaker when certain actions take place in your home.",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos@2x.png"
)
preferences {
page(name: "mainPage", title: "Control your Sonos when something happens", install: true, uninstall: true)
page(name: "mainPage", title: "Control your Speaker when something happens", install: true, uninstall: true)
page(name: "timeIntervalInput", title: "Only during a certain time") {
section {
input "starting", "time", title: "Starting", required: false
@@ -81,7 +81,7 @@ def mainPage() {
]
}
section {
input "sonos", "capability.musicPlayer", title: "Sonos music player", required: true
input "sonos", "capability.musicPlayer", title: "Speaker music player", required: true
}
section("More options", hideable: true, hidden: true) {
input "volume", "number", title: "Set the volume volume", description: "0-100%", required: false

View File

@@ -10,7 +10,7 @@
* 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.
*
* Sonos Mood Music
* Speaker Mood Music
*
* Author: SmartThings
* Date: 2014-02-12
@@ -65,7 +65,7 @@ private saveSelectedSong() {
}
definition(
name: "Sonos Mood Music",
name: "Speaker Mood Music",
namespace: "smartthings",
author: "SmartThings",
description: "Plays a selected song or station.",
@@ -75,7 +75,7 @@ definition(
)
preferences {
page(name: "mainPage", title: "Play a selected song or station on your Sonos when something happens", nextPage: "chooseTrack", uninstall: true)
page(name: "mainPage", title: "Play a selected song or station on your Speaker when something happens", nextPage: "chooseTrack", uninstall: true)
page(name: "chooseTrack", title: "Select a song", install: true)
page(name: "timeIntervalInput", title: "Only during a certain time") {
section {
@@ -125,7 +125,7 @@ def mainPage() {
ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
}
section {
input "sonos", "capability.musicPlayer", title: "On this Sonos player", required: true
input "sonos", "capability.musicPlayer", title: "On this Speaker player", required: true
}
section("More options", hideable: true, hidden: true) {
input "volume", "number", title: "Set the volume", description: "0-100%", required: false

View File

@@ -10,23 +10,23 @@
* 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.
*
* Sonos Custom Message
* Speaker Custom Message
*
* Author: SmartThings
* Date: 2014-1-29
*/
definition(
name: "Sonos Notify with Sound",
name: "Speaker Notify with Sound",
namespace: "smartthings",
author: "SmartThings",
description: "Play a sound or custom message through your Sonos when the mode changes or other events occur.",
description: "Play a sound or custom message through your Speaker when the mode changes or other events occur.",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos@2x.png"
)
preferences {
page(name: "mainPage", title: "Play a message on your Sonos when something happens", install: true, uninstall: true)
page(name: "mainPage", title: "Play a message on your Speaker when something happens", install: true, uninstall: true)
page(name: "chooseTrack", title: "Select a song or station")
page(name: "timeIntervalInput", title: "Only during a certain time") {
section {
@@ -92,7 +92,7 @@ def mainPage() {
input "message","text",title:"Play this message", required:false, multiple: false
}
section {
input "sonos", "capability.musicPlayer", title: "On this Sonos player", required: true
input "sonos", "capability.musicPlayer", title: "On this Speaker player", required: true
}
section("More options", hideable: true, hidden: true) {
input "resumePlaying", "bool", title: "Resume currently playing music after notification", required: false, defaultValue: true

View File

@@ -10,23 +10,23 @@
* 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.
*
* Sonos Weather Forecast
* Speaker Weather Forecast
*
* Author: SmartThings
* Date: 2014-1-29
*/
definition(
name: "Sonos Weather Forecast",
name: "Speaker Weather Forecast",
namespace: "smartthings",
author: "SmartThings",
description: "Play a weather report through your Sonos when the mode changes or other events occur",
description: "Play a weather report through your Speaker when the mode changes or other events occur",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos@2x.png"
)
preferences {
page(name: "mainPage", title: "Play the weather report on your sonos", install: true, uninstall: true)
page(name: "mainPage", title: "Play the weather report on your speaker", install: true, uninstall: true)
page(name: "chooseTrack", title: "Select a song or station")
page(name: "timeIntervalInput", title: "Only during a certain time") {
section {
@@ -85,7 +85,7 @@ def mainPage() {
)
}
section {
input "sonos", "capability.musicPlayer", title: "On this Sonos player", required: true
input "sonos", "capability.musicPlayer", title: "On this Speaker player", required: true
}
section("More options", hideable: true, hidden: true) {
input "resumePlaying", "bool", title: "Resume currently playing music after weather report finishes", required: false, defaultValue: true

View File

@@ -78,7 +78,7 @@ def firstPage()
def motionsDiscovered = motionsDiscovered()
def lightSwitchesDiscovered = lightSwitchesDiscovered()
return dynamicPage(name:"firstPage", title:"Discovery Started!", nextPage:"", refreshInterval: refreshInterval, install:true, uninstall: selectedSwitches != null || selectedMotions != null || selectedLightSwitches != null) {
return dynamicPage(name:"firstPage", title:"Discovery Started!", nextPage:"", refreshInterval: refreshInterval, install:true, uninstall: true) {
section("Select a device...") {
input "selectedSwitches", "enum", required:false, title:"Select Wemo Switches \n(${switchesDiscovered.size() ?: 0} found)", multiple:true, options:switchesDiscovered
input "selectedMotions", "enum", required:false, title:"Select Wemo Motions \n(${motionsDiscovered.size() ?: 0} found)", multiple:true, options:motionsDiscovered