/
QubinoFlushShutterDeviceHandler.groovy
929 lines (890 loc) · 45 KB
/
QubinoFlushShutterDeviceHandler.groovy
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
/**
* Qubino Flush Shutter
* Device Handler
* Version 1.0
* Date: 10.8.2017
* Author: Kristjan Jamšek (Kjamsek), Goap d.o.o.
* Copyright 2017 Kristjan Jamšek
*
* 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.
*
*
* |---------------------------- DEVICE HANDLER FOR QUBINO FLUSH SHUTTER Z-WAVE DEVICE -------------------------------------------------------|
* The handler supports all unsecure functions of the Qubino Flush Shutter device. Configuration parameters and
* association groups can be set in the device's preferences screen, but they are applied on the device only after
* pressing the 'Set configuration' and 'Set associations' buttons on the bottom of the details view.
*
* The Calibrate button issues a command to calibrate blinds. The Reset Power command resets accumulated power measurements.
* The Refresh power button is used to request and display kWH measurements from the device.
*
* This device handler supports data values that are currently not implemented as capabilities, so custom attribute
* states are used. Please use a SmartApp that supports custom attribute monitoring with this device in your rules.
* |-----------------------------------------------------------------------------------------------------------------------------------------------|
*
*
* TO-DO:
* - Implement secure mode
* - Implement Temperature Sensor functionality once inclusion in full configuration works
*
* CHANGELOG:
* 0.99: Final release code cleanup and commenting
* 1.00: Added comments to code for readability
* 1.10: Added Stop button to stop vertical axis motion
*/
metadata {
definition (name: "Qubino Flush Shutter", namespace: "Goap", author: "Kristjan Jamšek") {
capability "Actuator"
capability "Window Shade"
capability "Switch Level"
capability "Power Meter"
capability "Configuration" //Needed for configure() function to set any specific configurations
//capability "Temperature Measurement" //This capability is valid for devices with temperature sensors connected
attribute "kwhConsumption", "number" //attribute used to store and display power consumption in KWH
attribute "venetianLevel", "number" //attribute used to control and store venetian blinds level
attribute "venetianState", "string" //attribute for the binary control element of the venetian blinds control
command "setConfiguration" //command to issue Configuration Set commands to the module according to user preferences
command "setAssociation" //command to issue Association Set commands to the modules according to user preferences
command "refreshPowerConsumption" //command to issue Meter Get requests for KWH measurements from the device, W are already shown as part of Pwer Meter capability
command "resetPower" //command to issue Meter Reset commands to reset accumulated pwoer measurements
command "calibrate" //command to calibrate the shutter module
command "stop" //command to stop the vertical blind movement
command "setSlatLevel" //command to issue slat tilting controls
command "openSlats" //command to set maximum level for slats
command "closeSlats" //command to set minimum level for slats
fingerprint mfr:"0159", prod:"0003", model:"0052" //Manufacturer Information value for Qubino Flush Shutter
}
simulator {
// TESTED WITH PHYSICAL DEVICE - UNNEEDED
}
tiles(scale: 2) {
multiAttributeTile(name:"shade", type: "generic", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.windowShade", key: "PRIMARY_CONTROL") {
attributeState "open", label:'${name}', action:"close", icon:"st.Home.home9", backgroundColor:"#79b821", nextState:"closing"
attributeState "closed", label:'${name}', action:"open", icon:"st.Home.home9", backgroundColor:"#ffffff", nextState:"opening"
attributeState "opening", label:'${name}', action:"close", icon:"st.Home.home9", backgroundColor:"#79b821", nextState:"open"
attributeState "closing", label:'${name}', action:"open", icon:"st.Home.home9", backgroundColor:"#ffffff", nextState:"closed"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("device.power", key: "SECONDARY_CONTROL") {
attributeState "power", label:'Power level: ${currentValue} W', icon: "st.Appliances.appliances17"
}
}
standardTile("stop", "device.stop", decoration: "flat", width: 6, height: 2) {
state("stop", label:'', action:'stop', icon: "st.sonos.stop-btn")
}
standardTile("venetianLabel", "device.venetianLabel", decoration: "flat", width: 6, height: 2) {
state("venetianLabel", label:'SLAT TILT CONTROLS:')
}
multiAttributeTile(name:"venetianTile", type: "generic", width: 6, height: 4){
tileAttribute ("venetianState", key: "PRIMARY_CONTROL") {
attributeState "Slats open", label:'${name}', action:"closeSlats", backgroundColor:"#79b821", nextState:"Slats closing"
attributeState "Slats closed", label:'${name}', action:"openSlats", backgroundColor:"#ffffff", nextState:"Slats opening"
attributeState "Slats opening", label:'${name}', action:"closeSlats", backgroundColor:"#79b821", nextState:"Slats open"
attributeState "Slats closing", label:'${name}', action:"openSlats", backgroundColor:"#ffffff", nextState:"Slats closed"
}
tileAttribute ("venetianLevel", key: "SLIDER_CONTROL") {
attributeState "venetianLevel", action:"setSlatLevel"
}
}
standardTile("power", "device.power", decoration: "flat", width: 3, height: 3) {
state("power", label:'${currentValue} W', icon: 'st.Appliances.appliances17')
}
standardTile("kwhConsumption", "device.kwhConsumption", decoration: "flat", width: 3, height: 3) {
state("kwhConsumption", label:'${currentValue} kWh', icon: 'st.Appliances.appliances17')
}
standardTile("resetPower", "device.resetPower", decoration: "flat", width: 3, height: 3) {
state("resetPower", label:'Reset Power', action:'resetPower')
}
standardTile("refreshPowerConsumption", "device.refreshPowerConsumption", decoration: "flat", width: 3, height: 3) {
state("refreshPowerConsumption", label:'Refresh power', action:'refreshPowerConsumption')
}
/* //THIS VERSION DOESN?T SUPPORT TEMPERATURE SENSORS YET
standardTile("temperature", "device.temperature", width: 6, height: 3) {
state("temperature", label:'${currentValue} ${unit}', unit:'°', icon: 'st.Weather.weather2', backgroundColors: [
// Celsius Color Range
[value: 0, color: "#153591"],
[value: 7, color: "#1e9cbb"],
[value: 15, color: "#90d2a7"],
[value: 23, color: "#44b621"],
[value: 29, color: "#f1d801"],
[value: 33, color: "#d04e00"],
[value: 36, color: "#bc2323"],
// Fahrenheit Color Range
[value: 40, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 92, color: "#d04e00"],
[value: 96, color: "#bc2323"]
])
}
*/
standardTile("setConfiguration", "device.setConfiguration", decoration: "flat", width: 3, height: 3) {
state("setConfiguration", label:'Set Configuration', action:'setConfiguration')
}
standardTile("setAssociation", "device.setAssociation", decoration: "flat", width: 3, height: 3) {
state("setAssociation", label:'Set Associations', action:'setAssociation')
}
standardTile("calibrate", "device.calibrate", decoration: "flat", width: 6, height: 2) {
state("calibrate", label:'Calibrate', action:'calibrate')
}
main("shade")
details(["shade", "stop", "venetianLabel", "venetianTile", "power", "kwhConsumption", "resetPower", "refreshPowerConsumption", "setConfiguration", "setAssociation", "calibrate"])
}
preferences {
/**
* -------- CONFIGURATION PARAMETER SECTION --------
*/
input (
type: "paragraph",
element: "paragraph",
title: "CONFIGURATION PARAMETERS:",
description: "Configuration parameter settings."
)
input name: "param10", type: "enum", required: false,
options: ["0" : "0 - ALL ON is not active, ALL OFF is not active",
"1" : "1 - ALL ON is not active, ALL OFF active",
"2" : "2 - ALL ON active, ALL OFF is not active",
"255" : "255 - ALL ON active, ALL OFF active"],
title: "10. Activate / deactivate functions ALL ON / ALL OFF.\n " +
"Available settings:\n" +
"255 - ALL ON active, ALL OFF active.\n" +
"0 - ALL ON is not active, ALL OFF is not active.\n" +
"1 - ALL ON is not active, ALL OFF active.\n" +
"2 - ALL ON active, ALL OFF is not active.\n" +
"Default value: 255.\n" +
"Flush Shutter module responds to commands ALL ON / ALL OFF that may be sent by the main controller or by other controller belonging to the system."
input name: "param40", type: "number", range: "0..100", required: false,
title: "40. Power reporting in Watts on power change.\n" +
"Set value means percentage, set value from 0 - 100 = 0% - 100%.\n" +
"Available settings:\n" +
"0 - reporting disabled.\n" +
"1 - 100 = 1% - 100% Reporting enabled. Power report is send (push) only when actual power in Watts in real time changes for more than set percentage comparing to previous actual power in Watts, step is 1%.\n" +
"Default value: 5." +
"NOTE: if power changed is less than 1W, the report is not send (pushed), independent of percentage set."
input name: "param42", type: "number", range: "0..32767", required: false,
title: "42. Power reporting in Watts by time interval.\n" +
"Set value means time interval (0 - 32767) in seconds, when power report is send.\n" +
"Available settings:\n" +
"0 - reporting disabled.\n" +
"1 - 32767 = 1 second - 32767 seconds. Reporting enabled. Power report is send with time interval set by entered value.\n" +
"Default value: 0."
input name: "param71", type: "enum", required: false,
options: ["0" : "0 - Shutter mode.",
"1" : "1 - Venetian mode."],
title: "71. Operating modes.\n " +
"This parameter defines selection between two available operating modes.\n" +
"Available settings:\n" +
"0 - Shutter mode.\n" +
"1 - Venetian mode.\n" +
"Default value: 0.\n" +
"NOTE: After parameter change, first exclude module (without setting parameters to default value) then wait at least 30s and then re include the module!"
input name: "param72", type: "number", range: "0..32767", required: false,
title: "72. Slats tilting full turn time.\n" +
"This parameter defines the time necessary for slats to make full turn (180 degrees).\n" +
"Available settings:\n" +
"0 - tilting time disabled.\n" +
"1 - 32767 = 0,001 seconds - 327,67 seconds.\n" +
"Default value: 150 (1,5 seconds).\n" +
"NOTE: If time set is too high, this will result that after full turn, Shutter will start move up or down, for time remaining."
input name: "param73", type: "enum", required: false,
options: ["0" : "0 - Slats return to previously set position only in case of Z-wave control (not valid for limit switch positions).",
"1" : "1 - Slats return to previously set position in case of Z-wave control, push-button operation or when the lower limit switch is reached."],
title: "73. Slats position.\n " +
"This parameter defines slats position after up/down movement through Z-wave or push-buttons.\n" +
"Available settings:\n" +
"0 - Slats return to previously set position only in case of Z-wave control (not valid for limit switch positions).\n" +
"1 - Slats return to previously set position in case of Z-wave control, push-button operation or when the lower limit switch is reached.\n" +
"Default value: 1."
input name: "param74", type: "number", range: "0..32767", required: false,
title: "74. Motor moving up/down time.\n" +
"This parameter defines Shutter motor moving time of complete opening or complete closing.\n" +
"Available settings:\n" +
"0 - moving time disabled (working with limit switches).\n" +
"1 - 32767 = 0,1 seconds - 3276,7 seconds.\n" +
"Default value: 0.\n" +
"NOTE: Important is that the reference position to manually set moving time is always Shutter lower position!"
input name: "param76", type: "number", range: "0..127", required: false,
title: "76. Motor operation detection.\n" +
"Power threshold to be interpreted when motor reach the limit switch.\n" +
"Available settings:\n" +
"0 - 127 = 1 - 127 W. The value 0 means reaching a limit switch will not be detected.\n" +
"Default value: 30 = 30W."
input name: "param78", type: "enum", required: false,
options: ["0" : "0 - No calibration.",
"1" : "1 - Calibrate shutter."],
title: "78. Forced Shutter calibration.\n " +
"By modifying the parameters setting from 0 to 1 a Shutter enters the calibration mode..\n" +
"Available settings:\n" +
"0 - No calibration.\n" +
"1 - Start calibration process (when calibration process is finished, completing full cycle - up, down and up, set the parameter 78 (Forced Shutter calibration)value back to 0.\n" +
"Default value: 0."
input name: "param85", type: "number", range: "0..50", required: false,
title: "85. Power consumption max delay time.\n" +
"This parameter defines the max time before motor power consumption is read after one of the relays is switched ON. If there is no power consumption during this max time (motor not connected, damaged or requires higher time to start, motor in end position) the relay will switch OFF. Time is defined by entering it manually\n" +
"Available settings:\n" +
"0 - Time is set automatically.\n" +
"3 - 50 = 0,3 seconds - 5 seconds (100ms resolution).\n" +
"Default value: 30 = 3 seconds."
input name: "param90", type: "number", range: "1..30", required: false,
title: "90. Time delay for next motor movement.\n" +
"This parameter defines the minimum time delay between next motor movement (minimum time between switching motor off and on again).\n" +
"Available settings:\n" +
"1 - 30 = 0,1 seconds - 3 seconds (100ms resolution).\n" +
"Default value: 5 = 500 miliseconds."
input name: "param110", type: "number", range: "1..32536", required: false,
title: "110. Temperature sensor offset settings.\n" +
"Set value is added or subtracted to actual measured value by sensor..\n" +
"Available settings:\n" +
"32536 - offset is 0.0C.\n" +
"From 1 to 100 - value from 0.1 °C to 10.0 °C is added to actual measured temperature.\n" +
"From 1001 to 1100 - value from -0.1 °C to -10.0 °C is subtracted to actual measured temperature.\n" +
"Default value: 32536."
input name: "param120", type: "number", range: "0..127", required: false,
title: "120. Digital temperature sensor reporting.\n" +
"If digital temperature sensor is connected, module reports measured temperature on temperature change defined by this parameter.\n" +
"Available settings:\n" +
"0 - Reporting disabled.\n" +
"1 - 127 = 0,1°C - 12,7°C, step is 0,1°C.\n" +
"Default value: 5 = 0,5°C change."
input name: "param249", type: "enum", required: false,
options: ["0" : "0 – Disable reporting.",
"1" : "1 – Enable reporting."],
title: "249. Enable/Disable Reporting on Set command.\n" +
"Available settings:\n" +
"0 – Disable reporting.\n" +
"1 – Enable reporting.\n" +
"Default value: 1."
/**
* -------- ASSOCIATION GROUP SECTION --------
*/
input (
type: "paragraph",
element: "paragraph",
title: "ASSOCIATION GROUPS:",
description: "Association group settings."
)
input name: "assocGroup2", type: "text", required: false,
title: "Association group 2: \n" +
"Basic on/off (triggered at change of the input I1 state and reflecting its state) up to 16 nodes.\n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup3", type: "text", required: false,
title: "Association group 3: \n" +
"Basic on/off (triggered at change of the input I2 state and reflecting its state) up to 16 nodes." +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup4", type: "text", required: false,
title: "Association group 4: \n" +
"basic on/off (triggered at sensing moving direction of roller: up=FF, down=0) up to 16 nodes." +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup5", type: "text", required: false,
title: "Association group 5: \n" +
"Basic on/off (triggered at reaching roller position: bottom=FF, top=0) up to 16 nodes.\n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup6", type: "text", required: false,
title: "Association group 6: \n" +
"Basic on/off (triggered at reaching roller position: bottom=FF, not bottom=0) up to 16 nodes.\n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup7", type: "text", required: false,
title: "Association group 7: \n" +
"Multilevel set (triggered at changes of value of the Flush Shutter position) up to 16 nodes.\n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup8", type: "text", required: false,
title: "Association group 8: \n" +
"Multilevel set (triggered at changes of value of slats tilting position) up to 16 nodes.\n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup9", type: "text", required: false,
title: "Association group 9: \n" +
"Multilevel sensor report (triggered at change of temperature sensor) up to 16 nodes.\n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
}
}
/**
* -------- HELPER METHODS SECTION --------
*/
/**
* Converts a list of String type node id values to Integer type.
*
* @param stringList - a list of String type node id values.
* @return stringList - a list of Integer type node id values.
*/
def convertStringListToIntegerList(stringList){
log.debug stringList
if(stringList != null){
for(int i=0;i<stringList.size();i++){
stringList[i] = stringList[i].toInteger()
}
}
return stringList
}
/**
* Converts temperature values to fahrenheit or celsius scales according to user's setting.
*
* @param scaleParam user set scale parameter.
* @param encapCmd received temperature parsed value.
* @return String type value of the converted temperature value.
*/
def convertDegrees(scaleParam, encapCmd){
switch (scaleParam) {
default:
break;
case "F":
if(encapCmd.scale == 1){
return encapCmd.scaledSensorValue.toString()
}else{
return (encapCmd.scaledSensorValue * 9 / 5 + 32).toString()
}
break;
case "C":
if(encapCmd.scale == 0){
return encapCmd.scaledSensorValue.toString()
}else{
return (encapCmd.scaledSensorValue * 9 / 5 + 32).toString()
}
break;
}
}
/*
* -------- HANDLE COMMANDS SECTION --------
*/
/**
* Configuration capability command handler.
*
* @param void
* @return List of commands that will be executed in sequence with 500 ms delay inbetween.
*/
def configure() {
log.debug "Qubino Flush Shutter: configure()"
state.isMcDevice = false
log.debug state.isMcDevice
def assocCmds = []
assocCmds << zwave.associationV1.associationRemove(groupingIdentifier:1).format()
assocCmds << zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId).format()
assocCmds << zwave.multiChannelV3.multiChannelEndPointGet().format()
return delayBetween(assocCmds, 500)
}
/**
* Stop command handler. Issues StopLevelChange when operating as singlechannel device handler.
*
* @param void
* @return List of commands that will be executed in sequence with 500 ms delay inbetween.
*/
def stop() {
log.debug "Qubino Flush Shutter: stop()"
def cmds = []
cmds << zwave.switchMultilevelV3.switchMultilevelStopLevelChange().format()
cmds << zwave.switchMultilevelV3.switchMultilevelGet().format()
return delayBetween(cmds, 1000)
}
/**
* stopSlats command handler. Issues StopLevelChange to endpoint 2 of the device when operating as multichannel device handler.
*
* @param void
* @return List of commands that will be executed in sequence with 500 ms delay inbetween.
*/
def stopSlats(){
log.debug "Qubino Flush Shutter: stopSlats()"
def cmds = []
cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelStopLevelChange()).format()
cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelGet()).format()
return delayBetween(cmds, 500)
}
/**
* Switch capability command handler for ON state. It issues a Switch Multilevel Set command with value 0xFF and instantaneous duration.
* This command is followed by a Switch Multilevel Get command, that updates the actual state of the main shutter control.
*
* @param void
* @return void.
*/
def open() {
log.debug "Qubino Flush Shutter: open()"
return zwave.switchMultilevelV3.switchMultilevelSet(value: 0xFF, dimmingDuration: 0x00).format()
}
/**
* Window Shade capability command handler for closed state. It issues a Switch Multilevel Set command with value 0x00 and instantaneous duration.
*
* @param void
* @return void.
*/
def close() {
log.debug "Qubino Flush Shutter: close()"
return zwave.switchMultilevelV3.switchMultilevelSet(value: 0x00, dimmingDuration: 0x00).format()
}
/**
* Command handler for open slats command. It issues a Switch Multilevel Set command with value 0xFF to endpoint 2 of the device and instantaneous duration.
*
* @param void
* @return void.
*/
def openSlats(){
log.debug "Qubino Flush Shutter: openSlats()"
//zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: 0xFF, dimmingDuration: 0x00)).format()//change regarding full open state, will revert after discussion with sigma
log.debug settings.param72
if(settings.param72 == null){
return delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: 0x63, dimmingDuration: 0x00)).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelGet()).format()
], 1500)
}else{
def tempTurningTime = settings.param72.toInteger()*10
return delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: 0x63, dimmingDuration: 0x00)).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelGet()).format()
], tempTurningTime)
}
}
/**
* Command handler for close slats command. It issues a Switch Multilevel Set command with value 0x00 to endpoint 2 of the device and instantaneous duration.
*
* @param void
* @return void.
*/
def closeSlats(){
log.debug "Qubino Flush Shutter: closeSlats()"
//zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: 0x00, dimmingDuration: 0x00)).format()
log.debug settings.param72
if(settings.param72 == null){
return delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: 0x00, dimmingDuration: 0x00)).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelGet()).format()
], 1500)
}else{
def tempTurningTime = settings.param72.toInteger()*10
return delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: 0x00, dimmingDuration: 0x00)).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelGet()).format()
], tempTurningTime)
}
}
/**
* Command handler for setting the slat tilt level. It issues a Switch Multilevel Set command with specified value and instantaneous duration.
* We need to limit the max value to 99% by Z-Wave protocol definitions.
*
* @param void
* @return void.
*/
def setSlatLevel(level) {
log.debug "Qubino Flush Shutter: setSlatLevel()"
log.debug level
if(level > 99) level = 99
//zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: 0x00)).format()
if(settings.param72 == null){
return delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: 0x00)).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelGet()).format()
], 1500)
}else{
def tempTurningTime = settings.param72.toInteger()*10
return delayBetween([
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: 0x00)).format(),
zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2).encapsulate(zwave.switchMultilevelV3.switchMultilevelGet()).format()
], tempTurningTime)
}
}
/**
* Command handler for calibrating the shutter module. It does the same as setting configuration parameter 78 to 1. Available on the details page for convenience.
*
* @param void
* @return void.
*/
def calibrate() {
log.debug "Qubino Flush Shutter: calibrate()"
zwave.configurationV1.configurationSet(parameterNumber: 78, size: 1, scaledConfigurationValue: 1).format()
}
/**
* Window Shade capability command handler for a blinds level state. It issues a Switch Multilevel Set command with value contained in the parameter value and instantaneous duration.
* We need to limit the max value to 99% by Z-Wave protocol definitions.
*
* @param level The desired value of the dimmer we are trying to set.
* @return void.
*/
def setLevel(level) {
log.debug "Qubino Flush Shutter: setLevel()"
if(level > 99) level = 99
zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: 0x00).format()
}
/**
* Refresh Power Consumption command handler for updating the cumulative consumption fields in kWh. It will issue a Meter Get command with scale parameter set to kWh.
*
* @param void.
* @return void.
*/
def refreshPowerConsumption() {
log.debug "Qubino Flush Shutter: refreshPowerConsumption()"
delayBetween([
zwave.meterV2.meterGet(scale: 0).format(),
zwave.meterV2.meterGet(scale: 2).format()
], 1000)
}
/**
* Reset Power Consumption command handler for resetting the cumulative consumption fields in kWh. It will issue a Meter Reset command followed by Meter Get commands for active and accumulated power.
*
* @param void.
* @return void.
*/
def resetPower() {
log.debug "Qubino Flush Shutter: resetPower()"
zwave.meterV2.meterReset()
delayBetween([
zwave.meterV2.meterReset(),
zwave.meterV2.meterGet(scale: 0).format(),
zwave.meterV2.meterGet(scale: 2).format()
], 1000)
}
/**
* setAssociations command handler that sets user selected association groups. In case no node id is insetred the group is instead cleared.
* Lifeline association hidden from user influence by design.
*
* @param void
* @return List of Association commands that will be executed in sequence with 500 ms delay inbetween.
*/
def setAssociation() {
log.debug "Qubino Flush Shutter: setAssociation()"
def assocSet = []
if(settings.assocGroup2 != null){
def group2parsed = settings.assocGroup2.tokenize(",")
if(group2parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:settings.assocGroup2).format()
}else{
group2parsed = convertStringListToIntegerList(group2parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:group2parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:2).format()
}
if(settings.assocGroup3 != null){
def group3parsed = settings.assocGroup3.tokenize(",")
if(group3parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:3, nodeId:settings.assocGroup3).format()
}else{
group3parsed = convertStringListToIntegerList(group3parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:3, nodeId:group3parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:3).format()
}
if(settings.assocGroup4 != null){
def group4parsed = settings.assocGroup4.tokenize(",")
if(group4parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:4, nodeId:settings.assocGroup4).format()
}else{
group4parsed = convertStringListToIntegerList(group4parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:4, nodeId:group4parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:4).format()
}
if(settings.assocGroup5 != null){
def group5parsed = settings.assocGroup5.tokenize(",")
if(group5parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:5, nodeId:settings.assocGroup5).format()
}else{
group5parsed = convertStringListToIntegerList(group5parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:5, nodeId:group5parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:5).format()
}
if(settings.assocGroup6 != null){
def group6parsed = settings.assocGroup6.tokenize(",")
if(group6parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:6, nodeId:settings.assocGroup6).format()
}else{
group6parsed = convertStringListToIntegerList(group6parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:6, nodeId:group6parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:6).format()
}
if(settings.assocGroup7 != null){
def group7parsed = settings.assocGroup7.tokenize(",")
if(group7parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:7, nodeId:settings.assocGroup7).format()
}else{
group7parsed = convertStringListToIntegerList(group7parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:7, nodeId:group7parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:7).format()
}
if(settings.assocGroup8 != null){
def group8parsed = settings.assocGroup8.tokenize(",")
if(group8parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:8, nodeId:settings.assocGroup8).format()
}else{
group8parsed = convertStringListToIntegerList(group8parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:8, nodeId:group8parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:8).format()
}
if(settings.assocGroup9 != null){
def group9parsed = settings.assocGroup9.tokenize(",")
if(group9parsed == null){
assocSet << zwave.associationV1.associationSet(groupingIdentifier:9, nodeId:settings.assocGroup9).format()
}else{
group9parsed = convertStringListToIntegerList(group9parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:9, nodeId:group9parsed).format()
}
}else{
assocSet << zwave.associationV2.associationRemove(groupingIdentifier:9).format()
}
if(assocSet.size() > 0){
return delayBetween(assocSet, 500)
}
}
/**
* setConfigurationParams command handler that sets user selected configuration parameters on the device.
* In case no value is set for a specific parameter the method skips setting that parameter.
* Secure mode setting hidden from user influence by design.
*
* @param void
* @return List of Configuration Set commands that will be executed in sequence with 500 ms delay inbetween.
*/
def setConfiguration() {
log.debug "Qubino Flush Shutter: setConfiguration()"
def configSequence = []
if(settings.param10 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 10, size: 2, scaledConfigurationValue: settings.param10.toInteger()).format()
}
if(settings.param40 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 40, size: 1, scaledConfigurationValue: settings.param40.toInteger()).format()
}
if(settings.param42 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 42, size: 2, scaledConfigurationValue: settings.param42.toInteger()).format()
}
if(settings.param71 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 71, size: 1, scaledConfigurationValue: settings.param71.toInteger()).format()
}
if(settings.param72 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 72, size: 2, scaledConfigurationValue: settings.param72.toInteger()).format()
}
if(settings.param73 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 73, size: 1, scaledConfigurationValue: settings.param73.toInteger()).format()
}
if(settings.param74 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 74, size: 2, scaledConfigurationValue: settings.param74.toInteger()).format()
}
if(settings.param76 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 76, size: 1, scaledConfigurationValue: settings.param76.toInteger()).format()
}
if(settings.param78 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 78, size: 1, scaledConfigurationValue: settings.param78.toInteger()).format()
}
if(settings.param85 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 85, size: 1, scaledConfigurationValue: settings.param85.toInteger()).format()
}
if(settings.param90 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 90, size: 1, scaledConfigurationValue: settings.param90.toInteger()).format()
}
if(settings.param110 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 110, size: 2, scaledConfigurationValue: settings.param110.toInteger()).format()
}
if(settings.param120 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 120, size: 1, scaledConfigurationValue: settings.param120.toInteger()).format()
}
if(configSequence.size() > 0){
return delayBetween(configSequence, 500)
}
}
/*
* -------- EVENT PARSER SECTION --------
*/
/**
* parse function takes care of parsing received bytes and passing them on to event methods.
*
* @param description String type value of the received bytes.
* @return Parsed result of the received bytes.
*/
def parse(String description) {
log.debug "Qubino Flush Shutter: Parsing '${description}'"
def result = null
def cmd = zwave.parse(description)
if (cmd) {
result = zwaveEvent(cmd)
log.debug "Parsed ${cmd} to ${result.inspect()}"
} else {
log.debug "Non-parsed event: ${description}"
}
return result
}
/**
* Event handler for received Sensor Multilevel Report frames. These are for the temperature sensor connected to TS connector.
*
* @param cmd communication frame
* @return Event that updates the temperature values with received values.
*/
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){
log.debug "Qubino Flush Shutter: SensorMultilevelReport handler fired"
def resultEvents = []
resultEvents << createEvent(name:"temperature", value: convertDegrees(location.temperatureScale,cmd), unit:"°"+location.temperatureScale, descriptionText: "Temperature: "+convertDegrees(location.temperatureScale,cmd)+"°"+location.temperatureScale, isStateChange: true)
return resultEvents
}
/**
* Event handler for received Switch Multilevel Report frames.
*
* @param cmd communication frame
* @return List of events to update the ON / OFF and analogue control elements with received values.
*/
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd){
log.debug "Qubino Flush Shutter: firing switch multilevel event"
def result = []
result << createEvent(name:"windowShade", value: cmd.value ? "open" : "closed", isStateChange: true)
if(cmd.value > 99){
result << createEvent(name:"level", value: cmd.value, unit:"%", descriptionText:"${device.displayName} is uncalibrated! Please press calibrate!", isStateChange: true)
}else{
result << createEvent(name:"level", value: cmd.value, unit:"%", descriptionText:"${device.displayName} moved to ${cmd.value==99 ? 100 : cmd.value}%", isStateChange: true)
}
return result
}
/**
* Event handler for received MC Encapsulated Switch Multilevel Report frames.
*
* @param cmd communication frame, command mc encapsulated communication frame; needed to distinguish sources
* @return List of events to update the ON / OFF and analogue control elements with received values.
*/
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd, physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap command){
log.debug "Qubino Flush Shutter: firing MC switch multilevel event"
def result = []
switch(command.sourceEndPoint){
case 1:
result << createEvent(name:"windowShade", value: cmd.value ? "open" : "closed", isStateChange: true)
if(cmd.value > 99){
result << createEvent(name:"level", value: cmd.value, unit:"%", descriptionText:"${device.displayName} is uncalibrated! Please press calibrate!")
}else{
result << createEvent(name:"level", value: cmd.value, unit:"%", descriptionText:"${device.displayName} moved to ${cmd.value==99 ? 100 : cmd.value}%", isStateChange: true)
}
break;
case 2:
log.debug "Received command from EP2"
log.debug cmd
result << createEvent(name:"venetianState", value: cmd.value ? "Slats open" : "Slats closed", isStateChange: true)
if(cmd.value > 99){
result << createEvent(name:"venetianLevel", value: cmd.value, unit:"%", descriptionText:"${device.displayName} is uncalibrated! Please press calibrate!", isStateChange: true)
}else{
result << createEvent(name:"venetianLevel", value: cmd.value, unit:"%", descriptionText:"${device.displayName} tilted slats to ${cmd.value==99 ? 100 : cmd.value}%", isStateChange: true)
}
break;
}
return result
}
/**
* Event handler for received MC Encapsulated Meter Report frames.
*
* @param cmd communication frame, command mc encapsulated communication frame; needed to distinguish sources
* @return List of events to update the power consumption elements with received values.
*/
def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap command){
log.debug "Qubino Flush Shutter: firing MC Encap meter report event"
def result = []
switch(cmd.scale){
case 0:
result << createEvent(name:"kwhConsumption", value: cmd.scaledMeterValue, unit:"kWh", descriptionText:"${device.displayName} consumed ${cmd.scaledMeterValue} kWh", isStateChange: true)
break;
case 2:
result << createEvent(name:"power", value: cmd.scaledMeterValue, unit:"W", descriptionText:"${device.displayName} consumes ${cmd.scaledMeterValue} W", isStateChange: true)
break;
}
return result
}
/**
* Event handler for received Meter Report frames. Used for displaying W and kWh measurements.
*
* @param void
* @return Power consumption event for W data or kwhConsumption event for kWh data.
*/
def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) {
log.debug "Qubino Flush Shutter: firing meter report event"
def result = []
switch(cmd.scale){
case 0:
result << createEvent(name:"kwhConsumption", value: cmd.scaledMeterValue, unit:"kWh", descriptionText:"${device.displayName} consumed ${cmd.scaledMeterValue} kWh", isStateChange: true)
break;
case 2:
result << createEvent(name:"power", value: cmd.scaledMeterValue, unit:"W", descriptionText:"${device.displayName} consumes ${cmd.scaledMeterValue} W", isStateChange: true)
break;
}
return result
}
/**
* Event handler for received Configuration Report frames. Used for debugging purposes.
*
* @param void
* @return void.
*/
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd){
log.debug "Qubino Flush Shutter: firing configuration report event"
log.debug cmd.configurationValue
}
/**
* Event handler for received Basic Report frames. ST sends these for some reason every 10 seconds.
*
* @param cmd communication frame
* @return Main roller level state events.
*/
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd){
log.debug "Qubino Flush Shutter: firing basic report event"
def result = []
result << createEvent(name:"windowShade", value: cmd.value ? "open" : "closed", isStateChange: true)
if(cmd.value > 99){
result << createEvent(name:"level", value: cmd.value, unit:"%", descriptionText:"${device.displayName} is uncalibrated! Please press calibrate!", isStateChange: true)
}else{
result << createEvent(name:"level", value: cmd.value, unit:"%", descriptionText:"${device.displayName} moved to ${cmd.value==99 ? 100 : cmd.value}%", isStateChange: true)
}
return result
}
/**
* Event handler for received MultiChannelEndPointReport commands. Used to distinguish when the device is in singlechannel or multichannel configuration.
*
* @param cmd communication frame
* @return commands to set up a MC Lifeline association.
*/
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelEndPointReport cmd){
log.debug "Qubino Flush Shutter: firing MultiChannelEndPointReport"
if(cmd.endPoints > 0){
state.isMcDevice = true;
}
def cmds = []
cmds << response(zwave.associationV1.associationRemove(groupingIdentifier:1).format())
//cmds << "delay 500"
cmds << response(zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: [0,zwaveHubNodeId,1]).format())
return cmds
}
/**
* Event handler for received MultiChannelCapabilityReport commands. Used to distinguish when the device is in singlechannel or multichannel configuration.
*
* @param cmd communication frame
* @return commands to set up a MC Lifeline association.
*/
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCapabilityReport cmd){
log.debug "Qubino Flush Shutter: firing MultiChannelCapabilityReport"
state.isMcDevice = true
def cmds = []
cmds << response(zwave.associationV1.associationRemove(groupingIdentifier:1).format())
//cmds << "delay 500"
cmds << response(zwave.multiChannelAssociationV2.multiChannelAssociationSet(groupingIdentifier: 1, nodeId: [0,zwaveHubNodeId,1]).format())
return cmds
}
/**
* Event handler for received Multi Channel Encapsulated commands.
*
* @param cmd encapsulated communication frame
* @return parsed event.
*/
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd){
log.debug "Qubino Flush Shutter: firing MC Encapsulation event"
def encapsulatedCommand = cmd.encapsulatedCommand()
//log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand, cmd)
}
}