mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-04-07 06:13:07 +01:00
Update to use multi attr parsing in zigbee library
With the addition of the ability for parseDescriptionAsMap to hanle the return of multiple read attribute responses, we can be a little more explicit with how we interpret and parse the responses.
This commit is contained in:
@@ -117,14 +117,16 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
Map map = zigbee.getEvent(description)
|
def maps = []
|
||||||
if (!map) {
|
maps << zigbee.getEvent(description)
|
||||||
|
if (!maps[0]) {
|
||||||
|
maps = []
|
||||||
if (description?.startsWith('zone status')) {
|
if (description?.startsWith('zone status')) {
|
||||||
map = parseIasMessage(description)
|
maps += parseIasMessage(description)
|
||||||
} else {
|
} else {
|
||||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
Map descMap = zigbee.parseDescriptionAsMap(description)
|
||||||
if (descMap?.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
|
if (descMap?.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) {
|
||||||
map = getBatteryResult(Integer.parseInt(descMap.value, 16))
|
maps << getBatteryResult(Integer.parseInt(descMap.value, 16))
|
||||||
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
|
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
|
||||||
if (descMap.data[0] == "00") {
|
if (descMap.data[0] == "00") {
|
||||||
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
|
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
|
||||||
@@ -133,10 +135,12 @@ def parse(String description) {
|
|||||||
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
|
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
map = handleAcceleration(descMap)
|
|
||||||
|
maps += handleAcceleration(descMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (map.name == "temperature") {
|
} else if (maps[0].name == "temperature") {
|
||||||
|
def map = maps[0]
|
||||||
if (tempOffset) {
|
if (tempOffset) {
|
||||||
map.value = (int) map.value + (int) tempOffset
|
map.value = (int) map.value + (int) tempOffset
|
||||||
}
|
}
|
||||||
@@ -144,8 +148,11 @@ def parse(String description) {
|
|||||||
map.translatable = true
|
map.translatable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
def result = map ? createEvent(map) : [:]
|
def result = maps.inject([]) {acc, it ->
|
||||||
|
if (it) {
|
||||||
|
acc << createEvent(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
if (description?.startsWith('enroll request')) {
|
if (description?.startsWith('enroll request')) {
|
||||||
List cmds = zigbee.enrollResponse()
|
List cmds = zigbee.enrollResponse()
|
||||||
log.debug "enroll response: ${cmds}"
|
log.debug "enroll response: ${cmds}"
|
||||||
@@ -154,59 +161,81 @@ def parse(String description) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map handleAcceleration(descMap) {
|
private List<Map> handleAcceleration(descMap) {
|
||||||
Map result = [:]
|
def result = []
|
||||||
if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0010) {
|
if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0010) {
|
||||||
if (descMap.value.size() == 32) {
|
def value = descMap.value == "01" ? "active" : "inactive"
|
||||||
// value will look like 00ae29001403e2290013001629001201
|
log.debug "Acceleration $value"
|
||||||
// breaking this apart and swapping byte order where appropriate, this breaks down to:
|
result << [
|
||||||
// X (0x0012) = 0x0016
|
name : "acceleration",
|
||||||
// Y (0x0013) = 0x03E2
|
value : value,
|
||||||
// Z (0x0014) = 0x00AE
|
descriptionText: "{{ device.displayName }} was $value",
|
||||||
// note that there is a known bug in that the x,y,z attributes are interpreted in the wrong order
|
isStateChange : isStateChange(device, "acceleration", value),
|
||||||
// this will be fixed in a future update
|
translatable : true
|
||||||
def threeAxisAttributes = descMap.value[0..-9]
|
]
|
||||||
result << parseAxis(threeAxisAttributes)
|
|
||||||
descMap.value = descMap.value[-2..-1]
|
if (descMap.additionalAttrs) {
|
||||||
|
result += parseAxis(descMap.additionalAttrs)
|
||||||
}
|
}
|
||||||
result = getAccelerationResult(descMap.value)
|
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
|
||||||
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012 && descMap.value.size() == 24) {
|
def addAttrs = descMap.additionalAttrs
|
||||||
// The size is checked to ensure the attribute report contains X, Y and Z values
|
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
|
||||||
// If all three axis are not included then the attribute report is ignored
|
result += parseAxis(addAttrs)
|
||||||
result = parseAxis(descMap.value)
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map parseIasMessage(String description) {
|
private List<Map> parseAxis(List<Map> attrData) {
|
||||||
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
def results = []
|
||||||
Map resultMap = [:]
|
def x = hexToSignedInt(attrData.find { it.attrInt == 0x0012 }?.value)
|
||||||
|
def y = hexToSignedInt(attrData.find { it.attrInt == 0x0013 }?.value)
|
||||||
|
def z = hexToSignedInt(attrData.find { it.attrInt == 0x0014 }?.value)
|
||||||
|
|
||||||
if (garageSensor != "Yes") {
|
def xyzResults = [:]
|
||||||
resultMap = zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')
|
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||||
|
// This mapping matches the current behavior of the Device Handler for the Centralite sensors
|
||||||
|
xyzResults.x = z
|
||||||
|
xyzResults.y = y
|
||||||
|
xyzResults.z = -x
|
||||||
|
} else {
|
||||||
|
// The axises reported by the Device Handler differ from the axises reported by the sensor
|
||||||
|
// This may change in the future
|
||||||
|
xyzResults.x = z
|
||||||
|
xyzResults.y = x
|
||||||
|
xyzResults.z = y
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultMap
|
log.debug "parseAxis -- ${xyzResults}"
|
||||||
|
|
||||||
|
if (garageSensor == "Yes")
|
||||||
|
results += garageEvent(xyzResults.z)
|
||||||
|
|
||||||
|
def value = "${xyzResults.x},${xyzResults.y},${xyzResults.z}"
|
||||||
|
results << [
|
||||||
|
name : "threeAxis",
|
||||||
|
value : value,
|
||||||
|
linkText : getLinkText(device),
|
||||||
|
descriptionText: "${getLinkText(device)} was ${value}",
|
||||||
|
handlerName : name,
|
||||||
|
isStateChange : isStateChange(device, "threeAxis", value),
|
||||||
|
displayed : false
|
||||||
|
]
|
||||||
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
private List<Map> parseIasMessage(String description) {
|
||||||
log.debug "updated called"
|
ZoneStatus zs = zigbee.parseZoneStatus(description)
|
||||||
log.info "garage value : $garageSensor"
|
List<Map> results = []
|
||||||
if (garageSensor == "Yes") {
|
|
||||||
def descriptionText = "Updating device to garage sensor"
|
if (garageSensor != "Yes") {
|
||||||
if (device.latestValue("status") == "open") {
|
def value = zs.isAlarm1Set() ? 'open' : 'closed'
|
||||||
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true)
|
log.debug "Contact: ${device.displayName} value = ${value}"
|
||||||
} else if (device.latestValue("status") == "closed") {
|
def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
||||||
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true)
|
results << [name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true]
|
||||||
}
|
results << [name: 'status', value: value, descriptionText: descriptionText, translatable: true]
|
||||||
} else {
|
|
||||||
def descriptionText = "Updating device to open/close sensor"
|
|
||||||
if (device.latestValue("status") == "garage-open") {
|
|
||||||
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true)
|
|
||||||
} else if (device.latestValue("status") == "garage-closed") {
|
|
||||||
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map getBatteryResult(rawValue) {
|
private Map getBatteryResult(rawValue) {
|
||||||
@@ -247,35 +276,24 @@ private Map getBatteryResult(rawValue) {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map getContactResult(value) {
|
List<Map> garageEvent(zValue) {
|
||||||
log.debug "Contact: ${device.displayName} value = ${value}"
|
List<Map> results = []
|
||||||
def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
def absValue = zValue.abs()
|
||||||
sendEvent(name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true)
|
def contactValue = null
|
||||||
return [name: 'status', value: value, descriptionText: descriptionText, translatable: true]
|
def garageValue = null
|
||||||
}
|
if (absValue > 900) {
|
||||||
|
contactValue = 'closed'
|
||||||
private getAccelerationResult(numValue) {
|
garageValue = 'garage-closed'
|
||||||
log.debug "Acceleration"
|
} else if (absValue < 100) {
|
||||||
def name = "acceleration"
|
contactValue = 'open'
|
||||||
def value
|
garageValue = 'garage-open'
|
||||||
def descriptionText
|
|
||||||
|
|
||||||
if (numValue.endsWith("1")) {
|
|
||||||
value = "active"
|
|
||||||
descriptionText = '{{ device.displayName }} was active'
|
|
||||||
} else {
|
|
||||||
value = "inactive"
|
|
||||||
descriptionText = '{{ device.displayName }} was inactive'
|
|
||||||
}
|
}
|
||||||
|
if (contactValue != null) {
|
||||||
def isStateChange = isStateChange(device, name, value)
|
def descriptionText = contactValue == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
||||||
return [
|
results << [name: 'contact', value: contactValue, descriptionText: descriptionText, displayed: false, translatable: true]
|
||||||
name : name,
|
results << [name: 'status', value: garageValue, descriptionText: descriptionText, translatable: true]
|
||||||
value : value,
|
}
|
||||||
descriptionText: descriptionText,
|
results
|
||||||
isStateChange : isStateChange,
|
|
||||||
translatable : true
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,35 +350,24 @@ def configure() {
|
|||||||
return refresh() + configCmds
|
return refresh() + configCmds
|
||||||
}
|
}
|
||||||
|
|
||||||
private getEndpointId() {
|
def updated() {
|
||||||
new BigInteger(device.endpointId, 16).toString()
|
log.debug "updated called"
|
||||||
}
|
log.info "garage value : $garageSensor"
|
||||||
|
if (garageSensor == "Yes") {
|
||||||
private Map parseAxis(String description) {
|
def descriptionText = "Updating device to garage sensor"
|
||||||
def z = hexToSignedInt(description[0..3])
|
if (device.latestValue("status") == "open") {
|
||||||
def y = hexToSignedInt(description[10..13])
|
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true)
|
||||||
def x = hexToSignedInt(description[20..23])
|
} else if (device.latestValue("status") == "closed") {
|
||||||
def xyzResults = [x: x, y: y, z: z]
|
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true)
|
||||||
|
}
|
||||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
|
||||||
// This mapping matches the current behavior of the Device Handler for the Centralite sensors
|
|
||||||
xyzResults.x = z
|
|
||||||
xyzResults.y = y
|
|
||||||
xyzResults.z = -x
|
|
||||||
} else {
|
} else {
|
||||||
// The axises reported by the Device Handler differ from the axises reported by the sensor
|
def descriptionText = "Updating device to open/close sensor"
|
||||||
// This may change in the future
|
if (device.latestValue("status") == "garage-open") {
|
||||||
xyzResults.x = z
|
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true)
|
||||||
xyzResults.y = x
|
} else if (device.latestValue("status") == "garage-closed") {
|
||||||
xyzResults.z = y
|
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug "parseAxis -- ${xyzResults}"
|
|
||||||
|
|
||||||
if (garageSensor == "Yes")
|
|
||||||
garageEvent(xyzResults.z)
|
|
||||||
|
|
||||||
getXyzResult(xyzResults, description)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private hexToSignedInt(hexVal) {
|
private hexToSignedInt(hexVal) {
|
||||||
@@ -368,43 +375,6 @@ private hexToSignedInt(hexVal) {
|
|||||||
unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal
|
unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal
|
||||||
}
|
}
|
||||||
|
|
||||||
def garageEvent(zValue) {
|
|
||||||
def absValue = zValue.abs()
|
|
||||||
def contactValue = null
|
|
||||||
def garageValue = null
|
|
||||||
if (absValue > 900) {
|
|
||||||
contactValue = 'closed'
|
|
||||||
garageValue = 'garage-closed'
|
|
||||||
} else if (absValue < 100) {
|
|
||||||
contactValue = 'open'
|
|
||||||
garageValue = 'garage-open'
|
|
||||||
}
|
|
||||||
if (contactValue != null) {
|
|
||||||
def descriptionText = contactValue == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed'
|
|
||||||
sendEvent(name: 'contact', value: contactValue, descriptionText: descriptionText, displayed: false, translatable: true)
|
|
||||||
sendEvent(name: 'status', value: garageValue, descriptionText: descriptionText, translatable: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map getXyzResult(results, description) {
|
|
||||||
def name = "threeAxis"
|
|
||||||
def value = "${results.x},${results.y},${results.z}"
|
|
||||||
def linkText = getLinkText(device)
|
|
||||||
def descriptionText = "$linkText was $value"
|
|
||||||
def isStateChange = isStateChange(device, name, value)
|
|
||||||
|
|
||||||
[
|
|
||||||
name : name,
|
|
||||||
value : value,
|
|
||||||
unit : null,
|
|
||||||
linkText : linkText,
|
|
||||||
descriptionText: descriptionText,
|
|
||||||
handlerName : name,
|
|
||||||
isStateChange : isStateChange,
|
|
||||||
displayed : false
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
private getManufacturerCode() {
|
private getManufacturerCode() {
|
||||||
if (device.getDataValue("manufacturer") == "SmartThings") {
|
if (device.getDataValue("manufacturer") == "SmartThings") {
|
||||||
return "0x110A"
|
return "0x110A"
|
||||||
|
|||||||
Reference in New Issue
Block a user