mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-20 21:03:46 +00:00
Compare commits
1 Commits
DHF-7
...
MSA-1994-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55db0ac12a |
@@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* Utilitech Glass Break Sensor
|
||||||
|
*
|
||||||
|
* Author: Adam Heinmiller
|
||||||
|
*
|
||||||
|
* Date: 2014-11-09
|
||||||
|
*/
|
||||||
|
|
||||||
|
metadata
|
||||||
|
{
|
||||||
|
definition (namespace: "adamheinmiller", name: "Utilitech Glass Break Sensor", author: "Adam Heinmiller")
|
||||||
|
{
|
||||||
|
capability "Contact Sensor"
|
||||||
|
capability "Battery"
|
||||||
|
|
||||||
|
fingerprint deviceId:"0xA102", inClusters:"0x20, 0x9C, 0x80, 0x82, 0x84, 0x87, 0x85, 0x72, 0x86, 0x5A"
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator
|
||||||
|
{
|
||||||
|
status "Activate Sensor": "command: 9C02, payload: 26 00 FF 00 00"
|
||||||
|
status "Reset Sensor": "command: 9C02, payload: 26 00 00 00 00"
|
||||||
|
|
||||||
|
status "Battery Status 25%": "command: 8003, payload: 19"
|
||||||
|
status "Battery Status 50%": "command: 8003, payload: 32"
|
||||||
|
status "Battery Status 75%": "command: 8003, payload: 4B"
|
||||||
|
status "Battery Status 100%": "command: 8003, payload: 64"
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles
|
||||||
|
{
|
||||||
|
standardTile("contact", "device.contact", width: 2, height: 2)
|
||||||
|
{
|
||||||
|
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
||||||
|
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#FF0000"
|
||||||
|
}
|
||||||
|
|
||||||
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat")
|
||||||
|
{
|
||||||
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
|
}
|
||||||
|
|
||||||
|
main "contact"
|
||||||
|
details(["contact", "battery"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def installed()
|
||||||
|
{
|
||||||
|
|
||||||
|
updated()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def getTimestamp()
|
||||||
|
{
|
||||||
|
return new Date().time
|
||||||
|
}
|
||||||
|
|
||||||
|
def getBatteryLevel(int pNewLevel)
|
||||||
|
{
|
||||||
|
def bl = state.BatteryLevel ?: [pNewLevel, pNewLevel, pNewLevel] as int[]
|
||||||
|
|
||||||
|
def iAvg = 4 + ((int)(pNewLevel + bl[0] + bl[1] + bl[2]) / 4)
|
||||||
|
|
||||||
|
state.BatteryLevel = [pNewLevel, bl[0], bl[1]]
|
||||||
|
|
||||||
|
//log.debug "New Bat Level: ${iAvg - (iAvg % 5)}, $state.BatteryLevel"
|
||||||
|
|
||||||
|
return iAvg - (iAvg % 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def parse(String description)
|
||||||
|
{
|
||||||
|
def result = []
|
||||||
|
|
||||||
|
// "0x20, 0x9C, 0x80, 0x82, 0x84, 0x87, 0x85, 0x72, 0x86, 0x5A"
|
||||||
|
|
||||||
|
def cmd = zwave.parse(description)
|
||||||
|
|
||||||
|
|
||||||
|
//log.debug "Parse: Desc: $description, CMD: $cmd"
|
||||||
|
|
||||||
|
if (cmd)
|
||||||
|
{
|
||||||
|
result << zwaveEvent(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
|
||||||
|
{
|
||||||
|
logCommand(cmd)
|
||||||
|
|
||||||
|
def result = []
|
||||||
|
|
||||||
|
|
||||||
|
result << response(zwave.wakeUpV2.wakeUpNoMoreInformation())
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd)
|
||||||
|
{
|
||||||
|
logCommand(cmd)
|
||||||
|
|
||||||
|
def result = []
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
|
||||||
|
{
|
||||||
|
logCommand(cmd)
|
||||||
|
|
||||||
|
def result = []
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd)
|
||||||
|
{
|
||||||
|
logCommand(cmd)
|
||||||
|
|
||||||
|
def result = [name: "battery", unit: "%", value: getBatteryLevel(cmd.batteryLevel)]
|
||||||
|
|
||||||
|
return createEvent(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
|
||||||
|
{
|
||||||
|
logCommand(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def result = [name: "contact"]
|
||||||
|
|
||||||
|
if (cmd.sensorState == 0)
|
||||||
|
{
|
||||||
|
result += [value: "closed", descriptionText: "${device.displayName} has reset"]
|
||||||
|
}
|
||||||
|
else if (cmd.sensorState == 255)
|
||||||
|
{
|
||||||
|
result += [value: "open", descriptionText: "${device.displayName} detected broken glass"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return createEvent(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.Command cmd)
|
||||||
|
{
|
||||||
|
logCommand("**Unhandled**: $cmd")
|
||||||
|
|
||||||
|
return createEvent([descriptionText: "Unhandled: ${device.displayName}: ${cmd}", displayed: false])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def logCommand(cmd)
|
||||||
|
{
|
||||||
|
log.debug "Device Command: $cmd"
|
||||||
|
}
|
||||||
1545
devicetypes/ethayer/user-lock-manager.src/user-lock-manager.groovy
Normal file
1545
devicetypes/ethayer/user-lock-manager.src/user-lock-manager.groovy
Normal file
File diff suppressed because it is too large
Load Diff
@@ -39,8 +39,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
|
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
|
||||||
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
|
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||||
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
|
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
|
||||||
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
|
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ metadata {
|
|||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
capability "Health Check"
|
capability "Health Check"
|
||||||
|
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: ""
|
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: ""
|
||||||
|
|
||||||
fingerprint mfr:"010F", prod:"0801", model:"2001"
|
|
||||||
fingerprint mfr:"010F", prod:"0801", model:"1001"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
|
|||||||
@@ -0,0 +1,618 @@
|
|||||||
|
/**
|
||||||
|
* Centralite Keypad
|
||||||
|
*
|
||||||
|
* Copyright 2015-2016 Mitch Pond, Zack Cornelius
|
||||||
|
*
|
||||||
|
* 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: "Centralite Keypad", namespace: "mitchpond", author: "Mitch Pond") {
|
||||||
|
|
||||||
|
capability "Battery"
|
||||||
|
capability "Configuration"
|
||||||
|
capability "Motion Sensor"
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Temperature Measurement"
|
||||||
|
capability "Refresh"
|
||||||
|
capability "Lock Codes"
|
||||||
|
capability "Tamper Alert"
|
||||||
|
capability "Tone"
|
||||||
|
capability "button"
|
||||||
|
capability "polling"
|
||||||
|
capability "Contact Sensor"
|
||||||
|
|
||||||
|
attribute "armMode", "String"
|
||||||
|
attribute "lastUpdate", "String"
|
||||||
|
|
||||||
|
command "setDisarmed"
|
||||||
|
command "setArmedAway"
|
||||||
|
command "setArmedStay"
|
||||||
|
command "setArmedNight"
|
||||||
|
command "setExitDelay", ['number']
|
||||||
|
command "setEntryDelay", ['number']
|
||||||
|
command "testCmd"
|
||||||
|
command "sendInvalidKeycodeResponse"
|
||||||
|
command "acknowledgeArmRequest"
|
||||||
|
|
||||||
|
fingerprint endpointId: "01", profileId: "0104", deviceId: "0401", inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019,0501", manufacturer: "CentraLite", model: "3400", deviceJoinName: "Xfinity 3400-X Keypad"
|
||||||
|
fingerprint endpointId: "01", profileId: "0104", deviceId: "0401", inClusters: "0000,0001,0003,0020,0402,0500,0501,0B05,FC04", outClusters: "0019,0501", manufacturer: "CentraLite", model: "3405-L", deviceJoinName: "Iris 3405-L Keypad"
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences{
|
||||||
|
input ("tempOffset", "number", title: "Enter an offset to adjust the reported temperature",
|
||||||
|
defaultValue: 0, displayDuringSetup: false)
|
||||||
|
input ("beepLength", "number", title: "Enter length of beep in seconds",
|
||||||
|
defaultValue: 1, displayDuringSetup: false)
|
||||||
|
|
||||||
|
input ("motionTime", "number", title: "Time in seconds for Motion to become Inactive (Default:10, 0=disabled)", defaultValue: 10, displayDuringSetup: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles (scale: 2) {
|
||||||
|
multiAttributeTile(name: "keypad", type:"generic", width:6, height:4, canChangeIcon: true) {
|
||||||
|
tileAttribute ("device.armMode", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState("disarmed", label:'${currentValue}', icon:"st.Home.home2", backgroundColor:"#44b621")
|
||||||
|
attributeState("armedStay", label:'ARMED/STAY', icon:"st.Home.home3", backgroundColor:"#ffa81e")
|
||||||
|
attributeState("armedAway", label:'ARMED/AWAY', icon:"st.nest.nest-away", backgroundColor:"#d04e00")
|
||||||
|
}
|
||||||
|
tileAttribute("device.lastUpdate", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState("default", label:'Updated: ${currentValue}')
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
tileAttribute("device.battery", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState("default", label:'Battery: ${currentValue}%', unit:"%")
|
||||||
|
}
|
||||||
|
tileAttribute("device.battery", key: "VALUE_CONTROL") {
|
||||||
|
attributeState "VALUE_UP", action: "refresh"
|
||||||
|
attributeState "VALUE_DOWN", action: "refresh"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
|
||||||
|
attributeState "VALUE_UP", action: "refresh"
|
||||||
|
attributeState "VALUE_DOWN", action: "refresh"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
|
state "temperature", label: '${currentValue}°',
|
||||||
|
backgroundColors:[
|
||||||
|
[value: 31, color: "#153591"],
|
||||||
|
[value: 44, color: "#1e9cbb"],
|
||||||
|
[value: 59, color: "#90d2a7"],
|
||||||
|
[value: 74, color: "#44b621"],
|
||||||
|
[value: 84, color: "#f1d801"],
|
||||||
|
[value: 95, color: "#d04e00"],
|
||||||
|
[value: 96, color: "#bc2323"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("motion", "device.motion", decoration: "flat", canChangeBackground: true, width: 2, height: 2) {
|
||||||
|
state "active", label:'motion',icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
||||||
|
state "inactive", label:'no motion',icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
standardTile("tamper", "device.tamper", decoration: "flat", canChangeBackground: true, width: 2, height: 2) {
|
||||||
|
state "clear", label: 'Tamper', icon:"st.motion.acceleration.inactive", backgroundColor: "#ffffff"
|
||||||
|
state "detected", label: 'Tamper', icon:"st.motion.acceleration.active", backgroundColor:"#cc5c5c"
|
||||||
|
}
|
||||||
|
standardTile("Panic", "device.contact", decoration: "flat", canChangeBackground: true, width: 2, height: 2) {
|
||||||
|
state "open", label: 'Panic', icon:"st.security.alarm.alarm", backgroundColor: "#ffffff"
|
||||||
|
state "closed", label: 'Panic', icon:"st.security.alarm.clear", backgroundColor:"#bc2323"
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("Mode", "device.armMode", decoration: "flat", canChangeBackground: true, width: 2, height: 2) {
|
||||||
|
state "disarmed", label:'OFF', icon:"st.Home.home2", backgroundColor:"#44b621"
|
||||||
|
state "armedStay", label:'OFF', icon:"st.Home.home3", backgroundColor:"#ffffff"
|
||||||
|
state "armedAway", label:'OFF', icon:"st.net.nest-away", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("beep", "device.beep", decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
|
}
|
||||||
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "default", action:"configuration.configure", icon:"st.secondary.configure"
|
||||||
|
}
|
||||||
|
valueTile("armMode", "device.armMode", decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "armMode", label: '${currentValue}'
|
||||||
|
}
|
||||||
|
|
||||||
|
main (["keypad"])
|
||||||
|
details (["keypad","motion","tamper","Panic","Mode","beep","refresh","battery"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse events into attributes
|
||||||
|
def parse(String description) {
|
||||||
|
log.debug "Parsing '${description}'";
|
||||||
|
def results = [];
|
||||||
|
|
||||||
|
//------Miscellaneous Zigbee message------//
|
||||||
|
if (description?.startsWith('catchall:')) {
|
||||||
|
|
||||||
|
//log.debug zigbee.parse(description);
|
||||||
|
|
||||||
|
def message = zigbee.parse(description);
|
||||||
|
|
||||||
|
//------Profile-wide command (rattr responses, errors, etc.)------//
|
||||||
|
if (message?.isClusterSpecific == false) {
|
||||||
|
//------Default response------//
|
||||||
|
if (message?.command == 0x0B) {
|
||||||
|
if (message?.data[1] == 0x81)
|
||||||
|
log.error "Device: unrecognized command: "+description;
|
||||||
|
else if (message?.data[1] == 0x80)
|
||||||
|
log.error "Device: malformed command: "+description;
|
||||||
|
}
|
||||||
|
//------Read attributes responses------//
|
||||||
|
else if (message?.command == 0x01) {
|
||||||
|
if (message?.clusterId == 0x0402) {
|
||||||
|
log.debug "Device: read attribute response: "+description;
|
||||||
|
|
||||||
|
results = parseTempAttributeMsg(message)
|
||||||
|
}}
|
||||||
|
else
|
||||||
|
log.debug "Unhandled profile-wide command: "+description;
|
||||||
|
}
|
||||||
|
//------Cluster specific commands------//
|
||||||
|
else if (message?.isClusterSpecific) {
|
||||||
|
//------IAS ACE------//
|
||||||
|
if (message?.clusterId == 0x0501) {
|
||||||
|
if (message?.command == 0x07) {
|
||||||
|
motionON()
|
||||||
|
}
|
||||||
|
else if (message?.command == 0x04) {
|
||||||
|
results = createEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "$device.displayName panic button was pushed", isStateChange: true)
|
||||||
|
panicContact()
|
||||||
|
}
|
||||||
|
else if (message?.command == 0x00) {
|
||||||
|
results = handleArmRequest(message)
|
||||||
|
log.trace results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else log.debug "Unhandled cluster-specific command: "+description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------IAS Zone Enroll request------//
|
||||||
|
else if (description?.startsWith('enroll request')) {
|
||||||
|
log.debug "Sending IAS enroll response..."
|
||||||
|
results = zigbee.enrollResponse()
|
||||||
|
}
|
||||||
|
//------Read Attribute response------//
|
||||||
|
else if (description?.startsWith('read attr -')) {
|
||||||
|
results = parseReportAttributeMessage(description)
|
||||||
|
}
|
||||||
|
//------Temperature Report------//
|
||||||
|
else if (description?.startsWith('temperature: ')) {
|
||||||
|
log.debug "Got ST-style temperature report.."
|
||||||
|
results = createEvent(getTemperatureResult(zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())))
|
||||||
|
log.debug results
|
||||||
|
}
|
||||||
|
else if (description?.startsWith('zone status ')) {
|
||||||
|
results = parseIasMessage(description)
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def configure() {
|
||||||
|
log.debug "--- Configure Called"
|
||||||
|
String hubZigbeeId = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
def cmd = [
|
||||||
|
//------IAS Zone/CIE setup------//
|
||||||
|
"zcl global write 0x500 0x10 0xf0 {${hubZigbeeId}}", "delay 100",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 200",
|
||||||
|
|
||||||
|
//------Set up binding------//
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x500 {${device.zigbeeId}} {}", "delay 200",
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x501 {${device.zigbeeId}} {}", "delay 200",
|
||||||
|
|
||||||
|
] +
|
||||||
|
zigbee.configureReporting(1,0x20,0x20,3600,43200,0x01) +
|
||||||
|
zigbee.configureReporting(0x0402,0x00,0x29,30,3600,0x0064)
|
||||||
|
|
||||||
|
return cmd + refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
def poll() {
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
def refresh() {
|
||||||
|
return sendStatusToDevice() +
|
||||||
|
zigbee.readAttribute(0x0001,0x20) +
|
||||||
|
zigbee.readAttribute(0x0402,0x00)
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatLocalTime(time, format = "EEE, MMM d yyyy @ h:mm a z") {
|
||||||
|
if (time instanceof Long) {
|
||||||
|
time = new Date(time)
|
||||||
|
}
|
||||||
|
if (time instanceof String) {
|
||||||
|
//get UTC time
|
||||||
|
time = timeToday(time, location.timeZone)
|
||||||
|
}
|
||||||
|
if (!(time instanceof Date)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
def formatter = new java.text.SimpleDateFormat(format)
|
||||||
|
formatter.setTimeZone(location.timeZone)
|
||||||
|
return formatter.format(time)
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseReportAttributeMessage(String description) {
|
||||||
|
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||||
|
def nameAndValue = param.split(":")
|
||||||
|
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||||
|
}
|
||||||
|
//log.debug "Desc Map: $descMap"
|
||||||
|
|
||||||
|
def results = []
|
||||||
|
|
||||||
|
if (descMap.cluster == "0001" && descMap.attrId == "0020") {
|
||||||
|
log.debug "Received battery level report"
|
||||||
|
results = createEvent(getBatteryResult(Integer.parseInt(descMap.value, 16)))
|
||||||
|
}
|
||||||
|
else if (descMap.cluster == "0001" && descMap.attrId == "0034")
|
||||||
|
{
|
||||||
|
log.debug "Received Battery Rated Voltage: ${descMap.value}"
|
||||||
|
}
|
||||||
|
else if (descMap.cluster == "0001" && descMap.attrId == "0036")
|
||||||
|
{
|
||||||
|
log.debug "Received Battery Alarm Voltage: ${descMap.value}"
|
||||||
|
}
|
||||||
|
else if (descMap.cluster == "0402" && descMap.attrId == "0000") {
|
||||||
|
def value = getTemperature(descMap.value)
|
||||||
|
results = createEvent(getTemperatureResult(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseTempAttributeMsg(message) {
|
||||||
|
byte[] temp = message.data[-2..-1].reverse()
|
||||||
|
createEvent(getTemperatureResult(getTemperature(temp.encodeHex() as String)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map parseIasMessage(String description) {
|
||||||
|
List parsedMsg = description.split(' ')
|
||||||
|
String msgCode = parsedMsg[2]
|
||||||
|
|
||||||
|
Map resultMap = [:]
|
||||||
|
switch(msgCode) {
|
||||||
|
case '0x0020': // Closed/No Motion/Dry
|
||||||
|
resultMap = getContactResult('closed')
|
||||||
|
break
|
||||||
|
|
||||||
|
case '0x0021': // Open/Motion/Wet
|
||||||
|
resultMap = getContactResult('open')
|
||||||
|
break
|
||||||
|
|
||||||
|
case '0x0022': // Tamper Alarm
|
||||||
|
break
|
||||||
|
|
||||||
|
case '0x0023': // Battery Alarm
|
||||||
|
break
|
||||||
|
|
||||||
|
case '0x0024': // Supervision Report
|
||||||
|
resultMap = getContactResult('closed')
|
||||||
|
break
|
||||||
|
|
||||||
|
case '0x0025': // Restore Report
|
||||||
|
resultMap = getContactResult('open')
|
||||||
|
break
|
||||||
|
|
||||||
|
case '0x0026': // Trouble/Failure
|
||||||
|
break
|
||||||
|
|
||||||
|
case '0x0028': // Test Mode
|
||||||
|
break
|
||||||
|
case '0x0000':
|
||||||
|
resultMap = createEvent(name: "tamper", value: "clear", isStateChange: true, displayed: false)
|
||||||
|
break
|
||||||
|
case '0x0004':
|
||||||
|
resultMap = createEvent(name: "tamper", value: "detected", isStateChange: true, displayed: false)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.debug "Invalid message code in IAS message: ${msgCode}"
|
||||||
|
}
|
||||||
|
return resultMap
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map getMotionResult(value) {
|
||||||
|
String linkText = getLinkText(device)
|
||||||
|
String descriptionText = value == 'active' ? "${linkText} detected motion" : "${linkText} motion has stopped"
|
||||||
|
return [
|
||||||
|
name: 'motion',
|
||||||
|
value: value,
|
||||||
|
descriptionText: descriptionText
|
||||||
|
]
|
||||||
|
}
|
||||||
|
def motionON() {
|
||||||
|
log.debug "--- Motion Detected"
|
||||||
|
sendEvent(name: "motion", value: "active", displayed:true, isStateChange: true)
|
||||||
|
|
||||||
|
//-- Calculate Inactive timeout value
|
||||||
|
def motionTimeRun = (settings.motionTime?:0).toInteger()
|
||||||
|
|
||||||
|
//-- If Inactive timeout was configured
|
||||||
|
if (motionTimeRun > 0) {
|
||||||
|
log.debug "--- Will become inactive in $motionTimeRun seconds"
|
||||||
|
runIn(motionTimeRun, "motionOFF")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def motionOFF() {
|
||||||
|
log.debug "--- Motion Inactive (OFF)"
|
||||||
|
sendEvent(name: "motion", value: "inactive", displayed:true, isStateChange: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def panicContact() {
|
||||||
|
log.debug "--- Panic button hit"
|
||||||
|
sendEvent(name: "contact", value: "open", displayed: true, isStateChange: true)
|
||||||
|
runIn(3, "panicContactClose")
|
||||||
|
}
|
||||||
|
|
||||||
|
def panicContactClose()
|
||||||
|
{
|
||||||
|
sendEvent(name: "contact", value: "closed", displayed: true, isStateChange: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: find actual good battery voltage range and update this method with proper values for min/max
|
||||||
|
//
|
||||||
|
//Converts the battery level response into a percentage to display in ST
|
||||||
|
//and creates appropriate message for given level
|
||||||
|
|
||||||
|
private getBatteryResult(rawValue) {
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
|
||||||
|
def result = [name: 'battery']
|
||||||
|
|
||||||
|
def volts = rawValue / 10
|
||||||
|
def descriptionText
|
||||||
|
if (volts > 3.5) {
|
||||||
|
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
def minVolts = 2.5
|
||||||
|
def maxVolts = 3.0
|
||||||
|
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
||||||
|
result.value = Math.min(100, (int) pct * 100)
|
||||||
|
result.descriptionText = "${linkText} battery was ${result.value}%"
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTemperature(value) {
|
||||||
|
def celcius = Integer.parseInt(value, 16).shortValue() / 100
|
||||||
|
if(getTemperatureScale() == "C"){
|
||||||
|
return celcius
|
||||||
|
} else {
|
||||||
|
return celsiusToFahrenheit(celcius) as Integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map getTemperatureResult(value) {
|
||||||
|
log.debug 'TEMP'
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
if (tempOffset) {
|
||||||
|
def offset = tempOffset as int
|
||||||
|
def v = value as int
|
||||||
|
value = v + offset
|
||||||
|
}
|
||||||
|
def descriptionText = "${linkText} was ${value}°${temperatureScale}"
|
||||||
|
return [
|
||||||
|
name: 'temperature',
|
||||||
|
value: value,
|
||||||
|
descriptionText: descriptionText
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
//------Command handlers------//
|
||||||
|
private handleArmRequest(message){
|
||||||
|
def keycode = new String(message.data[2..-2] as byte[],'UTF-8')
|
||||||
|
def reqArmMode = message.data[0]
|
||||||
|
//state.lastKeycode = keycode
|
||||||
|
log.debug "Received arm command with keycode/armMode: ${keycode}/${reqArmMode}"
|
||||||
|
|
||||||
|
//Acknowledge the command. This may not be *technically* correct, but it works
|
||||||
|
/*List cmds = [
|
||||||
|
"raw 0x501 {09 01 00 0${reqArmMode}}", "delay 200",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
|
||||||
|
]
|
||||||
|
def results = cmds?.collect { new physicalgraph.device.HubAction(it) } + createCodeEntryEvent(keycode, reqArmMode)
|
||||||
|
*/
|
||||||
|
def results = createCodeEntryEvent(keycode, reqArmMode)
|
||||||
|
log.trace "Method: handleArmRequest(message): "+results
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
def createCodeEntryEvent(keycode, armMode) {
|
||||||
|
createEvent(name: "codeEntered", value: keycode as String, data: armMode as String,
|
||||||
|
isStateChange: true, displayed: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//The keypad seems to be expecting responses that are not in-line with the HA 1.2 spec. Maybe HA 1.3 or Zigbee 3.0??
|
||||||
|
//
|
||||||
|
private sendStatusToDevice() {
|
||||||
|
log.debug 'Sending status to device...'
|
||||||
|
def armMode = device.currentValue("armMode")
|
||||||
|
log.trace 'Arm mode: '+armMode
|
||||||
|
def status = ''
|
||||||
|
if (armMode == null || armMode == 'disarmed') status = 0
|
||||||
|
else if (armMode == 'armedAway') status = 3
|
||||||
|
else if (armMode == 'armedStay') status = 1
|
||||||
|
else if (armMode == 'armedNight') status = 2
|
||||||
|
|
||||||
|
// If we're not in one of the 4 basic modes, don't update the status, don't want to override beep timings, exit delay is dependent on it being correct
|
||||||
|
if (status != '')
|
||||||
|
{
|
||||||
|
return sendRawStatus(status)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Statuses:
|
||||||
|
// 00 - Disarmed
|
||||||
|
// 01 - Armed partial
|
||||||
|
// 02 - Armed partial
|
||||||
|
// 03 - Armed Away
|
||||||
|
// 04 - ?
|
||||||
|
// 05 - Fast beep (1 per second)
|
||||||
|
// 05 - Entry delay (Uses seconds) Appears to keep the status lights as it was
|
||||||
|
// 06 - Amber status blink (Ignores seconds)
|
||||||
|
// 07 - ?
|
||||||
|
// 08 - Red status blink
|
||||||
|
// 09 - ?
|
||||||
|
// 10 - Exit delay Slow beep (2 per second, accelerating to 1 beep per second for the last 10 seconds) - With red flashing status - Uses seconds
|
||||||
|
// 11 - ?
|
||||||
|
// 12 - ?
|
||||||
|
// 13 - ?
|
||||||
|
|
||||||
|
private sendRawStatus(status, seconds = 00) {
|
||||||
|
log.debug "Sending Status ${zigbee.convertToHexString(status)}${zigbee.convertToHexString(seconds)} to device..."
|
||||||
|
|
||||||
|
// Seems to require frame control 9, which indicates a "Server to client" cluster specific command (which seems backward? I thought the keypad was the server)
|
||||||
|
List cmds = ["raw 0x501 {09 01 04 ${zigbee.convertToHexString(status)}${zigbee.convertToHexString(seconds)}}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", 'delay 100']
|
||||||
|
|
||||||
|
def results = cmds?.collect { new physicalgraph.device.HubAction(it) };
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
def notifyPanelStatusChanged(status) {
|
||||||
|
//TODO: not yet implemented. May not be needed.
|
||||||
|
}
|
||||||
|
//------------------------//
|
||||||
|
|
||||||
|
def setDisarmed() { setModeHelper("disarmed",0) }
|
||||||
|
def setArmedAway(def delay=0) { setModeHelper("armedAway",delay) }
|
||||||
|
def setArmedStay(def delay=0) { setModeHelper("armedStay",delay) }
|
||||||
|
def setArmedNight(def delay=0) { setModeHelper("armedNight",delay) }
|
||||||
|
|
||||||
|
def setEntryDelay(delay) {
|
||||||
|
setModeHelper("entryDelay", delay)
|
||||||
|
sendRawStatus(5, delay) // Entry delay beeps
|
||||||
|
}
|
||||||
|
|
||||||
|
def setExitDelay(delay) {
|
||||||
|
setModeHelper("exitDelay", delay)
|
||||||
|
sendRawStatus(10, delay) // Exit delay
|
||||||
|
}
|
||||||
|
|
||||||
|
private setModeHelper(String armMode, delay) {
|
||||||
|
sendEvent([name: "armMode", value: armMode, data: [delay: delay as int], isStateChange: true])
|
||||||
|
def lastUpdate = formatLocalTime(now())
|
||||||
|
sendEvent(name: "lastUpdate", value: lastUpdate, displayed: false)
|
||||||
|
sendStatusToDevice()
|
||||||
|
}
|
||||||
|
|
||||||
|
private setKeypadArmMode(armMode){
|
||||||
|
Map mode = [disarmed: '00', armedAway: '03', armedStay: '01', armedNight: '02', entryDelay: '', exitDelay: '']
|
||||||
|
if (mode[armMode] != '')
|
||||||
|
{
|
||||||
|
return ["raw 0x501 {09 01 04 ${mode[armMode]}00}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", 'delay 100']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def acknowledgeArmRequest(armMode){
|
||||||
|
List cmds = [
|
||||||
|
"raw 0x501 {09 01 00 0${armMode}}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 100"
|
||||||
|
]
|
||||||
|
def results = cmds?.collect { new physicalgraph.device.HubAction(it) }
|
||||||
|
log.trace "Method: acknowledgeArmRequest(armMode): "+results
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
def sendInvalidKeycodeResponse(){
|
||||||
|
List cmds = [
|
||||||
|
"raw 0x501 {09 01 00 04}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 100"
|
||||||
|
]
|
||||||
|
|
||||||
|
log.trace 'Method: sendInvalidKeycodeResponse(): '+cmds
|
||||||
|
return (cmds?.collect { new physicalgraph.device.HubAction(it) }) + sendStatusToDevice()
|
||||||
|
}
|
||||||
|
|
||||||
|
def beep(def beepLength = settings.beepLength) {
|
||||||
|
if ( beepLength == null )
|
||||||
|
{
|
||||||
|
beepLength = 0
|
||||||
|
}
|
||||||
|
def len = zigbee.convertToHexString(beepLength, 2)
|
||||||
|
List cmds = ["raw 0x501 {09 01 04 05${len}}", 'delay 200',
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", 'delay 500']
|
||||||
|
cmds
|
||||||
|
}
|
||||||
|
|
||||||
|
//------Utility methods------//
|
||||||
|
|
||||||
|
private String swapEndianHex(String hex) {
|
||||||
|
reverseArray(hex.decodeHex()).encodeHex()
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] reverseArray(byte[] array) {
|
||||||
|
int i = 0;
|
||||||
|
int j = array.length - 1;
|
||||||
|
byte tmp;
|
||||||
|
while (j > i) {
|
||||||
|
tmp = array[j];
|
||||||
|
array[j] = array[i];
|
||||||
|
array[i] = tmp;
|
||||||
|
j--;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
//------------------------//
|
||||||
|
|
||||||
|
private testCmd(){
|
||||||
|
//log.trace zigbee.parse('catchall: 0104 0501 01 01 0140 00 4F2D 01 00 0000 07 00 ')
|
||||||
|
//beep(10)
|
||||||
|
//test exit delay
|
||||||
|
//log.debug device.zigbeeId
|
||||||
|
//testingTesting()
|
||||||
|
//discoverCmds()
|
||||||
|
//zigbee.configureReporting(1,0x20,0x20,3600,43200,0x01) //battery reporting
|
||||||
|
//["raw 0x0001 {00 00 06 00 2000 20 100E FEFF 01}",
|
||||||
|
//"send 0x${device.deviceNetworkId} 1 1"]
|
||||||
|
//zigbee.command(0x0003, 0x00, "0500") //Identify: blinks connection light
|
||||||
|
|
||||||
|
//log.debug //temperature reporting
|
||||||
|
|
||||||
|
return zigbee.readAttribute(0x0020,0x01) +
|
||||||
|
zigbee.readAttribute(0x0020,0x02) +
|
||||||
|
zigbee.readAttribute(0x0020,0x03)
|
||||||
|
}
|
||||||
|
|
||||||
|
private discoverCmds(){
|
||||||
|
List cmds = ["raw 0x0501 {08 01 11 0011}", 'delay 200',
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", 'delay 500']
|
||||||
|
cmds
|
||||||
|
}
|
||||||
|
|
||||||
|
private testingTesting() {
|
||||||
|
log.debug "Delay: "+device.currentState("armMode").toString()
|
||||||
|
List cmds = ["raw 0x501 {09 01 04 050A}", 'delay 200',
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", 'delay 500']
|
||||||
|
cmds
|
||||||
|
}
|
||||||
@@ -21,7 +21,6 @@ metadata {
|
|||||||
capability "Battery"
|
capability "Battery"
|
||||||
|
|
||||||
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85"
|
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85"
|
||||||
fingerprint mfr: "0086", prod: "0001", model: "0026", deviceJoinName: "Aeon Panic Button"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -131,12 +130,5 @@ def updated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def initialize() {
|
def initialize() {
|
||||||
def zwMap = getZwaveInfo()
|
sendEvent(name: "numberOfButtons", value: 4)
|
||||||
def buttons = 4 // Default for Key Fob
|
|
||||||
|
|
||||||
// Only one button for Aeon Panic Button
|
|
||||||
if (zwMap && zwMap.mfr == "0086" && zwMap.prod == "0001" && zwMap.model == "0026") {
|
|
||||||
buttons = 1
|
|
||||||
}
|
|
||||||
sendEvent(name: "numberOfButtons", value: buttons)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
.st-ignore
|
|
||||||
README.md
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# Aeon Multisensor 6
|
|
||||||
|
|
||||||
Cloud Execution
|
|
||||||
|
|
||||||
Works with:
|
|
||||||
|
|
||||||
* [Aeon Labs MultiSensor 6](https://www.smartthings.com/products/aeon-labs-multisensor-6)
|
|
||||||
|
|
||||||
## Table of contents
|
|
||||||
|
|
||||||
* [Capabilities](#capabilities)
|
|
||||||
* [Health](#device-health)
|
|
||||||
* [Troubleshooting](#troubleshooting)
|
|
||||||
|
|
||||||
## Capabilities
|
|
||||||
|
|
||||||
* **Motion Sensor** - can detect motion
|
|
||||||
* **Temperature Measurement** - defines device measures current temperature
|
|
||||||
* **Relative Humidity Measurement** - allow reading the relative humidity from devices that support it
|
|
||||||
* **Illuminance Measurement** - gives the illuminance reading from devices that support it
|
|
||||||
* **Ultraviolet Index** - gives the ability to get the ultraviolet index from devices that report it
|
|
||||||
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
|
|
||||||
* **Sensor** - detects sensor events
|
|
||||||
* **Battery** - defines device uses a battery
|
|
||||||
* **Health Check** - indicates ability to get device health notifications
|
|
||||||
|
|
||||||
## Device Health
|
|
||||||
|
|
||||||
Aeon Labs MultiSensor 6 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 MultiSensor 6 Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206157226)
|
|
||||||
@@ -22,7 +22,6 @@ metadata {
|
|||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Health Check"
|
|
||||||
|
|
||||||
attribute "tamper", "enum", ["detected", "clear"]
|
attribute "tamper", "enum", ["detected", "clear"]
|
||||||
attribute "batteryStatus", "string"
|
attribute "batteryStatus", "string"
|
||||||
@@ -30,7 +29,6 @@ metadata {
|
|||||||
|
|
||||||
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
|
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
|
||||||
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A"
|
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A"
|
||||||
fingerprint mfr:"0086", prod:"0102", model:"0064", deviceJoinName: "Aeon Labs MultiSensor 6"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -129,14 +127,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def installed(){
|
|
||||||
// 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])
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
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])
|
|
||||||
log.debug "Updated with settings: ${settings}"
|
log.debug "Updated with settings: ${settings}"
|
||||||
log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}"
|
log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}"
|
||||||
|
|
||||||
@@ -335,13 +326,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
|||||||
createEvent(descriptionText: cmd.toString(), isStateChange: false)
|
createEvent(descriptionText: cmd.toString(), isStateChange: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
|
||||||
secure(zwave.batteryV1.batteryGet())
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
// This sensor joins as a secure device if you double-click the button to include it
|
// This sensor joins as a secure device if you double-click the button to include it
|
||||||
log.debug "${device.displayName} is configuring its settings"
|
log.debug "${device.displayName} is configuring its settings"
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ metadata {
|
|||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Health Check"
|
|
||||||
|
|
||||||
attribute "thermostatFanState", "string"
|
attribute "thermostatFanState", "string"
|
||||||
|
|
||||||
@@ -19,7 +18,6 @@ metadata {
|
|||||||
command "quickSetHeat"
|
command "quickSetHeat"
|
||||||
|
|
||||||
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
|
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
|
||||||
fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulator metadata
|
// simulator metadata
|
||||||
@@ -108,16 +106,6 @@ 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])
|
|
||||||
}
|
|
||||||
|
|
||||||
def installed() {
|
|
||||||
// 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])
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(String description)
|
def parse(String description)
|
||||||
{
|
{
|
||||||
def result = []
|
def result = []
|
||||||
@@ -451,14 +439,6 @@ def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
|
|||||||
], delay)
|
], delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* PING is used by Device-Watch in attempt to reach the Device
|
|
||||||
* */
|
|
||||||
def ping() {
|
|
||||||
log.debug "ping() called"
|
|
||||||
refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
delayBetween([
|
delayBetween([
|
||||||
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
|
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2017 SmartThings
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Everspring ST815 Illuminance Sensor
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2017-3-4
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "Everspring Illuminance Sensor", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Illuminance Measurement"
|
|
||||||
capability "Battery"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Sensor"
|
|
||||||
capability "Health Check"
|
|
||||||
|
|
||||||
fingerprint mfr:"0060", prod:"0007", model:"0001"
|
|
||||||
}
|
|
||||||
|
|
||||||
simulator {
|
|
||||||
for( int i = 0; i <= 100; i += 20 ) {
|
|
||||||
status "illuminace ${i} lux": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
|
|
||||||
scaledSensorValue: i, precision: 0, sensorType: 3, scale: 1).incomingMessage()
|
|
||||||
}
|
|
||||||
|
|
||||||
for( int i = 0; i <= 100; i += 20 ) {
|
|
||||||
status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
|
|
||||||
batteryLevel: i).incomingMessage()
|
|
||||||
}
|
|
||||||
|
|
||||||
status "wakeup": "command: 8407, payload: "
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
|
||||||
state "temperature", label:'${currentValue}°',
|
|
||||||
backgroundColors:[
|
|
||||||
[value: 32, color: "#153591"],
|
|
||||||
[value: 44, color: "#1e9cbb"],
|
|
||||||
[value: 59, color: "#90d2a7"],
|
|
||||||
[value: 74, color: "#44b621"],
|
|
||||||
[value: 84, color: "#f1d801"],
|
|
||||||
[value: 92, color: "#d04e00"],
|
|
||||||
[value: 98, color: "#bc2323"]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
|
|
||||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
|
||||||
}
|
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
|
||||||
}
|
|
||||||
|
|
||||||
main( ["temperature", "humidity"] )
|
|
||||||
details( ["temperature", "humidity", "battery"] )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
state.configured = false
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(String description) {
|
|
||||||
def result = []
|
|
||||||
|
|
||||||
def cmd = zwave.parse(description, [0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
|
|
||||||
|
|
||||||
if (cmd) {
|
|
||||||
result = zwaveEvent(cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result instanceof List) {
|
|
||||||
log.debug "Parsed '$description' to ${result.collect { it.respondsTo("toHubAction") ? it.toHubAction() : it }}"
|
|
||||||
} else {
|
|
||||||
log.debug "Parsed '$description' to ${result}"
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
|
|
||||||
def result = [
|
|
||||||
createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
|
|
||||||
]
|
|
||||||
if (state.configured) {
|
|
||||||
result << response(zwave.batteryV1.batteryGet())
|
|
||||||
} else {
|
|
||||||
result << response(configure())
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
|
|
||||||
if (cmd.alarmType == 1 && cmd.alarmType == 0xFF) {
|
|
||||||
return createEvent(descriptionText: "${device.displayName} battery is low", isStateChange: true)
|
|
||||||
} else if (cmd.alarmType == 2 && cmd.alarmLevel == 1) {
|
|
||||||
return createEvent(descriptionText: "${device.displayName} powered up", isStateChange: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) {
|
|
||||||
|
|
||||||
def map = [:]
|
|
||||||
switch( cmd.sensorType ) {
|
|
||||||
case 3:
|
|
||||||
// luminance
|
|
||||||
map.value = cmd.scaledSensorValue.toInteger().toString()
|
|
||||||
map.unit = "lux"
|
|
||||||
map.name = "illuminance"
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return createEvent(map)
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
|
||||||
def map = [ name: "battery", unit: "%" ]
|
|
||||||
if (cmd.batteryLevel == 0xFF) {
|
|
||||||
map.value = 1
|
|
||||||
map.descriptionText = "${device.displayName} has a low battery"
|
|
||||||
map.isStateChange = true
|
|
||||||
} else {
|
|
||||||
map.value = cmd.batteryLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
def response_cmds = []
|
|
||||||
if (!currentTemperature) {
|
|
||||||
response_cmds << zwave.sensorMultilevelV2.sensorMultilevelGet().format()
|
|
||||||
response_cmds << "delay 1000"
|
|
||||||
}
|
|
||||||
response_cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
|
|
||||||
|
|
||||||
return [createEvent(map), response(response_cmds)]
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
|
||||||
log.debug "Unhandled: ${cmd.toString()}"
|
|
||||||
return [:]
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
state.configured = true
|
|
||||||
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
|
||||||
delayBetween([
|
|
||||||
// Auto report time interval in minutes
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 2, scaledConfigurationValue: 20).format(),
|
|
||||||
|
|
||||||
// Auto report lux change threshold
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: 30).format(),
|
|
||||||
|
|
||||||
// Get battery – report triggers WakeUpNMI
|
|
||||||
zwave.batteryV1.batteryGet().format()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2017 SmartThings
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Everspring ST814 Temperature/Humidity Sensor
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
* Date: 2017-3-4
|
|
||||||
*/
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
definition (name: "Everspring ST814", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Temperature Measurement"
|
|
||||||
capability "Relative Humidity Measurement"
|
|
||||||
capability "Battery"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Sensor"
|
|
||||||
capability "Health Check"
|
|
||||||
|
|
||||||
fingerprint mfr:"0060", prod:"0006", model:"0001"
|
|
||||||
}
|
|
||||||
|
|
||||||
simulator {
|
|
||||||
for( int i = 0; i <= 100; i += 20 ) {
|
|
||||||
status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
|
|
||||||
scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
|
|
||||||
}
|
|
||||||
|
|
||||||
for( int i = 0; i <= 100; i += 20 ) {
|
|
||||||
status "humidity ${i}%": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
|
|
||||||
scaledSensorValue: i, precision: 0, sensorType: 5).incomingMessage()
|
|
||||||
}
|
|
||||||
|
|
||||||
for( int i = 0; i <= 100; i += 20 ) {
|
|
||||||
status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
|
|
||||||
batteryLevel: i).incomingMessage()
|
|
||||||
}
|
|
||||||
status "wakeup": "command: 8407, payload: "
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
|
||||||
state "temperature", label:'${currentValue}°',
|
|
||||||
backgroundColors:[
|
|
||||||
[value: 32, color: "#153591"],
|
|
||||||
[value: 44, color: "#1e9cbb"],
|
|
||||||
[value: 59, color: "#90d2a7"],
|
|
||||||
[value: 74, color: "#44b621"],
|
|
||||||
[value: 84, color: "#f1d801"],
|
|
||||||
[value: 92, color: "#d04e00"],
|
|
||||||
[value: 98, color: "#bc2323"]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
|
|
||||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
|
||||||
}
|
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
|
||||||
}
|
|
||||||
|
|
||||||
main( ["temperature", "humidity"] )
|
|
||||||
details( ["temperature", "humidity", "battery"] )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
state.configured = false
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(String description) {
|
|
||||||
def result = []
|
|
||||||
|
|
||||||
def cmd = zwave.parse(description, [0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
|
|
||||||
|
|
||||||
if (cmd) {
|
|
||||||
result = zwaveEvent(cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result instanceof List) {
|
|
||||||
log.debug "Parsed '$description' to ${result.collect { it.respondsTo("toHubAction") ? it.toHubAction() : it }}"
|
|
||||||
} else {
|
|
||||||
log.debug "Parsed '$description' to ${result}"
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
|
|
||||||
def result = [
|
|
||||||
createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
|
|
||||||
]
|
|
||||||
if (state.configured) {
|
|
||||||
result << response(zwave.batteryV1.batteryGet())
|
|
||||||
} else {
|
|
||||||
result << response(configure())
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
|
|
||||||
if (cmd.alarmType == 1 && cmd.alarmType == 0xFF) {
|
|
||||||
return createEvent(descriptionText: "${device.displayName} battery is low", isStateChange: true)
|
|
||||||
} else if (cmd.alarmType == 2 && cmd.alarmLevel == 1) {
|
|
||||||
return createEvent(descriptionText: "${device.displayName} powered up", isStateChange: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) {
|
|
||||||
|
|
||||||
def map = [:]
|
|
||||||
switch( cmd.sensorType ) {
|
|
||||||
case 1:
|
|
||||||
/* temperature */
|
|
||||||
def cmdScale = cmd.scale == 1 ? "F" : "C"
|
|
||||||
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
|
|
||||||
map.unit = getTemperatureScale()
|
|
||||||
map.name = "temperature"
|
|
||||||
break
|
|
||||||
case 5:
|
|
||||||
/* humidity */
|
|
||||||
map.value = cmd.scaledSensorValue.toInteger().toString()
|
|
||||||
map.unit = "%"
|
|
||||||
map.name = "humidity"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return createEvent(map)
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
|
||||||
def map = [ name: "battery", unit: "%" ]
|
|
||||||
if (cmd.batteryLevel == 0xFF) {
|
|
||||||
map.value = 1
|
|
||||||
map.descriptionText = "${device.displayName} has a low battery"
|
|
||||||
map.isStateChange = true
|
|
||||||
} else {
|
|
||||||
map.value = cmd.batteryLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
def response_cmds = []
|
|
||||||
if (!currentTemperature) {
|
|
||||||
response_cmds << zwave.sensorMultilevelV2.sensorMultilevelGet().format()
|
|
||||||
response_cmds << "delay 1000"
|
|
||||||
}
|
|
||||||
response_cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
|
|
||||||
|
|
||||||
return [createEvent(map), response(response_cmds)]
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
|
|
||||||
def result = null
|
|
||||||
def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
|
|
||||||
log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
|
|
||||||
if (encapsulatedCommand) {
|
|
||||||
result = zwaveEvent(encapsulatedCommand)
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
|
||||||
log.debug "Unhandled: ${cmd.toString()}"
|
|
||||||
return [:]
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure() {
|
|
||||||
state.configured = true
|
|
||||||
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
|
||||||
delayBetween([
|
|
||||||
// Auto report time interval in minutes
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: 20).format(),
|
|
||||||
|
|
||||||
// Auto report temperature change threshold
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 7, size: 1, scaledConfigurationValue: 2).format(),
|
|
||||||
|
|
||||||
// Auto report humidity change threshold
|
|
||||||
zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: 5).format(),
|
|
||||||
|
|
||||||
// Get battery – report triggers WakeUpNMI
|
|
||||||
zwave.batteryV1.batteryGet().format()
|
|
||||||
])
|
|
||||||
}
|
|
||||||
@@ -47,14 +47,14 @@
|
|||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Health Check"
|
capability "Health Check"
|
||||||
command "resetParams2StDefaults"
|
|
||||||
command "listCurrentParams"
|
|
||||||
command "updateZwaveParam"
|
|
||||||
command "test"
|
|
||||||
command "configure"
|
|
||||||
|
|
||||||
fingerprint mfr:"010F", prod:"0800", model:"2001"
|
command "resetParams2StDefaults"
|
||||||
fingerprint mfr:"010F", prod:"0800", model:"1001"
|
command "listCurrentParams"
|
||||||
|
command "updateZwaveParam"
|
||||||
|
command "test"
|
||||||
|
command "configure"
|
||||||
|
|
||||||
|
fingerprint deviceId: "0x2001", inClusters: "0x30,0x84,0x85,0x80,0x8F,0x56,0x72,0x86,0x70,0x8E,0x31,0x9C,0xEF,0x30,0x31,0x9C"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -107,8 +107,8 @@
|
|||||||
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
|
||||||
}
|
}
|
||||||
standardTile("acceleration", "device.acceleration") {
|
standardTile("acceleration", "device.acceleration") {
|
||||||
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#00a0dc")
|
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
||||||
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc")
|
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.watervalve") {
|
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Health Check"
|
capability "Health Check"
|
||||||
capability "Valve"
|
capability "Valve"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70"
|
fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70"
|
||||||
fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve"
|
fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve"
|
||||||
}
|
}
|
||||||
@@ -34,22 +34,19 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tile definitions
|
// tile definitions
|
||||||
tiles(scale: 2) {
|
tiles {
|
||||||
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
standardTile("contact", "device.contact", width: 2, height: 2, canChangeIcon: true) {
|
||||||
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") {
|
state "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
||||||
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
state "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
||||||
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
state "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
|
||||||
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
|
state "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
||||||
attributeState "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||||
standardTile("refresh", "device.valve", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "valve"
|
main "contact"
|
||||||
details(["valve","refresh"])
|
details(["contact","refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,23 +62,22 @@ def updated(){
|
|||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.trace description
|
log.trace description
|
||||||
|
def result = null
|
||||||
def cmd = zwave.parse(description)
|
def cmd = zwave.parse(description)
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
return zwaveEvent(cmd)
|
result = createEvent(zwaveEvent(cmd))
|
||||||
}
|
}
|
||||||
log.debug "Could not parse message"
|
log.debug "Parse returned ${result?.descriptionText}"
|
||||||
return null
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
||||||
def value = cmd.value ? "closed" : "open"
|
def value = cmd.value ? "closed" : "open"
|
||||||
|
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
|
||||||
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
|
|
||||||
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||||
return createEvent([:]) // Handles all Z-Wave commands we aren't interested in
|
[:] // Handles all Z-Wave commands we aren't interested in
|
||||||
}
|
}
|
||||||
|
|
||||||
def open() {
|
def open() {
|
||||||
@@ -102,9 +98,3 @@ def ping() {
|
|||||||
def refresh() {
|
def refresh() {
|
||||||
zwave.switchBinaryV1.switchBinaryGet().format()
|
zwave.switchBinaryV1.switchBinaryGet().format()
|
||||||
}
|
}
|
||||||
|
|
||||||
def createEventWithDebug(eventMap) {
|
|
||||||
def event = createEvent(eventMap)
|
|
||||||
log.debug "Event created with ${event?.descriptionText}"
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) {
|
multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) {
|
||||||
tileAttribute("device.motion", key: "PRIMARY_CONTROL") {
|
tileAttribute("device.motion", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC"
|
attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#53a7c0"
|
||||||
attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#cccccc"
|
attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#ffffff"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ metadata {
|
|||||||
state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc")
|
state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc")
|
||||||
}
|
}
|
||||||
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
||||||
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#00a0dc")
|
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#53a7c0")
|
||||||
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#cccccc")
|
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#ffffff")
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
state("temperature", label: '${currentValue}°',
|
state("temperature", label: '${currentValue}°',
|
||||||
@@ -178,7 +178,7 @@ private List<Map> handleAcceleration(descMap) {
|
|||||||
result += parseAxis(descMap.additionalAttrs)
|
result += parseAxis(descMap.additionalAttrs)
|
||||||
}
|
}
|
||||||
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
|
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
|
||||||
def addAttrs = descMap.additionalAttrs ?: []
|
def addAttrs = descMap.additionalAttrs
|
||||||
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
|
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
|
||||||
result += parseAxis(addAttrs)
|
result += parseAxis(addAttrs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2) {
|
standardTile("motion", "device.motion", width: 2, height: 2) {
|
||||||
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
|
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
||||||
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC")
|
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
||||||
state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000")
|
state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import physicalgraph.zigbee.zcl.DataType
|
|||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ metadata {
|
|||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
||||||
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
||||||
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
||||||
@@ -83,9 +83,6 @@ def parse(String description) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendEvent(event)
|
sendEvent(event)
|
||||||
//handle valve attribute
|
|
||||||
event.name = "valve"
|
|
||||||
sendEvent(event)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
def descMap = zigbee.parseDescriptionAsMap(description)
|
def descMap = zigbee.parseDescriptionAsMap(description)
|
||||||
|
|||||||
@@ -75,10 +75,6 @@ def parse(String description) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
def uninstalled() {
|
|
||||||
sendEvent(name: "epEvent", value: "delete all", isStateChange: true, displayed: false, descriptionText: "Delete endpoint devices")
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
|
||||||
[ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true),
|
[ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true),
|
||||||
response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ]
|
response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ]
|
||||||
|
|||||||
@@ -30,15 +30,9 @@ metadata {
|
|||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82"
|
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82"
|
||||||
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+
|
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+
|
||||||
fingerprint mfr:"0086", prod:"0002", model:"001D", deviceJoinName: "Aeon Labs Door/Window Sensor (Gen 5)"
|
fingerprint mfr:"0086", prod:"0002", model:"001D", deviceJoinName: "Aeon Labs Door/Window Sensor (Gen 5)"
|
||||||
fingerprint mfr:"0086", prod:"0102", model:"0070", deviceJoinName: "Aeon Labs Door/Window Sensor 6"
|
|
||||||
fingerprint mfr:"0086", prod:"0102", model:"0059", deviceJoinName: "Aeon Labs Recessed Door Sensor"
|
|
||||||
fingerprint mfr:"014A", prod:"0001", model:"0002", deviceJoinName: "Ecolink Door/Window Sensor"
|
fingerprint mfr:"014A", prod:"0001", model:"0002", deviceJoinName: "Ecolink Door/Window Sensor"
|
||||||
fingerprint mfr:"014A", prod:"0001", model:"0003", deviceJoinName: "Ecolink Tilt Sensor"
|
fingerprint mfr:"0086", prod:"0102", model:"0070", deviceJoinName: "Aeon Labs Door/Window Sensor 6"
|
||||||
fingerprint mfr:"011A", prod:"0601", model:"0903", deviceJoinName: "Enerwave Magnetic Door/Window Sensor"
|
fingerprint mfr:"011A", prod:"0601", model:"0903", deviceJoinName: "Enerwave Magnetic Door/Window Sensor"
|
||||||
fingerprint mfr:"014F", prod:"2001", model:"0102", deviceJoinName: "Nortek GoControl Door/Window Sensor"
|
|
||||||
fingerprint mfr:"0063", prod:"4953", model:"3031", deviceJoinName: "Jasco Hinge Pin Door Sensor"
|
|
||||||
fingerprint mfr:"019A", prod:"0003", model:"0003", deviceJoinName: "Sensative Strips"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulator metadata
|
// simulator metadata
|
||||||
|
|||||||
@@ -26,24 +26,7 @@ metadata {
|
|||||||
|
|
||||||
fingerprint deviceId: "0x4003", inClusters: "0x98"
|
fingerprint deviceId: "0x4003", inClusters: "0x98"
|
||||||
fingerprint deviceId: "0x4004", inClusters: "0x98"
|
fingerprint deviceId: "0x4004", inClusters: "0x98"
|
||||||
fingerprint mfr:"0090", prod:"0001", model:"0236", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock"
|
fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Key Free Touchscreen Deadbolt"
|
||||||
fingerprint mfr:"0090", prod:"0003", model:"0238", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock"
|
|
||||||
fingerprint mfr:"0090", prod:"0001", model:"0001", deviceJoinName: "KwikSet SmartCode 910 Contemporary Deadbolt Door Lock"
|
|
||||||
fingerprint mfr:"0090", prod:"0003", model:"0339", deviceJoinName: "KwikSet SmartCode 912 Lever Door Lock"
|
|
||||||
fingerprint mfr:"0090", prod:"0003", model:"4006", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock" //backlit version
|
|
||||||
fingerprint mfr:"0090", prod:"0003", model:"0440", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock"
|
|
||||||
fingerprint mfr:"0090", prod:"0001", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock"
|
|
||||||
fingerprint mfr:"0090", prod:"0003", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock"
|
|
||||||
fingerprint mfr:"003B", prod:"6341", model:"0544", deviceJoinName: "Schlage Camelot Touchscreen Deadbolt Door Lock"
|
|
||||||
fingerprint mfr:"003B", prod:"6341", model:"5044", deviceJoinName: "Schlage Century Touchscreen Deadbolt Door Lock"
|
|
||||||
fingerprint mfr:"003B", prod:"634B", model:"504C", deviceJoinName: "Schlage Connected Keypad Lever Door Lock"
|
|
||||||
fingerprint mfr:"0129", prod:"0002", model:"0800", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD120
|
|
||||||
fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD220, YRD240
|
|
||||||
fingerprint mfr:"0129", prod:"0002", model:"FFFF", deviceJoinName: "Yale Touchscreen Lever Door Lock" // YRD220
|
|
||||||
fingerprint mfr:"0129", prod:"0004", model:"0800", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD110
|
|
||||||
fingerprint mfr:"0129", prod:"0004", model:"0000", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD210
|
|
||||||
fingerprint mfr:"0129", prod:"0001", model:"0000", deviceJoinName: "Yale Push Button Lever Door Lock" // YRD210
|
|
||||||
fingerprint mfr:"0129", prod:"8002", model:"0600", deviceJoinName: "Yale Assure Lock with Bluetooth"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -152,10 +135,6 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupported
|
|||||||
|
|
||||||
def zwaveEvent(DoorLockOperationReport cmd) {
|
def zwaveEvent(DoorLockOperationReport cmd) {
|
||||||
def result = []
|
def result = []
|
||||||
|
|
||||||
unschedule(followupStateCheck)
|
|
||||||
unschedule(stateCheck)
|
|
||||||
|
|
||||||
def map = [ name: "lock" ]
|
def map = [ name: "lock" ]
|
||||||
if (cmd.doorLockMode == 0xFF) {
|
if (cmd.doorLockMode == 0xFF) {
|
||||||
map.value = "locked"
|
map.value = "locked"
|
||||||
@@ -369,7 +348,7 @@ def zwaveEvent(UserCodeReport cmd) {
|
|||||||
code = state["set$name"] ?: decrypt(state[name]) ?: "****"
|
code = state["set$name"] ?: decrypt(state[name]) ?: "****"
|
||||||
state.remove("set$name".toString())
|
state.remove("set$name".toString())
|
||||||
} else {
|
} else {
|
||||||
map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ], isStateChange: true ]
|
map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ] ]
|
||||||
map.descriptionText = "$device.displayName code $cmd.userIdentifier is set"
|
map.descriptionText = "$device.displayName code $cmd.userIdentifier is set"
|
||||||
map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode)
|
map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode)
|
||||||
map.isStateChange = true
|
map.isStateChange = true
|
||||||
@@ -460,12 +439,11 @@ def zwaveEvent(physicalgraph.zwave.commands.timev1.TimeGet cmd) {
|
|||||||
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
|
||||||
// The old Schlage locks use group 1 for basic control - we don't want that, so unsubscribe from group 1
|
// The old Schlage locks use group 1 for basic control - we don't want that, so unsubscribe from group 1
|
||||||
def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ]
|
def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ]
|
||||||
def cmds = [
|
result << response(zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
||||||
zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format(),
|
if (state.assoc != zwaveHubNodeId) {
|
||||||
"delay 1200",
|
result << response(zwave.associationV1.associationGet(groupingIdentifier:2))
|
||||||
zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
}
|
||||||
]
|
result
|
||||||
[result, response(cmds)]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
||||||
@@ -535,18 +513,11 @@ def unlockwtimeout() {
|
|||||||
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
|
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PING is used by Device-Watch in attempt to reach the Device
|
||||||
|
* */
|
||||||
def ping() {
|
def ping() {
|
||||||
runIn(30, followupStateCheck)
|
refresh()
|
||||||
secure(zwave.doorLockV1.doorLockOperationGet())
|
|
||||||
}
|
|
||||||
|
|
||||||
def followupStateCheck() {
|
|
||||||
runEvery1Hour(stateCheck)
|
|
||||||
stateCheck()
|
|
||||||
}
|
|
||||||
|
|
||||||
def stateCheck() {
|
|
||||||
sendHubCommand(new physicalgraph.device.HubAction(secure(zwave.doorLockV1.doorLockOperationGet())))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ metadata {
|
|||||||
fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814
|
fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814
|
||||||
fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02
|
fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02
|
||||||
fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC
|
fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC
|
||||||
fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Portable Smart Motion Sensor"
|
fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Smart Motion Sensor"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ metadata {
|
|||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("motion", "device.motion", width: 3, height: 2) {
|
standardTile("motion", "device.motion", width: 3, height: 2) {
|
||||||
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
|
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
||||||
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC"
|
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
|
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ metadata {
|
|||||||
attribute "alarmState", "string"
|
attribute "alarmState", "string"
|
||||||
|
|
||||||
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
|
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
|
||||||
fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector"
|
|
||||||
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
|
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.watervalve") {
|
definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Health Check"
|
capability "Health Check"
|
||||||
capability "Valve"
|
capability "Valve"
|
||||||
@@ -37,7 +37,7 @@ metadata {
|
|||||||
// tile definitions
|
// tile definitions
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
|
||||||
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
|
||||||
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
|
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
|
||||||
@@ -45,7 +45,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.valve", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.contact", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,19 +68,18 @@ def updated() {
|
|||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.trace "parse description : $description"
|
log.trace "parse description : $description"
|
||||||
|
def result = null
|
||||||
def cmd = zwave.parse(description, [0x20: 1])
|
def cmd = zwave.parse(description, [0x20: 1])
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
return zwaveEvent(cmd)
|
result = createEvent(zwaveEvent(cmd))
|
||||||
}
|
}
|
||||||
log.debug "Could not parse message"
|
log.debug "Parse returned ${result?.descriptionText}"
|
||||||
return null
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||||
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
|
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
|
||||||
|
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
|
||||||
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
|
|
||||||
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { //TODO should show MSR when device is discovered
|
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { //TODO should show MSR when device is discovered
|
||||||
@@ -90,22 +89,20 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
|
|||||||
log.debug "productTypeId: ${cmd.productTypeId}"
|
log.debug "productTypeId: ${cmd.productTypeId}"
|
||||||
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
|
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
|
||||||
updateDataValue("MSR", msr)
|
updateDataValue("MSR", msr)
|
||||||
return createEventWithDebug([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
|
[descriptionText: "$device.displayName MSR: $msr", isStateChange: false]
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
|
||||||
return createEventWithDebug([descriptionText: cmd.toString(), isStateChange: true, displayed: true])
|
[descriptionText: cmd.toString(), isStateChange: true, displayed: true]
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
||||||
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
|
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
|
||||||
|
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
|
||||||
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
|
|
||||||
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||||
return createEvent([:]) // Handles all Z-Wave commands we aren't interested in
|
[:] // Handles all Z-Wave commands we aren't interested in
|
||||||
}
|
}
|
||||||
|
|
||||||
def open() {
|
def open() {
|
||||||
@@ -141,9 +138,3 @@ def refresh() {
|
|||||||
}
|
}
|
||||||
delayBetween(commands,100)
|
delayBetween(commands,100)
|
||||||
}
|
}
|
||||||
|
|
||||||
def createEventWithDebug(eventMap) {
|
|
||||||
def event = createEvent(eventMap)
|
|
||||||
log.debug "Event created with ${event?.descriptionText}"
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
|
|||||||
1545
smartapps/ethayer/user-lock-manager.src/user-lock-manager.groovy
Normal file
1545
smartapps/ethayer/user-lock-manager.src/user-lock-manager.groovy
Normal file
File diff suppressed because it is too large
Load Diff
@@ -98,7 +98,7 @@ def motionHandler(evt) {
|
|||||||
else {
|
else {
|
||||||
state.motionStopTime = now()
|
state.motionStopTime = now()
|
||||||
if(delayMinutes) {
|
if(delayMinutes) {
|
||||||
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: true])
|
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: false])
|
||||||
} else {
|
} else {
|
||||||
turnOffMotionAfterDelay()
|
turnOffMotionAfterDelay()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -296,7 +296,10 @@ def pageHistory() {
|
|||||||
if (history.size() == 0) {
|
if (history.size() == 0) {
|
||||||
paragraph "No history available."
|
paragraph "No history available."
|
||||||
} else {
|
} else {
|
||||||
paragraph "Not implemented"
|
history.each() {
|
||||||
|
def text = "" + new Date(it.time + location.timeZone.rawOffset ).format("yyyy-MM-dd HH:mm") + ": " + it.event + " - " + it.description
|
||||||
|
paragraph text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -405,6 +408,7 @@ def pageConfigureZones() {
|
|||||||
section("${it.displayName} (contact)") {
|
section("${it.displayName} (contact)") {
|
||||||
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"exterior"
|
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"exterior"
|
||||||
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:true
|
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:true
|
||||||
|
input "chime_${devId}", "bool", title:"Chime on open", defaultValue:true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -416,6 +420,7 @@ def pageConfigureZones() {
|
|||||||
section("${it.displayName} (motion)") {
|
section("${it.displayName} (motion)") {
|
||||||
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"interior"
|
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"interior"
|
||||||
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
||||||
|
input "chime_${devId}", "bool", title:"Chime on motion", defaultValue:false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -427,6 +432,7 @@ def pageConfigureZones() {
|
|||||||
section("${it.displayName} (movement)") {
|
section("${it.displayName} (movement)") {
|
||||||
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"interior"
|
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"interior"
|
||||||
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
||||||
|
input "chime_${devId}", "bool", title:"Chime on movement", defaultValue:false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -438,6 +444,7 @@ def pageConfigureZones() {
|
|||||||
section("${it.displayName} (smoke)") {
|
section("${it.displayName} (smoke)") {
|
||||||
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"alert"
|
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"alert"
|
||||||
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
||||||
|
input "chime_${devId}", "bool", title:"Chime on smoke", defaultValue:false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,6 +456,7 @@ def pageConfigureZones() {
|
|||||||
section("${it.displayName} (moisture)") {
|
section("${it.displayName} (moisture)") {
|
||||||
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"alert"
|
input "type_${devId}", "enum", title:"Zone Type", metadata:[values:zoneTypes], defaultValue:"alert"
|
||||||
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
input "delay_${devId}", "bool", title:"Entry/Exit Delays", defaultValue:false
|
||||||
|
input "chime_${devId}", "bool", title:"Chime on water", defaultValue:false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,6 +479,14 @@ def pageArmingOptions() {
|
|||||||
"is armed without setting off an alarm. You can optionally disable " +
|
"is armed without setting off an alarm. You can optionally disable " +
|
||||||
"entry and exit delay when the alarm is armed in Stay mode."
|
"entry and exit delay when the alarm is armed in Stay mode."
|
||||||
|
|
||||||
|
def inputKeypads = [
|
||||||
|
name: "keypads",
|
||||||
|
type: "capability.lockCodes",
|
||||||
|
title: "Keypads for Exit / Entry delay",
|
||||||
|
multiple: true,
|
||||||
|
required: false
|
||||||
|
]
|
||||||
|
|
||||||
def inputAwayModes = [
|
def inputAwayModes = [
|
||||||
name: "awayModes",
|
name: "awayModes",
|
||||||
type: "mode",
|
type: "mode",
|
||||||
@@ -507,10 +523,19 @@ def pageArmingOptions() {
|
|||||||
def inputDelayStay = [
|
def inputDelayStay = [
|
||||||
name: "stayDelayOff",
|
name: "stayDelayOff",
|
||||||
type: "bool",
|
type: "bool",
|
||||||
title: "Disable delays in Stay mode",
|
title: "Disable alarm (entry) delay in Stay mode",
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
required: true
|
required: true
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def inputExitDelayStay = [
|
||||||
|
name: "stayExitDelayOff",
|
||||||
|
type: "bool",
|
||||||
|
title: "Disable arming (exit) delay in Stay mode",
|
||||||
|
defaultValue: true,
|
||||||
|
required: true
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def pageProperties = [
|
def pageProperties = [
|
||||||
name: "pageArmingOptions",
|
name: "pageArmingOptions",
|
||||||
@@ -524,16 +549,21 @@ def pageArmingOptions() {
|
|||||||
paragraph helpArming
|
paragraph helpArming
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section("Keypads") {
|
||||||
|
input inputKeypads
|
||||||
|
}
|
||||||
|
|
||||||
section("Modes") {
|
section("Modes") {
|
||||||
input inputAwayModes
|
input inputAwayModes
|
||||||
input inputStayModes
|
input inputStayModes
|
||||||
input inputDisarmModes
|
input inputDisarmModes
|
||||||
}
|
}
|
||||||
|
|
||||||
section("Exit and Entry Delay") {
|
section("Exit and Entry Delay") {
|
||||||
paragraph helpDelay
|
paragraph helpDelay
|
||||||
input inputDelay
|
input inputDelay
|
||||||
input inputDelayStay
|
input inputDelayStay
|
||||||
|
input inputExitDelayStay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,6 +593,14 @@ def pageAlarmOptions() {
|
|||||||
defaultValue: "Both"
|
defaultValue: "Both"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def inputSirenEntryStrobe = [
|
||||||
|
name: "sirenEntryStrobe",
|
||||||
|
type: "bool",
|
||||||
|
title: "Strobe siren during entry delay",
|
||||||
|
defaultValue: true,
|
||||||
|
required: true
|
||||||
|
]
|
||||||
|
|
||||||
def inputSwitches = [
|
def inputSwitches = [
|
||||||
name: "switches",
|
name: "switches",
|
||||||
type: "capability.switch",
|
type: "capability.switch",
|
||||||
@@ -602,6 +640,7 @@ def pageAlarmOptions() {
|
|||||||
section("Sirens") {
|
section("Sirens") {
|
||||||
input inputAlarms
|
input inputAlarms
|
||||||
input inputSirenMode
|
input inputSirenMode
|
||||||
|
input inputSirenEntryStrobe
|
||||||
}
|
}
|
||||||
section("Switches") {
|
section("Switches") {
|
||||||
input inputSwitches
|
input inputSwitches
|
||||||
@@ -624,7 +663,49 @@ def pageNotifications() {
|
|||||||
"disarmed or when an alarm is set off. Notifications can be send " +
|
"disarmed or when an alarm is set off. Notifications can be send " +
|
||||||
"using either Push messages, SMS (text) messages and Pushbullet " +
|
"using either Push messages, SMS (text) messages and Pushbullet " +
|
||||||
"messaging service. Smart Alarm can also notify you with sounds or " +
|
"messaging service. Smart Alarm can also notify you with sounds or " +
|
||||||
"voice alerts using compatible audio devices, such as Sonos."
|
"voice alerts using compatible audio devices, such as Sonos." +
|
||||||
|
"Or using a SmartAlarm dashboard virtual device."
|
||||||
|
|
||||||
|
def inputNotificationDevice = [
|
||||||
|
name: "notificationDevice",
|
||||||
|
type: "capability.notification",
|
||||||
|
title: "Which smart alarm notification device?",
|
||||||
|
multiple: false,
|
||||||
|
required: false
|
||||||
|
]
|
||||||
|
|
||||||
|
def inputChimeDevices = [
|
||||||
|
name: "chimeDevices",
|
||||||
|
type: "capability.tone",
|
||||||
|
title: "Which Chime Devices?",
|
||||||
|
multiple: true,
|
||||||
|
required: false
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def inputSirenOnWaterAlert = [
|
||||||
|
name: "sirenOnWaterAlert",
|
||||||
|
type: "bool",
|
||||||
|
title: "Use Siren for Water Leak?",
|
||||||
|
defaultValue: true,
|
||||||
|
required: true
|
||||||
|
]
|
||||||
|
|
||||||
|
def inputSirenOnSmokeAlert = [
|
||||||
|
name: "sirenOnSmokeAlert",
|
||||||
|
type: "bool",
|
||||||
|
title: "Use Siren for Smoke Alert?",
|
||||||
|
defaultValue: true,
|
||||||
|
required: true
|
||||||
|
]
|
||||||
|
|
||||||
|
def inputSirenOnIntrusionAlert = [
|
||||||
|
name: "sirenOnIntrusionAlert",
|
||||||
|
type: "bool",
|
||||||
|
title: "Use Siren for Intrusion Alert?",
|
||||||
|
defaultValue: true,
|
||||||
|
required: true
|
||||||
|
]
|
||||||
|
|
||||||
def inputPushAlarm = [
|
def inputPushAlarm = [
|
||||||
name: "pushMessage",
|
name: "pushMessage",
|
||||||
@@ -807,6 +888,19 @@ def pageNotifications() {
|
|||||||
section("Notification Options") {
|
section("Notification Options") {
|
||||||
paragraph helpAbout
|
paragraph helpAbout
|
||||||
}
|
}
|
||||||
|
section("Notification Device")
|
||||||
|
{
|
||||||
|
input inputNotificationDevice
|
||||||
|
}
|
||||||
|
section("Chime Devices") {
|
||||||
|
input inputChimeDevices
|
||||||
|
}
|
||||||
|
section("Siren Notifcations")
|
||||||
|
{
|
||||||
|
input inputSirenOnWaterAlert
|
||||||
|
input inputSirenOnSmokeAlert
|
||||||
|
input inputSirenOnIntrusionAlert
|
||||||
|
}
|
||||||
section("Push Notifications") {
|
section("Push Notifications") {
|
||||||
input inputPushAlarm
|
input inputPushAlarm
|
||||||
input inputPushStatus
|
input inputPushStatus
|
||||||
@@ -1047,6 +1141,7 @@ private def setupInit() {
|
|||||||
state.zones = []
|
state.zones = []
|
||||||
state.alarms = []
|
state.alarms = []
|
||||||
state.history = []
|
state.history = []
|
||||||
|
state.alertType = "None"
|
||||||
} else {
|
} else {
|
||||||
def version = state.version as String
|
def version = state.version as String
|
||||||
if (version == null || version.startsWith('1')) {
|
if (version == null || version.startsWith('1')) {
|
||||||
@@ -1065,7 +1160,7 @@ private def initialize() {
|
|||||||
clearAlarm()
|
clearAlarm()
|
||||||
state.delay = settings.delay?.toInteger() ?: 30
|
state.delay = settings.delay?.toInteger() ?: 30
|
||||||
state.offSwitches = []
|
state.offSwitches = []
|
||||||
state.history = []
|
//state.history = []
|
||||||
|
|
||||||
if (settings.awayModes?.contains(location.mode)) {
|
if (settings.awayModes?.contains(location.mode)) {
|
||||||
state.armed = true
|
state.armed = true
|
||||||
@@ -1082,8 +1177,20 @@ private def initialize() {
|
|||||||
initButtons()
|
initButtons()
|
||||||
initRestApi()
|
initRestApi()
|
||||||
subscribe(location, onLocation)
|
subscribe(location, onLocation)
|
||||||
|
|
||||||
|
if (settings.notificationDevice)
|
||||||
|
{
|
||||||
|
subscribe(settings.notificationDevice, "switch.off", gotDismissMessage)
|
||||||
|
}
|
||||||
|
|
||||||
STATE()
|
STATE()
|
||||||
|
reportStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
def gotDismissMessage(evt)
|
||||||
|
{
|
||||||
|
log.debug "Got the dismiss message from the notification device.. clearing alarm!"
|
||||||
|
clearAlarm()
|
||||||
}
|
}
|
||||||
|
|
||||||
private def clearAlarm() {
|
private def clearAlarm() {
|
||||||
@@ -1103,6 +1210,7 @@ private def clearAlarm() {
|
|||||||
}
|
}
|
||||||
state.offSwitches = []
|
state.offSwitches = []
|
||||||
}
|
}
|
||||||
|
reportStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
private def initZones() {
|
private def initZones() {
|
||||||
@@ -1123,7 +1231,8 @@ private def initZones() {
|
|||||||
deviceId: it.id,
|
deviceId: it.id,
|
||||||
sensorType: "contact",
|
sensorType: "contact",
|
||||||
zoneType: settings["type_${it.id}"] ?: "exterior",
|
zoneType: settings["type_${it.id}"] ?: "exterior",
|
||||||
delay: settings["delay_${it.id}"]
|
delay: settings["delay_${it.id}"],
|
||||||
|
chime: settings["chime_${it.id}"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
subscribe(settings.z_contact, "contact.open", onContact)
|
subscribe(settings.z_contact, "contact.open", onContact)
|
||||||
@@ -1135,7 +1244,8 @@ private def initZones() {
|
|||||||
deviceId: it.id,
|
deviceId: it.id,
|
||||||
sensorType: "motion",
|
sensorType: "motion",
|
||||||
zoneType: settings["type_${it.id}"] ?: "interior",
|
zoneType: settings["type_${it.id}"] ?: "interior",
|
||||||
delay: settings["delay_${it.id}"]
|
delay: settings["delay_${it.id}"],
|
||||||
|
chime: settings["chime_${it.id}"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
subscribe(settings.z_motion, "motion.active", onMotion)
|
subscribe(settings.z_motion, "motion.active", onMotion)
|
||||||
@@ -1147,7 +1257,8 @@ private def initZones() {
|
|||||||
deviceId: it.id,
|
deviceId: it.id,
|
||||||
sensorType: "acceleration",
|
sensorType: "acceleration",
|
||||||
zoneType: settings["type_${it.id}"] ?: "interior",
|
zoneType: settings["type_${it.id}"] ?: "interior",
|
||||||
delay: settings["delay_${it.id}"]
|
delay: settings["delay_${it.id}"],
|
||||||
|
chime: settings["chime_${it.id}"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
subscribe(settings.z_movement, "acceleration.active", onMovement)
|
subscribe(settings.z_movement, "acceleration.active", onMovement)
|
||||||
@@ -1159,7 +1270,8 @@ private def initZones() {
|
|||||||
deviceId: it.id,
|
deviceId: it.id,
|
||||||
sensorType: "smoke",
|
sensorType: "smoke",
|
||||||
zoneType: settings["type_${it.id}"] ?: "alert",
|
zoneType: settings["type_${it.id}"] ?: "alert",
|
||||||
delay: settings["delay_${it.id}"]
|
delay: settings["delay_${it.id}"],
|
||||||
|
chime: settings["chime_${it.id}"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
subscribe(settings.z_smoke, "smoke.detected", onSmoke)
|
subscribe(settings.z_smoke, "smoke.detected", onSmoke)
|
||||||
@@ -1174,7 +1286,8 @@ private def initZones() {
|
|||||||
deviceId: it.id,
|
deviceId: it.id,
|
||||||
sensorType: "water",
|
sensorType: "water",
|
||||||
zoneType: settings["type_${it.id}"] ?: "alert",
|
zoneType: settings["type_${it.id}"] ?: "alert",
|
||||||
delay: settings["delay_${it.id}"]
|
delay: settings["delay_${it.id}"],
|
||||||
|
chime: settings["chime_${it.id}"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
subscribe(settings.z_water, "water.wet", onWater)
|
subscribe(settings.z_water, "water.wet", onWater)
|
||||||
@@ -1257,20 +1370,37 @@ def onWater(evt) { onZoneEvent(evt, "water") }
|
|||||||
private def onZoneEvent(evt, sensorType) {
|
private def onZoneEvent(evt, sensorType) {
|
||||||
LOG("onZoneEvent(${evt.displayName}, ${sensorType})")
|
LOG("onZoneEvent(${evt.displayName}, ${sensorType})")
|
||||||
|
|
||||||
|
state.alertType = sensorType
|
||||||
def zone = getZoneForDevice(evt.deviceId, sensorType)
|
def zone = getZoneForDevice(evt.deviceId, sensorType)
|
||||||
if (!zone) {
|
if (!zone) {
|
||||||
log.warn "Cannot find zone for device ${evt.deviceId}"
|
log.warn "Cannot find zone for device ${evt.deviceId}"
|
||||||
|
state.alertType = "None"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zone.armed) {
|
if (zone.armed) {
|
||||||
state.alarms << evt.displayName
|
state.alarms << evt.displayName
|
||||||
if (zone.zoneType == "alert" || !zone.delay || (state.stay && settings.stayDelayOff)) {
|
if (zone.zoneType == "alert" || !zone.delay || (state.stay && settings.stayDelayOff)) {
|
||||||
|
history("Alarm", "Alarm triggered by ${sensorType} sensor ${evt.displayName}")
|
||||||
activateAlarm()
|
activateAlarm()
|
||||||
} else {
|
} else {
|
||||||
|
history("Entry Delay", "Entry delay triggered by ${sensorType} sensor ${evt.displayName}")
|
||||||
|
if(settings.sirenEntryStrobe)
|
||||||
|
{
|
||||||
|
settings.alarms*.strobe()
|
||||||
|
}
|
||||||
|
keypads?.each() { it.setEntryDelay(state.delay) }
|
||||||
myRunIn(state.delay, activateAlarm)
|
myRunIn(state.delay, activateAlarm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (zone.chime)
|
||||||
|
{
|
||||||
|
chimeDevices?.each() {
|
||||||
|
it.beep()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def onLocation(evt) {
|
def onLocation(evt) {
|
||||||
@@ -1311,23 +1441,27 @@ def onButtonEvent(evt) {
|
|||||||
|
|
||||||
def armAway() {
|
def armAway() {
|
||||||
LOG("armAway()")
|
LOG("armAway()")
|
||||||
|
history("Armed Away", "Alarm armed away")
|
||||||
|
|
||||||
if (!atomicState.armed || atomicState.stay) {
|
if (!atomicState.armed || atomicState.stay) {
|
||||||
armPanel(false)
|
armPanel(false)
|
||||||
}
|
}
|
||||||
|
reportStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
def armStay() {
|
def armStay() {
|
||||||
LOG("armStay()")
|
LOG("armStay()")
|
||||||
|
history("Armed Stay", "Alarm armed stay")
|
||||||
|
|
||||||
if (!atomicState.armed || !atomicState.stay) {
|
if (!atomicState.armed || !atomicState.stay) {
|
||||||
armPanel(true)
|
armPanel(true)
|
||||||
}
|
}
|
||||||
|
reportStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
def disarm() {
|
def disarm() {
|
||||||
LOG("disarm()")
|
LOG("disarm()")
|
||||||
|
history("Disarmed", "Alarm disarmed")
|
||||||
if (atomicState.armed) {
|
if (atomicState.armed) {
|
||||||
state.armed = false
|
state.armed = false
|
||||||
state.zones.each() {
|
state.zones.each() {
|
||||||
@@ -1335,9 +1469,12 @@ def disarm() {
|
|||||||
it.armed = false
|
it.armed = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keypads?.each() { it.setDisarmed() }
|
||||||
|
|
||||||
reset()
|
reset()
|
||||||
}
|
}
|
||||||
|
reportStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
def panic() {
|
def panic() {
|
||||||
@@ -1364,6 +1501,7 @@ def reset() {
|
|||||||
|
|
||||||
notify(msg)
|
notify(msg)
|
||||||
notifyVoice()
|
notifyVoice()
|
||||||
|
reportStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
def exitDelayExpired() {
|
def exitDelayExpired() {
|
||||||
@@ -1383,6 +1521,16 @@ def exitDelayExpired() {
|
|||||||
it.armed = true
|
it.armed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(stay)
|
||||||
|
{
|
||||||
|
keypads?.each() { it.setArmedStay() }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keypads?.each() { it.setArmedAway() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def msg = "${location.name}: all "
|
def msg = "${location.name}: all "
|
||||||
if (stay) {
|
if (stay) {
|
||||||
@@ -1406,7 +1554,7 @@ private def armPanel(stay) {
|
|||||||
state.zones.each() {
|
state.zones.each() {
|
||||||
def zoneType = it.zoneType
|
def zoneType = it.zoneType
|
||||||
if (zoneType == "exterior") {
|
if (zoneType == "exterior") {
|
||||||
if (it.delay) {
|
if (it.delay && !(stay && settings.stayExitDelayOff)) {
|
||||||
it.armed = false
|
it.armed = false
|
||||||
armDelay = true
|
armDelay = true
|
||||||
} else {
|
} else {
|
||||||
@@ -1424,10 +1572,22 @@ private def armPanel(stay) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def delay = armDelay && !(stay && settings.stayDelayOff) ? atomicState.delay : 0
|
def delay = armDelay && !(stay && settings.stayExitDelayOff) ? atomicState.delay : 0
|
||||||
if (delay) {
|
if (delay) {
|
||||||
|
keypads?.each() { it.setExitDelay(delay) }
|
||||||
myRunIn(delay, exitDelayExpired)
|
myRunIn(delay, exitDelayExpired)
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(stay)
|
||||||
|
{
|
||||||
|
keypads?.each() { it.setArmedStay() }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keypads?.each() { it.setArmedAway() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def mode = stay ? "STAY" : "AWAY"
|
def mode = stay ? "STAY" : "AWAY"
|
||||||
def msg = "${location.name} "
|
def msg = "${location.name} "
|
||||||
@@ -1532,21 +1692,50 @@ def activateAlarm() {
|
|||||||
log.warn "activateAlarm: false alarm"
|
log.warn "activateAlarm: false alarm"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
history("Alarm", "Alarm Triggered")
|
||||||
|
|
||||||
switch (settings.sirenMode) {
|
if(settings.sirenEntryStrobe)
|
||||||
case "Siren":
|
{
|
||||||
settings.alarms*.siren()
|
settings.alarms*.off()
|
||||||
break
|
|
||||||
|
|
||||||
case "Strobe":
|
|
||||||
settings.alarms*.strobe()
|
|
||||||
break
|
|
||||||
|
|
||||||
case "Both":
|
|
||||||
settings.alarms*.both()
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def atype = state.alertType
|
||||||
|
|
||||||
|
if ((atype == "Water" && settings.sirenOnWaterAlert) ||
|
||||||
|
(atype == "Smoke" && settings.sirenOnSmokeAlert) ||
|
||||||
|
((atype == "contact" || atype == "acceleration" || atype == "motion") && settings.sirenOnIntrusionAlert))
|
||||||
|
{
|
||||||
|
switch (settings.sirenMode) {
|
||||||
|
case "Siren":
|
||||||
|
settings.alarms*.siren()
|
||||||
|
break
|
||||||
|
|
||||||
|
case "Strobe":
|
||||||
|
settings.alarms*.strobe()
|
||||||
|
break
|
||||||
|
|
||||||
|
case "Both":
|
||||||
|
settings.alarms*.both()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.debug "No siren for $atype Alert"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def activateAlarmPostDelay(String lastAlertType)
|
||||||
|
{
|
||||||
|
// no alarm check here as if door opens only for second with delay and system is not disarmed
|
||||||
|
// we still want alarm even if door is closed after delay.. Basically like real alarm the delay is only
|
||||||
|
// to disarm the system. Otherwise someone can open door come it, quickly close and there is not alarm LGK.
|
||||||
|
|
||||||
|
// issue here is that after delay we could have lost the alert type so pass it in
|
||||||
|
log.debug "activate alarm post delay check - alert type = $lastAlertType"
|
||||||
|
|
||||||
|
activateSirenAfterCheck(lastAlertType)
|
||||||
|
|
||||||
// Only turn on those switches that are currently off
|
// Only turn on those switches that are currently off
|
||||||
def switchesOn = settings.switches?.findAll { it?.currentSwitch == "off" }
|
def switchesOn = settings.switches?.findAll { it?.currentSwitch == "off" }
|
||||||
LOG("switchesOn: ${switchesOn}")
|
LOG("switchesOn: ${switchesOn}")
|
||||||
@@ -1570,6 +1759,8 @@ def activateAlarm() {
|
|||||||
notify(msg)
|
notify(msg)
|
||||||
notifyVoice()
|
notifyVoice()
|
||||||
|
|
||||||
|
reportStatus()
|
||||||
|
|
||||||
myRunIn(180, reset)
|
myRunIn(180, reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1668,12 +1859,61 @@ private def notifyVoice() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def reportStatus()
|
||||||
|
{
|
||||||
|
log.debug "in report status"
|
||||||
|
log.debug "notification device = ${settings.notificationDevice}"
|
||||||
|
|
||||||
|
if (settings.notificationDevice)
|
||||||
|
{
|
||||||
|
def phrase = ""
|
||||||
|
if (state.alarms.size())
|
||||||
|
{
|
||||||
|
phrase = "Alert: Alarm at ${location.name}!"
|
||||||
|
notificationDevice.deviceNotification(phrase)
|
||||||
|
log.debug "sending notification alert: = $phrase"
|
||||||
|
def zones = "Zones: "
|
||||||
|
state.alarms.each()
|
||||||
|
{
|
||||||
|
//log.debug "in loop it"
|
||||||
|
//log.debug "it = $it"
|
||||||
|
zones = "Zones: "
|
||||||
|
zones += " $it" +"\n"
|
||||||
|
}
|
||||||
|
notificationDevice.deviceNotification(zones)
|
||||||
|
log.debug "sending nofication zones = $zones"
|
||||||
|
|
||||||
|
// send zone type
|
||||||
|
phrase = "AlertType: "
|
||||||
|
def atype = state.alertType
|
||||||
|
if (atype == null)
|
||||||
|
atype = "None"
|
||||||
|
phrase += " $atype"
|
||||||
|
notificationDevice.deviceNotification(phrase)
|
||||||
|
log.debug "sending nofication alert type = $phrase"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
phrase = "Status: "
|
||||||
|
if (state.armed)
|
||||||
|
{
|
||||||
|
def mode = state.stay ? "Armed - Stay" : "Armed - Away"
|
||||||
|
phrase += "${mode}"
|
||||||
|
} else {
|
||||||
|
phrase += "Disarmed"
|
||||||
|
}
|
||||||
|
log.debug "sending notification status = $phrase"
|
||||||
|
notificationDevice.deviceNotification(phrase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private def history(String event, String description = "") {
|
private def history(String event, String description = "") {
|
||||||
LOG("history(${event}, ${description})")
|
LOG("history(${event}, ${description})")
|
||||||
|
|
||||||
def history = atomicState.history
|
def history = atomicState.history
|
||||||
history << [time: now(), event: event, description: description]
|
history << [time: now(), event: event, description: description]
|
||||||
if (history.size() > 10) {
|
if (history.size() > 20) {
|
||||||
history = history.sort{it.time}
|
history = history.sort{it.time}
|
||||||
history = history[1..-1]
|
history = history[1..-1]
|
||||||
}
|
}
|
||||||
@@ -1850,3 +2090,27 @@ private def LOG(message) {
|
|||||||
private def STATE() {
|
private def STATE() {
|
||||||
//log.trace "state: ${state}"
|
//log.trace "state: ${state}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def onAlarmSystemStatus(evt) {
|
||||||
|
LOG("Alarm System Status has been changed to '${evt.value}'")
|
||||||
|
String mode = evt.value.toLowerCase()
|
||||||
|
if (mode == "away") {
|
||||||
|
armAway()
|
||||||
|
} else if (mode == "stay") {
|
||||||
|
armStay()
|
||||||
|
} else if (mode == "off") {
|
||||||
|
disarm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def setAlarmMode(name) {
|
||||||
|
LOG("Alarm System Status will be set to '${name}'")
|
||||||
|
def event = [
|
||||||
|
name: "alarmSystemStatus",
|
||||||
|
value: name,
|
||||||
|
isStateChange: true,
|
||||||
|
displayed: true,
|
||||||
|
description: "alarm system status is ${name}",
|
||||||
|
]
|
||||||
|
sendLocationEvent(event)
|
||||||
|
}
|
||||||
@@ -125,19 +125,19 @@
|
|||||||
if(allOk) {
|
if(allOk) {
|
||||||
|
|
||||||
if(everyoneIsAway() && (state.sunMode == "sunrise")) {
|
if(everyoneIsAway() && (state.sunMode == "sunrise")) {
|
||||||
log.debug("Home is Empty Setting New Away Mode")
|
log.info("Home is Empty Setting New Away Mode")
|
||||||
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
||||||
runIn(delay, "setAway")
|
runIn(delay, "setAway")
|
||||||
}
|
}
|
||||||
|
|
||||||
if(everyoneIsAway() && (state.sunMode == "sunset")) {
|
if(everyoneIsAway() && (state.sunMode == "sunset")) {
|
||||||
log.debug("Home is Empty Setting New Away Mode")
|
log.info("Home is Empty Setting New Away Mode")
|
||||||
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
||||||
runIn(delay, "setAway")
|
runIn(delay, "setAway")
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
log.debug("Home is Occupied Setting New Home Mode")
|
log.info("Home is Occupied Setting New Home Mode")
|
||||||
setHome()
|
setHome()
|
||||||
|
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
log.debug("Checking if everyone is away")
|
log.debug("Checking if everyone is away")
|
||||||
|
|
||||||
if(everyoneIsAway()) {
|
if(everyoneIsAway()) {
|
||||||
log.debug("Nobody is home, running away sequence")
|
log.info("Nobody is home, running away sequence")
|
||||||
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
|
||||||
runIn(delay, "setAway")
|
runIn(delay, "setAway")
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
else {
|
else {
|
||||||
def lastTime = state[evt.deviceId]
|
def lastTime = state[evt.deviceId]
|
||||||
if (lastTime == null || now() - lastTime >= 1 * 60000) {
|
if (lastTime == null || now() - lastTime >= 1 * 60000) {
|
||||||
log.debug("Someone is home, running home sequence")
|
log.info("Someone is home, running home sequence")
|
||||||
setHome()
|
setHome()
|
||||||
}
|
}
|
||||||
state[evt.deviceId] = now()
|
state[evt.deviceId] = now()
|
||||||
@@ -175,14 +175,14 @@
|
|||||||
if(everyoneIsAway()) {
|
if(everyoneIsAway()) {
|
||||||
if(state.sunMode == "sunset") {
|
if(state.sunMode == "sunset") {
|
||||||
def message = "Performing \"${awayNight}\" for you as requested."
|
def message = "Performing \"${awayNight}\" for you as requested."
|
||||||
log.debug(message)
|
log.info(message)
|
||||||
sendAway(message)
|
sendAway(message)
|
||||||
location.helloHome.execute(settings.awayNight)
|
location.helloHome.execute(settings.awayNight)
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(state.sunMode == "sunrise") {
|
else if(state.sunMode == "sunrise") {
|
||||||
def message = "Performing \"${awayDay}\" for you as requested."
|
def message = "Performing \"${awayDay}\" for you as requested."
|
||||||
log.debug(message)
|
log.info(message)
|
||||||
sendAway(message)
|
sendAway(message)
|
||||||
location.helloHome.execute(settings.awayDay)
|
location.helloHome.execute(settings.awayDay)
|
||||||
}
|
}
|
||||||
@@ -192,19 +192,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
log.debug("Somebody returned home before we set to '${newAwayMode}'")
|
log.info("Somebody returned home before we set to '${newAwayMode}'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//set home mode when house is occupied
|
//set home mode when house is occupied
|
||||||
def setHome() {
|
def setHome() {
|
||||||
sendOutOfDateNotification()
|
sendOutOfDateNotification()
|
||||||
log.debug("Setting Home Mode!!")
|
log.info("Setting Home Mode!!")
|
||||||
if(anyoneIsHome()) {
|
if(anyoneIsHome()) {
|
||||||
if(state.sunMode == "sunset"){
|
if(state.sunMode == "sunset"){
|
||||||
if (location.mode != "${homeModeNight}"){
|
if (location.mode != "${homeModeNight}"){
|
||||||
def message = "Performing \"${homeNight}\" for you as requested."
|
def message = "Performing \"${homeNight}\" for you as requested."
|
||||||
log.debug(message)
|
log.info(message)
|
||||||
sendHome(message)
|
sendHome(message)
|
||||||
location.helloHome.execute(settings.homeNight)
|
location.helloHome.execute(settings.homeNight)
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@
|
|||||||
if(state.sunMode == "sunrise"){
|
if(state.sunMode == "sunrise"){
|
||||||
if (location.mode != "${homeModeDay}"){
|
if (location.mode != "${homeModeDay}"){
|
||||||
def message = "Performing \"${homeDay}\" for you as requested."
|
def message = "Performing \"${homeDay}\" for you as requested."
|
||||||
log.debug(message)
|
log.info(message)
|
||||||
sendHome(message)
|
sendHome(message)
|
||||||
location.helloHome.execute(settings.homeDay)
|
location.helloHome.execute(settings.homeDay)
|
||||||
}
|
}
|
||||||
@@ -329,4 +329,4 @@
|
|||||||
sendNotification("Your version of Hello, Home Phrase Director is currently out of date. Please look for the new version of Hello, Home Phrase Director now called 'Routine Director' in the marketplace.")
|
sendNotification("Your version of Hello, Home Phrase Director is currently out of date. Please look for the new version of Hello, Home Phrase Director now called 'Routine Director' in the marketplace.")
|
||||||
state.lastTime = (new Date() + 31).getTime()
|
state.lastTime = (new Date() + 31).getTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user