Skip to content

Commit 065cf2f

Browse files
authored
Merge pull request SmartThingsCommunity#50822 from SmartThingsCommunity/acceptance
Rolling up acceptance to production for deploy
2 parents 9ee38cd + 7840694 commit 065cf2f

File tree

16 files changed

+314
-70
lines changed

16 files changed

+314
-70
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus
2+
metadata {
3+
definition (name: "GatorSystem HomeWatcher", namespace: "GS", author: "GS_coder000") {
4+
capability "Motion Sensor"
5+
capability "Battery"
6+
capability "Contact Sensor"
7+
capability "Presence Sensor"
8+
9+
// Raw Description 08 0104 0402 00 02 0000 0500 01 0502
10+
fingerprint manufacturer: "GatorSystem", model: "GSHW01", deviceJoinName: "GatorSystem Multipurpose Sensor"
11+
}
12+
}
13+
14+
def parse(String description) {
15+
log.debug "${device.displayName} description: $description"
16+
Map map = [:]
17+
if (description?.startsWith('catchall:')) { //raw commands that smartthings does not or cannot interpret
18+
map = zigbee.parseDescriptionAsMap(description)
19+
} else if (description?.startsWith('read attr -')) {
20+
map = zigbee.parseDescriptionAsMap(description)
21+
} else if (description?.startsWith('zone status')) {
22+
map = parseIasMessage(description)
23+
}
24+
log.debug "Parse returned map $map"
25+
if (map != null) {
26+
createEvent(map)
27+
}
28+
}
29+
30+
private Map parseIasMessage(String description) {
31+
ZoneStatus zs = zigbee.parseZoneStatus(description)
32+
Map resultMap = [:]
33+
def oneMinute = 60
34+
def twoMinutes = 120
35+
def resultOccupied = '0x8000'
36+
def resultOpenned = '0x4000'
37+
def resultClosed = '0x2000'
38+
def resultBatteryNew = '0x1000'
39+
def resultBatteryOut = '0x0800'
40+
if (zs.isAlarm1Set()) {
41+
runIn(twoMinutes, stopMotion)
42+
resultMap = getMotionResult('active')
43+
} else if (zs.isBatterySet()) {
44+
resultMap = getBatteryResult(10)
45+
} else if (description.contains(resultOccupied)) {
46+
runIn(oneMinute, resetOccupancy)
47+
resultMap = getMotionResult('occupied')
48+
} else if (description.contains(resultOpenned)) {
49+
resultMap = getMotionResult('openned')
50+
} else if (description.contains(resultClosed)) {
51+
resultMap = getMotionResult('closed')
52+
} else if (description.contains(resultBatteryNew)) {
53+
resultMap = getBatteryResult(100)
54+
} else if (description.contains(resultBatteryOut)) {
55+
resultMap = getBatteryResult(0)
56+
}
57+
}
58+
59+
private Map getBatteryResult(rawValue) {
60+
log.debug "Battery rawValue = ${rawValue}"
61+
createEvent(name:"battery", value:rawValue)
62+
}
63+
64+
private Map getMotionResult(value) {
65+
if (value == 'active') {
66+
log.debug 'detected intrusion'
67+
String descriptionText = "{{ device.displayName }} detected intrusion"
68+
createEvent(
69+
name: 'motion',
70+
value: value,
71+
descriptionText: descriptionText,
72+
translatable: false
73+
)
74+
} else if (value == 'occupied') {
75+
log.debug 'detected occupancy'
76+
String descriptionText = "{{ device.displayName }} detected occupancy"
77+
createEvent(
78+
name: 'presence',
79+
value: "present",
80+
descriptionText: descriptionText,
81+
translatable: false
82+
)
83+
} else if (value == 'openned') {
84+
log.debug 'detected window openned'
85+
String descriptionText = "{{ device.displayName }} detected window openned"
86+
createEvent(
87+
name: 'contact',
88+
value: "open",
89+
descriptionText: descriptionText,
90+
translatable: false
91+
)
92+
} else if (value == 'closed') {
93+
log.debug 'detected window closed'
94+
String descriptionText = "{{ device.displayName }} detected window closed"
95+
createEvent(
96+
name: 'contact',
97+
value: "closed",
98+
descriptionText: descriptionText,
99+
translatable: false
100+
)
101+
}
102+
}
103+
104+
def installed() {
105+
initialize()
106+
}
107+
108+
def initialize() {
109+
sendEvent(name:"motion", value:"inactive")
110+
sendEvent(name:"battery", value:"100")
111+
sendEvent(name:"presence", value:"not present")
112+
sendEvent(name:"contact", value:"closed")
113+
}
114+
115+
def stopMotion() {
116+
if (device.currentState('motion')?.value == "active") {
117+
sendEvent(name:"motion", value:"inactive", isStateChange: true)
118+
log.debug "${device.displayName} reset to monitoring after 120 seconds"
119+
}
120+
}
121+
122+
def resetOccupancy() {
123+
if (device.currentState('presence')?.value == "present") {
124+
sendEvent(name:"presence", value:"not present", isStateChange: true)
125+
log.debug "${device.displayName} reset to sensing after 60 seconds"
126+
}
127+
}

devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ metadata {
3434
// Qubino Flush Dimmer 0-10V - ZMNHVD
3535
// Raw Description: zw:L type:1100 mfr:0159 prod:0001 model:0053 ver:2.04 zwv:4.34 lib:03 cc:5E,86,5A,72,73,27,25,26,85,8E,59,70 ccOut:20,26 role:05 ff:9C00 ui:9C00
3636
fingerprint mfr: "0159", prod: "0001", model: "0053", deviceJoinName: "Qubino Dimmer", mnmn: "SmartThings", vid:"generic-dimmer"
37+
38+
//Qubino Mini Dimmer
39+
// Raw Description: zw:Ls type:1101 mfr:0159 prod:0001 model:0055 ver:20.02 zwv:5.03 lib:03 cc:5E,6C,55,98,9F sec:86,25,26,85,59,72,5A,70,32,71,73
40+
fingerprint mfr:"0159", prod:"0001", model:"0055", deviceJoinName: "Qubino Dimmer"
3741
}
3842

3943
tiles(scale: 2) {
@@ -158,6 +162,8 @@ def excludeParameterFromSync(preference){
158162
if (isDINDimmer() || isFlushDimmer010V()) {
159163
exclude = true
160164
}
165+
} else if (preference.key == "minimumDimmingValue"){
166+
exclude = true
161167
}
162168

163169
if (exclude) {
@@ -232,13 +238,6 @@ def configure() {
232238
commands << zwave.associationV1.associationSet(groupingIdentifier:6, nodeId:[zwaveHubNodeId])
233239
commands << zwave.multiChannelV3.multiChannelEndPointGet()
234240
commands += getRefreshCommands()
235-
236-
// 1% is default Minimum dimming value for dimmers,
237-
// when device is set to 1% - it turns off and device does not send any level reports
238-
// Minimum dimming value has to be set to 2%, so the device's internal range would be 2-100%
239-
// Still, for users it will relatively be 1-100% on the UI and device will report it.
240-
// Parameter no. 60 – Minimum dimming value
241-
commands << zwave.configurationV2.configurationSet(scaledConfigurationValue: 2, parameterNumber: 60, size: 1)
242241
commands += getReadConfigurationFromTheDeviceCommands()
243242

244243
encapCommands(commands)
@@ -394,6 +393,14 @@ private dimmerEvents(physicalgraph.zwave.Command cmd, ep = null) {
394393
return result
395394
}
396395

396+
Integer adjustValueToRange(value){
397+
if(value == 0){
398+
return 0
399+
}
400+
def minDimmingLvlPref = settings.minimumDimmingValue ?: parameterMap.find({it.key == 'minimumDimmingValue'}).defaultValue
401+
return Math.max(value, minDimmingLvlPref)
402+
}
403+
397404
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd, ep = null) {
398405
log.info "SensorMultilevelReport: ${cmd}, endpoint: ${ep}"
399406
def result = []
@@ -482,7 +489,9 @@ def setLevel(value, duration = null) {
482489
getStatusDelay = duration < 128 ? (duration * 1000) + 2000 : (Math.round(duration / 60) * 60 * 1000) + 2000
483490
}
484491

485-
commands << zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration)
492+
def adjustedLevel = adjustValueToRange(level)
493+
494+
commands << zwave.switchMultilevelV3.switchMultilevelSet(value: adjustedLevel, dimmingDuration: dimmingDuration)
486495
commands << zwave.switchMultilevelV3.switchMultilevelGet()
487496

488497
encapCommands(commands, getStatusDelay)
@@ -619,6 +628,16 @@ private getParameterMap() {[
619628
optionActive: 1, activeDescription: " Flush Dimmer 0-10V module does not save the state after a power failure, it returns to off position",
620629
description: "Set whether the device stores or does not store the last output level in the event of a power outage."
621630
],
631+
[
632+
name : "Minimum dimming value",
633+
key : "minimumDimmingValue",
634+
type : "range",
635+
parameterNumber: 60,
636+
size : 1,
637+
defaultValue : 1,
638+
range : "1..98",
639+
description : "Select minimum dimming value for this device. When the switch type is selected as Bi-stable, it is not possible to dim the value between min and max."
640+
],
622641
[
623642
name: "Dimming time (soft on/off)", key: "dimmingTime(SoftOn/Off)", type: "range",
624643
parameterNumber: 65, size: 2, defaultValue: 100,

devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ def excludeParameterFromSync(preference){
132132
def addToAssociationGroupIfNeeded() {
133133
def cmds = []
134134
if (zwaveInfo?.model?.equals("0052")) {
135-
cmds += encap(zwave.associationV2.associationSet(groupingIdentifier: 2, nodeId: [zwaveHubNodeId]))
135+
//Hub automatically adds device to multiChannelAssosciationGroup and this needs to be removed
136+
cmds += encap(zwave.multiChannelAssociationV2.multiChannelAssociationRemove(groupingIdentifier: 1, nodeId:[]))
137+
cmds += encap(zwave.associationV2.associationSet(groupingIdentifier: 1, nodeId: [zwaveHubNodeId]))
136138
}
137139
cmds
138140
}
@@ -245,17 +247,6 @@ def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null)
245247
changeSwitch(ep, cmd)
246248
}
247249

248-
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd, ep = null) {
249-
log.debug "Basic ${cmd}" + (ep ? " from endpoint $ep" : "")
250-
[
251-
changeSwitch(ep, cmd),
252-
response([
253-
"delay 2000",
254-
encap(zwave.meterV3.meterGet(scale: 2), endpoint)
255-
])
256-
]
257-
}
258-
259250
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) {
260251
log.debug "Binary ${cmd}" + (ep ? " from endpoint $ep" : "")
261252
changeSwitch(ep, cmd)

devicetypes/smartthings/centralite-thermostat.src/centralite-thermostat.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ metadata {
2020
capability "Actuator"
2121
capability "Temperature Measurement"
2222
capability "Thermostat"
23+
capability "Thermostat Heating Setpoint"
24+
capability "Thermostat Cooling Setpoint"
25+
capability "Thermostat Mode"
26+
capability "Thermostat Fan Mode"
2327
capability "Configuration"
2428
capability "Refresh"
2529
capability "Sensor"

devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ metadata {
55
capability "Temperature Measurement"
66
capability "Relative Humidity Measurement"
77
capability "Thermostat"
8+
capability "Thermostat Heating Setpoint"
9+
capability "Thermostat Cooling Setpoint"
10+
capability "Thermostat Operating State"
11+
capability "Thermostat Mode"
12+
capability "Thermostat Fan Mode"
813
capability "Battery"
914
capability "Refresh"
1015
capability "Sensor"

devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ metadata {
2020
capability "Thermostat Heating Setpoint"
2121
capability "Health Check"
2222
capability "Thermostat"
23+
capability "Thermostat Mode"
2324
capability "Temperature Measurement"
2425

2526
command "setThermostatSetpointUp"

devicetypes/smartthings/fidure-thermostat.src/fidure-thermostat.groovy

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ metadata {
1212
capability "Actuator"
1313
capability "Temperature Measurement"
1414
capability "Thermostat"
15+
capability "Thermostat Heating Setpoint"
16+
capability "Thermostat Cooling Setpoint"
17+
capability "Thermostat Operating State"
18+
capability "Thermostat Mode"
19+
capability "Thermostat Fan Mode"
1520
capability "Configuration"
1621
capability "Refresh"
1722
capability "Sensor"
@@ -41,8 +46,6 @@ metadata {
4146

4247
attribute "lastTimeSync", "string"
4348

44-
attribute "thermostatOperatingState", "string"
45-
4649
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0201,0204,0B05", outClusters: "000A, 0019", deviceJoinName: "Fidure Thermostat"
4750
fingerprint manufacturer: "Fidure", model: "A1732R3" , deviceJoinName: "Fidure Thermostat"// same clusters as above
4851

@@ -94,9 +97,7 @@ metadata {
9497
}
9598

9699
standardTile("hvacStatus", "thermostatOperatingState", inactiveLabel: false, decoration: "flat") {
97-
state "Resting", label: 'Resting'
98-
state "Heating", icon:"st.thermostat.heating"
99-
state "Cooling", icon:"st.thermostat.cooling"
100+
state "thermostatOperatingState", label:'${currentValue}'
100101
}
101102

102103

@@ -496,7 +497,7 @@ def Program() {
496497

497498

498499
def getThermostatOperatingState(value) {
499-
String[] m = [ "heating", "cooling", "fan", "Heat2", "Cool2", "Fan2", "Fan3"]
500+
String[] m = [ "heating", "cooling", "fan only", "heating", "cooling", "fan only", "fan only"]
500501
String desc = 'idle'
501502
value = Integer.parseInt(''+value, 16)
502503

devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy

100755100644
Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ metadata {
3434
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor", mnmn: "SmartThings", vid: "smartthings-water-leak-3315S-STSWTR"
3535
fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "water", deviceJoinName: "Water Leak Sensor", mnmn: "SmartThings", vid: "smartthings-water-leak-IM6001"
3636
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Sercomm Corp.", model: "SZ-WTD03", deviceJoinName: "Sercomm Water Leak Sensor" //Sercomm Water Leak Detector
37+
fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,000F,0020,0500,0502", outClusters: "000A,0019", manufacturer: "frient A/S", model :"FLSZB-110", deviceJoinName: "frient Water Leak Sensor" // frient Water Leak Detector
3738
}
3839

3940
simulator {
@@ -84,6 +85,9 @@ metadata {
8485
}
8586
}
8687

88+
def getBATTERY_VOLTAGE_ATTR() { 0x0020 }
89+
def getBATTERY_PERCENT_ATTR() { 0x0021 }
90+
8791
private List<Map> collectAttributes(Map descMap) {
8892
List<Map> descMaps = new ArrayList<Map>()
8993

@@ -111,13 +115,13 @@ def parse(String description) {
111115
List<Map> descMaps = collectAttributes(descMap)
112116

113117
if (device.getDataValue("manufacturer") == "Samjin") {
114-
def battMap = descMaps.find { it.attrInt == 0x0021 }
118+
def battMap = descMaps.find { it.attrInt == BATTERY_PERCENT_ATTR }
115119

116120
if (battMap) {
117121
map = getBatteryPercentageResult(Integer.parseInt(battMap.value, 16))
118122
}
119123
} else {
120-
def battMap = descMaps.find { it.attrInt == 0x0020 }
124+
def battMap = descMaps.find { it.attrInt == BATTERY_VOLTAGE_ATTR }
121125

122126
if (battMap) {
123127
map = getBatteryResult(Integer.parseInt(battMap.value, 16))
@@ -192,7 +196,7 @@ private Map getBatteryResult(rawValue) {
192196
def pct = batteryMap[volts]
193197
result.value = pct
194198
} else {
195-
def minVolts = 2.1
199+
def minVolts = isFrientSensor() ? 2.3 : 2.1
196200
def maxVolts = 3.0
197201
def pct = (volts - minVolts) / (maxVolts - minVolts)
198202
def roundedPct = Math.round(pct * 100)
@@ -247,9 +251,9 @@ def refresh() {
247251
def refreshCmds = []
248252

249253
if (device.getDataValue("manufacturer") == "Samjin") {
250-
refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021)
254+
refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_PERCENT_ATTR)
251255
} else {
252-
refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
256+
refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_VOLTAGE_ATTR)
253257
}
254258
refreshCmds += zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
255259
zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) +
@@ -269,11 +273,20 @@ def configure() {
269273
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
270274
// battery minReport 30 seconds, maxReportTime 6 hrs by default
271275
if (device.getDataValue("manufacturer") == "Samjin") {
272-
configCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 21600, 0x10)
276+
configCmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_PERCENT_ATTR, DataType.UINT8, 30, 21600, 0x10)
273277
} else {
274278
configCmds += zigbee.batteryConfig()
275279
}
276-
configCmds += zigbee.temperatureConfig(30, 300)
280+
281+
if (isFrientSensor()) {
282+
configCmds += zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000, DataType.INT16, 60, 600, 0x64, [destEndpoint: 0x26])
283+
} else {
284+
configCmds += zigbee.temperatureConfig(30, 300)
285+
}
277286

278287
return refresh() + configCmds + refresh() // send refresh cmds as part of config
279288
}
289+
290+
private Boolean isFrientSensor() {
291+
device.getDataValue("manufacturer") == "frient A/S"
292+
}

0 commit comments

Comments
 (0)