Compare commits

...

3 Commits

Author SHA1 Message Date
Patrick Malm
6cef95c141 MSA-1846: null 2017-03-16 13:59:18 -07:00
Jack Chi
4dac7b5379 Merge pull request #1786 from skt123/aeon_siren
[CHF-552] Implementation of Health Check for Aeon Siren.
2017-03-16 10:18:08 -07:00
sushant.k1
1326881142 Implemented of Health Check for Aeon Siren. 2017-03-16 15:24:53 +05:30
4 changed files with 196 additions and 1 deletions

View File

@@ -0,0 +1,2 @@
.st-ignore
README.md

View File

@@ -0,0 +1,37 @@
# Aeon Siren
Cloud Execution
Works with:
* [Aeon Labs Siren (Gen 5)](https://www.smartthings.com/works-with-smartthings/aeon-labs/aeon-labs-siren-gen-5)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Alarm** - allows for interacting with devices that serve as alarms
* **Switch** - can detect state (possible values: on/off)
* **Health Check** - indicates ability to get device health notifications
## Device Health
Aeon Labs Siren (Gen 5) is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Aeon Labs Siren (Gen 5) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204555240-Aeon-Labs-Siren-Gen-5-)

View File

@@ -20,10 +20,11 @@ metadata {
capability "Actuator"
capability "Alarm"
capability "Switch"
capability "Health Check"
command "test"
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98"
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98", deviceJoinName: "Aeon Labs Siren (Gen 5)"
}
simulator {
@@ -58,6 +59,9 @@ metadata {
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
if(!state.sound) state.sound = 1
if(!state.volume) state.volume = 3
@@ -148,3 +152,10 @@ def test() {
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.basicV1.basicGet())
}

View File

@@ -0,0 +1,145 @@
/**
* JSON
*
* Copyright 2015 Jesse Newland
*
* 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: "JSON API",
namespace: "jnewland",
author: "Jesse Newland",
description: "A JSON API for SmartThings",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
oauth: true)
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
if (!state.accessToken) {
createAccessToken()
}
}
preferences {
page(name: "copyConfig")
}
def copyConfig() {
if (!state.accessToken) {
createAccessToken()
}
dynamicPage(name: "copyConfig", title: "Config", install:true) {
section("Select devices to include in the /devices API call") {
input "switches", "capability.switch", title: "Switches", multiple: true, required: false
input "hues", "capability.colorControl", title: "Hues", multiple: true, required: false
}
section() {
paragraph "View this SmartApp's configuration to use it in other places."
href url:"https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/config?access_token=${state.accessToken}", style:"embedded", required:false, title:"Config", description:"Tap, select, copy, then click \"Done\""
}
section() {
href url:"https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/devices?access_token=${state.accessToken}", style:"embedded", required:false, title:"Debug", description:"View accessories JSON"
}
}
}
def renderConfig() {
def configJson = new groovy.json.JsonOutput().toJson([
description: "JSON API",
platforms: [
[
platform: "SmartThings",
name: "SmartThings",
app_id: app.id,
access_token: state.accessToken
]
],
])
def configString = new groovy.json.JsonOutput().prettyPrint(configJson)
render contentType: "text/plain", data: configString
}
def deviceCommandMap(device, type) {
device.supportedCommands.collectEntries { command->
def commandUrl = "https://graph.api.smartthings.com/api/smartapps/installations/${app.id}/${type}/${device.id}/command/${command.name}?access_token=${state.accessToken}"
[
(command.name): commandUrl
]
}
}
def authorizedDevices() {
[
switches: switches,
hues: hues
]
}
def renderDevices() {
def deviceData = authorizedDevices().collectEntries { devices->
[
(devices.key): devices.value.collect { device->
[
name: device.displayName,
commands: deviceCommandMap(device, devices.key)
]
}
]
}
def deviceJson = new groovy.json.JsonOutput().toJson(deviceData)
def deviceString = new groovy.json.JsonOutput().prettyPrint(deviceJson)
render contentType: "application/json", data: deviceString
}
def deviceCommand() {
def device = authorizedDevices()[params.type].find { it.id == params.id }
def command = params.command
if (!device) {
httpError(404, "Device not found")
} else {
if (params.value) {
device."$command"(params.value)
} else {
device."$command"()
}
}
}
mappings {
if (!params.access_token || (params.access_token && params.access_token != state.accessToken)) {
path("/devices") { action: [GET: "authError"] }
path("/config") { action: [GET: "authError"] }
path("/:type/:id/command/:command") { action: [PUT: "authError"] }
} else {
path("/devices") { action: [GET: "renderDevices"] }
path("/config") { action: [GET: "renderConfig"] }
path("/:type/:id/command/:command") { action: [PUT: "deviceCommand"] }
}
}
def authError() {
[error: "Permission denied"]
}