Skip to content

Commit d78e8f7

Browse files
authored
Merge pull request SmartThingsCommunity#4190 from SmartThingsCommunity/staging
Rolling up staging to production for deploy
2 parents 71a1d52 + df609b2 commit d78e8f7

File tree

9 files changed

+335
-8
lines changed

9 files changed

+335
-8
lines changed

devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ metadata {
118118

119119
def installed() {
120120
sendEvent(name: "tamper", value: "clear", displayed: false)
121-
sendEvent(name: "motionText", value: "Disabled", displayed: false)
121+
sendEvent(name: "motionText", value: "X: 0.0\nY: 0.0\nZ: 0.0", displayed: false)
122122
sendEvent(name: "motion", value: "inactive", displayed: false)
123123
multiStatusEvent("Sync OK.", true, true)
124124
}
@@ -364,6 +364,10 @@ def configure() {
364364
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
365365
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1)
366366
cmds += zwave.sensorBinaryV2.sensorBinaryGet()
367+
cmds += zwave.configurationV2.configurationSet(scaledConfigurationValue: 2, parameterNumber: 24, size: 1)
368+
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 52)
369+
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 53)
370+
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 54)
367371
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
368372

369373
encapSequence(cmds, 500)
@@ -397,13 +401,13 @@ private encap(physicalgraph.zwave.Command cmd) {
397401
private motionEvent(Integer sensorType, value) {
398402
logging("${device.displayName} - Executing motionEvent() with parameters: ${sensorType}, ${value}", "debug")
399403
def axisMap = [52: "yAxis", 53: "zAxis", 54: "xAxis"]
400-
switch (sensorType) {
404+
switch (sensorType as Integer) {
401405
case 25:
402406
sendEvent(name: "motionText", value: "Vibration:\n${value} MMI", displayed: false)
403407
break
404408
case 52..54:
405409
sendEvent(name: axisMap[sensorType], value: value, displayed: false)
406-
runIn(2, "axisEvent")
410+
runIn(2, "axisEvent", [overwrite: true, forceForLocallyExecuting: true])
407411
break
408412
}
409413
}

devicetypes/smartthings/ezex-temp-humidity-sensor.src/ezex-temp-humidity-sensor.groovy

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
import physicalgraph.zigbee.zcl.DataType
1717

1818
metadata {
19-
definition(name: "eZEX Temp & Humidity Sensor", namespace: "smartthings", author: "SmartThings", mnmn:"SmartThings", vid:"generic-humidity") {
19+
definition(name: "eZEX Temp & Humidity Sensor", namespace: "smartthings", author: "SmartThings", mnmn:"SmartThings", vid:"generic-humidity-3") {
2020
capability "Configuration"
2121
capability "Temperature Measurement"
2222
capability "Relative Humidity Measurement"
2323
capability "Sensor"
24+
capability "Health Check"
2425

2526
fingerprint profileId: "0104", inClusters: "0000,0003,0402,0405,0500", outClusters: "0019", model: "E282-KR0B0Z1-HA", deviceJoinName: "Smart Temperature/Humidity Sensor (AC Type)"
2627
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2019 SmartThings
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4+
# use this file except in compliance with the License. You may obtain a copy
5+
# of the License at:
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
# Chinese
16+
'''Button'''.zh-cn=无线开关
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
/*
2+
* Copyright 2016 SmartThings
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy
6+
* of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
17+
import physicalgraph.zigbee.zcl.DataType
18+
19+
metadata {
20+
definition(name: "SmartSense Button", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.022.0000', executeCommandsLocally: false, mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Button", ocfDeviceType: "x.com.st.d.remotecontroller") {
21+
capability "Configuration"
22+
capability "Battery"
23+
capability "Refresh"
24+
capability "Temperature Measurement"
25+
capability "Button"
26+
capability "Holdable Button"
27+
capability "Health Check"
28+
capability "Sensor"
29+
30+
command "enrollResponse"
31+
32+
fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "button", deviceJoinName: "Button"
33+
}
34+
35+
simulator {
36+
status "button 1 pushed": "catchall: 0104 0500 01 01 0140 00 6C3F 00 00 0000 01 01 020000190100"
37+
}
38+
39+
preferences {
40+
section {
41+
image(name: 'educationalcontent', multiple: true, images: [
42+
"http://cdn.device-gse.smartthings.com/Moisture/Moisture1.png",
43+
"http://cdn.device-gse.smartthings.com/Moisture/Moisture2.png",
44+
"http://cdn.device-gse.smartthings.com/Moisture/Moisture3.png"
45+
])
46+
}
47+
section {
48+
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"
49+
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
50+
}
51+
}
52+
53+
tiles(scale: 2) {
54+
multiAttributeTile(name: "button", type: "generic", width: 6, height: 4) {
55+
tileAttribute("device.button", key: "PRIMARY_CONTROL") {
56+
attributeState "pushed", label: "Pressed", icon:"st.Weather.weather14", backgroundColor:"#53a7c0"
57+
attributeState "double", label: "Pressed Twice", icon:"st.Weather.weather11", backgroundColor:"#53a7c0"
58+
attributeState "held", label: "Held", icon:"st.Weather.weather13", backgroundColor:"#53a7c0"
59+
}
60+
}
61+
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
62+
state "temperature", label: '${currentValue}°',
63+
backgroundColors: [
64+
[value: 31, color: "#153591"],
65+
[value: 44, color: "#1e9cbb"],
66+
[value: 59, color: "#90d2a7"],
67+
[value: 74, color: "#44b621"],
68+
[value: 84, color: "#f1d801"],
69+
[value: 95, color: "#d04e00"],
70+
[value: 96, color: "#bc2323"]
71+
]
72+
}
73+
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
74+
state "battery", label: '${currentValue}% battery', unit: ""
75+
}
76+
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
77+
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
78+
}
79+
80+
main(["button", "temperature"])
81+
details(["button", "temperature", "battery", "refresh"])
82+
}
83+
}
84+
85+
def installed() {
86+
sendEvent(name: "supportedButtonValues", value: ["pushed","held","double"].encodeAsJSON(), displayed: false)
87+
sendEvent(name: "numberOfButtons", value: 1, displayed: false)
88+
sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], displayed: false)
89+
}
90+
91+
private List<Map> collectAttributes(Map descMap) {
92+
List<Map> descMaps = new ArrayList<Map>()
93+
94+
descMaps.add(descMap)
95+
96+
if (descMap.additionalAttrs) {
97+
descMaps.addAll(descMap.additionalAttrs)
98+
}
99+
100+
return descMaps
101+
}
102+
103+
def parse(String description) {
104+
log.debug "description: $description"
105+
106+
// getEvent will handle temperature and humidity
107+
Map map = zigbee.getEvent(description)
108+
if (!map) {
109+
if (description?.startsWith('zone status')) {
110+
map = parseIasMessage(description)
111+
} else {
112+
Map descMap = zigbee.parseDescriptionAsMap(description)
113+
114+
if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap.value) {
115+
List<Map> descMaps = collectAttributes(descMap)
116+
117+
if (device.getDataValue("manufacturer") == "Samjin") {
118+
def battMap = descMaps.find { it.attrInt == 0x0021 }
119+
120+
if (battMap) {
121+
map = getBatteryPercentageResult(Integer.parseInt(battMap.value, 16))
122+
}
123+
} else {
124+
def battMap = descMaps.find { it.attrInt == 0x0020 }
125+
126+
if (battMap) {
127+
map = getBatteryResult(Integer.parseInt(battMap.value, 16))
128+
}
129+
}
130+
} else if (descMap?.clusterInt == 0x0500 && descMap.attrInt == 0x0002) {
131+
def zs = new ZoneStatus(zigbee.convertToInt(descMap.value, 16))
132+
map = translateZoneStatus(zs)
133+
} else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
134+
if (descMap.data[0] == "00") {
135+
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
136+
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
137+
} else {
138+
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
139+
}
140+
} else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS && descMap?.value) {
141+
map = translateZoneStatus(new ZoneStatus(zigbee.convertToInt(descMap?.value)))
142+
}
143+
}
144+
} else if (map.name == "temperature") {
145+
if (tempOffset) {
146+
map.value = (int) map.value + (int) tempOffset
147+
map.unit = getTemperatureScale()
148+
}
149+
map.descriptionText = getTemperatureScale() == 'C' ? "${ device.displayName } was ${ map.value }°C" : "${ device.displayName } was ${ map.value }°F"
150+
map.translatable = true
151+
}
152+
153+
log.debug "Parse returned $map"
154+
def result = map ? createEvent(map) : [:]
155+
156+
if (description?.startsWith('enroll request')) {
157+
List cmds = zigbee.enrollResponse()
158+
log.debug "enroll response: ${cmds}"
159+
result = cmds?.collect { new physicalgraph.device.HubAction(it) }
160+
}
161+
return result
162+
}
163+
164+
private Map parseIasMessage(String description) {
165+
ZoneStatus zs = zigbee.parseZoneStatus(description)
166+
167+
translateZoneStatus(zs)
168+
}
169+
170+
private Map translateZoneStatus(ZoneStatus zs) {
171+
if (zs.isAlarm1Set() && zs.isAlarm2Set()) {
172+
return getButtonResult('held')
173+
} else if (zs.isAlarm1Set()) {
174+
return getButtonResult('pushed')
175+
} else if (zs.isAlarm2Set()) {
176+
return getButtonResult('double')
177+
} else { }
178+
}
179+
180+
private Map getBatteryResult(rawValue) {
181+
log.debug "Battery rawValue = ${rawValue}"
182+
def linkText = getLinkText(device)
183+
184+
def result = [:]
185+
186+
def volts = rawValue / 10
187+
188+
if (!(rawValue == 0 || rawValue == 255)) {
189+
result.name = 'battery'
190+
result.translatable = true
191+
result.descriptionText = "${ device.displayName } battery was ${ value }%"
192+
if (device.getDataValue("manufacturer") == "SmartThings") {
193+
volts = rawValue // For the batteryMap to work the key needs to be an int
194+
def batteryMap = [28: 100, 27: 100, 26: 100, 25: 90, 24: 90, 23: 70,
195+
22: 70, 21: 50, 20: 50, 19: 30, 18: 30, 17: 15, 16: 1, 15: 0]
196+
def minVolts = 15
197+
def maxVolts = 28
198+
199+
if (volts < minVolts)
200+
volts = minVolts
201+
else if (volts > maxVolts)
202+
volts = maxVolts
203+
def pct = batteryMap[volts]
204+
result.value = pct
205+
} else {
206+
def minVolts = 2.1
207+
def maxVolts = 3.0
208+
def pct = (volts - minVolts) / (maxVolts - minVolts)
209+
def roundedPct = Math.round(pct * 100)
210+
if (roundedPct <= 0)
211+
roundedPct = 1
212+
result.value = Math.min(100, roundedPct)
213+
}
214+
215+
}
216+
217+
return result
218+
}
219+
220+
private Map getBatteryPercentageResult(rawValue) {
221+
log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%"
222+
def result = [:]
223+
224+
if (0 <= rawValue && rawValue <= 200) {
225+
result.name = 'battery'
226+
result.translatable = true
227+
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
228+
result.value = Math.round(rawValue / 2)
229+
}
230+
231+
return result
232+
}
233+
234+
private Map getButtonResult(value) {
235+
def descriptionText
236+
if (value == "pushed")
237+
descriptionText = "${ device.displayName } was pushed"
238+
else if (value == "held")
239+
descriptionText = "${ device.displayName } was held"
240+
else
241+
descriptionText = "${ device.displayName } was pushed twice"
242+
return [
243+
name : 'button',
244+
value : value,
245+
descriptionText: descriptionText,
246+
translatable : true,
247+
isStateChange : true,
248+
data : [buttonNumber: 1]
249+
]
250+
}
251+
252+
/**
253+
* PING is used by Device-Watch in attempt to reach the Device
254+
* */
255+
def ping() {
256+
zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS)
257+
}
258+
259+
def refresh() {
260+
log.debug "Refreshing Values"
261+
def refreshCmds = []
262+
263+
if (device.getDataValue("manufacturer") == "Samjin") {
264+
refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021)
265+
} else {
266+
refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
267+
}
268+
refreshCmds += zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
269+
zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) +
270+
zigbee.enrollResponse()
271+
272+
return refreshCmds
273+
}
274+
275+
def configure() {
276+
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
277+
// enrolls with default periodic reporting until newer 5 min interval is confirmed
278+
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
279+
280+
log.debug "Configuring Reporting"
281+
def configCmds = []
282+
283+
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
284+
// battery minReport 30 seconds, maxReportTime 6 hrs by default
285+
if (device.getDataValue("manufacturer") == "Samjin") {
286+
configCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 21600, 0x10)
287+
} else {
288+
configCmds += zigbee.batteryConfig()
289+
}
290+
configCmds += zigbee.temperatureConfig(30, 300)
291+
292+
return refresh() + configCmds + refresh() // send refresh cmds as part of config
293+
}

devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ metadata {
1818
capability "Refresh"
1919
capability "Health Check"
2020
capability "Sensor"
21+
capability "Configuration"
2122

2223
fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR080Z0-HA", deviceJoinName: "Smart Sub-meter(CT Type)"
2324

@@ -50,6 +51,14 @@ def parse(String description) {
5051
def event = zigbee.getEvent(description)
5152
if (event) {
5253
log.info event
54+
if (event.name == "power") {
55+
event.value = event.value/1000
56+
event.unit = "W"
57+
} else if (event.name == "energy") {
58+
event.value = event.value/1000000
59+
event.unit = "kWh"
60+
}
61+
log.info "event outer:$event"
5362
sendEvent(event)
5463
} else {
5564
List result = []
@@ -66,11 +75,13 @@ def parse(String description) {
6675
log.debug "meter"
6776
map.name = "power"
6877
map.value = zigbee.convertHexToInt(it.value)/1000
78+
map.unit = "W"
6979
}
7080
if (it.clusterInt == 0x0702 && it.attrInt == 0x0000) {
7181
log.debug "energy"
7282
map.name = "energy"
7383
map.value = zigbee.convertHexToInt(it.value)/1000000
84+
map.unit = "kWh"
7485
}
7586

7687
if (map) {

0 commit comments

Comments
 (0)