Compare commits

..

8 Commits

Author SHA1 Message Date
Duncan McKee
43912b75bd DHF-7 Z-Wave Lock: Add scheduled checks in case ping() is missed 2017-05-23 16:24:27 -04:00
Duncan McKee
82d57a9f0f Add mfr fingerprints to Fibaro Motion
NVS-6
2017-05-23 16:08:47 -04:00
Duncan McKee
e817f5c415 Merge pull request #1748 from mckeed/DVCSMP-2489
DVCSMP-2489 Everspring ST814 and ST815 Multilevel Sensors
2017-05-23 13:35:39 -04:00
Duncan McKee
10964873cd Merge pull request #2001 from mckeed/DVCSMP-2493
DVCSMP-2493 Notify Multi-Channel Control app when root device is deleted
2017-05-23 13:33:55 -04:00
Zach Varberg
20f086fe69 Merge pull request #2023 from varzac/fix-multisensor-npe
[DVCSMP-2668] Fix NPE for smartsense multi
2017-05-23 09:08:47 -05:00
Zach Varberg
97c9ec7a95 Fix NPE for smartsense multi
There was a common NPE caused by assuming there would be additional
attributes reported with one acceleration value.  This corrects it to
instead properly handle the case where there weren't additional
attributes.

This resolves: https://smartthings.atlassian.net/browse/DVCSMP-2668
2017-05-22 11:52:13 -05:00
Duncan McKee
52c57f66fb DVCSMP-2493 Notify Multi-Channel Control app when root device is deleted 2017-03-06 13:31:32 -05:00
Duncan McKee
91c358c3a6 Everspring ST814 and ST815 Multilevel Sensors 2017-03-05 18:50:55 -05:00
8 changed files with 391 additions and 22 deletions

View File

@@ -24,7 +24,10 @@ metadata {
capability "Temperature Measurement"
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 {

View File

@@ -0,0 +1,163 @@
/**
* 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()
])
}

View File

@@ -0,0 +1,188 @@
/**
* 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()
])
}

View File

@@ -47,14 +47,14 @@
capability "Sensor"
capability "Battery"
capability "Health Check"
command "resetParams2StDefaults"
command "listCurrentParams"
command "updateZwaveParam"
command "test"
command "configure"
command "resetParams2StDefaults"
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"
fingerprint mfr:"010F", prod:"0800", model:"2001"
fingerprint mfr:"010F", prod:"0800", model:"1001"
}
simulator {

View File

@@ -178,7 +178,7 @@ private List<Map> handleAcceleration(descMap) {
result += parseAxis(descMap.additionalAttrs)
}
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
def addAttrs = descMap.additionalAttrs
def addAttrs = descMap.additionalAttrs ?: []
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
result += parseAxis(addAttrs)
}

View File

@@ -34,8 +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: "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: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,0020,0101,0B05", outClusters: "000A, 0019, 0B05", manufacturer: "Danalock", model: "V3-BTZB",deviceJoinName: "Danalock V3-BTZB"
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) {
@@ -171,4 +170,4 @@ private Map parseReportAttributeMessage(String description) {
log.debug "parseReportAttributeMessage() --- ignoring attribute"
}
return resultMap
}
}

View File

@@ -75,6 +75,10 @@ def parse(String description) {
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) {
[ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true),
response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ]

View File

@@ -152,6 +152,10 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupported
def zwaveEvent(DoorLockOperationReport cmd) {
def result = []
unschedule(followupStateCheck)
unschedule(stateCheck)
def map = [ name: "lock" ]
if (cmd.doorLockMode == 0xFF) {
map.value = "locked"
@@ -365,7 +369,7 @@ def zwaveEvent(UserCodeReport cmd) {
code = state["set$name"] ?: decrypt(state[name]) ?: "****"
state.remove("set$name".toString())
} else {
map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ] ]
map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ], isStateChange: true ]
map.descriptionText = "$device.displayName code $cmd.userIdentifier is set"
map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode)
map.isStateChange = true
@@ -456,11 +460,12 @@ def zwaveEvent(physicalgraph.zwave.commands.timev1.TimeGet 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
def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ]
result << response(zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId))
if (state.assoc != zwaveHubNodeId) {
result << response(zwave.associationV1.associationGet(groupingIdentifier:2))
}
result
def cmds = [
zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format(),
"delay 1200",
zwave.associationV1.associationGet(groupingIdentifier:2).format()
]
[result, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
@@ -530,11 +535,18 @@ def unlockwtimeout() {
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
runIn(30, followupStateCheck)
secure(zwave.doorLockV1.doorLockOperationGet())
}
def followupStateCheck() {
runEvery1Hour(stateCheck)
stateCheck()
}
def stateCheck() {
sendHubCommand(new physicalgraph.device.HubAction(secure(zwave.doorLockV1.doorLockOperationGet())))
}
def refresh() {