From 90d8534b46613cc5fbfe7efb8cfd941c08d5cc6a Mon Sep 17 00:00:00 2001 From: Fredrik Westman Date: Fri, 28 Apr 2017 02:03:16 -0700 Subject: [PATCH] MSA-1925: The DH is developed by SmartThings and the only changes are made within Tiles and UI. --- .../sensative-zb-strips.groovy | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 devicetypes/sensative/sensative-zb-strips.src/sensative-zb-strips.groovy diff --git a/devicetypes/sensative/sensative-zb-strips.src/sensative-zb-strips.groovy b/devicetypes/sensative/sensative-zb-strips.src/sensative-zb-strips.groovy new file mode 100644 index 0000000..9dcf4c4 --- /dev/null +++ b/devicetypes/sensative/sensative-zb-strips.src/sensative-zb-strips.groovy @@ -0,0 +1,182 @@ +/** + * SmartSense Open/Closed Sensor + * + * Copyright 2014 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. + * + */ +import physicalgraph.zigbee.clusters.iaszone.ZoneStatus + +metadata { + definition(name: "Sensative ZB Strips", namespace: "sensative", author: "SmartThings") { + capability "Battery" + capability "Configuration" + capability "Contact Sensor" + capability "Refresh" + capability "Temperature Measurement" + capability "Health Check" + capability "Sensor" + + command "enrollResponse" + + + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Sensative", model: "Strips-001" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Sensative", model: "Strips-001" + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Sensativee", model: "Strips-001", deviceJoinName: "Sensative ZB Strips" + + } + + simulator { + + } + + preferences { + input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph" + input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + } + + tiles(scale: 2) { + multiAttributeTile(name: "contact", type: "generic", width: 6, height: 4) { + tileAttribute("device.contact", key: "PRIMARY_CONTROL") { + attributeState "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13" + attributeState "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC" + } + } + + valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { + state "temperature", label: '${currentValue}°F', + 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"] + ] + } + valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) { + state "battery", label: 'Battery\n${currentValue}%', unit: "" + } + + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", action: "refresh.refresh", icon: "st.secondary.refresh" + } + + main(["contact"]) + details(["contact", "battery", "temperature", "refresh"]) + } +} + +def parse(String description) { + log.debug "description: $description" + + Map map = zigbee.getEvent(description) + if (!map) { + if (description?.startsWith('zone status')) { + map = parseIasMessage(description) + } else { + Map descMap = zigbee.parseDescriptionAsMap(description) + if (descMap?.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) { + map = getBatteryResult(Integer.parseInt(descMap.value, 16)) + } else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) { + if (descMap.data[0] == "00") { + log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap" + sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + } else { + log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}" + } + } + } + } else if (map.name == "temperature") { + if (tempOffset) { + map.value = (int) map.value + (int) tempOffset + } + map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F' + map.translatable = true + } + + log.debug "Parse returned $map" + def result = map ? createEvent(map) : [:] + + if (description?.startsWith('enroll request')) { + List cmds = zigbee.enrollResponse() + log.debug "enroll response: ${cmds}" + result = cmds?.collect { new physicalgraph.device.HubAction(it) } + } + return result +} + + +private Map parseIasMessage(String description) { + ZoneStatus zs = zigbee.parseZoneStatus(description) + return zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed') +} + +private Map getBatteryResult(rawValue) { + log.debug 'Battery' + def linkText = getLinkText(device) + + def result = [:] + + def volts = rawValue / 10 + if (!(rawValue == 0 || rawValue == 255)) { + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) + result.descriptionText = "${linkText} battery was ${result.value}%" + result.name = 'battery' + } + + return result +} + +private Map getContactResult(value) { + log.debug 'Contact Status' + def linkText = getLinkText(device) + def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}" + return [ + name : 'contact', + value : value, + descriptionText: descriptionText + ] +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level +} + +def refresh() { + log.debug "Refreshing Temperature and Battery" + def refreshCmds = zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) + + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + + return refreshCmds + zigbee.enrollResponse() +} + +def configure() { + // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time) + // enrolls with default periodic reporting until newer 5 min interval is confirmed + sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + + log.debug "Configuring Reporting, IAS CIE, and Bindings." + + // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity + // battery minReport 30 seconds, maxReportTime 6 hrs by default + return refresh() + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) // send refresh cmds as part of config +} \ No newline at end of file