-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathzwaveTools.binaryAndMultilevelDeviceTools.groovy
More file actions
273 lines (226 loc) · 11.8 KB
/
Copy pathzwaveTools.binaryAndMultilevelDeviceTools.groovy
File metadata and controls
273 lines (226 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
library (
base: "driver",
author: "jvm33",
category: "zwave",
description: "Handles Events for Switches, Dimmers, Fans, Window Shades ",
name: "binaryAndMultilevelDeviceTools",
namespace: "zwaveTools",
documentationLink: "https://github.com/jvmahon/HubitatDriverTools",
version: "0.0.1",
dependencies: "zwaveTools.sendReceiveTools, zwaveTools.endpointTools",
librarySource:"https://raw.githubusercontent.com/jvmahon/HubitatDriverTools/main/binaryAndMultiLevelDeviceTools.groovy"
)
//// Send Simple Z-Wave Commands to Device ////
void sendInitialCommand() {
// If a device uses 'Supervision', then following a restart, code doesn't know the last sessionID that was sent to
// the device, so to reset that, send a command twice at startup.
if (device.hasAttribute("switch") && (device.currentValue("switch") == "off")) {
sendZwaveValue(value:0)
sendZwaveValue(value:0)
} else if ( device.hasAttribute("switch") && (device.currentValue("switch") == "on")) {
if (device.hasAttribute("level")) {
sendZwaveValue(value:(device.currentValue("level") as Integer ))
sendZwaveValue(value:(device.currentValue("level") as Integer ))
} else {
sendZwaveValue(value:99)
sendZwaveValue(value:99)
}
}
}
//// Send Simple Z-Wave Commands to Device ////
void sendZwaveValue(Map params = [value: null , duration: null , ep: null ] )
{
Integer newValue = Math.max(Math.min(params.value, 99),0)
List<Integer> supportedClasses = getThisEndpointClasses(params.ep ?:0)
if (supportedClasses.contains(0x26)) { // Multilevel type device
if (! params.duration.is( null ) ) advancedZwaveSend(zwave.switchMultilevelV4.switchMultilevelSet(value: newValue, dimmingDuration:params.duration), params.ep)
else advancedZwaveSend(zwave.switchMultilevelV1.switchMultilevelSet(value: newValue), params.ep)
} else if (supportedClasses.contains(0x25)) { // Switch Binary Type device
advancedZwaveSend(zwave.switchBinaryV1.switchBinarySet(switchValue: newValue ), params.ep)
} else if (supportedClasses.contains(0x20)) { // Basic Set Type device
log.warn "Device ${device.displayName}: Using Basic Set to turn on device. A more specific command class should be used!"
advancedZwaveSend(zwave.basicV1.basicSet(value: newValue ), params.ep)
} else {
log.error "Device ${device.displayName}: Error in function sendZwaveValue(). Device does not implement a supported class to control the device!.${ep ? " Endpoint # is: ${params.ep}." : ""}"
return
}
}
void zwaveEvent(hubitat.zwave.commands.switchbinaryv2.SwitchBinaryReport cmd, Integer ep = null )
{
String newSwitchState = ((cmd.value > 0) ? "on" : "off")
Map switchEvent = [name: "switch", value: newSwitchState, descriptionText: "Switch set to ${newSwitchState}", type: "physical"]
List <com.hubitat.app.DeviceWrapper> targetDevices = getChildDeviceListByEndpoint(ep ?: 0)?.findAll{it.hasAttribute("switch")}
if (((ep ?: 0 )== 0) && device.hasAttribute ("switch")) targetDevices += device
targetDevices.each { it.sendEvent(switchEvent)
if (txtEnable) log.info "Device ${it.displayName} set to ${newSwitchState}."
}
if (targetDevices.size() < 1) log.error "Device ${device.displayName}: received a Switch Binary Report for a device that does not have a switch attribute. Endpoint ${ep ?: 0}."
}
@groovy.transform.CompileStatic
void zwaveEvent(hubitat.zwave.commands.switchmultilevelv4.SwitchMultilevelReport cmd, Integer ep = null ) { processSwitchReport(cmd, ep) }
@groovy.transform.CompileStatic
void zwaveEvent(hubitat.zwave.commands.basicv2.BasicReport cmd, Integer ep = null ) { processSwitchReport(cmd, ep) }
void processSwitchReport(cmd, ep)
{
List<com.hubitat.app.DeviceWrapper> targetDevices = getChildDeviceListByEndpoint(ep)
if ((ep ?: 0 )== 0) targetDevices += device
Integer targetLevel = ((Integer) cmd.value == 99) ? 100 : cmd.value
if (cmd.hasProperty("targetValue") && cmd.targetValue && (cmd.duration > 0 ) ) {
targetLevel = ((Integer) cmd.targetValue == 99) ? 100 : cmd.targetValue
}
targetDevices.each{ it ->
if (it.hasAttribute("position")) {
it.sendEvent( name: "position", value: targetLevel , unit: "%", descriptionText: "Position set to ${targetLevel}%", type: "physical" )
}
if (it.hasAttribute("windowShade")) {
String positionDescription = [0:"closed", 99:"open", 100:"open"].get(targetLevel, "partially open")
it.sendEvent( name: "windowShade", value: positionDescription, descriptionText: "Window Shade position set to ${positionDescription}.", type: "physical" )
}
if (it.hasAttribute("level") || it.hasAttribute("switch") ) // Switch or a fan
{
String newSwitchState = ((targetLevel != 0) ? "on" : "off")
if (it.hasAttribute("switch")) {
it.sendEvent( name: "switch", value: newSwitchState, descriptionText: "Switch state set to ${newSwitchState}", type: "physical" )
if (txtEnable) log.info "Device ${it.displayName} set to ${newSwitchState}."
}
if (it.hasAttribute("speed")) {
it.sendEvent( name: "speed", value: levelToSpeed(targetLevel), descriptionText: "Speed set", type: "physical" )
}
if (it.hasAttribute("level") && (targetLevel != 0 )) // Only handle on values 1-99 here. If device was turned off, that would be handle in the switch state block above.
{
it.sendEvent( name: "level", value: targetLevel, descriptionText: "Level set to ${targetLevel}%.", unit:"%", type: "physical" )
if (txtEnable) log.info "Device ${it.displayName} level set to ${targetLevel}%"
}
}
}
}
@groovy.transform.CompileStatic
void componentOn(com.hubitat.app.DeviceWrapper cd){ on(cd:cd) }
void on(Map inputs = [:] )
{
Map params = [cd: null , duration: null , level: null ] << inputs
Integer ep = getChildEndpointNumber(params.cd)
sendEventToEndpoints(event:[name: "switch", value: "on", descriptionText: "Device turned on", type: "digital"] , ep:ep)
Integer targetLevel = 100
if (params.level) {
targetLevel = (params.level as Integer)
} else {
List<com.hubitat.app.DeviceWrapper> targets = getChildDeviceListByEndpoint(ep)
if (ep == 0) targets += device
targetLevel = (targets?.find{it.hasAttribute("level")}?.currentValue("level") as Integer) ?: 100
}
targetLevel = Math.min(Math.max(targetLevel, 1), 100)
sendEventToEndpoints(event:[name: "level", value: targetLevel, descriptionText: "Device level set", unit:"%", type: "digital"], ep:ep)
sendZwaveValue(value: targetLevel, duration: params.duration, ep: ep)
}
@groovy.transform.CompileStatic
void componentOff(com.hubitat.app.DeviceWrapper cd){ off(cd:cd) }
void off(Map inputs = [:]) {
Map params = [cd: null , duration: null ] << inputs
Integer ep = getChildEndpointNumber(params.cd)
sendEventToEndpoints(event:[name: "switch", value: "off", descriptionText: "Device turned off", type: "digital"], ep:ep)
sendZwaveValue(value: 0, duration: params.duration, ep: ep)
}
@groovy.transform.CompileStatic
void componentSetLevel(com.hubitat.app.DeviceWrapper cd, level, transitionTime = null) {
if (cd.hasCapability("FanControl") ) {
setSpeed(cd:cd, level:level, speed:levelToSpeed(level as Integer))
} else {
setLevel(level:level, duration:transitionTime, cd:cd)
}
}
@groovy.transform.CompileStatic
void setLevel(level, duration = null ) {
setLevel(level:level, duration:duration)
}
@groovy.transform.CompileStatic
void setLevel(Map params = [cd: null , level: null , duration: null ])
{
if ( (params.level as Integer) <= 0) {
off(cd:params.cd, duration:params.duration)
} else {
on(cd:params.cd, level:params.level, duration:params.duration)
}
}
@groovy.transform.CompileStatic
void componentStartLevelChange(com.hubitat.app.DeviceWrapper cd, String direction) { startLevelChange(direction, cd) }
void startLevelChange(String direction, com.hubitat.app.DeviceWrapper cd = null ){
com.hubitat.app.DeviceWrapper targetDevice = (cd ? cd : device)
Integer ep = cd ? (cd.deviceNetworkId.split("-ep")[-1] as Integer) : null
Integer upDown = (direction == "down") ? 1 : 0
def sendMe = zwave.switchMultilevelV1.switchMultilevelStartLevelChange(upDown: upDown, ignoreStartLevel: 1, startLevel: 0)
advancedZwaveSend(sendMe, ep)
}
@groovy.transform.CompileStatic
void componentStopLevelChange(com.hubitat.app.DeviceWrapper cd) { stopLevelChange(cd) }
void stopLevelChange(cd = null ){
com.hubitat.app.DeviceWrapper targetDevice = (cd ? cd : device)
Integer ep = cd ? (cd.deviceNetworkId.split("-ep")[-1] as Integer) : null
advancedZwaveSend(zwave.switchMultilevelV4.switchMultilevelStopLevelChange(), ep)
advancedZwaveSend(zwave.basicV1.basicGet(), ep)
}
////////////////////////////////////////////////////////
////// Handle Fans ///////
////////////////////////////////////////////////////////
@groovy.transform.CompileStatic
String levelToSpeed(Integer level)
{
// Map speeds = [(0..0):"off", (1..20):"low", (21..40):"medium-low", (41-60):"medium", (61..80):"medium-high", (81..100):"high"]
// return (speeds.find{ key, value -> key.contains(level) }).value
switch (level)
{
case 0 : return "off" ; break
case 1..20: return "low" ; break
case 21..40: return "medium-low" ; break
case 41..60: return "medium" ; break
case 61..80: return "medium-high" ; break
case 81..100: return "high" ; break
default : return null
}
}
Integer speedToLevel(String speed) {
return ["off": 0, "low":20, "medium-low":40, "medium":60, "medium-high":80, "high":100].get(speed)
}
@groovy.transform.CompileStatic
void componentSetSpeed(com.hubitat.app.DeviceWrapper cd, speed) { setSpeed(speed:speed, cd:cd) }
@groovy.transform.CompileStatic
void setSpeed(speed, com.hubitat.app.DeviceWrapper cd = null ) { setSpeed(speed:speed, cd:cd) }
void setSpeed(Map params = [speed: null , level: null , cd: null ])
{
com.hubitat.app.DeviceWrapper originatingDevice = params.cd ?: device
Integer ep = params.cd ? (originatingDevice.deviceNetworkId.split("-ep")[-1] as Integer) : 0
List<com.hubitat.app.DeviceWrapper> targetDevices = getChildDeviceListByEndpoint(ep)
if (params.speed.is( null ) ) {
log.error "Device ${originatingDevice.displayName}: setSpeed command received without a valid speed setting. Speed setting was ${params.speed}. Returning without doing anything!"
return
}
if (logEnable) log.info "Device ${device.displayName}: received setSpeed(${params.speed}) request from child ${originatingDevice.displayName}"
String currentOnState = originatingDevice.currentValue("switch")
Integer currentLevel = originatingDevice.currentValue("level") // Null if attribute isn't supported.
Integer targetLevel
if (params.speed == "on")
{
currentLevel = currentLevel ?: 100 // If it was a a level of 0, turn to 100%. Level should never be 0 -- except it might be 0 or null on first startup!
targetDevices.each{
it.sendEvent(name: "switch", value: "on", descriptionText: "Fan turned on", type: "digital")
it.sendEvent(name: "level", value: currentLevel, descriptionText: "Fan level set", unit:"%", type: "digital")
it.sendEvent(name: "speed", value: levelToSpeed(currentLevel), descriptionText: "Fan speed set", type: "digital")
}
sendZwaveValue(value: currentLevel, duration: 0, ep: ep)
} else if (params.speed == "off")
{
targetDevices.each{
it.sendEvent(name: "switch", value: "off", descriptionText: "Fan switched off", type: "digital")
it.sendEvent(name: "speed", value: "off", descriptionText: "Fan speed set", type: "digital")
}
sendZwaveValue(value: 0, duration: 0, ep: ep)
} else {
targetLevel = (params.level as Integer) ?: speedToLevel(params.speed) ?: currentLevel
targetDevices.each{
it.sendEvent(name: "switch", value: "on", descriptionText: "Fan turned on", type: "digital")
it.sendEvent(name: "speed", value: params.speed, descriptionText: "Fan speed set", type: "digital")
it.sendEvent(name: "level", value: targetLevel, descriptionText: "Fan level set", unit:"%", type: "digital")
}
sendZwaveValue(value: targetLevel, duration: 0, ep: ep)
}
}