mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-17 21:03:30 +00:00
Compare commits
3 Commits
PROD_2016.
...
MSA-1435-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f3c29bc91 | ||
|
|
c7396349f1 | ||
|
|
089cc1a5dd |
@@ -1,8 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Iris Smart Fob
|
* ZigBee Button
|
||||||
*
|
*
|
||||||
* Copyright 2015 Mitch Pond
|
* Copyright 2015 Mitch Pond
|
||||||
* Presence code adapted from SmartThings Arrival Sensor HA device type
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
* 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:
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
@@ -14,181 +13,235 @@
|
|||||||
* for the specific language governing permissions and limitations under the License.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "ZigBee Button", namespace: "smartthings", author: "Mitch Pond") {
|
definition (name: "ZigBee Button", namespace: "smartthings", author: "Mitch Pond") {
|
||||||
capability "Battery"
|
capability "Actuator"
|
||||||
capability "Button"
|
capability "Battery"
|
||||||
|
capability "Button"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Presence Sensor"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
//fingerprint endpointId: "01", profileId: "0104", inClusters: "0000,0001,0003,0007,0020,0B05", outClusters: "0003,0006,0019", model:"3450-L", manufacturer: "CentraLite"
|
command "enrollResponse"
|
||||||
}
|
|
||||||
|
|
||||||
preferences{
|
fingerprint inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "OSRAM", model: "LIGHTIFY Dimming Switch", deviceJoinName: "OSRAM LIGHTIFY Dimming Switch"
|
||||||
input ("holdTime", "number", title: "Minimum time in seconds for a press to count as \"held\"",
|
//fingerprint inClusters: "0000, 0001, 0003, 0020, 0500", outClusters: "0003,0019", manufacturer: "CentraLite", model: "3455-L", deviceJoinName: "Iris Care Pendant"
|
||||||
defaultValue: 3, displayDuringSetup: false)
|
//fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0402, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model: "3460-L", deviceJoinName: "Iris Smart Button"
|
||||||
input "checkInterval", "enum", title: "Presence timeout (minutes)",
|
//fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L", deviceJoinName: "Iris KeyFob"
|
||||||
defaultValue:"2", options: ["2", "3", "5"], displayDuringSetup: false
|
|
||||||
input "logging", "bool", title: "Enable debug logging",
|
|
||||||
defaultValue: false, displayDuringSetup: false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
simulator {}
|
||||||
standardTile("presence", "device.presence", width: 4, height: 4, canChangeBackground: true) {
|
|
||||||
state "present", label: "Present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
|
||||||
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
|
|
||||||
}
|
|
||||||
standardTile("button", "device.button", decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
|
|
||||||
}
|
|
||||||
valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
|
||||||
}
|
|
||||||
|
|
||||||
main (["presence"])
|
preferences {
|
||||||
details(["presence","button","battery"])
|
section {
|
||||||
}
|
input ("holdTime", "number", title: "Minimum time in seconds for a press to count as \"held\"", defaultValue: 1, displayDuringSetup: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles {
|
||||||
|
standardTile("button", "device.button", width: 2, height: 2) {
|
||||||
|
state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
|
||||||
|
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
|
||||||
|
}
|
||||||
|
|
||||||
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
|
||||||
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
|
||||||
|
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
main (["button"])
|
||||||
|
details(["button", "battery", "refresh"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
def descMap = zigbee.parseDescriptionAsMap(description)
|
log.debug "description is $description"
|
||||||
logIt descMap
|
def event = zigbee.getEvent(description)
|
||||||
state.lastCheckin = now()
|
if (event) {
|
||||||
logIt "lastCheckin = ${state.lastCheckin}"
|
sendEvent(event)
|
||||||
handlePresenceEvent(true)
|
}
|
||||||
|
else {
|
||||||
|
if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) {
|
||||||
|
def descMap = zigbee.parseDescriptionAsMap(description)
|
||||||
|
if (descMap.clusterInt == 0x0001 && descMap.attrInt == 0x0020) {
|
||||||
|
event = getBatteryResult(zigbee.convertHexToInt(descMap.value))
|
||||||
|
}
|
||||||
|
else if (descMap.clusterInt == 0x0006 || descMap.clusterInt == 0x0008) {
|
||||||
|
event = parseNonIasButtonMessage(descMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (description?.startsWith('zone status')) {
|
||||||
|
event = parseIasButtonMessage(description)
|
||||||
|
}
|
||||||
|
|
||||||
def results = []
|
log.debug "Parse returned $event"
|
||||||
if (description?.startsWith('catchall:'))
|
def result = event ? createEvent(event) : []
|
||||||
results = parseCatchAllMessage(descMap)
|
|
||||||
else if (description?.startsWith('read attr -'))
|
|
||||||
results = parseReportAttributeMessage(descMap)
|
|
||||||
else logIt(descMap, "trace")
|
|
||||||
|
|
||||||
return results;
|
if (description?.startsWith('enroll request')) {
|
||||||
|
List cmds = enrollResponse()
|
||||||
|
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map parseIasButtonMessage(String description) {
|
||||||
|
int zoneInt = Integer.parseInt((description - "zone status 0x"), 16)
|
||||||
|
if (zoneInt & 0x02) {
|
||||||
|
resultMap = getButtonResult('press')
|
||||||
|
} else {
|
||||||
|
resultMap = getButtonResult('release')
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultMap
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map getBatteryResult(rawValue) {
|
||||||
|
log.debug 'Battery'
|
||||||
|
def volts = rawValue / 10
|
||||||
|
if (volts > 3.0 || volts == 0 || rawValue == 0xFF) {
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
def result = [
|
||||||
|
name: 'battery'
|
||||||
|
]
|
||||||
|
def minVolts = 2.1
|
||||||
|
def maxVolts = 3.0
|
||||||
|
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
||||||
|
result.value = Math.min(100, (int) pct * 100)
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
result.descriptionText = "${linkText} battery was ${result.value}%"
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map parseNonIasButtonMessage(Map descMap){
|
||||||
|
def buttonState = ""
|
||||||
|
def buttonNumber = 0
|
||||||
|
if (((device.getDataValue("model") == "3460-L") || (device.getDataValue("model") == "3450-L"))
|
||||||
|
&&(descMap.clusterInt == 0x0006)) {
|
||||||
|
if (descMap.command == "01") {
|
||||||
|
getButtonResult("press")
|
||||||
|
}
|
||||||
|
else if (descMap.command == "00") {
|
||||||
|
getButtonResult("release")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (descMap.clusterInt == 0x0006) {
|
||||||
|
buttonState = "pushed"
|
||||||
|
if (descMap.command == "01") {
|
||||||
|
buttonNumber = 1
|
||||||
|
}
|
||||||
|
else if (descMap.command == "00") {
|
||||||
|
buttonNumber = 2
|
||||||
|
}
|
||||||
|
if (buttonNumber !=0) {
|
||||||
|
def descriptionText = "$device.displayName button $buttonNumber was $buttonState"
|
||||||
|
return createEvent(name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (descMap.clusterInt == 0x0008) {
|
||||||
|
if (descMap.command == "05") {
|
||||||
|
state.buttonNumber = 1
|
||||||
|
getButtonResult("press", 1)
|
||||||
|
}
|
||||||
|
else if (descMap.command == "01") {
|
||||||
|
state.buttonNumber = 2
|
||||||
|
getButtonResult("press", 2)
|
||||||
|
}
|
||||||
|
else if (descMap.command == "03") {
|
||||||
|
getButtonResult("release", state.buttonNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def refresh() {
|
||||||
|
log.debug "Refreshing Battery"
|
||||||
|
|
||||||
|
return zigbee.readAttribute(0x0001, 0x20) +
|
||||||
|
zigbee.enrollResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
def configure() {
|
||||||
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
|
def cmds = []
|
||||||
|
if (device.getDataValue("model") == "3450-L") {
|
||||||
|
cmds << [
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 300",
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 2 1 6 {${device.zigbeeId}} {}", "delay 300",
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 3 1 6 {${device.zigbeeId}} {}", "delay 300",
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 4 1 6 {${device.zigbeeId}} {}", "delay 300"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return zigbee.onOffConfig() +
|
||||||
|
zigbee.levelConfig() +
|
||||||
|
zigbee.configureReporting(0x0001, 0x20, 0x20, 30, 21600, 0x01) +
|
||||||
|
zigbee.enrollResponse() +
|
||||||
|
zigbee.readAttribute(0x0001, 0x20) +
|
||||||
|
cmds
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map getButtonResult(buttonState, buttonNumber = 1) {
|
||||||
|
if (buttonState == 'release') {
|
||||||
|
log.debug "Button was value : $buttonState"
|
||||||
|
def timeDiff = now() - state.pressTime
|
||||||
|
log.info "timeDiff: $timeDiff"
|
||||||
|
def holdPreference = holdTime ?: 1
|
||||||
|
log.info "holdp1 : $holdPreference"
|
||||||
|
holdPreference = (holdPreference as int) * 1000
|
||||||
|
log.info "holdp2 : $holdPreference"
|
||||||
|
if (timeDiff > 10000) { //timeDiff>10sec check for refresh sending release value causing actions to be executed
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (timeDiff < holdPreference) {
|
||||||
|
buttonState = "pushed"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buttonState = "held"
|
||||||
|
}
|
||||||
|
def descriptionText = "$device.displayName button $buttonNumber was $buttonState"
|
||||||
|
return createEvent(name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (buttonState == 'press') {
|
||||||
|
log.debug "Button was value : $buttonState"
|
||||||
|
state.pressTime = now()
|
||||||
|
log.info "presstime: ${state.pressTime}"
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
startTimer()
|
initialize()
|
||||||
configure()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure(){
|
def initialize() {
|
||||||
logIt "Configuring Smart Fob..."
|
if ((device.getDataValue("manufacturer") == "OSRAM") && (device.getDataValue("model") == "LIGHTIFY Dimming Switch")) {
|
||||||
[
|
sendEvent(name: "numberOfButtons", value: 2)
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 2 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 3 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 4 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 200"
|
|
||||||
] +
|
|
||||||
zigbee.configureReporting(0x0001,0x0020,0x20,20,20,0x01)
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseCatchAllMessage(descMap) {
|
|
||||||
if (descMap?.clusterId == "0006" && descMap?.command == "01") //button pressed
|
|
||||||
handleButtonPress(descMap.sourceEndpoint as int)
|
|
||||||
else if (descMap?.clusterId == "0006" && descMap?.command == "00") //button released
|
|
||||||
handleButtonRelease(descMap.sourceEndpoint as int)
|
|
||||||
else logIt("Parse: Unhandled message: ${descMap}","trace")
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseReportAttributeMessage(descMap) {
|
|
||||||
if (descMap?.cluster == "0001" && descMap?.attrId == "0020") createBatteryEvent(getBatteryLevel(descMap.value))
|
|
||||||
else logIt descMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private createBatteryEvent(percent) {
|
|
||||||
logIt "Battery level at " + percent
|
|
||||||
return createEvent([name: "battery", value: percent])
|
|
||||||
}
|
|
||||||
|
|
||||||
//this method determines if a press should count as a push or a hold and returns the relevant event type
|
|
||||||
private handleButtonRelease(button) {
|
|
||||||
logIt "lastPress state variable: ${state.lastPress}"
|
|
||||||
def sequenceError = {logIt("Uh oh...missed a message? Dropping this event.", "error"); state.lastPress = null; return []}
|
|
||||||
|
|
||||||
if (!state.lastPress) return sequenceError()
|
|
||||||
else if (state.lastPress.button != button) return sequenceError()
|
|
||||||
|
|
||||||
def currentTime = now()
|
|
||||||
def startOfPress = state.lastPress?.time
|
|
||||||
def timeDif = currentTime - startOfPress
|
|
||||||
def holdTimeMillisec = (settings.holdTime?:3).toInteger() * 1000
|
|
||||||
|
|
||||||
state.lastPress = null //we're done with this. clear it to make error conditions easier to catch
|
|
||||||
|
|
||||||
if (timeDif < 0)
|
|
||||||
//likely a message sequence issue or dropped packet. Drop this press and wait for another.
|
|
||||||
return sequenceError()
|
|
||||||
else if (timeDif < holdTimeMillisec)
|
|
||||||
return createButtonEvent(button,"pushed")
|
|
||||||
else
|
|
||||||
return createButtonEvent(button,"held")
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleButtonPress(button) {
|
|
||||||
state.lastPress = [button: button, time: now()]
|
|
||||||
}
|
|
||||||
|
|
||||||
private createButtonEvent(button,action) {
|
|
||||||
logIt "Button ${button} ${action}"
|
|
||||||
return createEvent([
|
|
||||||
name: "button",
|
|
||||||
value: action,
|
|
||||||
data:[buttonNumber: button],
|
|
||||||
descriptionText: "${device.displayName} button ${button} was ${action}",
|
|
||||||
isStateChange: true,
|
|
||||||
displayed: true])
|
|
||||||
}
|
|
||||||
|
|
||||||
private getBatteryLevel(rawValue) {
|
|
||||||
def intValue = Integer.parseInt(rawValue,16)
|
|
||||||
def min = 2.1
|
|
||||||
def max = 3.0
|
|
||||||
def vBatt = intValue / 10
|
|
||||||
return ((vBatt - min) / (max - min) * 100) as int
|
|
||||||
}
|
|
||||||
|
|
||||||
private handlePresenceEvent(present) {
|
|
||||||
def wasPresent = device.currentState("presence")?.value == "present"
|
|
||||||
if (!wasPresent && present) {
|
|
||||||
logIt "Sensor is present"
|
|
||||||
startTimer()
|
|
||||||
} else if (!present) {
|
|
||||||
logIt "Sensor is not present"
|
|
||||||
stopTimer()
|
|
||||||
}
|
}
|
||||||
def linkText = getLinkText(device)
|
else if ((device.getDataValue("manufacturer") == "CentraLite") &&
|
||||||
def eventMap = [
|
((device.getDataValue("model") == "3455-L") || (device.getDataValue("model") == "3460-L"))) {
|
||||||
name: "presence",
|
sendEvent(name: "numberOfButtons", value: 1)
|
||||||
value: present ? "present" : "not present",
|
|
||||||
linkText: linkText,
|
|
||||||
descriptionText: "${linkText} has ${present ? 'arrived' : 'left'}",
|
|
||||||
]
|
|
||||||
logIt "Creating presence event: ${eventMap}"
|
|
||||||
sendEvent(eventMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
private startTimer() {
|
|
||||||
logIt "Scheduling periodic timer"
|
|
||||||
schedule("0 * * * * ?", checkPresenceCallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
private stopTimer() {
|
|
||||||
logIt "Stopping periodic timer"
|
|
||||||
unschedule()
|
|
||||||
}
|
|
||||||
|
|
||||||
def checkPresenceCallback() {
|
|
||||||
def timeSinceLastCheckin = (now() - state.lastCheckin) / 1000
|
|
||||||
def theCheckInterval = (checkInterval ? checkInterval as int : 2) * 60
|
|
||||||
logIt "Sensor checked in ${timeSinceLastCheckin} seconds ago"
|
|
||||||
if (timeSinceLastCheckin >= theCheckInterval) {
|
|
||||||
handlePresenceEvent(false)
|
|
||||||
}
|
}
|
||||||
|
else if ((device.getDataValue("manufacturer") == "CentraLite") && (device.getDataValue("model") == "3450-L")) {
|
||||||
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//default. can be changed
|
||||||
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****** Utility functions ******
|
|
||||||
|
|
||||||
private logIt(str, logLevel = 'debug') {if (settings.logging) log."$logLevel"(str) }
|
|
||||||
520
smartapps/ucic-io/ubi.src/ubi.groovy
Normal file
520
smartapps/ucic-io/ubi.src/ubi.groovy
Normal file
@@ -0,0 +1,520 @@
|
|||||||
|
/**
|
||||||
|
* Ubi
|
||||||
|
*
|
||||||
|
* Copyright 2016 UCIC
|
||||||
|
*
|
||||||
|
* 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: "Ubi",
|
||||||
|
namespace: "ucic.io",
|
||||||
|
author: "UCIC",
|
||||||
|
description: "Connect Ubi with SmartThings",
|
||||||
|
category: "SmartThings Labs",
|
||||||
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/ubi-app-icn.png",
|
||||||
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ubi-app-icn@2x.png",
|
||||||
|
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ubi-app-icn@2x.png",
|
||||||
|
oauth: true)
|
||||||
|
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
section("Allow a web application to control these things...") {
|
||||||
|
input name: "switches", type: "capability.switch", title: "Which Switches?", multiple: true, required: false
|
||||||
|
input name: "motions", type: "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false
|
||||||
|
input name: "locks", type: "capability.lock", title: "Which Locks?", multiple: true, required: false
|
||||||
|
input name: "contactSensors", type: "capability.contactSensor", title: "Which Contact Sensors?", multiple: true, required: false
|
||||||
|
input name: "presenceSensors", type: "capability.presenceSensor", title: "Which Presence Sensors?", multiple: true, required: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mappings {
|
||||||
|
path("/list") {
|
||||||
|
action: [
|
||||||
|
GET: "listAll"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/events/:id") {
|
||||||
|
action: [
|
||||||
|
GET: "showEvents"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/switches") {
|
||||||
|
action: [
|
||||||
|
GET: "listSwitches",
|
||||||
|
PUT: "updateSwitches",
|
||||||
|
POST: "updateSwitches"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/switches/:id") {
|
||||||
|
action: [
|
||||||
|
GET: "showSwitch",
|
||||||
|
PUT: "updateSwitch",
|
||||||
|
POST: "updateSwitch"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/switches/subscriptions") {
|
||||||
|
//log.debug "switches added"
|
||||||
|
action: [
|
||||||
|
POST: "addSwitchSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/switches/subscriptions/:id") {
|
||||||
|
action: [
|
||||||
|
DELETE: "removeSwitchSubscription",
|
||||||
|
GET: "removeSwitchSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/motionSensors") {
|
||||||
|
action: [
|
||||||
|
GET: "listMotions",
|
||||||
|
PUT: "updateMotions",
|
||||||
|
POST: "updateMotions"
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/motionSensors/:id") {
|
||||||
|
action: [
|
||||||
|
GET: "showMotion",
|
||||||
|
PUT: "updateMotion",
|
||||||
|
POST: "updateMotion"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/motionSensors/subscriptions") {
|
||||||
|
//log.debug "motionSensors added"
|
||||||
|
action: [
|
||||||
|
POST: "addMotionSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/motionSensors/subscriptions/:id") {
|
||||||
|
//log.debug "motionSensors Deleted"
|
||||||
|
action: [
|
||||||
|
DELETE: "removeMotionSubscription",
|
||||||
|
GET: "removeMotionSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/locks") {
|
||||||
|
action: [
|
||||||
|
GET: "listLocks",
|
||||||
|
PUT: "updateLock",
|
||||||
|
POST: "updateLock"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/locks/:id") {
|
||||||
|
action: [
|
||||||
|
GET: "showLock",
|
||||||
|
PUT: "updateLock",
|
||||||
|
POST: "updateLock"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/locks/subscriptions") {
|
||||||
|
action: [
|
||||||
|
POST: "addLockSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/locks/subscriptions/:id") {
|
||||||
|
action: [
|
||||||
|
DELETE: "removeLockSubscription",
|
||||||
|
GET: "removeLockSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/contactSensors") {
|
||||||
|
action: [
|
||||||
|
GET: "listContactSensors",
|
||||||
|
PUT: "updateContactSensor",
|
||||||
|
POST: "updateContactSensor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/contactSensors/:id") {
|
||||||
|
action: [
|
||||||
|
GET: "showContactSensor",
|
||||||
|
PUT: "updateContactSensor",
|
||||||
|
POST: "updateContactSensor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/contactSensors/subscriptions") {
|
||||||
|
log.debug "contactSensors/subscriptions"
|
||||||
|
action: [
|
||||||
|
POST: "addContactSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/contactSensors/subscriptions/:id") {
|
||||||
|
action: [
|
||||||
|
DELETE: "removeContactSensorSubscription",
|
||||||
|
GET: "removeContactSensorSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/presenceSensors") {
|
||||||
|
action: [
|
||||||
|
GET: "listPresenceSensors",
|
||||||
|
PUT: "updatePresenceSensor",
|
||||||
|
POST: "updatePresenceSensor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/presenceSensors/:id") {
|
||||||
|
action: [
|
||||||
|
GET: "showPresenceSensor",
|
||||||
|
PUT: "updatePresenceSensor",
|
||||||
|
POST: "updatePresenceSensor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/presenceSensors/subscriptions") {
|
||||||
|
//log.debug "PresenceSensors/subscriptions"
|
||||||
|
action: [
|
||||||
|
POST: "addPresenceSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/presenceSensors/subscriptions/:id") {
|
||||||
|
action: [
|
||||||
|
DELETE: "removePresenceSensorSubscription",
|
||||||
|
GET: "removePresenceSensorSubscription"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/state") {
|
||||||
|
action: [
|
||||||
|
GET: "currentState"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
path("/phrases") {
|
||||||
|
action: [
|
||||||
|
GET: "listPhrases"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
path("/phrases/:phraseName") {
|
||||||
|
action: [
|
||||||
|
GET: "executePhrase",
|
||||||
|
POST: "executePhrase",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
log.debug "initialize, do nothing..."
|
||||||
|
}
|
||||||
|
|
||||||
|
def listAll() {
|
||||||
|
listSwitches() + listMotions() + listLocks() + listContactSensors() + listPresenceSensors()
|
||||||
|
}
|
||||||
|
|
||||||
|
def listContactSensors() {
|
||||||
|
contactSensors.collect { device(it, "contactSensor") }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void updateContactSensors() {
|
||||||
|
updateAll(contactSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
def showContactSensor() {
|
||||||
|
show(contactSensors, "contact")
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateContactSensor() {
|
||||||
|
update(contactSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
def addContactSubscription() {
|
||||||
|
log.debug "addContactSensorSubscription, params: ${params}"
|
||||||
|
addSubscription(contactSensors, "contact")
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeContactSensorSubscription() {
|
||||||
|
removeSubscription(contactSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def listPresenceSensors() {
|
||||||
|
presenceSensors.collect { device(it, "presenceSensor") }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void updatePresenceSensors() {
|
||||||
|
updateAll(presenceSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
def showPresenceSensor() {
|
||||||
|
show(presenceSensors, "presence")
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePresenceSensor() {
|
||||||
|
update(presenceSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
def addPresenceSubscription() {
|
||||||
|
log.debug "addPresenceSensorSubscription, params: ${params}"
|
||||||
|
addSubscription(presenceSensors, "presence")
|
||||||
|
}
|
||||||
|
|
||||||
|
def removePresenceSensorSubscription() {
|
||||||
|
removeSubscription(presenceSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def listSwitches() {
|
||||||
|
switches.collect { device(it, "switch") }
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSwitches() {
|
||||||
|
updateAll(switches)
|
||||||
|
}
|
||||||
|
|
||||||
|
def showSwitch() {
|
||||||
|
show(switches, "switch")
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSwitch() {
|
||||||
|
update(switches)
|
||||||
|
}
|
||||||
|
|
||||||
|
def addSwitchSubscription() {
|
||||||
|
log.debug "addSwitchSubscription, params: ${params}"
|
||||||
|
addSubscription(switches, "switch")
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeSwitchSubscription() {
|
||||||
|
removeSubscription(switches)
|
||||||
|
}
|
||||||
|
|
||||||
|
def listMotions() {
|
||||||
|
motions.collect { device(it, "motionSensor") }
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMotions() {
|
||||||
|
updateAll(motions)
|
||||||
|
}
|
||||||
|
|
||||||
|
def showMotion() {
|
||||||
|
show(motions, "motion")
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMotion() {
|
||||||
|
update(motions)
|
||||||
|
}
|
||||||
|
|
||||||
|
def addMotionSubscription() {
|
||||||
|
|
||||||
|
addSubscription(motions, "motion")
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeMotionSubscription() {
|
||||||
|
removeSubscription(motions)
|
||||||
|
}
|
||||||
|
|
||||||
|
def listLocks() {
|
||||||
|
locks.collect { device(it, "lock") }
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLocks() {
|
||||||
|
updateAll(locks)
|
||||||
|
}
|
||||||
|
|
||||||
|
def showLock() {
|
||||||
|
show(locks, "lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLock() {
|
||||||
|
update(locks)
|
||||||
|
}
|
||||||
|
|
||||||
|
def addLockSubscription() {
|
||||||
|
addSubscription(locks, "lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
def removeLockSubscription() {
|
||||||
|
removeSubscription(locks)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
def motionOpenHandler(evt) {
|
||||||
|
//log.trace "$evt.value: $evt, $settings"
|
||||||
|
|
||||||
|
log.debug "$motions was active, sending push message to user"
|
||||||
|
//sendPush("Your ${contact1.label ?: contact1.name} was opened")
|
||||||
|
|
||||||
|
|
||||||
|
httpPostJson(uri: "http://automatesolutions.ca/test.php", path: '', body: [evt: [value: "motionSensor Active"]]) {
|
||||||
|
log.debug "Event data successfully posted"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
def contactOpenHandler(evt) {
|
||||||
|
//log.trace "$evt.value: $evt, $settings"
|
||||||
|
|
||||||
|
log.debug "$contactSensors was opened, sending push message to user"
|
||||||
|
//sendPush("Your ${contact1.label ?: contact1.name} was opened")
|
||||||
|
|
||||||
|
|
||||||
|
httpPostJson(uri: "http://automatesolutions.ca/test.php", path: '', body: [evt: [value: "ContactSensor Opened"]]) {
|
||||||
|
log.debug "Event data successfully posted"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
def deviceHandler(evt) {
|
||||||
|
log.debug "~~~~~TEST~~~~~~"
|
||||||
|
def deviceInfo = state[evt.deviceId]
|
||||||
|
if (deviceInfo)
|
||||||
|
{
|
||||||
|
httpPostJson(uri: deviceInfo.callbackUrl, path: '', body: [evt: [value: evt.value]]) {
|
||||||
|
log.debug "Event data successfully posted"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.debug "No subscribed device found"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def currentState() {
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
def showStates() {
|
||||||
|
def device = (switches + motions + locks).find { it.id == params.id }
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
httpError(404, "Switch not found")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device.events(params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def listPhrases() {
|
||||||
|
location.helloHome.getPhrases().label
|
||||||
|
}
|
||||||
|
|
||||||
|
def executePhrase() {
|
||||||
|
def phraseName = params.phraseName
|
||||||
|
if (phraseName)
|
||||||
|
{
|
||||||
|
location.helloHome.execute(phraseName)
|
||||||
|
log.debug "executed phrase: $phraseName"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
httpError(404, "Phrase not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAll(devices) {
|
||||||
|
def command = request.JSON?.command
|
||||||
|
if (command)
|
||||||
|
{
|
||||||
|
command = command.toLowerCase()
|
||||||
|
devices."$command"()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(devices) {
|
||||||
|
log.debug "update, request: ${request.JSON}, params: ${params}, devices: $devices.id"
|
||||||
|
//def command = request.JSON?.command
|
||||||
|
def command = params.command
|
||||||
|
if (command)
|
||||||
|
{
|
||||||
|
command = command.toLowerCase()
|
||||||
|
def device = devices.find { it.id == params.id }
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
httpError(404, "Device not found")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device."$command"()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private show(devices, type) {
|
||||||
|
def device = devices.find { it.id == params.id }
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
httpError(404, "Device not found")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
def attributeName = type
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def s = device.currentState(attributeName)
|
||||||
|
[id: device.id, label: device.displayName, value: s?.value, unitTime: s?.date?.time, type: type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private addSubscription(devices, attribute) {
|
||||||
|
//def deviceId = request.JSON?.deviceId
|
||||||
|
//def callbackUrl = request.JSON?.callbackUrl
|
||||||
|
|
||||||
|
log.debug "addSubscription, params: ${params}"
|
||||||
|
|
||||||
|
def deviceId = params.deviceId
|
||||||
|
def callbackUrl = params.callbackUrl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def myDevice = devices.find { it.id == deviceId }
|
||||||
|
if (myDevice)
|
||||||
|
{
|
||||||
|
if (state[deviceId])
|
||||||
|
{
|
||||||
|
log.debug "Switch subscription already exists, unsubcribing"
|
||||||
|
unsubscribe(myDevice)
|
||||||
|
}
|
||||||
|
log.debug "Adding switch subscription" + callbackUrl
|
||||||
|
state[deviceId] = [callbackUrl: callbackUrl]
|
||||||
|
log.debug "Added state: $state"
|
||||||
|
subscribe(myDevice, attribute, deviceHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeSubscription(devices) {
|
||||||
|
def deviceId = params.id
|
||||||
|
def device = devices.find { it.id == deviceId }
|
||||||
|
if (device)
|
||||||
|
{
|
||||||
|
log.debug "Removing $device.displayName subscription"
|
||||||
|
state.remove(device.id)
|
||||||
|
unsubscribe(device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private device(it, type) {
|
||||||
|
it ? [id: it.id, label: it.displayName, type: type] : null
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user