Compare commits

..

1 Commits

Author SHA1 Message Date
Light Engine R&D
c8b38c1073 MSA-1799: ZWave Switch 2017-02-20 20:31:17 -08:00
7 changed files with 138 additions and 53 deletions

View File

@@ -7,7 +7,6 @@
metadata { metadata {
// Automatically generated. Make future change here. // Automatically generated. Make future change here.
definition (name: "Hue Bridge", namespace: "smartthings", author: "SmartThings") { definition (name: "Hue Bridge", namespace: "smartthings", author: "SmartThings") {
capability "Bridge"
capability "Health Check" capability "Health Check"
attribute "networkAddress", "string" attribute "networkAddress", "string"

View File

@@ -24,7 +24,6 @@ metadata {
capability "Refresh" capability "Refresh"
capability "Actuator" capability "Actuator"
capability "Sensor" capability "Sensor"
capability "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-ZHAC" fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-ZHAC"
@@ -80,8 +79,7 @@ def parse(String description) {
*/ */
event.value = event.value / 10 event.value = event.value / 10
} }
return event
return event ? createEvent(event) : event
} }
def setLevel(value) { def setLevel(value) {

View File

@@ -4,7 +4,6 @@ metadata {
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
capability "Sensor" capability "Sensor"
capability "Outlet"
fingerprint profileId: "0104", inClusters: "0006, 0004, 0003, 0000, 0005", outClusters: "0019", manufacturer: "Compacta International, Ltd", model: "ZBMPlug15", deviceJoinName: "SmartPower Outlet V1" fingerprint profileId: "0104", inClusters: "0006, 0004, 0003, 0000, 0005", outClusters: "0019", manufacturer: "Compacta International, Ltd", model: "ZBMPlug15", deviceJoinName: "SmartPower Outlet V1"
} }

View File

@@ -83,8 +83,9 @@ def parse(String description) {
if (event) { if (event) {
if (event.name == "power") { if (event.name == "power") {
def value = (event.value as Integer) / 10 event.value = event.value / 10
event = createEvent(name: event.name, value: value, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true) event.descriptionText = '{{ device.displayName }} power is {{ value }} Watts'
event.translatable = true
} else if (event.name == "switch") { } else if (event.name == "switch") {
def descriptionText = event.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off' def descriptionText = event.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off'
event = createEvent(name: event.name, value: event.value, descriptionText: descriptionText, translatable: true) event = createEvent(name: event.name, value: event.value, descriptionText: descriptionText, translatable: true)
@@ -105,7 +106,7 @@ def parse(String description) {
log.debug "${cluster}" log.debug "${cluster}"
} }
} }
return event ? createEvent(event) : event return event
} }
def off() { def off() {

View File

@@ -0,0 +1,95 @@
/**
* Web Services SmartApp
*
* Copyright 2017 Light Engine R&D
*
* 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: "Web Services SmartApp",
namespace: "lightenginernd",
author: "Light Engine R&D",
description: "Web Services SmartApp 1st",
category: "",
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: [displayName: "Web Services SmartApp", displayLink: "http://localhost:4567"]
)
preferences {
section ("Allow external service to control these things...") {
input "switches", "capability.switch", multiple: true, required: true
}
}
mappings {
path("/switches") {
action: [
GET: "listSwitches"
]
}
path("/switches/:command") {
action: [
PUT: "updateSwitches"
]
}
}
// returns a list like
// [[name: "kitchen lamp", value: "off"], [name: "bathroom", value: "on"]]
def listSwitches() {
def resp = []
switches.each {
resp << [name: it.displayName, value: it.currentValue("switch")]
}
return resp
}
void updateSwitches() {
// use the built-in request object to get the command parameter
def command = params.command
// all switches have the comand
// execute the command on all switches
// (note we can do this on the array - the command will be invoked on every element
switch(command) {
case "on":
switches.on()
break
case "off":
switches.off()
break
default:
httpError(400, "$command is not a valid command for all switches specified")
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
// TODO: subscribe to attributes, devices, locations, etc.
}
// TODO: implement event handlers

View File

@@ -17,14 +17,14 @@
*/ */
definition( definition(
name: "Hue (Connect)", name: "Hue (Connect)",
namespace: "smartthings", namespace: "smartthings",
author: "SmartThings", author: "SmartThings",
description: "Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Adjust colors by going to the Thing detail screen for your Hue lights (tap the gear on Hue tiles).\n\nPlease update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.", description: "Allows you to connect your Philips Hue lights with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Adjust colors by going to the Thing detail screen for your Hue lights (tap the gear on Hue tiles).\n\nPlease update your Hue Bridge first, outside of the SmartThings app, using the Philips Hue app.",
category: "SmartThings Labs", category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png", iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png",
singleInstance: true singleInstance: true
) )
preferences { preferences {
@@ -85,8 +85,7 @@ def bridgeDiscovery(params=[:])
} }
return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) { return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) {
section("Please wait while we discover your Hue Bridge. Kindly note that you must first configure your Hue Bridge and Lights using the Philips Hue application. " + section("Please wait while we discover your Hue Bridge. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
"Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options, submitOnChange: true input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options, submitOnChange: true
} }
} }
@@ -179,7 +178,7 @@ def bulbDiscovery() {
} }
if (bulbRefreshCount > 200 && numFound == 0) { if (bulbRefreshCount > 200 && numFound == 0) {
// Time out after 10 minutes // Time out to avoid endless discovery
state.inBulbDiscovery = false state.inBulbDiscovery = false
bulbRefreshCount = 0 bulbRefreshCount = 0
return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Failed!", nextPage:"", refreshInterval:0, install:true, uninstall: true) { return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Failed!", nextPage:"", refreshInterval:0, install:true, uninstall: true) {
@@ -217,32 +216,32 @@ private sendDeveloperReq() {
def token = app.id def token = app.id
def host = getBridgeIP() def host = getBridgeIP()
sendHubCommand(new physicalgraph.device.HubAction([ sendHubCommand(new physicalgraph.device.HubAction([
method: "POST", method: "POST",
path: "/api", path: "/api",
headers: [ headers: [
HOST: host HOST: host
], ],
body: [devicetype: "$token-0"]], "${selectedHue}", [callback: "usernameHandler"])) body: [devicetype: "$token-0"]], "${selectedHue}", [callback: "usernameHandler"]))
} }
private discoverHueBulbs() { private discoverHueBulbs() {
def host = getBridgeIP() def host = getBridgeIP()
sendHubCommand(new physicalgraph.device.HubAction([ sendHubCommand(new physicalgraph.device.HubAction([
method: "GET", method: "GET",
path: "/api/${state.username}/lights", path: "/api/${state.username}/lights",
headers: [ headers: [
HOST: host HOST: host
]], "${selectedHue}", [callback: "lightsHandler"])) ]], "${selectedHue}", [callback: "lightsHandler"]))
} }
private verifyHueBridge(String deviceNetworkId, String host) { private verifyHueBridge(String deviceNetworkId, String host) {
log.trace "Verify Hue Bridge $deviceNetworkId" log.trace "Verify Hue Bridge $deviceNetworkId"
sendHubCommand(new physicalgraph.device.HubAction([ sendHubCommand(new physicalgraph.device.HubAction([
method: "GET", method: "GET",
path: "/description.xml", path: "/description.xml",
headers: [ headers: [
HOST: host HOST: host
]], deviceNetworkId, [callback: "bridgeDescriptionHandler"])) ]], deviceNetworkId, [callback: "bridgeDescriptionHandler"]))
} }
private verifyHueBridges() { private verifyHueBridges() {
@@ -400,7 +399,7 @@ def addBulbs() {
log.debug "$dni in not longer paired to the Hue Bridge or ID changed" log.debug "$dni in not longer paired to the Hue Bridge or ID changed"
} }
} else { } else {
//backwards compatable //backwards compatable
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni } newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub) d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub)
d?.completedSetup = true d?.completedSetup = true
@@ -1152,7 +1151,7 @@ def setColorTemperature(childDevice, huesettings) {
def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings) def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings)
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/$id/state", [ct: ct, on: true]) put("lights/$id/state", [ct: ct, on: true])
return "Setting color temperature to $ct" return "Setting color temperature to $percent"
} }
def setColor(childDevice, huesettings) { def setColor(childDevice, huesettings) {
@@ -1227,7 +1226,7 @@ private poll() {
def uri = "/api/${state.username}/lights/" def uri = "/api/${state.username}/lights/"
log.debug "GET: $host$uri" log.debug "GET: $host$uri"
sendHubCommand(new physicalgraph.device.HubAction("GET ${uri} HTTP/1.1\r\n" + sendHubCommand(new physicalgraph.device.HubAction("GET ${uri} HTTP/1.1\r\n" +
"HOST: ${host}\r\n\r\n", physicalgraph.device.Protocol.LAN, selectedHue)) "HOST: ${host}\r\n\r\n", physicalgraph.device.Protocol.LAN, selectedHue))
} }
private isOnline(id) { private isOnline(id) {
@@ -1244,10 +1243,10 @@ private put(path, body) {
log.debug "BODY: ${bodyJSON}" log.debug "BODY: ${bodyJSON}"
sendHubCommand(new physicalgraph.device.HubAction("PUT $uri HTTP/1.1\r\n" + sendHubCommand(new physicalgraph.device.HubAction("PUT $uri HTTP/1.1\r\n" +
"HOST: ${host}\r\n" + "HOST: ${host}\r\n" +
"Content-Length: ${length}\r\n" + "Content-Length: ${length}\r\n" +
"\r\n" + "\r\n" +
"${bodyJSON}", physicalgraph.device.Protocol.LAN, "${selectedHue}")) "${bodyJSON}", physicalgraph.device.Protocol.LAN, "${selectedHue}"))
} }
/* /*

View File

@@ -346,7 +346,7 @@ def devicesList(selector = '') {
if (resp.status == 200) { if (resp.status == 200) {
return resp.data return resp.data
} else { } else {
log.debug("No response from device list call. ${resp.status} ${resp.data}") log.error("Non-200 from device list call. ${resp.status} ${resp.data}")
return [] return []
} }
} }
@@ -418,15 +418,9 @@ def updateDevices() {
} }
getChildDevices().findAll { !selectors.contains("${it.deviceNetworkId}") }.each { getChildDevices().findAll { !selectors.contains("${it.deviceNetworkId}") }.each {
log.info("Deleting ${it.deviceNetworkId}") log.info("Deleting ${it.deviceNetworkId}")
if (state.devices[it.deviceNetworkId]) state.devices[it.deviceNetworkId] = null
state.devices[it.deviceNetworkId] = null deleteChildDevice(it.deviceNetworkId)
// The reason the implementation is trying to delete this bulb is because it is not longer connected to the LIFX location.
// Adding "try" will prevent this exception from happening.
// Ideally device health would show to the user that the device is not longer accessible so that the user can either force delete it or remove it from the SmartApp.
try {
deleteChildDevice(it.deviceNetworkId)
} catch (Exception e) {
log.debug("Can't remove this device because it's being used by an SmartApp")
}
} }
} }