Compare commits

..

6 Commits

Author SHA1 Message Date
Donald Kirker
eae2a9ca08 Remove 3axis tile definition from 1st gen multi. 2016-03-01 10:53:42 -08:00
Donald Kirker
0c87601c64 DVCSMP-1440 Remove three-axis values.
Remove 3axis tile definition as well.
2016-02-24 13:59:46 -08:00
Vinay Rao
a6bec43f2a Merge pull request #474 from tpmanley/bugfix/multi_cmd_failure
multi: Fix occasional failures in sending ZigBee commands during configure
2016-02-02 23:04:58 -04:00
Tom Manley
5ec82217ac multi: Fix occasional failures in sending ZigBee commands during configure
The missing delay after some of the commands was sometimes causing the
ZigBee command to fail.

Resolves:
    https://smartthings.atlassian.net/browse/DVCSMP-1225
2016-01-29 14:41:12 -06:00
Kristofer Schaller
3b89368d45 Merge pull request #467 from davidsulpy/master
New Initial State Event Streamer: removed buffering and sched-tasks
2016-01-25 13:08:51 -08:00
David Sulpy
12f6039de5 New Initial State Event Streamer: removed buffering and scheduled tasks for flushing buffer 2016-01-22 19:23:37 -06:00
4 changed files with 83 additions and 288 deletions

View File

@@ -1,177 +0,0 @@
/**
* Nest
*
* Copyright 2016 John Lister
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Nest", namespace: "smartthings-users", author: "John Lister") {
capability "Polling"
capability "Presence Sensor"
capability "Relative Humidity Measurement"
capability "Sensor"
capability "Thermostat"
attribute "temperatureUnit", "string"
command "away"
command "present"
command "setPresence"
command "heatingSetpointUp"
command "heatingSetpointDown"
command "coolingSetpointUp"
command "coolingSetpointDown"
command "setFahrenheit"
command "setCelsius"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
// TODO: define your main and details tiles here
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'presence' attribute
// TODO: handle 'humidity' attribute
// TODO: handle 'temperature' attribute
// TODO: handle 'heatingSetpoint' attribute
// TODO: handle 'coolingSetpoint' attribute
// TODO: handle 'thermostatSetpoint' attribute
// TODO: handle 'thermostatMode' attribute
// TODO: handle 'thermostatFanMode' attribute
// TODO: handle 'thermostatOperatingState' attribute
// TODO: handle 'schedule' attribute
// TODO: handle 'temperatureUnit' attribute
}
// handle commands
def poll() {
log.debug "Executing 'poll'"
// TODO: handle 'poll' command
}
def setHeatingSetpoint() {
log.debug "Executing 'setHeatingSetpoint'"
// TODO: handle 'setHeatingSetpoint' command
}
def setCoolingSetpoint() {
log.debug "Executing 'setCoolingSetpoint'"
// TODO: handle 'setCoolingSetpoint' command
}
def off() {
log.debug "Executing 'off'"
// TODO: handle 'off' command
}
def heat() {
log.debug "Executing 'heat'"
// TODO: handle 'heat' command
}
def emergencyHeat() {
log.debug "Executing 'emergencyHeat'"
// TODO: handle 'emergencyHeat' command
}
def cool() {
log.debug "Executing 'cool'"
// TODO: handle 'cool' command
}
def setThermostatMode() {
log.debug "Executing 'setThermostatMode'"
// TODO: handle 'setThermostatMode' command
}
def fanOn() {
log.debug "Executing 'fanOn'"
// TODO: handle 'fanOn' command
}
def fanAuto() {
log.debug "Executing 'fanAuto'"
// TODO: handle 'fanAuto' command
}
def fanCirculate() {
log.debug "Executing 'fanCirculate'"
// TODO: handle 'fanCirculate' command
}
def setThermostatFanMode() {
log.debug "Executing 'setThermostatFanMode'"
// TODO: handle 'setThermostatFanMode' command
}
def auto() {
log.debug "Executing 'auto'"
// TODO: handle 'auto' command
}
def setSchedule() {
log.debug "Executing 'setSchedule'"
// TODO: handle 'setSchedule' command
}
def away() {
log.debug "Executing 'away'"
// TODO: handle 'away' command
}
def present() {
log.debug "Executing 'present'"
// TODO: handle 'present' command
}
def setPresence() {
log.debug "Executing 'setPresence'"
// TODO: handle 'setPresence' command
}
def heatingSetpointUp() {
log.debug "Executing 'heatingSetpointUp'"
// TODO: handle 'heatingSetpointUp' command
}
def heatingSetpointDown() {
log.debug "Executing 'heatingSetpointDown'"
// TODO: handle 'heatingSetpointDown' command
}
def coolingSetpointUp() {
log.debug "Executing 'coolingSetpointUp'"
// TODO: handle 'coolingSetpointUp' command
}
def coolingSetpointDown() {
log.debug "Executing 'coolingSetpointDown'"
// TODO: handle 'coolingSetpointDown' command
}
def setFahrenheit() {
log.debug "Executing 'setFahrenheit'"
// TODO: handle 'setFahrenheit' command
}
def setCelsius() {
log.debug "Executing 'setCelsius'"
// TODO: handle 'setCelsius' command
}

View File

@@ -100,9 +100,6 @@ metadata {
]
)
}
valueTile("3axis", "device.threeAxis", decoration: "flat", wordWrap: false, width: 2, height: 2) {
state("threeAxis", label:'${currentValue}', unit:"", backgroundColor:"#ffffff")
}
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
@@ -112,7 +109,7 @@ metadata {
main(["status", "acceleration", "temperature"])
details(["status", "acceleration", "temperature", "3axis", "battery", "refresh"])
details(["status", "acceleration", "temperature", "battery", "refresh"])
}
}
@@ -441,28 +438,28 @@ def configure() {
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", "delay 200", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0xFC02 {${device.zigbeeId}} {}", "delay 200",
"zcl mfg-code ${manufacturerCode}",
"zcl global send-me-a-report 0xFC02 0x0010 0x18 10 3600 {01}",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0010 0x18 10 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}",
"zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {01}",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0012 0x29 1 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}",
"zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {01}",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0013 0x29 1 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zcl mfg-code ${manufacturerCode}",
"zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {01}",
"zcl mfg-code ${manufacturerCode}", "delay 200",
"zcl global send-me-a-report 0xFC02 0x0014 0x29 1 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
]
@@ -481,7 +478,7 @@ def enrollResponse() {
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
//Enroll Response
"raw 0x500 {01 23 00 00 00}",
"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
]
}

View File

@@ -72,15 +72,12 @@ metadata {
]
)
}
valueTile("3axis", "device.threeAxis", decoration: "flat", wordWrap: false, width: 2, height: 2) {
state("threeAxis", label:'${currentValue}', unit:"", backgroundColor:"#ffffff")
}
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main(["contact", "acceleration", "temperature"])
details(["contact", "acceleration", "temperature", "3axis", "battery"])
details(["contact", "acceleration", "temperature", "battery"])
}
}

View File

@@ -1,7 +1,7 @@
/**
* Initial State Event Streamer
*
* Copyright 2015 David Sulpy
* Copyright 2016 David Sulpy
*
* 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:
@@ -77,6 +77,62 @@ mappings {
}
}
def getAccessKey() {
log.trace "get access key"
if (atomicState.accessKey == null) {
httpError(404, "Access Key Not Found")
} else {
[
accessKey: atomicState.accessKey
]
}
}
def getBucketKey() {
log.trace "get bucket key"
if (atomicState.bucketKey == null) {
httpError(404, "Bucket key Not Found")
} else {
[
bucketKey: atomicState.bucketKey,
bucketName: atomicState.bucketName
]
}
}
def setBucketKey() {
log.trace "set bucket key"
def newBucketKey = request.JSON?.bucketKey
def newBucketName = request.JSON?.bucketName
log.debug "bucket name: $newBucketName"
log.debug "bucket key: $newBucketKey"
if (newBucketKey && (newBucketKey != atomicState.bucketKey || newBucketName != atomicState.bucketName)) {
atomicState.bucketKey = "$newBucketKey"
atomicState.bucketName = "$newBucketName"
atomicState.isBucketCreated = false
}
tryCreateBucket()
}
def setAccessKey() {
log.trace "set access key"
def newAccessKey = request.JSON?.accessKey
def newGrokerSubdomain = request.JSON?.grokerSubdomain
if (newGrokerSubdomain && newGrokerSubdomain != "" && newGrokerSubdomain != atomicState.grokerSubdomain) {
atomicState.grokerSubdomain = "$newGrokerSubdomain"
atomicState.isBucketCreated = false
}
if (newAccessKey && newAccessKey != atomicState.accessKey) {
atomicState.accessKey = "$newAccessKey"
atomicState.isBucketCreated = false
}
}
def subscribeToEvents() {
if (accelerometers != null) {
subscribe(accelerometers, "acceleration", genericHandler)
@@ -169,85 +225,27 @@ def subscribeToEvents() {
}
}
def getAccessKey() {
log.trace "get access key"
if (atomicState.accessKey == null) {
httpError(404, "Access Key Not Found")
} else {
[
accessKey: atomicState.accessKey
]
}
}
def getBucketKey() {
log.trace "get bucket key"
if (atomicState.bucketKey == null) {
httpError(404, "Bucket key Not Found")
} else {
[
bucketKey: atomicState.bucketKey,
bucketName: atomicState.bucketName
]
}
}
def setBucketKey() {
log.trace "set bucket key"
def newBucketKey = request.JSON?.bucketKey
def newBucketName = request.JSON?.bucketName
log.debug "bucket name: $newBucketName"
log.debug "bucket key: $newBucketKey"
if (newBucketKey && (newBucketKey != atomicState.bucketKey || newBucketName != atomicState.bucketName)) {
atomicState.bucketKey = "$newBucketKey"
atomicState.bucketName = "$newBucketName"
atomicState.isBucketCreated = false
}
tryCreateBucket()
}
def setAccessKey() {
log.trace "set access key"
def newAccessKey = request.JSON?.accessKey
def newGrokerSubdomain = request.JSON?.grokerSubdomain
if (newGrokerSubdomain && newGrokerSubdomain != "" && newGrokerSubdomain != atomicState.grokerSubdomain) {
atomicState.grokerSubdomain = "$newGrokerSubdomain"
atomicState.isBucketCreated = false
}
if (newAccessKey && newAccessKey != atomicState.accessKey) {
atomicState.accessKey = "$newAccessKey"
atomicState.isBucketCreated = false
}
}
def installed() {
atomicState.version = "1.0.18"
atomicState.version = "1.1.0"
atomicState.isBucketCreated = false
atomicState.grokerSubdomain = "groker"
subscribeToEvents()
atomicState.isBucketCreated = false
atomicState.grokerSubdomain = "groker"
atomicState.eventBuffer = []
runEvery15Minutes(flushBuffer)
log.debug "installed (version $atomicState.version)"
}
def updated() {
atomicState.version = "1.0.18"
atomicState.version = "1.1.0"
unsubscribe()
if (atomicState.bucketKey != null && atomicState.accessKey != null) {
atomicState.isBucketCreated = false
}
if (atomicState.eventBuffer == null) {
atomicState.eventBuffer = []
}
if (atomicState.grokerSubdomain == null || atomicState.grokerSubdomain == "") {
atomicState.grokerSubdomain = "groker"
}
@@ -327,37 +325,17 @@ def genericHandler(evt) {
eventHandler(key, value)
}
// This is a handler function for flushing the event buffer
// after a specified amount of time to reduce the load on ST servers
def flushBuffer() {
def eventBuffer = atomicState.eventBuffer
log.trace "About to flush the buffer on schedule"
if (eventBuffer != null && eventBuffer.size() > 0) {
atomicState.eventBuffer = []
tryShipEvents(eventBuffer)
}
}
def eventHandler(name, value) {
def epoch = now() / 1000
def eventBuffer = atomicState.eventBuffer ?: []
eventBuffer << [key: "$name", value: "$value", epoch: "$epoch"]
if (eventBuffer.size() >= 10) {
// Clear eventBuffer right away since we've already pulled it off of atomicState to reduce the risk of missing
// events. This assumes the grokerSubdomain, accessKey, and bucketKey are set correctly to avoid the eventBuffer
// from growing unbounded.
atomicState.eventBuffer = []
tryShipEvents(eventBuffer)
} else {
// Make sure we persist the updated eventBuffer with the new event added back to atomicState
atomicState.eventBuffer = eventBuffer
}
log.debug "Event added to buffer: " + eventBuffer
def event = new JsonSlurper().parseText("{\"key\": \"$name\", \"value\": \"$value\", \"epoch\": \"$epoch\"}")
tryShipEvents(event)
log.debug "Shipped Event: " + event
}
// a helper function for shipping the atomicState.eventBuffer to Initial State
def tryShipEvents(eventBuffer) {
def tryShipEvents(event) {
def grokerSubdomain = atomicState.grokerSubdomain
// can't ship events if there is no grokerSubdomain
@@ -380,7 +358,7 @@ def tryShipEvents(eventBuffer) {
"X-IS-AccessKey": "${accessKey}",
"Accept-Version": "0.0.2"
],
body: eventBuffer
body: event
]
try {