mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-19 05:10:51 +00:00
Compare commits
28 Commits
MSA-1494-2
...
PROD_2016.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f5eb7b85a | ||
|
|
64e4ccc517 | ||
|
|
aa890ae3d5 | ||
|
|
8d701b9fea | ||
|
|
719b24ecd6 | ||
|
|
9d5ab3bfc8 | ||
|
|
aae7f23a22 | ||
|
|
218cc43520 | ||
|
|
5b0ca4b815 | ||
|
|
9ddc020f04 | ||
|
|
aab3b8d7f8 | ||
|
|
a0ccf35eaa | ||
|
|
9fbbaec8f6 | ||
|
|
e4c1824afd | ||
|
|
797a58cb68 | ||
|
|
c428267d63 | ||
|
|
02f30cf425 | ||
|
|
fea802ffce | ||
|
|
6400d26f4a | ||
|
|
5e3aaa3270 | ||
|
|
f5c3997679 | ||
|
|
30993aa218 | ||
|
|
2f8ed277ff | ||
|
|
230541a145 | ||
|
|
8c4f7edc83 | ||
|
|
4f188581df | ||
|
|
0b7bb40474 | ||
|
|
e373b6f92e |
@@ -87,16 +87,27 @@ def beep() {
|
|||||||
up to this long from the time you send the message to the time you hear a sound.
|
up to this long from the time you send the message to the time you hear a sound.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Used source endpoint of 0x02 because we are using smartthings manufacturer specific cluster.
|
||||||
[
|
[
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
"delay 7000",
|
"delay 7000",
|
||||||
"raw 0xFC05 {15 0A 11 00 00 15 01}"
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 200",
|
||||||
|
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,11 +105,21 @@ def parseDescriptionAsMap(description) {
|
|||||||
|
|
||||||
// Commands to device
|
// Commands to device
|
||||||
def on() {
|
def on() {
|
||||||
'zcl on-off on'
|
[
|
||||||
|
'zcl on-off on',
|
||||||
|
'delay 200',
|
||||||
|
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
|
||||||
|
'delay 500'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
'zcl on-off off'
|
[
|
||||||
|
'zcl on-off off',
|
||||||
|
'delay 200',
|
||||||
|
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
|
||||||
|
'delay 500'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(value) {
|
def setLevel(value) {
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ metadata {
|
|||||||
command "switchMode"
|
command "switchMode"
|
||||||
command "switchFanMode"
|
command "switchFanMode"
|
||||||
|
|
||||||
attribute "thermostatSetpoint","number"
|
attribute "thermostatSetpoint", "number"
|
||||||
attribute "thermostatStatus","string"
|
attribute "thermostatStatus", "string"
|
||||||
attribute "maxHeatingSetpoint", "number"
|
attribute "maxHeatingSetpoint", "number"
|
||||||
attribute "minHeatingSetpoint", "number"
|
attribute "minHeatingSetpoint", "number"
|
||||||
attribute "maxCoolingSetpoint", "number"
|
attribute "maxCoolingSetpoint", "number"
|
||||||
attribute "minCoolingSetpoint", "number"
|
attribute "minCoolingSetpoint", "number"
|
||||||
attribute "deviceTemperatureUnit", "number"
|
attribute "deviceTemperatureUnit", "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
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 "Health Check"
|
||||||
|
|
||||||
attribute "networkAddress", "string"
|
attribute "networkAddress", "string"
|
||||||
// Used to indicate if bridge is reachable or not, i.e. is the bridge connected to the network
|
// Used to indicate if bridge is reachable or not, i.e. is the bridge connected to the network
|
||||||
// Possible values "Online" or "Offline"
|
// Possible values "Online" or "Offline"
|
||||||
attribute "status", "string"
|
attribute "status", "string"
|
||||||
// Id is the number on the back of the hub, Hue uses last six digits of Mac address
|
// Id is the number on the back of the hub, Hue uses last six digits of Mac address
|
||||||
// This is also used in the Hue application as ID
|
// This is also used in the Hue application as ID
|
||||||
@@ -42,6 +44,10 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void installed() {
|
||||||
|
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "lan"], displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(description) {
|
def parse(description) {
|
||||||
log.debug "Parsing '${description}'"
|
log.debug "Parsing '${description}'"
|
||||||
@@ -70,13 +76,8 @@ def parse(description) {
|
|||||||
def bulbs = new groovy.json.JsonSlurper().parseText(msg.body)
|
def bulbs = new groovy.json.JsonSlurper().parseText(msg.body)
|
||||||
if (bulbs.state) {
|
if (bulbs.state) {
|
||||||
log.info "Bridge response: $msg.body"
|
log.info "Bridge response: $msg.body"
|
||||||
} else {
|
|
||||||
// Sending Bulbs List to parent"
|
|
||||||
if (parent.isInBulbDiscovery())
|
|
||||||
log.info parent.bulbListHandler(device.hub.id, msg.body)
|
|
||||||
}
|
}
|
||||||
}
|
} else if (contentType?.contains("xml")) {
|
||||||
else if (contentType?.contains("xml")) {
|
|
||||||
log.debug "HUE BRIDGE ALREADY PRESENT"
|
log.debug "HUE BRIDGE ALREADY PRESENT"
|
||||||
parent.hubVerification(device.hub.id, msg.body)
|
parent.hubVerification(device.hub.id, msg.body)
|
||||||
}
|
}
|
||||||
@@ -85,3 +86,7 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def ping() {
|
||||||
|
log.debug "${parent.ping(this)}"
|
||||||
|
}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ void setColorTemperature(value) {
|
|||||||
|
|
||||||
void refresh() {
|
void refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent?.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
def verifyPercent(percent) {
|
def verifyPercent(percent) {
|
||||||
|
|||||||
@@ -47,9 +47,21 @@ def parse(String description) {
|
|||||||
|
|
||||||
// Commands to device
|
// Commands to device
|
||||||
def on() {
|
def on() {
|
||||||
'zcl on-off on'
|
[
|
||||||
|
'zcl on-off on',
|
||||||
|
'delay 200',
|
||||||
|
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
|
||||||
|
'delay 500'
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
'zcl on-off off'
|
[
|
||||||
|
'zcl on-off off',
|
||||||
|
'delay 200',
|
||||||
|
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
|
||||||
|
'delay 500'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,9 +180,9 @@ private Map parseIasMessage(String description) {
|
|||||||
def getTemperature(value) {
|
def getTemperature(value) {
|
||||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||||
if(getTemperatureScale() == "C"){
|
if(getTemperatureScale() == "C"){
|
||||||
return celsius
|
return Math.round(celsius)
|
||||||
} else {
|
} else {
|
||||||
return celsiusToFahrenheit(celsius) as Integer
|
return Math.round(celsiusToFahrenheit(celsius))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,9 +194,9 @@ private Map parseIasMessage(String description) {
|
|||||||
def getTemperature(value) {
|
def getTemperature(value) {
|
||||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||||
if(getTemperatureScale() == "C"){
|
if(getTemperatureScale() == "C"){
|
||||||
return celsius
|
return Math.round(celsius)
|
||||||
} else {
|
} else {
|
||||||
return celsiusToFahrenheit(celsius) as Integer
|
return Math.round(celsiusToFahrenheit(celsius))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -261,9 +261,9 @@ def updated() {
|
|||||||
def getTemperature(value) {
|
def getTemperature(value) {
|
||||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||||
if(getTemperatureScale() == "C"){
|
if(getTemperatureScale() == "C"){
|
||||||
return celsius
|
return Math.round(celsius)
|
||||||
} else {
|
} else {
|
||||||
return celsiusToFahrenheit(celsius) as Integer
|
return Math.round(celsiusToFahrenheit(celsius))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -454,17 +454,23 @@ def sendStopEvent(source) {
|
|||||||
eventData.value += "cancelled"
|
eventData.value += "cancelled"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send 100% completion event
|
||||||
|
sendTimeRemainingEvent(100)
|
||||||
|
|
||||||
|
// send a non-displayed 0% completion to reset tiles
|
||||||
|
sendTimeRemainingEvent(0, false)
|
||||||
|
|
||||||
|
// send sessionStatus event last so the event feed is ordered properly
|
||||||
sendControllerEvent(eventData)
|
sendControllerEvent(eventData)
|
||||||
sendTimeRemainingEvent(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def sendTimeRemainingEvent(percentComplete) {
|
def sendTimeRemainingEvent(percentComplete, displayed = true) {
|
||||||
log.trace "sendTimeRemainingEvent(${percentComplete})"
|
log.trace "sendTimeRemainingEvent(${percentComplete})"
|
||||||
|
|
||||||
def percentCompleteEventData = [
|
def percentCompleteEventData = [
|
||||||
name: "percentComplete",
|
name: "percentComplete",
|
||||||
value: percentComplete as int,
|
value: percentComplete as int,
|
||||||
displayed: true,
|
displayed: displayed,
|
||||||
isStateChange: true
|
isStateChange: true
|
||||||
]
|
]
|
||||||
sendControllerEvent(percentCompleteEventData)
|
sendControllerEvent(percentCompleteEventData)
|
||||||
@@ -474,7 +480,7 @@ def sendTimeRemainingEvent(percentComplete) {
|
|||||||
def timeRemainingEventData = [
|
def timeRemainingEventData = [
|
||||||
name: "timeRemaining",
|
name: "timeRemaining",
|
||||||
value: displayableTime(timeRemaining),
|
value: displayableTime(timeRemaining),
|
||||||
displayed: true,
|
displayed: displayed,
|
||||||
isStateChange: true
|
isStateChange: true
|
||||||
]
|
]
|
||||||
sendControllerEvent(timeRemainingEventData)
|
sendControllerEvent(timeRemainingEventData)
|
||||||
@@ -608,8 +614,6 @@ private completion() {
|
|||||||
handleCompletionMessaging()
|
handleCompletionMessaging()
|
||||||
|
|
||||||
handleCompletionModesAndPhrases()
|
handleCompletionModesAndPhrases()
|
||||||
|
|
||||||
sendTimeRemainingEvent(100)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleCompletionSwitches() {
|
private handleCompletionSwitches() {
|
||||||
|
|||||||
@@ -83,7 +83,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. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
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.") {
|
||||||
input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options
|
input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options, submitOnChange: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,10 +131,7 @@ def bulbDiscovery() {
|
|||||||
def refreshInterval = 3
|
def refreshInterval = 3
|
||||||
state.inBulbDiscovery = true
|
state.inBulbDiscovery = true
|
||||||
def bridge = null
|
def bridge = null
|
||||||
if (selectedHue) {
|
|
||||||
bridge = getChildDevice(selectedHue)
|
|
||||||
subscribe(bridge, "bulbList", bulbListData)
|
|
||||||
}
|
|
||||||
state.bridgeRefreshCount = 0
|
state.bridgeRefreshCount = 0
|
||||||
def allLightsFound = bulbsDiscovered() ?: [:]
|
def allLightsFound = bulbsDiscovered() ?: [:]
|
||||||
|
|
||||||
@@ -259,10 +256,6 @@ Map bulbsDiscovered() {
|
|||||||
return bulbmap
|
return bulbmap
|
||||||
}
|
}
|
||||||
|
|
||||||
def bulbListData(evt) {
|
|
||||||
state.bulbs = evt.jsonData
|
|
||||||
}
|
|
||||||
|
|
||||||
Map getHueBulbs() {
|
Map getHueBulbs() {
|
||||||
state.bulbs = state.bulbs ?: [:]
|
state.bulbs = state.bulbs ?: [:]
|
||||||
}
|
}
|
||||||
@@ -316,29 +309,6 @@ def uninstalled(){
|
|||||||
state.username = null
|
state.username = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles events to add new bulbs
|
|
||||||
def bulbListHandler(hub, data = "") {
|
|
||||||
def msg = "Bulbs list not processed. Only while in settings menu."
|
|
||||||
def bulbs = [:]
|
|
||||||
if (state.inBulbDiscovery) {
|
|
||||||
def logg = ""
|
|
||||||
log.trace "Adding bulbs to state..."
|
|
||||||
state.bridgeProcessedLightList = true
|
|
||||||
def object = new groovy.json.JsonSlurper().parseText(data)
|
|
||||||
object.each { k,v ->
|
|
||||||
if (v instanceof Map)
|
|
||||||
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub, online: v.state?.reachable]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def bridge = null
|
|
||||||
if (selectedHue) {
|
|
||||||
bridge = getChildDevice(selectedHue)
|
|
||||||
}
|
|
||||||
bridge.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false)
|
|
||||||
msg = "${bulbs.size()} bulbs found. ${bulbs}"
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
private upgradeDeviceType(device, newHueType) {
|
private upgradeDeviceType(device, newHueType) {
|
||||||
def deviceType = getDeviceType(newHueType)
|
def deviceType = getDeviceType(newHueType)
|
||||||
|
|
||||||
@@ -490,24 +460,25 @@ def ssdpBridgeHandler(evt) {
|
|||||||
def host = ip + ":" + port
|
def host = ip + ":" + port
|
||||||
log.debug "Device ($parsedEvent.mac) was already found in state with ip = $host."
|
log.debug "Device ($parsedEvent.mac) was already found in state with ip = $host."
|
||||||
def dstate = bridges."${parsedEvent.ssdpUSN.toString()}"
|
def dstate = bridges."${parsedEvent.ssdpUSN.toString()}"
|
||||||
def dni = "${parsedEvent.mac}"
|
def dniReceived = "${parsedEvent.mac}"
|
||||||
def d = getChildDevice(dni)
|
def currentDni = dstate.mac
|
||||||
|
def d = getChildDevice(dniReceived)
|
||||||
def networkAddress = null
|
def networkAddress = null
|
||||||
if (!d) {
|
if (!d) {
|
||||||
childDevices.each {
|
// There might be a mismatch between bridge DNI and the actual bridge mac address, correct that
|
||||||
if (it.getDeviceDataByName("mac")) {
|
log.debug "Bridge with $dniReceived not found"
|
||||||
def newDNI = "${it.getDeviceDataByName("mac")}"
|
def bridge = childDevices.find { it.deviceNetworkId == currentDni }
|
||||||
d = it
|
if (bridge != null) {
|
||||||
if (newDNI != it.deviceNetworkId) {
|
log.warn "Bridge is set to ${bridge.deviceNetworkId}, updating to $dniReceived"
|
||||||
def oldDNI = it.deviceNetworkId
|
bridge.setDeviceNetworkId("${dniReceived}")
|
||||||
log.debug "updating dni for device ${it} with $newDNI - previous DNI = ${it.deviceNetworkId}"
|
dstate.mac = dniReceived
|
||||||
it.setDeviceNetworkId("${newDNI}")
|
// Check to see if selectedHue is a valid bridge, otherwise update it
|
||||||
if (oldDNI == selectedHue) {
|
def isSelectedValid = bridges?.find {it.value?.mac == selectedHue}
|
||||||
app.updateSetting("selectedHue", newDNI)
|
if (isSelectedValid == null) {
|
||||||
}
|
log.warn "Correcting selectedHue in state"
|
||||||
doDeviceSync()
|
app.updateSetting("selectedHue", dniReceived)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
doDeviceSync()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updateBridgeStatus(d)
|
updateBridgeStatus(d)
|
||||||
@@ -525,6 +496,18 @@ def ssdpBridgeHandler(evt) {
|
|||||||
d.sendEvent(name:"networkAddress", value: host)
|
d.sendEvent(name:"networkAddress", value: host)
|
||||||
d.updateDataValue("networkAddress", host)
|
d.updateDataValue("networkAddress", host)
|
||||||
}
|
}
|
||||||
|
if (dstate.mac != dniReceived) {
|
||||||
|
log.warn "Correcting bridge mac address in state"
|
||||||
|
dstate.mac = dniReceived
|
||||||
|
}
|
||||||
|
if (selectedHue != dniReceived) {
|
||||||
|
// Check to see if selectedHue is a valid bridge, otherwise update it
|
||||||
|
def isSelectedValid = bridges?.find {it.value?.mac == selectedHue}
|
||||||
|
if (isSelectedValid == null) {
|
||||||
|
log.warn "Correcting selectedHue in state"
|
||||||
|
app.updateSetting("selectedHue", dniReceived)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -557,11 +540,8 @@ void lightsHandler(physicalgraph.device.HubResponse hubResponse) {
|
|||||||
if (isValidSource(hubResponse.mac)) {
|
if (isValidSource(hubResponse.mac)) {
|
||||||
def body = hubResponse.json
|
def body = hubResponse.json
|
||||||
if (!body?.state?.on) { //check if first time poll made it here by mistake
|
if (!body?.state?.on) { //check if first time poll made it here by mistake
|
||||||
def bulbs = getHueBulbs()
|
|
||||||
log.debug "Adding bulbs to state!"
|
log.debug "Adding bulbs to state!"
|
||||||
body.each { k, v ->
|
updateBulbState(body, hubResponse.hubId)
|
||||||
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub: hubResponse.hubId]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -677,11 +657,8 @@ def locationHandler(evt) {
|
|||||||
} else {
|
} else {
|
||||||
//GET /api/${state.username}/lights response (application/json)
|
//GET /api/${state.username}/lights response (application/json)
|
||||||
if (!body?.state?.on) { //check if first time poll made it here by mistake
|
if (!body?.state?.on) { //check if first time poll made it here by mistake
|
||||||
def bulbs = getHueBulbs()
|
|
||||||
log.debug "Adding bulbs to state!"
|
log.debug "Adding bulbs to state!"
|
||||||
body.each { k,v ->
|
updateBulbState(body, parsedEvent.hub)
|
||||||
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:parsedEvent.hub]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -741,7 +718,7 @@ private void checkBridgeStatus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (it.value.lastActivity < time) { // it.value.lastActivity != null &&
|
if (it.value.lastActivity < time) { // it.value.lastActivity != null &&
|
||||||
log.warn "Bridge $it.key is Offline"
|
log.warn "Bridge $it.value.idNumber is Offline"
|
||||||
d.sendEvent(name: "status", value: "Offline")
|
d.sendEvent(name: "status", value: "Offline")
|
||||||
|
|
||||||
state.bulbs?.each {
|
state.bulbs?.each {
|
||||||
@@ -766,6 +743,31 @@ def isInBulbDiscovery() {
|
|||||||
return state.inBulbDiscovery
|
return state.inBulbDiscovery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateBulbState(messageBody, hub) {
|
||||||
|
def bulbs = getHueBulbs()
|
||||||
|
|
||||||
|
// Copy of bulbs used to locate old lights in state that are no longer on bridge
|
||||||
|
def toRemove = [:]
|
||||||
|
toRemove << bulbs
|
||||||
|
|
||||||
|
messageBody.each { k,v ->
|
||||||
|
|
||||||
|
if (v instanceof Map) {
|
||||||
|
if (bulbs[k] == null) {
|
||||||
|
bulbs[k] = [:]
|
||||||
|
}
|
||||||
|
bulbs[k] << [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub, remove: false]
|
||||||
|
toRemove.remove(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove bulbs from state that are no longer discovered
|
||||||
|
toRemove.each { k,v ->
|
||||||
|
log.warn "${bulbs[k].name} no longer exists on bridge, removing"
|
||||||
|
bulbs.remove(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
//CHILD DEVICE METHODS
|
//CHILD DEVICE METHODS
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
@@ -950,6 +952,14 @@ private handleCommandResponse(body) {
|
|||||||
* @return empty array
|
* @return empty array
|
||||||
*/
|
*/
|
||||||
private handlePoll(body) {
|
private handlePoll(body) {
|
||||||
|
// Used to track "unreachable" time
|
||||||
|
// Device is considered "offline" if it has been in the "unreachable" state for
|
||||||
|
// 11 minutes (e.g. two poll intervals)
|
||||||
|
// Note, Hue Bridge marks devices as "unreachable" often even when they accept commands
|
||||||
|
Calendar time11 = Calendar.getInstance()
|
||||||
|
time11.add(Calendar.MINUTE, -11)
|
||||||
|
Calendar currentTime = Calendar.getInstance()
|
||||||
|
|
||||||
def bulbs = getChildDevices()
|
def bulbs = getChildDevices()
|
||||||
for (bulb in body) {
|
for (bulb in body) {
|
||||||
def device = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"}
|
def device = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"}
|
||||||
@@ -959,7 +969,10 @@ private handlePoll(body) {
|
|||||||
// light just came back online, notify device watch
|
// light just came back online, notify device watch
|
||||||
def lastActivity = now()
|
def lastActivity = now()
|
||||||
device.sendEvent(name: "deviceWatch-status", value: "ONLINE", description: "Last Activity is on ${new Date((long) lastActivity)}", displayed: false, isStateChange: true)
|
device.sendEvent(name: "deviceWatch-status", value: "ONLINE", description: "Last Activity is on ${new Date((long) lastActivity)}", displayed: false, isStateChange: true)
|
||||||
|
log.debug "$device is Online"
|
||||||
}
|
}
|
||||||
|
// Mark light as "online"
|
||||||
|
state.bulbs[bulb.key]?.unreachableSince = null
|
||||||
state.bulbs[bulb.key]?.online = true
|
state.bulbs[bulb.key]?.online = true
|
||||||
|
|
||||||
// If user just executed commands, then do not send events to avoid confusing the turning on/off state
|
// If user just executed commands, then do not send events to avoid confusing the turning on/off state
|
||||||
@@ -969,9 +982,18 @@ private handlePoll(body) {
|
|||||||
sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode)
|
sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.bulbs[bulb.key]?.online = false
|
if (state.bulbs[bulb.key]?.unreachableSince == null) {
|
||||||
log.warn "$device is not reachable by Hue bridge"
|
// Store the first time where device was reported as "unreachable"
|
||||||
device.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", displayed: false, isStateChange: true)
|
state.bulbs[bulb.key]?.unreachableSince = currentTime.getTimeInMillis()
|
||||||
|
} else if (state.bulbs[bulb.key]?.online) {
|
||||||
|
// Check if device was "unreachable" for more than 11 minutes and mark "offline" if necessary
|
||||||
|
if (state.bulbs[bulb.key]?.unreachableSince < time11.getTimeInMillis()) {
|
||||||
|
log.warn "$device went Offline"
|
||||||
|
state.bulbs[bulb.key]?.online = false
|
||||||
|
device.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", displayed: false, isStateChange: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.warn "$device may not reachable by Hue bridge"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1006,9 +1028,6 @@ def hubVerification(bodytext) {
|
|||||||
def on(childDevice) {
|
def on(childDevice) {
|
||||||
log.debug "Executing 'on'"
|
log.debug "Executing 'on'"
|
||||||
def id = getId(childDevice)
|
def id = getId(childDevice)
|
||||||
if (!isOnline(id)) {
|
|
||||||
return "Bulb is unreachable"
|
|
||||||
}
|
|
||||||
updateInProgress()
|
updateInProgress()
|
||||||
createSwitchEvent(childDevice, "on")
|
createSwitchEvent(childDevice, "on")
|
||||||
put("lights/$id/state", [on: true])
|
put("lights/$id/state", [on: true])
|
||||||
@@ -1018,9 +1037,6 @@ def on(childDevice) {
|
|||||||
def off(childDevice) {
|
def off(childDevice) {
|
||||||
log.debug "Executing 'off'"
|
log.debug "Executing 'off'"
|
||||||
def id = getId(childDevice)
|
def id = getId(childDevice)
|
||||||
if (!isOnline(id)) {
|
|
||||||
return "Bulb is unreachable"
|
|
||||||
}
|
|
||||||
updateInProgress()
|
updateInProgress()
|
||||||
createSwitchEvent(childDevice, "off")
|
createSwitchEvent(childDevice, "off")
|
||||||
put("lights/$id/state", [on: false])
|
put("lights/$id/state", [on: false])
|
||||||
@@ -1030,9 +1046,6 @@ def off(childDevice) {
|
|||||||
def setLevel(childDevice, percent) {
|
def setLevel(childDevice, percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
def id = getId(childDevice)
|
def id = getId(childDevice)
|
||||||
if (!isOnline(id)) {
|
|
||||||
return "Bulb is unreachable"
|
|
||||||
}
|
|
||||||
updateInProgress()
|
updateInProgress()
|
||||||
// 1 - 254
|
// 1 - 254
|
||||||
def level
|
def level
|
||||||
@@ -1057,10 +1070,6 @@ def setLevel(childDevice, percent) {
|
|||||||
def setSaturation(childDevice, percent) {
|
def setSaturation(childDevice, percent) {
|
||||||
log.debug "Executing 'setSaturation($percent)'"
|
log.debug "Executing 'setSaturation($percent)'"
|
||||||
def id = getId(childDevice)
|
def id = getId(childDevice)
|
||||||
if (!isOnline(id)) {
|
|
||||||
return "Bulb is unreachable"
|
|
||||||
}
|
|
||||||
|
|
||||||
updateInProgress()
|
updateInProgress()
|
||||||
// 0 - 254
|
// 0 - 254
|
||||||
def level = Math.min(Math.round(percent * 254 / 100), 254)
|
def level = Math.min(Math.round(percent * 254 / 100), 254)
|
||||||
@@ -1073,9 +1082,6 @@ def setSaturation(childDevice, percent) {
|
|||||||
def setHue(childDevice, percent) {
|
def setHue(childDevice, percent) {
|
||||||
log.debug "Executing 'setHue($percent)'"
|
log.debug "Executing 'setHue($percent)'"
|
||||||
def id = getId(childDevice)
|
def id = getId(childDevice)
|
||||||
if (!isOnline(id)) {
|
|
||||||
return "Bulb is unreachable"
|
|
||||||
}
|
|
||||||
updateInProgress()
|
updateInProgress()
|
||||||
// 0 - 65535
|
// 0 - 65535
|
||||||
def level = Math.min(Math.round(percent * 65535 / 100), 65535)
|
def level = Math.min(Math.round(percent * 65535 / 100), 65535)
|
||||||
@@ -1088,9 +1094,6 @@ def setHue(childDevice, percent) {
|
|||||||
def setColorTemperature(childDevice, huesettings) {
|
def setColorTemperature(childDevice, huesettings) {
|
||||||
log.debug "Executing 'setColorTemperature($huesettings)'"
|
log.debug "Executing 'setColorTemperature($huesettings)'"
|
||||||
def id = getId(childDevice)
|
def id = getId(childDevice)
|
||||||
if (!isOnline(id)) {
|
|
||||||
return "Bulb is unreachable"
|
|
||||||
}
|
|
||||||
updateInProgress()
|
updateInProgress()
|
||||||
// 153 (6500K) to 500 (2000K)
|
// 153 (6500K) to 500 (2000K)
|
||||||
def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings)
|
def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings)
|
||||||
@@ -1102,9 +1105,6 @@ def setColorTemperature(childDevice, huesettings) {
|
|||||||
def setColor(childDevice, huesettings) {
|
def setColor(childDevice, huesettings) {
|
||||||
log.debug "Executing 'setColor($huesettings)'"
|
log.debug "Executing 'setColor($huesettings)'"
|
||||||
def id = getId(childDevice)
|
def id = getId(childDevice)
|
||||||
if (!isOnline(id)) {
|
|
||||||
return "Bulb is unreachable"
|
|
||||||
}
|
|
||||||
updateInProgress()
|
updateInProgress()
|
||||||
|
|
||||||
def value = [:]
|
def value = [:]
|
||||||
@@ -1120,7 +1120,7 @@ def setColor(childDevice, huesettings) {
|
|||||||
value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
|
value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
|
||||||
if (huesettings.saturation != null)
|
if (huesettings.saturation != null)
|
||||||
value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254)
|
value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254)
|
||||||
} else if (huesettings.hex != null && false) {
|
} else if (huesettings.hex != null) {
|
||||||
// For now ignore model to get a consistent color if same color is set across multiple devices
|
// For now ignore model to get a consistent color if same color is set across multiple devices
|
||||||
// def model = state.bulbs[getId(childDevice)]?.modelid
|
// def model = state.bulbs[getId(childDevice)]?.modelid
|
||||||
// value.xy = calculateXY(huesettings.hex, model)
|
// value.xy = calculateXY(huesettings.hex, model)
|
||||||
@@ -1162,7 +1162,14 @@ def setColor(childDevice, huesettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def ping(childDevice) {
|
def ping(childDevice) {
|
||||||
if (isOnline(getId(childDevice))) {
|
if (childDevice.device?.deviceNetworkId?.equalsIgnoreCase(selectedHue)) {
|
||||||
|
if (childDevice.device?.currentValue("status")?.equalsIgnoreCase("Online")) {
|
||||||
|
childDevice.sendEvent(name: "deviceWatch-ping", value: "ONLINE", description: "Hue Bridge is reachable", displayed: false, isStateChange: true)
|
||||||
|
return "Bridge is Online"
|
||||||
|
} else {
|
||||||
|
return "Bridge is Offline"
|
||||||
|
}
|
||||||
|
} else if (isOnline(getId(childDevice))) {
|
||||||
childDevice.sendEvent(name: "deviceWatch-ping", value: "ONLINE", description: "Hue Light is reachable", displayed: false, isStateChange: true)
|
childDevice.sendEvent(name: "deviceWatch-ping", value: "ONLINE", description: "Hue Light is reachable", displayed: false, isStateChange: true)
|
||||||
return "Device is Online"
|
return "Device is Online"
|
||||||
} else {
|
} else {
|
||||||
@@ -1224,7 +1231,7 @@ private getBridgeIP() {
|
|||||||
if (d) {
|
if (d) {
|
||||||
if (d.getDeviceDataByName("networkAddress"))
|
if (d.getDeviceDataByName("networkAddress"))
|
||||||
host = d.getDeviceDataByName("networkAddress")
|
host = d.getDeviceDataByName("networkAddress")
|
||||||
else
|
else
|
||||||
host = d.latestState('networkAddress').stringValue
|
host = d.latestState('networkAddress').stringValue
|
||||||
}
|
}
|
||||||
if (host == null || host == "") {
|
if (host == null || host == "") {
|
||||||
@@ -1663,7 +1670,7 @@ private boolean checkPointInLampsReach(p, colorPoints) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an RGB color in hex to HSV.
|
* Converts an RGB color in hex to HSV/HSB.
|
||||||
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
|
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
|
||||||
*
|
*
|
||||||
* @param colorStr color value in hex (#ff03d3)
|
* @param colorStr color value in hex (#ff03d3)
|
||||||
@@ -1673,32 +1680,32 @@ private boolean checkPointInLampsReach(p, colorPoints) {
|
|||||||
def hexToHsv(colorStr){
|
def hexToHsv(colorStr){
|
||||||
def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255
|
def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255
|
||||||
def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255
|
def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255
|
||||||
def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255;
|
def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255
|
||||||
|
|
||||||
def max = Math.max(Math.max(r, g), b)
|
def max = Math.max(Math.max(r, g), b)
|
||||||
def min = Math.min(Math.min(r, g), b)
|
def min = Math.min(Math.min(r, g), b)
|
||||||
|
|
||||||
def h, s, v = max;
|
def h, s, v = max
|
||||||
|
|
||||||
def d = max - min;
|
def d = max - min
|
||||||
s = max == 0 ? 0 : d / max;
|
s = max == 0 ? 0 : d / max
|
||||||
|
|
||||||
if(max == min){
|
if(max == min){
|
||||||
h = 0;
|
h = 0
|
||||||
}else{
|
}else{
|
||||||
switch(max){
|
switch(max){
|
||||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
case r: h = (g - b) / d + (g < b ? 6 : 0); break
|
||||||
case g: h = (b - r) / d + 2; break;
|
case g: h = (b - r) / d + 2; break
|
||||||
case b: h = (r - g) / d + 4; break;
|
case b: h = (r - g) / d + 4; break
|
||||||
}
|
}
|
||||||
h /= 6;
|
h /= 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [(h * 100).round(), (s * 100).round(), (v * 100).round()];
|
return [Math.round(h * 100), Math.round(s * 100), Math.round(v * 100)]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts HSV color to RGB in hex.
|
* Converts HSV/HSB color to RGB in hex.
|
||||||
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
|
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
|
||||||
*
|
*
|
||||||
* @param hue hue 0-100
|
* @param hue hue 0-100
|
||||||
@@ -1713,11 +1720,11 @@ def hsvToHex(hue, sat, value = 100){
|
|||||||
def s = sat / 100
|
def s = sat / 100
|
||||||
def v = value / 100
|
def v = value / 100
|
||||||
|
|
||||||
def i = Math.floor(h * 6);
|
def i = Math.floor(h * 6)
|
||||||
def f = h * 6 - i;
|
def f = h * 6 - i
|
||||||
def p = v * (1 - s);
|
def p = v * (1 - s)
|
||||||
def q = v * (1 - f * s);
|
def q = v * (1 - f * s)
|
||||||
def t = v * (1 - (1 - f) * s);
|
def t = v * (1 - (1 - f) * s)
|
||||||
|
|
||||||
switch (i % 6) {
|
switch (i % 6) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -1753,9 +1760,9 @@ def hsvToHex(hue, sat, value = 100){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Converting float components to int components.
|
// Converting float components to int components.
|
||||||
def r1 = String.format("%02X", (int) (r * 255.0f));
|
def r1 = String.format("%02X", (int) (r * 255.0f))
|
||||||
def g1 = String.format("%02X", (int) (g * 255.0f));
|
def g1 = String.format("%02X", (int) (g * 255.0f))
|
||||||
def b1 = String.format("%02X", (int) (b * 255.0f));
|
def b1 = String.format("%02X", (int) (b * 255.0f))
|
||||||
|
|
||||||
return "#$r1$g1$b1"
|
return "#$r1$g1$b1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
* locks | lock | lock, unlock | locked, unlocked
|
* locks | lock | lock, unlock | locked, unlocked
|
||||||
* ---------------------+-------------------+-----------------------------+------------------------------------
|
* ---------------------+-------------------+-----------------------------+------------------------------------
|
||||||
*/
|
*/
|
||||||
|
include 'asynchttp_v1'
|
||||||
|
|
||||||
definition(
|
definition(
|
||||||
name: "Logitech Harmony (Connect)",
|
name: "Logitech Harmony (Connect)",
|
||||||
@@ -109,26 +110,28 @@ def authPage() {
|
|||||||
//device discovery request every 5 //25 seconds
|
//device discovery request every 5 //25 seconds
|
||||||
int deviceRefreshCount = !state.deviceRefreshCount ? 0 : state.deviceRefreshCount as int
|
int deviceRefreshCount = !state.deviceRefreshCount ? 0 : state.deviceRefreshCount as int
|
||||||
state.deviceRefreshCount = deviceRefreshCount + 1
|
state.deviceRefreshCount = deviceRefreshCount + 1
|
||||||
def refreshInterval = 3
|
def refreshInterval = 5
|
||||||
|
|
||||||
def huboptions = state.HarmonyHubs ?: []
|
def huboptions = state.HarmonyHubs ?: []
|
||||||
def actoptions = state.HarmonyActivities ?: []
|
def actoptions = state.HarmonyActivities ?: []
|
||||||
|
|
||||||
def numFoundHub = huboptions.size() ?: 0
|
def numFoundHub = huboptions.size() ?: 0
|
||||||
def numFoundAct = actoptions.size() ?: 0
|
def numFoundAct = actoptions.size() ?: 0
|
||||||
|
|
||||||
if((deviceRefreshCount % 5) == 0) {
|
if((deviceRefreshCount % 5) == 0) {
|
||||||
discoverDevices()
|
discoverDevices()
|
||||||
}
|
}
|
||||||
|
|
||||||
return dynamicPage(name:"Credentials", title:"Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
|
return dynamicPage(name:"Credentials", title:"Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
|
||||||
section("Please wait while we discover your Harmony Hubs and Activities. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
section("Please wait while we discover your Harmony Hubs and Activities. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||||
input "selectedhubs", "enum", required:false, title:"Select Harmony Hubs (${numFoundHub} found)", multiple:true, options:huboptions
|
input "selectedhubs", "enum", required:false, title:"Select Harmony Hubs (${numFoundHub} found)", multiple:true, submitOnChange: true, options:huboptions
|
||||||
}
|
}
|
||||||
// Virtual activity flag
|
// Virtual activity flag
|
||||||
if (numFoundHub > 0 && numFoundAct > 0 && true)
|
if (numFoundHub > 0 && numFoundAct > 0 && true)
|
||||||
section("You can also add activities as virtual switches for other convenient integrations") {
|
section("You can also add activities as virtual switches for other convenient integrations") {
|
||||||
input "selectedactivities", "enum", required:false, title:"Select Harmony Activities (${numFoundAct} found)", multiple:true, options:actoptions
|
input "selectedactivities", "enum", required:false, title:"Select Harmony Activities (${numFoundAct} found)", multiple:true, submitOnChange: true, options:actoptions
|
||||||
}
|
}
|
||||||
if (state.resethub)
|
if (state.resethub)
|
||||||
section("Connection to the hub timed out. Please restart the hub and try again.") {}
|
section("Connection to the hub timed out. Please restart the hub and try again.") {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,8 +383,6 @@ def discovery() {
|
|||||||
log.debug "valid Token"
|
log.debug "valid Token"
|
||||||
state.Harmonydevices = response.data
|
state.Harmonydevices = response.data
|
||||||
state.resethub = false
|
state.resethub = false
|
||||||
getActivityList()
|
|
||||||
poll()
|
|
||||||
} else {
|
} else {
|
||||||
log.debug "Error: $response.status"
|
log.debug "Error: $response.status"
|
||||||
}
|
}
|
||||||
@@ -430,142 +431,182 @@ def addDevice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def activity(dni,mode) {
|
def activity(dni,mode) {
|
||||||
def Params = [auth: state.HarmonyAccessToken]
|
def tokenParam = [auth: state.HarmonyAccessToken]
|
||||||
def msg = "Command failed"
|
def url
|
||||||
def url = ''
|
|
||||||
if (dni == "all") {
|
if (dni == "all") {
|
||||||
url = "https://home.myharmony.com/cloudapi/activity/off?${toQueryString(Params)}"
|
url = "https://home.myharmony.com/cloudapi/activity/off?${toQueryString(tokenParam)}"
|
||||||
} else {
|
} else {
|
||||||
def aux = dni.split('-')
|
def aux = dni.split('-')
|
||||||
def hubId = aux[1]
|
def hubId = aux[1]
|
||||||
if (mode == "hub" || (aux.size() <= 2) || (aux[2] == "off")){
|
if (mode == "hub" || (aux.size() <= 2) || (aux[2] == "off")){
|
||||||
url = "https://home.myharmony.com/cloudapi/hub/${hubId}/activity/off?${toQueryString(Params)}"
|
url = "https://home.myharmony.com/cloudapi/hub/${hubId}/activity/off?${toQueryString(tokenParam)}"
|
||||||
} else {
|
} else {
|
||||||
def activityId = aux[2]
|
def activityId = aux[2]
|
||||||
url = "https://home.myharmony.com/cloudapi/hub/${hubId}/activity/${activityId}/${mode}?${toQueryString(Params)}"
|
url = "https://home.myharmony.com/cloudapi/hub/${hubId}/activity/${activityId}/${mode}?${toQueryString(tokenParam)}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
def params = [
|
||||||
httpPostJson(uri: url) { response ->
|
uri: url,
|
||||||
if (response.data.code == 200 || dni == "all") {
|
contentType: 'application/json'
|
||||||
msg = "Command sent succesfully"
|
]
|
||||||
state.aux = 0
|
asynchttp_v1.post('activityResponse', params)
|
||||||
} else {
|
return "Command Sent"
|
||||||
msg = "Command failed. Error: $response.data.code"
|
}
|
||||||
}
|
|
||||||
}
|
def activityResponse(response, data) {
|
||||||
} catch (groovyx.net.http.HttpResponseException ex) {
|
if (response.hasError()) {
|
||||||
log.error ex
|
log.error "Logitech Harmony - response has error: $response.errorMessage"
|
||||||
if (state.aux == 0) {
|
if (response.status == 401) { // token is expired
|
||||||
state.aux = 1
|
state.remove("HarmonyAccessToken")
|
||||||
activity(dni,mode)
|
log.warn "Logitech Harmony - Access token has expired"
|
||||||
} else {
|
|
||||||
msg = ex
|
|
||||||
state.aux = 0
|
|
||||||
}
|
|
||||||
} catch(Exception ex) {
|
|
||||||
msg = ex
|
|
||||||
}
|
}
|
||||||
runIn(10, "poll", [overwrite: true])
|
} else {
|
||||||
return msg
|
def ResponseValues
|
||||||
|
try {
|
||||||
|
// json response already parsed into JSONElement object
|
||||||
|
ResponseValues = response.json
|
||||||
|
} catch (e) {
|
||||||
|
log.error "Logitech Harmony - error parsing json from response: $e"
|
||||||
|
}
|
||||||
|
if (ResponseValues) {
|
||||||
|
if (ResponseValues.code == 200) {
|
||||||
|
log.trace "Command sent succesfully"
|
||||||
|
poll()
|
||||||
|
} else {
|
||||||
|
log.trace "Command failed. Error: $response.data.code"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug "Logitech Harmony - did not get json results from response body: $response.data"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
// GET THE LIST OF ACTIVITIES
|
// GET THE LIST OF ACTIVITIES
|
||||||
if (state.HarmonyAccessToken) {
|
if (state.HarmonyAccessToken) {
|
||||||
getActivityList()
|
getActivityList()
|
||||||
def Params = [auth: state.HarmonyAccessToken]
|
def tokenParam = [auth: state.HarmonyAccessToken]
|
||||||
def url = "https://home.myharmony.com/cloudapi/state?${toQueryString(Params)}"
|
def params = [
|
||||||
try {
|
uri: "https://home.myharmony.com/cloudapi/state?${toQueryString(tokenParam)}",
|
||||||
httpGet(uri: url, headers: ["Accept": "application/json"]) {response ->
|
headers: ["Accept": "application/json"],
|
||||||
def map = [:]
|
contentType: 'application/json'
|
||||||
response.data.hubs.each {
|
]
|
||||||
if (it.value.message == "OK") {
|
asynchttp_v1.get('pollResponse', params)
|
||||||
map["${it.key}"] = "${it.value.response.data.currentAvActivity},${it.value.response.data.activityStatus}"
|
} else {
|
||||||
def hub = getChildDevice("harmony-${it.key}")
|
log.warn "Logitech Harmony - Access token has expired"
|
||||||
if (hub) {
|
}
|
||||||
if (it.value.response.data.currentAvActivity == "-1") {
|
}
|
||||||
hub.sendEvent(name: "currentActivity", value: "--", descriptionText: "There isn't any activity running", display: false)
|
|
||||||
} else {
|
def pollResponse(response, data) {
|
||||||
def currentActivity = getActivityName(it.value.response.data.currentAvActivity,it.key)
|
if (response.hasError()) {
|
||||||
hub.sendEvent(name: "currentActivity", value: currentActivity, descriptionText: "Current activity is ${currentActivity}", display: false)
|
log.error "Logitech Harmony - response has error: $response.errorMessage"
|
||||||
}
|
if (response.status == 401) { // token is expired
|
||||||
}
|
state.remove("HarmonyAccessToken")
|
||||||
} else {
|
log.warn "Logitech Harmony - Access token has expired"
|
||||||
log.trace it.value.message
|
}
|
||||||
}
|
} else {
|
||||||
}
|
def ResponseValues
|
||||||
def activities = getChildDevices()
|
try {
|
||||||
def activitynotrunning = true
|
// json response already parsed into JSONElement object
|
||||||
activities.each { activity ->
|
ResponseValues = response.json
|
||||||
def act = activity.deviceNetworkId.split('-')
|
} catch (e) {
|
||||||
if (act.size() > 2) {
|
log.error "Logitech Harmony - error parsing json from response: $e"
|
||||||
def aux = map.find { it.key == act[1] }
|
}
|
||||||
if (aux) {
|
if (ResponseValues) {
|
||||||
def aux2 = aux.value.split(',')
|
def map = [:]
|
||||||
def childDevice = getChildDevice(activity.deviceNetworkId)
|
ResponseValues.hubs.each {
|
||||||
if ((act[2] == aux2[0]) && (aux2[1] == "1" || aux2[1] == "2")) {
|
if (it.value.message == "OK") {
|
||||||
childDevice?.sendEvent(name: "switch", value: "on")
|
map["${it.key}"] = "${it.value.response.data.currentAvActivity},${it.value.response.data.activityStatus}"
|
||||||
if (aux2[1] == "1")
|
def hub = getChildDevice("harmony-${it.key}")
|
||||||
runIn(5, "poll", [overwrite: true])
|
if (hub) {
|
||||||
} else {
|
if (it.value.response.data.currentAvActivity == "-1") {
|
||||||
childDevice?.sendEvent(name: "switch", value: "off")
|
hub.sendEvent(name: "currentActivity", value: "--", descriptionText: "There isn't any activity running", display: false)
|
||||||
if (aux2[1] == "3")
|
} else {
|
||||||
runIn(5, "poll", [overwrite: true])
|
def currentActivity = getChildDevice("harmony-${it.key}-${it.value.response.data.currentAvActivity}").device.displayName
|
||||||
}
|
hub.sendEvent(name: "currentActivity", value: currentActivity, descriptionText: "Current activity is ${currentActivity}", display: false)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.trace "Logitech Harmony - error response: $it.value.message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def activities = getChildDevices()
|
||||||
|
def activitynotrunning = true
|
||||||
|
activities.each { activity ->
|
||||||
|
def act = activity.deviceNetworkId.split('-')
|
||||||
|
if (act.size() > 2) {
|
||||||
|
def aux = map.find { it.key == act[1] }
|
||||||
|
if (aux) {
|
||||||
|
def aux2 = aux.value.split(',')
|
||||||
|
def childDevice = getChildDevice(activity.deviceNetworkId)
|
||||||
|
if ((act[2] == aux2[0]) && (aux2[1] == "1" || aux2[1] == "2")) {
|
||||||
|
childDevice?.sendEvent(name: "switch", value: "on")
|
||||||
|
if (aux2[1] == "1")
|
||||||
|
runIn(5, "poll", [overwrite: true])
|
||||||
|
} else {
|
||||||
|
childDevice?.sendEvent(name: "switch", value: "off")
|
||||||
|
if (aux2[1] == "3")
|
||||||
|
runIn(5, "poll", [overwrite: true])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "Poll completed $map - $state.hubs"
|
|
||||||
}
|
}
|
||||||
} catch (groovyx.net.http.HttpResponseException e) {
|
|
||||||
if (e.statusCode == 401) { // token is expired
|
|
||||||
state.remove("HarmonyAccessToken")
|
|
||||||
log.warn "Harmony Access token has expired"
|
|
||||||
}
|
|
||||||
} catch (java.net.SocketTimeoutException e) {
|
|
||||||
log.warn "Connection to the hub timed out. Please restart the hub and try again."
|
|
||||||
state.resethub = true
|
|
||||||
} catch (e) {
|
|
||||||
log.info "Logitech Harmony - Error: $e"
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.debug "Logitech Harmony - did not get json results from response body: $response.data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getActivityList() {
|
||||||
|
if (state.HarmonyAccessToken) {
|
||||||
|
def tokenParam = [auth: state.HarmonyAccessToken]
|
||||||
|
def params = [
|
||||||
|
uri: "https://home.myharmony.com/cloudapi/activity/all?${toQueryString(tokenParam)}",
|
||||||
|
headers: ["Accept": "application/json"],
|
||||||
|
contentType: 'application/json'
|
||||||
|
]
|
||||||
|
asynchttp_v1.get('activityListResponse', params)
|
||||||
|
} else {
|
||||||
|
log.warn "Logitech Harmony - Access token has expired"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def activityListResponse(response, data) {
|
||||||
def getActivityList() {
|
if (response.hasError()) {
|
||||||
// GET ACTIVITY'S NAME
|
log.error "Logitech Harmony - response has error: $response.errorMessage"
|
||||||
if (state.HarmonyAccessToken) {
|
if (response.status == 401) { // token is expired
|
||||||
def Params = [auth: state.HarmonyAccessToken]
|
state.remove("HarmonyAccessToken")
|
||||||
def url = "https://home.myharmony.com/cloudapi/activity/all?${toQueryString(Params)}"
|
log.warn "Logitech Harmony - Access token has expired"
|
||||||
try {
|
}
|
||||||
httpGet(uri: url, headers: ["Accept": "application/json"]) {response ->
|
} else {
|
||||||
response.data.hubs.each {
|
def ResponseValues
|
||||||
def hub = getChildDevice("harmony-${it.key}")
|
try {
|
||||||
if (hub) {
|
// json response already parsed into JSONElement object
|
||||||
def hubname = getHubName("${it.key}")
|
ResponseValues = response.json
|
||||||
def activities = []
|
} catch (e) {
|
||||||
def aux = it.value.response.data.activities.size()
|
log.error "Logitech Harmony - error parsing json from response: $e"
|
||||||
if (aux >= 1) {
|
}
|
||||||
activities = it.value.response.data.activities.collect {
|
if (ResponseValues) {
|
||||||
[id: it.key, name: it.value['name'], type: it.value['type']]
|
ResponseValues.hubs.each {
|
||||||
}
|
def hub = getChildDevice("harmony-${it.key}")
|
||||||
activities += [id: "off", name: "Activity OFF", type: "0"]
|
if (hub) {
|
||||||
log.trace activities
|
def hubname = getHubName("${it.key}")
|
||||||
}
|
def activities = []
|
||||||
hub.sendEvent(name: "activities", value: new groovy.json.JsonBuilder(activities).toString(), descriptionText: "Activities are ${activities.collect { it.name }?.join(', ')}", display: false)
|
def aux = it.value.response?.data.activities.size()
|
||||||
}
|
if (aux >= 1) {
|
||||||
}
|
activities = it.value.response.data.activities.collect {
|
||||||
}
|
[id: it.key, name: it.value['name'], type: it.value['type']]
|
||||||
} catch (groovyx.net.http.HttpResponseException e) {
|
}
|
||||||
log.trace e
|
activities += [id: "off", name: "Activity OFF", type: "0"]
|
||||||
} catch (java.net.SocketTimeoutException e) {
|
log.trace activities
|
||||||
log.trace e
|
}
|
||||||
} catch(Exception e) {
|
hub.sendEvent(name: "activities", value: new groovy.json.JsonBuilder(activities).toString(), descriptionText: "Activities are ${activities.collect { it.name }?.join(', ')}", display: false)
|
||||||
log.trace e
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
return activity
|
log.debug "Logitech Harmony - did not get json results from response body: $response.data"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getActivityName(activity,hubId) {
|
def getActivityName(activity,hubId) {
|
||||||
@@ -746,7 +787,7 @@ def addSubscription() {
|
|||||||
def attribute = data.attributeName
|
def attribute = data.attributeName
|
||||||
def callbackUrl = data.callbackUrl
|
def callbackUrl = data.callbackUrl
|
||||||
|
|
||||||
log.debug "addSubscription, params: ${params}, request: ${data}"
|
log.debug "Logitech Harmony - addSubscription, params: ${params}, request: ${data}"
|
||||||
if (!attribute) {
|
if (!attribute) {
|
||||||
render status: 400, data: '{"msg": "attributeName is required"}'
|
render status: 400, data: '{"msg": "attributeName is required"}'
|
||||||
} else {
|
} else {
|
||||||
@@ -808,6 +849,7 @@ def deviceHandler(evt) {
|
|||||||
def deviceInfo = state[evt.deviceId]
|
def deviceInfo = state[evt.deviceId]
|
||||||
if (state.harmonyHubs) {
|
if (state.harmonyHubs) {
|
||||||
state.harmonyHubs.each { harmonyHub ->
|
state.harmonyHubs.each { harmonyHub ->
|
||||||
|
log.trace "Logitech Harmony - Sending data to $harmonyHub.name"
|
||||||
sendToHarmony(evt, harmonyHub.callbackUrl)
|
sendToHarmony(evt, harmonyHub.callbackUrl)
|
||||||
}
|
}
|
||||||
} else if (deviceInfo) {
|
} else if (deviceInfo) {
|
||||||
|
|||||||
@@ -1,800 +0,0 @@
|
|||||||
/**
|
|
||||||
* Home Remote
|
|
||||||
*
|
|
||||||
* Copyright 2015 The Home Remote
|
|
||||||
*
|
|
||||||
* 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: "Home Remote",
|
|
||||||
namespace: "thehomeremote.homeremote",
|
|
||||||
author: "The Home Remote",
|
|
||||||
description: "Web service that enables communication between the Home Remote app and a SmartThings hub.",
|
|
||||||
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: [displayName: "The Home Remote", displayLink: "http://thehomeremote.com/"])
|
|
||||||
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
section() {
|
|
||||||
input "accelerationSensors", "capability.accelerationSensor",title: "Acceleration Sensors", multiple: true, required: false
|
|
||||||
input "alarms", "capability.alarm",title: "Alarms", multiple: true, required: false
|
|
||||||
input "batteries", "capability.battery",title: "Batteries", multiple: true, required: false
|
|
||||||
input "beacons", "capability.beacon",title: "Beacons", multiple: true, required: false
|
|
||||||
input "buttonGroup", "capability.button",title: "Buttons", multiple: true, required: false
|
|
||||||
input "carbonMonoxideDetectors", "capability.carbonMonoxideDetector",title: "CO Detectors", multiple: true, required: false
|
|
||||||
input "colorControls", "capability.colorControl",title: "Color Lights", multiple: true, required: false
|
|
||||||
input "contactSensors", "capability.contactSensor",title: "Contact Sensors", multiple: true, required: false
|
|
||||||
input "doorControls", "capability.doorControl",title: "Door Controllers", multiple: true, required: false
|
|
||||||
input "energyMeters", "capability.energyMeter",title: "Energy Meters", multiple: true, required: false
|
|
||||||
input "illuminanceMeasurements", "capability.illuminanceMeasurement",title: "Illuminance Sensors", multiple: true, required: false
|
|
||||||
input "imageCaptures", "capability.imageCapture",title: "Cameras", multiple: true, required: false
|
|
||||||
input "locks", "capability.lock",title: "Locks", multiple: true, required: false
|
|
||||||
input "mediaControllers", "capability.mediaController",title: "Media Controllers", multiple: true, required: false
|
|
||||||
input "momentaries", "capability.momentary",title: "Momentary Buttons", multiple: true, required: false
|
|
||||||
input "motionSensors", "capability.motionSensor",title: "Motion Sensors", multiple: true, required: false
|
|
||||||
input "musicPlayers", "capability.musicPlayer",title: "Music Players", multiple: true, required: false
|
|
||||||
input "powerMeters", "capability.powerMeter",title: "Power Meters", multiple: true, required: false
|
|
||||||
input "presenceSensors", "capability.presenceSensor",title: "Presence Sensors", multiple: true, required: false
|
|
||||||
input "relativeHumidityMeasurements", "capability.relativeHumidityMeasurement",title: "Humidity Sensors", multiple: true, required: false
|
|
||||||
input "relaySwitches", "capability.relaySwitch",title: "Relays", multiple: true, required: false
|
|
||||||
input "signalStrengths", "capability.signalStrength",title: "Signal Strengths", multiple: true, required: false
|
|
||||||
input "sleepSensors", "capability.sleepSensor",title: "Sleep Sensors", multiple: true, required: false
|
|
||||||
input "smokeDetectors", "capability.smokeDetector",title: "Smoke Detectors", multiple: true, required: false
|
|
||||||
input "speechSyntheses", "capability.speechSynthesis",title: "Speech Syntheses", multiple: true, required: false
|
|
||||||
input "stepSensors", "capability.stepSensor",title: "Step Sensors", multiple: true, required: false
|
|
||||||
input "switches", "capability.switch",title: "Switches", multiple: true, required: false
|
|
||||||
input "switchLevels", "capability.switchLevel",title: "Dimmers", multiple: true, required: false
|
|
||||||
input "temperatureMeasurements", "capability.temperatureMeasurement",title: "Temperature Sensors", multiple: true, required: false
|
|
||||||
input "thermostats", "capability.thermostat",title: "Thermostats", multiple: true, required: false
|
|
||||||
input "threeAxes", "capability.threeAxis",title: "Three axis Sensors", multiple: true, required: false
|
|
||||||
input "tones", "capability.tone",title: "Tones", multiple: true, required: false
|
|
||||||
input "touchSensors", "capability.touchSensor",title: "Touch Sensors", multiple: true, required: false
|
|
||||||
input "valves", "capability.valve",title: "Valves", multiple: true, required: false
|
|
||||||
input "waterSensors", "capability.waterSensor",title: "Water Sensors", multiple: true, required: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mappings {
|
|
||||||
path("/GetCurrentValues") {
|
|
||||||
action: [
|
|
||||||
GET: "getCurrentValues"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
path("/GetCurrentValuesWithDisplayName") {
|
|
||||||
action: [
|
|
||||||
GET: "getCurrentValuesWithDisplayName"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
path("/GetRoutines") {
|
|
||||||
action: [
|
|
||||||
GET: "getRoutines"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
path("/ExecuteCommand") {
|
|
||||||
action: [
|
|
||||||
PUT: "executeCommand"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
path("/ExecuteRoutine") {
|
|
||||||
action: [
|
|
||||||
PUT: "executeRoutine"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getCurrentValues() {
|
|
||||||
def resp = []
|
|
||||||
|
|
||||||
accelerationSensors.each {
|
|
||||||
resp << [id: it.id, capability: "AccelerationSensor", attribute: "acceleration", value: it.currentValue("acceleration")]
|
|
||||||
}
|
|
||||||
|
|
||||||
alarms.each {
|
|
||||||
resp << [id: it.id, capability: "Alarm", attribute: "alarm", value: it.currentValue("alarm")]
|
|
||||||
}
|
|
||||||
|
|
||||||
batteries.each {
|
|
||||||
resp << [id: it.id, capability: "Battery", attribute: "battery", value: it.currentValue("battery")]
|
|
||||||
}
|
|
||||||
|
|
||||||
beacons.each {
|
|
||||||
resp << [id: it.id, capability: "Beacon", attribute: "presence", value: it.currentValue("presence")]
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonGroup.each {
|
|
||||||
resp << [id: it.id, capability: "Button", attribute: "button", value: it.currentValue("button")]
|
|
||||||
}
|
|
||||||
|
|
||||||
carbonMonoxideDetectors.each {
|
|
||||||
resp << [id: it.id, capability: "CarbonMonoxideDetector", attribute: "carbonMonoxide", value: it.currentValue("carbonMonoxide")]
|
|
||||||
}
|
|
||||||
|
|
||||||
colorControls.each {
|
|
||||||
resp << [id: it.id, capability: "ColorControl", attribute: "hue", value: it.currentValue("hue")]
|
|
||||||
}
|
|
||||||
|
|
||||||
colorControls.each {
|
|
||||||
resp << [id: it.id, capability: "ColorControl", attribute: "saturation", value: it.currentValue("saturation")]
|
|
||||||
}
|
|
||||||
|
|
||||||
colorControls.each {
|
|
||||||
resp << [id: it.id, capability: "ColorControl", attribute: "color", value: it.currentValue("color")]
|
|
||||||
}
|
|
||||||
|
|
||||||
contactSensors.each {
|
|
||||||
resp << [id: it.id, capability: "ContactSensor", attribute: "contact", value: it.currentValue("contact")]
|
|
||||||
}
|
|
||||||
|
|
||||||
doorControls.each {
|
|
||||||
resp << [id: it.id, capability: "DoorControl", attribute: "door", value: it.currentValue("door")]
|
|
||||||
}
|
|
||||||
|
|
||||||
energyMeters.each {
|
|
||||||
resp << [id: it.id, capability: "EnergyMeter", attribute: "energy", value: it.currentValue("energy")]
|
|
||||||
}
|
|
||||||
|
|
||||||
illuminanceMeasurements.each {
|
|
||||||
resp << [id: it.id, capability: "IlluminanceMeasurement", attribute: "illuminance", value: it.currentValue("illuminance")]
|
|
||||||
}
|
|
||||||
|
|
||||||
imageCaptures.each {
|
|
||||||
resp << [id: it.id, capability: "ImageCapture", attribute: "image", value: it.currentValue("image")]
|
|
||||||
}
|
|
||||||
|
|
||||||
locks.each {
|
|
||||||
resp << [id: it.id, capability: "Lock", attribute: "lock", value: it.currentValue("lock")]
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaControllers.each {
|
|
||||||
resp << [id: it.id, capability: "MediaController", attribute: "activities", value: it.currentValue("activities")]
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaControllers.each {
|
|
||||||
resp << [id: it.id, capability: "MediaController", attribute: "currentActivity", value: it.currentValue("currentActivity")]
|
|
||||||
}
|
|
||||||
|
|
||||||
motionSensors.each {
|
|
||||||
resp << [id: it.id, capability: "MotionSensor", attribute: "motion", value: it.currentValue("motion")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, capability: "MusicPlayer", attribute: "status", value: it.currentValue("status")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, capability: "MusicPlayer", attribute: "level", value: it.currentValue("level")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, capability: "MusicPlayer", attribute: "trackDescription", value: it.currentValue("trackDescription")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, capability: "MusicPlayer", attribute: "trackData", value: it.currentValue("trackData")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, capability: "MusicPlayer", attribute: "mute", value: it.currentValue("mute")]
|
|
||||||
}
|
|
||||||
|
|
||||||
powerMeters.each {
|
|
||||||
resp << [id: it.id, capability: "PowerMeter", attribute: "power", value: it.currentValue("power")]
|
|
||||||
}
|
|
||||||
|
|
||||||
presenceSensors.each {
|
|
||||||
resp << [id: it.id, capability: "PresenceSensor", attribute: "presence", value: it.currentValue("presence")]
|
|
||||||
}
|
|
||||||
|
|
||||||
relativeHumidityMeasurements.each {
|
|
||||||
resp << [id: it.id, capability: "RelativeHumidityMeasurement", attribute: "humidity", value: it.currentValue("humidity")]
|
|
||||||
}
|
|
||||||
|
|
||||||
relaySwitches.each {
|
|
||||||
resp << [id: it.id, capability: "RelaySwitch", attribute: "switch", value: it.currentValue("switch")]
|
|
||||||
}
|
|
||||||
|
|
||||||
signalStrengths.each {
|
|
||||||
resp << [id: it.id, capability: "SignalStrength", attribute: "lqi", value: it.currentValue("lqi")]
|
|
||||||
}
|
|
||||||
|
|
||||||
signalStrengths.each {
|
|
||||||
resp << [id: it.id, capability: "SignalStrength", attribute: "rssi", value: it.currentValue("rssi")]
|
|
||||||
}
|
|
||||||
|
|
||||||
sleepSensors.each {
|
|
||||||
resp << [id: it.id, capability: "SleepSensor", attribute: "sleeping", value: it.currentValue("sleeping")]
|
|
||||||
}
|
|
||||||
|
|
||||||
smokeDetectors.each {
|
|
||||||
resp << [id: it.id, capability: "SmokeDetector", attribute: "smoke", value: it.currentValue("smoke")]
|
|
||||||
}
|
|
||||||
|
|
||||||
stepSensors.each {
|
|
||||||
resp << [id: it.id, capability: "StepSensor", attribute: "steps", value: it.currentValue("steps")]
|
|
||||||
}
|
|
||||||
|
|
||||||
stepSensors.each {
|
|
||||||
resp << [id: it.id, capability: "StepSensor", attribute: "goal", value: it.currentValue("goal")]
|
|
||||||
}
|
|
||||||
|
|
||||||
switches.each {
|
|
||||||
resp << [id: it.id, capability: "Switch", attribute: "switch", value: it.currentValue("switch")]
|
|
||||||
}
|
|
||||||
|
|
||||||
switchLevels.each {
|
|
||||||
resp << [id: it.id, capability: "SwitchLevel", attribute: "level", value: it.currentValue("level")]
|
|
||||||
}
|
|
||||||
|
|
||||||
temperatureMeasurements.each {
|
|
||||||
resp << [id: it.id, capability: "TemperatureMeasurement", attribute: "temperature", value: it.currentValue("temperature")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, capability: "Thermostat", attribute: "temperature", value: it.currentValue("temperature")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, capability: "Thermostat", attribute: "heatingSetpoint", value: it.currentValue("heatingSetpoint")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, capability: "Thermostat", attribute: "coolingSetpoint", value: it.currentValue("coolingSetpoint")]
|
|
||||||
}
|
|
||||||
|
|
||||||
//Commented out on 7/23/2016. This randomly started throwing number format exceptions with either my ecobee or Lyric thermostat.
|
|
||||||
//thermostats.each {
|
|
||||||
// resp << [id: it.id, capability: "Thermostat", attribute: "thermostatSetpoint", value: it.currentValue("thermostatSetpoint")]
|
|
||||||
//}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, capability: "Thermostat", attribute: "thermostatMode", value: it.currentValue("thermostatMode")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, capability: "Thermostat", attribute: "thermostatFanMode", value: it.currentValue("thermostatFanMode")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, capability: "Thermostat", attribute: "thermostatOperatingState", value: it.currentValue("thermostatOperatingState")]
|
|
||||||
}
|
|
||||||
|
|
||||||
threeAxes.each {
|
|
||||||
resp << [id: it.id, capability: "ThreeAxis", attribute: "threeAxis", value: it.currentValue("threeAxis")]
|
|
||||||
}
|
|
||||||
|
|
||||||
touchSensors.each {
|
|
||||||
resp << [id: it.id, capability: "TouchSensor", attribute: "touch", value: it.currentValue("touch")]
|
|
||||||
}
|
|
||||||
|
|
||||||
valves.each {
|
|
||||||
resp << [id: it.id, capability: "Valve", attribute: "contact", value: it.currentValue("contact")]
|
|
||||||
}
|
|
||||||
|
|
||||||
waterSensors.each {
|
|
||||||
resp << [id: it.id, capability: "WaterSensor", attribute: "water", value: it.currentValue("water")]
|
|
||||||
}
|
|
||||||
|
|
||||||
//resp << [id: 0, capability: "Heartbeat", attribute: "heartbeat", value: String.valueOf(state.heartbeat)]
|
|
||||||
|
|
||||||
state.heartbeat = !state.heartbeat
|
|
||||||
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
|
|
||||||
def getCurrentValuesWithDisplayName() {
|
|
||||||
def resp = []
|
|
||||||
|
|
||||||
accelerationSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "AccelerationSensor", attribute: "acceleration", value: it.currentValue("acceleration")]
|
|
||||||
}
|
|
||||||
|
|
||||||
alarms.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Alarm", attribute: "alarm", value: it.currentValue("alarm")]
|
|
||||||
}
|
|
||||||
|
|
||||||
batteries.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Battery", attribute: "battery", value: it.currentValue("battery")]
|
|
||||||
}
|
|
||||||
|
|
||||||
beacons.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Beacon", attribute: "presence", value: it.currentValue("presence")]
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonGroup.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Button", attribute: "button", value: it.currentValue("button")]
|
|
||||||
}
|
|
||||||
|
|
||||||
carbonMonoxideDetectors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "CarbonMonoxideDetector", attribute: "carbonMonoxide", value: it.currentValue("carbonMonoxide")]
|
|
||||||
}
|
|
||||||
|
|
||||||
colorControls.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "ColorControl", attribute: "hue", value: it.currentValue("hue")]
|
|
||||||
}
|
|
||||||
|
|
||||||
colorControls.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "ColorControl", attribute: "saturation", value: it.currentValue("saturation")]
|
|
||||||
}
|
|
||||||
|
|
||||||
colorControls.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "ColorControl", attribute: "color", value: it.currentValue("color")]
|
|
||||||
}
|
|
||||||
|
|
||||||
contactSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "ContactSensor", attribute: "contact", value: it.currentValue("contact")]
|
|
||||||
}
|
|
||||||
|
|
||||||
doorControls.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "DoorControl", attribute: "door", value: it.currentValue("door")]
|
|
||||||
}
|
|
||||||
|
|
||||||
energyMeters.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "EnergyMeter", attribute: "energy", value: it.currentValue("energy")]
|
|
||||||
}
|
|
||||||
|
|
||||||
illuminanceMeasurements.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "IlluminanceMeasurement", attribute: "illuminance", value: it.currentValue("illuminance")]
|
|
||||||
}
|
|
||||||
|
|
||||||
imageCaptures.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "ImageCapture", attribute: "image", value: it.currentValue("image")]
|
|
||||||
}
|
|
||||||
|
|
||||||
locks.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Lock", attribute: "lock", value: it.currentValue("lock")]
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaControllers.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MediaController", attribute: "activities", value: it.currentValue("activities")]
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaControllers.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MediaController", attribute: "currentActivity", value: it.currentValue("currentActivity")]
|
|
||||||
}
|
|
||||||
|
|
||||||
motionSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MotionSensor", attribute: "motion", value: it.currentValue("motion")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "status", value: it.currentValue("status")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "level", value: it.currentValue("level")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "trackDescription", value: it.currentValue("trackDescription")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "trackData", value: it.currentValue("trackData")]
|
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayers.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "mute", value: it.currentValue("mute")]
|
|
||||||
}
|
|
||||||
|
|
||||||
powerMeters.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "PowerMeter", attribute: "power", value: it.currentValue("power")]
|
|
||||||
}
|
|
||||||
|
|
||||||
presenceSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "PresenceSensor", attribute: "presence", value: it.currentValue("presence")]
|
|
||||||
}
|
|
||||||
|
|
||||||
relativeHumidityMeasurements.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "RelativeHumidityMeasurement", attribute: "humidity", value: it.currentValue("humidity")]
|
|
||||||
}
|
|
||||||
|
|
||||||
relaySwitches.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "RelaySwitch", attribute: "switch", value: it.currentValue("switch")]
|
|
||||||
}
|
|
||||||
|
|
||||||
signalStrengths.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "SignalStrength", attribute: "lqi", value: it.currentValue("lqi")]
|
|
||||||
}
|
|
||||||
|
|
||||||
signalStrengths.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "SignalStrength", attribute: "rssi", value: it.currentValue("rssi")]
|
|
||||||
}
|
|
||||||
|
|
||||||
sleepSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "SleepSensor", attribute: "sleeping", value: it.currentValue("sleeping")]
|
|
||||||
}
|
|
||||||
|
|
||||||
smokeDetectors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "SmokeDetector", attribute: "smoke", value: it.currentValue("smoke")]
|
|
||||||
}
|
|
||||||
|
|
||||||
stepSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "StepSensor", attribute: "steps", value: it.currentValue("steps")]
|
|
||||||
}
|
|
||||||
|
|
||||||
stepSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "StepSensor", attribute: "goal", value: it.currentValue("goal")]
|
|
||||||
}
|
|
||||||
|
|
||||||
switches.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Switch", attribute: "switch", value: it.currentValue("switch")]
|
|
||||||
}
|
|
||||||
|
|
||||||
switchLevels.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "SwitchLevel", attribute: "level", value: it.currentValue("level")]
|
|
||||||
}
|
|
||||||
|
|
||||||
temperatureMeasurements.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "TemperatureMeasurement", attribute: "temperature", value: it.currentValue("temperature")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "temperature", value: it.currentValue("temperature")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "heatingSetpoint", value: it.currentValue("heatingSetpoint")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "coolingSetpoint", value: it.currentValue("coolingSetpoint")]
|
|
||||||
}
|
|
||||||
|
|
||||||
//Commented out on 7/23/2016. This randomly started throwing number format exceptions with either my ecobee or Lyric thermostat.
|
|
||||||
//thermostats.each {
|
|
||||||
// resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatSetpoint", value: it.currentValue("thermostatSetpoint")]
|
|
||||||
//}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatMode", value: it.currentValue("thermostatMode")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatFanMode", value: it.currentValue("thermostatFanMode")]
|
|
||||||
}
|
|
||||||
|
|
||||||
thermostats.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatOperatingState", value: it.currentValue("thermostatOperatingState")]
|
|
||||||
}
|
|
||||||
|
|
||||||
threeAxes.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "ThreeAxis", attribute: "threeAxis", value: it.currentValue("threeAxis")]
|
|
||||||
}
|
|
||||||
|
|
||||||
touchSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "TouchSensor", attribute: "touch", value: it.currentValue("touch")]
|
|
||||||
}
|
|
||||||
|
|
||||||
valves.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Valve", attribute: "contact", value: it.currentValue("contact")]
|
|
||||||
}
|
|
||||||
|
|
||||||
waterSensors.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "WaterSensor", attribute: "water", value: it.currentValue("water")]
|
|
||||||
}
|
|
||||||
|
|
||||||
momentaries.each {
|
|
||||||
resp << [id: it.id, displayName: it.displayName, capability: "Momentary", attribute: "", value: ""]
|
|
||||||
}
|
|
||||||
|
|
||||||
//resp << [id: 0, displayName: "Heartbeat", capability: "Heartbeat", attribute: "heartbeat", value: state.heartbeat]
|
|
||||||
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
|
|
||||||
def getDevices(capability){
|
|
||||||
|
|
||||||
def result
|
|
||||||
|
|
||||||
switch (capability) {
|
|
||||||
case "Alarm":
|
|
||||||
result = alarms
|
|
||||||
break
|
|
||||||
case "ColorControl":
|
|
||||||
result = colorControls
|
|
||||||
break
|
|
||||||
case "DoorControl":
|
|
||||||
result = doorControls
|
|
||||||
break
|
|
||||||
case "ImageCapture":
|
|
||||||
result = imageCaptures
|
|
||||||
break
|
|
||||||
case "Lock":
|
|
||||||
result = locks
|
|
||||||
break
|
|
||||||
case "MediaController":
|
|
||||||
result = mediaControllers
|
|
||||||
break
|
|
||||||
case "Momentary":
|
|
||||||
result = momentaries
|
|
||||||
break
|
|
||||||
case "MusicPlayer":
|
|
||||||
result = musicPlayers
|
|
||||||
break
|
|
||||||
case "RelaySwitch":
|
|
||||||
result = relaySwitches
|
|
||||||
break
|
|
||||||
case "SpeechSynthesis":
|
|
||||||
result = speechSyntheses
|
|
||||||
break
|
|
||||||
case "Switch":
|
|
||||||
result = switches
|
|
||||||
break
|
|
||||||
case "SwitchLevel":
|
|
||||||
result = switchLevels
|
|
||||||
break
|
|
||||||
case "Thermostat":
|
|
||||||
result = thermostats
|
|
||||||
break
|
|
||||||
case "ThermostatCoolingSetpoint":
|
|
||||||
result = thermostatCoolingSetpoints
|
|
||||||
break
|
|
||||||
case "ThermostatFanMode":
|
|
||||||
result = thermostatFanModes
|
|
||||||
break
|
|
||||||
case "ThermostatHeatingSetpoint":
|
|
||||||
result = thermostatHeatingSetpoints
|
|
||||||
break
|
|
||||||
case "ThermostatMode":
|
|
||||||
result = thermostatModes
|
|
||||||
break
|
|
||||||
case "Tone":
|
|
||||||
result = tones
|
|
||||||
break
|
|
||||||
case "Valve":
|
|
||||||
result = valves
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
result = valves
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def getDoorControlCommand(value){
|
|
||||||
def result
|
|
||||||
switch (value) {
|
|
||||||
case "closed":
|
|
||||||
result = "close"
|
|
||||||
break
|
|
||||||
case "open":
|
|
||||||
result = "open"
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
result = value
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def getLockCommand(value){
|
|
||||||
def result
|
|
||||||
switch (value) {
|
|
||||||
case "locked":
|
|
||||||
result = "lock"
|
|
||||||
break
|
|
||||||
case "unlocked":
|
|
||||||
result = "unlock"
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
result = value
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def getMuteCommand(value){
|
|
||||||
def result
|
|
||||||
switch (value) {
|
|
||||||
case "muted":
|
|
||||||
result = "mute"
|
|
||||||
break
|
|
||||||
case "unmuted":
|
|
||||||
result = "unmute"
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
result = value
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def getContactCommand(value){
|
|
||||||
def result
|
|
||||||
switch (value) {
|
|
||||||
case "closed":
|
|
||||||
result = "close"
|
|
||||||
break
|
|
||||||
case "open":
|
|
||||||
result = "open"
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
result = value
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def getRoutines() {
|
|
||||||
return location.helloHome?.getPhrases()*.label
|
|
||||||
}
|
|
||||||
|
|
||||||
def getThermostatFanModeCommand(value){
|
|
||||||
def result
|
|
||||||
switch (value) {
|
|
||||||
case "on":
|
|
||||||
result = "fanOn"
|
|
||||||
break
|
|
||||||
case "auto":
|
|
||||||
result = "fanAuto"
|
|
||||||
break
|
|
||||||
case "circulate":
|
|
||||||
result = "fanCirculate"
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
result = value
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
void executeCommand() {
|
|
||||||
def deviceId = request.JSON?.deviceId
|
|
||||||
def capability = request.JSON?.capability
|
|
||||||
def attribute = request.JSON?.attribute
|
|
||||||
def value = request.JSON?.value
|
|
||||||
if (deviceId) {
|
|
||||||
def devices = getDevices(capability)
|
|
||||||
def command
|
|
||||||
def valueIsParameter = false
|
|
||||||
def valueIsInteger = false
|
|
||||||
switch (attribute) {
|
|
||||||
case "hue":
|
|
||||||
command = "setHue"
|
|
||||||
valueIsParameter = true
|
|
||||||
valueIsInteger = true
|
|
||||||
break
|
|
||||||
case "saturation":
|
|
||||||
command = "setSaturation"
|
|
||||||
valueIsParameter = true
|
|
||||||
valueIsInteger = true
|
|
||||||
break
|
|
||||||
case "color":
|
|
||||||
command = "setColor"
|
|
||||||
def rgb = hexToRgb(value)
|
|
||||||
def hsl = rgbToHSL(rgb)
|
|
||||||
value = [hue:hsl.h.toInteger(), saturation:hsl.s.toInteger()]
|
|
||||||
valueIsParameter = true
|
|
||||||
break
|
|
||||||
case "level":
|
|
||||||
command = "setLevel"
|
|
||||||
valueIsParameter = true
|
|
||||||
valueIsInteger = true
|
|
||||||
break
|
|
||||||
case "heatingSetpoint":
|
|
||||||
command = "setHeatingSetpoint"
|
|
||||||
valueIsParameter = true
|
|
||||||
break
|
|
||||||
case "coolingSetpoint":
|
|
||||||
command = "setCoolingSetpoint"
|
|
||||||
valueIsParameter = true
|
|
||||||
break
|
|
||||||
case "currentActivity":
|
|
||||||
command = "startActivity"
|
|
||||||
valueIsParameter = true
|
|
||||||
break
|
|
||||||
case "door":
|
|
||||||
command = getDoorControlCommand(value)
|
|
||||||
break
|
|
||||||
case "lock":
|
|
||||||
command = getLockCommand(value)
|
|
||||||
break
|
|
||||||
case "mute":
|
|
||||||
command = getMuteCommand(value)
|
|
||||||
break
|
|
||||||
case "thermostatFanMode":
|
|
||||||
command = getThermostatFanModeCommand(value)
|
|
||||||
break
|
|
||||||
case "thermostatMode":
|
|
||||||
if (value == "emergency heat") {
|
|
||||||
command = "emergencyHeat"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
command = value
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case "contact":
|
|
||||||
command = getContactCommand(value)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
command = value
|
|
||||||
}
|
|
||||||
devices.each {
|
|
||||||
if (it.id == deviceId) {
|
|
||||||
// check that the device supports the specified command
|
|
||||||
// If not, return an error using httpError, providing a HTTP status code.
|
|
||||||
if (!it.hasCommand(command)) {
|
|
||||||
httpError(501, "$command is not a valid command for the device")
|
|
||||||
}
|
|
||||||
if(valueIsParameter){
|
|
||||||
if(valueIsInteger){
|
|
||||||
it."$command"(value as int)
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
it."$command"(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
it."$command"()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void executeRoutine() {
|
|
||||||
def routine = request.JSON?.routine
|
|
||||||
location.helloHome?.execute(routine)
|
|
||||||
}
|
|
||||||
|
|
||||||
def rgbToHSL(rgb) {
|
|
||||||
def r = rgb.r / 255
|
|
||||||
def g = rgb.g / 255
|
|
||||||
def b = rgb.b / 255
|
|
||||||
def h = 0
|
|
||||||
def s = 0
|
|
||||||
def l = 0
|
|
||||||
|
|
||||||
def var_min = [r,g,b].min()
|
|
||||||
def var_max = [r,g,b].max()
|
|
||||||
def del_max = var_max - var_min
|
|
||||||
|
|
||||||
l = (var_max + var_min) / 2
|
|
||||||
|
|
||||||
if (del_max == 0) {
|
|
||||||
h = 0
|
|
||||||
s = 0
|
|
||||||
} else {
|
|
||||||
if (l < 0.5) { s = del_max / (var_max + var_min) }
|
|
||||||
else { s = del_max / (2 - var_max - var_min) }
|
|
||||||
|
|
||||||
def del_r = (((var_max - r) / 6) + (del_max / 2)) / del_max
|
|
||||||
def del_g = (((var_max - g) / 6) + (del_max / 2)) / del_max
|
|
||||||
def del_b = (((var_max - b) / 6) + (del_max / 2)) / del_max
|
|
||||||
|
|
||||||
if (r == var_max) { h = del_b - del_g }
|
|
||||||
else if (g == var_max) { h = (1 / 3) + del_r - del_b }
|
|
||||||
else if (b == var_max) { h = (2 / 3) + del_g - del_r }
|
|
||||||
|
|
||||||
if (h < 0) { h += 1 }
|
|
||||||
if (h > 1) { h -= 1 }
|
|
||||||
}
|
|
||||||
def hsl = [:]
|
|
||||||
hsl = [h: h * 100, s: s * 100, l: l]
|
|
||||||
|
|
||||||
hsl
|
|
||||||
}
|
|
||||||
|
|
||||||
def hexToRgb(colorHex) {
|
|
||||||
def rrInt = Integer.parseInt(colorHex.substring(1,3),16)
|
|
||||||
def ggInt = Integer.parseInt(colorHex.substring(3,5),16)
|
|
||||||
def bbInt = Integer.parseInt(colorHex.substring(5,7),16)
|
|
||||||
|
|
||||||
def colorData = [:]
|
|
||||||
colorData = [r: rrInt, g: ggInt, b: bbInt]
|
|
||||||
colorData
|
|
||||||
}
|
|
||||||
|
|
||||||
def installed() {
|
|
||||||
state.heartbeat = false
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
state.heartbeat = false
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user