-
Notifications
You must be signed in to change notification settings - Fork 1
/
iris_v1_keypad.groovy
2111 lines (1838 loc) · 80.8 KB
/
iris_v1_keypad.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
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Iris v1 KeyPad Driver
Hubitat Iris v1 KeyPad driver
Supports keypad disarm arm functions (all modes)
Works with Lock Code Manager (4-15 digit Pin size supported)
Works with Hubitat® Safety Monitor
Plays chime codes and alarm strobe
Button Controller support to map coomands to buttons 1-0
_____ _____ _____ _____ __ _ __ _
|_ _| __ \|_ _|/ ____| /_ | | |/ / | |
| | | |__) | | | | (___ __ _| | | ' / ___ _ _ _ __ __ _ __| |
| | | _ / | | \___ \ \ \ / / | | < / _ \ | | | '_ \ / _` |/ _` |
_| |_| | \ \ _| |_ ____) | \ V /| | | . \ __/ |_| | |_) | (_| | (_| |
|_____|_| \_\_____|_____/ \_/ |_| |_|\_\___|\__, | .__/ \__,_|\__,_|
__/ | |
|___/|_|
Must set keypad in (Hubitat® Safety Monitor) and (Lock Code manager) for it to work
=================================================================================================
v7.0.3 02/15/2024 Valid pin presses OFF for you.
This fixes a problem with the new firmware being slower than it was in 2022
v7.0.2 11/12/2022 Another bug fix for presence
v7.0.0 11/11/2022 Rewrote logging code (smaller code size) Added improvements from my iris drivers
v6.9.0 10/30/2022 Bug fix in presence routine was not giving warning before timing out.
v6.8.5 10/10/2022 Bat 2 detection removed more work needed.
v6.8.4 10/10/2022 Cancel/Disarm code rewritten. Switch capability added. Routines can now turn off/on
alarm by switch. 2 new tones added depends on your firmware if they work.
Rewrote HSM send cmd code. Rewrote HSM delay code.
Changes in arming from keypad now sends arm to HSM and waits for HSM to send ARM.
Was arming first. Should help keep the countdown timer in sync with slugish hubs.
BadPin tone setting added.
v6.8.2 09/30/2022 STROBE added to alarm setting to fix alt firmware problems.
v6.8.1 09/30/2022 Fingerprint adjusted Finaly have autopair working
Firmware 2012-06-11 does not autorepeate the alarm tone fixed. Redirected to strobe.
if your firmware doesnt repeat alarm tones I need to know.
v6.8 09/24/2022 Pin code logging bug fixed. Reduce bat events
v6.7.1 09/22/2022 New presence routine
v6.7 09/21/2022 Ranging Adjustments
v6.6 09/19/2022 Rewrote logging routines.
v6.5 09/17/2022 Increased database to 10 PINS
v6.4 09/16/2022 Allow HSM to send more than 1 off cmd. Bug in panic timeout fixed.
Rewrite of ranging code. Rewrite of battery logging code. Updating iris block code on all my iris drivers.
Pin logging rewritten. Hide pin from log.
v6.3 09/10/2022 Reversing v.61 update
v6.2 09/04/2022 Updating iris block code on all my iris drivers.
v6.1 09/03/2022 ---
v6.0 09/02/2022 Changed Init boot up routines. Trying to prevent Beep on reboot.
Enrole Request detect added.
v5.9 08/26/2022 New iris cluster seen on the mesh, added detection for it.
v5.8 08/09/2022 Fixed looping if 2 alarm commands sent.
v5.7 06/28/2022 Stop runaway countdown if disarmed by app during entry.
Added more events to logs
v5.6 04/28/2022 Added command to unschedule pausing cron for debuging.
v5.5 04/18/2022 Fine Tunning disarm during entry. Chimes countdown sometimes didnt stop.
Hide PINS from the info log for security
v5.4 04/12/2022 More adj to alkaline batt lasting longer than expected.
v5.3 03/12/2022 Battery routine and log adjustments.
v5.2 02/22/2022 Added new firmware detect
v5.1 01/18/2022 Minor cosmetic changes
v5.0 11/25/2021 Bug in arm home was armingaway
v4.9 11/09/2021 Silent arming options. min bat voltage adjustments.
Door chime still walking over entry chime. New fix.
Upgrade lockdata fileds in hsm arming to match keypad arming.
v4.8 10/29/2021 No longer sending HSM arming commands. HSM now reads the keyboard state.
error in panic cancel fixed
v4.7 10/28/2021 Logging for HSM SYNC. Verifies proper operation in log.
Disarmed during Entry did not always stop alarm fixed
Syntax error causing arm away to arm 2 times.
ON is now AWAY only. Part can be customized
Door chime during entry is a problem. Fixed
v4.6 10/27/2021 added armingIn event,
Logging changed to match standard digital/physical
Arming routine changed, No longer waits for HSM to start.
Rewrite of arming/entry/disarm routine. Less log clutter
Direct HSM arming can be disabled.
Fingerprint updated. Testing to see if detection will work
Would arm if you cancled arming. fixed
Arming delays now set direct by HSM.
v4.5 10/26/2021 Error in cron on driver change.
v4.4 10/22/2021 Added Beep cmd. Tamper or shock alarm for bad pin.
Arming overides chime rewritten. Automatic dead bat detection
v4.3 10/21/2021 Arming and Entry have priority over chime. Timeout timmer for chime
v4.2 10/20/2021 Code cleanup UI text changes Longer PIN'S added.
More Undocumented chimes found. Door chime is sound 10. Bad PIN sound added.
Entry Alarm fixed. Uncluttering the logs.
v4.1 10/19/2021 Rewrite Entry code.
v4.0 10/19/2021 Bugs in arming disarming and entry Fixed
Alarm tones setup. Chimes now working using play command.
v3.9 10/18/2021 Bug in the entry delay chimes.
v3.8 10/18/2021 Bug in Pin fixed. Arming sounds added. Alarm is working Enabled.
Chimes 1 2 3 4 added but not fully working.
Added alarm arming delay
v3.7 10/17/2021 bug in reboot logging throwing a error fixed
v3.6 10/17/2021 Master PIN any legenth all PINS legenth increased to 10
v3.5 10/16/2021 No longer polling HSM sate. This requires that Keyboard be enabled in HSM
Last pin stats bug, was only reporting disarm
Added codeChanged Lock manager may look for this.
Added entry HSM sends this command with a delay. Future use.
v3.4 10/14/2021 HSM was throwing errors if keyboard was enable in HSM. Fixed
v3.3 10/12/2021 Bug fix * and # reversed in the logs. More debugging in logs
v3.2 10/09/2021 Added cancel cmd to stop Smoke/Water alarms by OFF.
Added lights flash after action.
v3.1 10/08/2021 Lock Manager dupe checking.Bug on PIN code 5 fixed.It was broken from the begining.
v3.0 10/07/2021 Lock Code manager can now read PINs from Keypad. Max PIN legenth increased to 7
v2.9 10/07/2021 Reduced dec to 2 in bat voltage to many reports.
v2.8.3 10/06/2021 Only the pad that sets PANIC can remove it so it now times out
v2.8.2 " HSM status was reporting disarmed when sending arm
added delay to allow it to take action before testing state
v2.8.1 " OFF was not clearing PANIC if alarm was OFF Fixed
v2.8 " Last PIN code rewrite broke button actions Fixed
v2.7.1 10/05/2021 Last update slowed down driver screen fixed.
v2.7 " Bat Bug fixed. Arm with Pin added. Unlock with pin and OFF added.
Panic sets custom panic flag.
v2.6 10/02/2021 Added DisarmedBy command, Settings to remap Command Buttons
v2.5 " Config for tamper,Log debug cleanup,Remove alarm no sounds
v2.4 09/30/2021 Custom Panic command added. Added Config options for * # OFF
v2.3 09/30/2021 battery value changes
v2.2 09/29/2021 Version detection and auto upgrade/install.
v2.1 09/29/2021 Tamper bugs fixed, Log fix,Old IRIS command found and Logged, Master pin added
v2.0 09/28/2021 Keypad support debugged , Commands debounced, Logging cleaned up,
Invalid pins trapped Star key sends a 6 digit PIN *# * Now trapped.
v1.1 09/27/2021 Cleanup Button controler is working
v1.0 09/27/2021 Beta test version Buttons now reporting Bat working
=================================================================================================
Arming Buttons setup on driver page
Disarming
Enter PIN and press OFF
4-15 digit Pin size supported
Arming
Can be set to require PIN or not
ActionButtons can be remaped.
HSM is armed direct can be disabled in setup.
Alarm
Siren = plays tone set
strobe= strobes panic
both = plays tone set
Note: Key pad has its own HSM alarm mode.
sending alarm while in HSM alarming will change the tones.
Button Support
If a key is pressed once it acts like a button not a PIN
All keypad number buttons mapped to 10 push buttons.
Tamper
Invalid PIN will press tamper
Passcodes
Lock Manager can store monitor and delete passcode but not recall
MASTER 7 digit pin
Panic
Panic sets a panic on or off
This must be disarmed on the keyboard thats in Panic.
Lock Code Manager
Manager can add delete and verify.
Play chimes select 1 to 13
1 KEYCLICK
2 LOSTHUB
3 ARMING
4 ARMED
5 HOME
6 NIGHT
7 ALARM
8 PANIC
9 BADPIN
10 Clasic Iris Door Chime
11 GAME
12 CPU
13 Real Bad PIN
Chimes repeat to stop them I have added a countdown timmer.
Beware sometimes the keypad is slow and you may not get the same tone legenth every time..
Eratic Operation:
It is possible for the cpu to become corupted and cause problems such as
countdown timmer not stopping not taking commands and missing sounds.
I saw this in testing when sending lots of diffrent tones confusing the unit.
The solution is to reboot the pad by removing batteries.
Please Note:
If you have problems with the lock code manager erase all your pins manualy using the driver. Do not reinstall LCM
There is no error checking in LCM it will dupe and corrup PINS. Causing it to crash.
I have added Error corection to prevent corrupting my pin storage.
It is possible to use this driver without LCM just add pins using the driver.
Total worktime to build up to v2 2 days. Have fun.
FCC ID:FU5TSA04 https://fccid.io/FU5TSA04
Built by Everspring Industry Co Ltd Smart Keypad TSA04
I wrote this for my keyboards you are welcome to use it.
================================================================================================
Tested on Firmware 2013-06-28 and 2012-12-11 Only 3 known firmware versions exist
https://github.com/tmastersmart/hubitat-code
Post your comments here.
http://www.winnfreenet.com/wp/2021/09/iris-v1-keyboard-driver-for-hubitat/
* To Reset Device:
* Insert two batteries side-by-side at one end or the other and then press "ON" button device 5 times (8 times?) within the first 10 seconds.
*
* The keypad is responsible for;
* 1. Driving its LEDs according to its state
* 2. Accumulating a PIN
* 3. Sending an action key and/or PIN when appropriate
* 4. Making sound sequences on demand
*
* The keypad expects to be told its state, and may also send a triplet of attributes whenever an "action" key is used.
* The triplet is ATTRID_PIN (if there is one), ATTRID_ACTIONKEY_ID and ATTRID_ACTIONKEY_TIME.
*
* While an actionKey is held down, the keypad will send ATTRID_ACTIONKEY_ID and ATTRID_ACTIONKEY_TIME once per second.
* It’ll also send an ATTRID_PIN (if available) with the first ATTRID_ACTIONKEY_ID.
*
* If a PIN has been typed in, but no action key pressed within 2 seconds of the last digit, then a single ATTRID_PIN
* will be sent to the hub.
*
Used forked code bellow from a contact/motion switch. This included
ranging code and some detection code and zigbee sending commans.
All added code is orginal code written by me. Keypad routines were back engerned by me
and commands to control keypad were created by trial and error. Lock code storage code
was created to replace the copyrighted hubitat code. I created my own button code to use
with the button manager. HSM connection code created from scratch since no docs exist.
Lock code manager reverse engenered since no docs exist for it and it crashes easialy.
This code recreates how the keypad functioned on Iris,
I beleive it even works better because of the extra custom options I have added.
This code looks diffrent because I learned to program on a Timex Sinclair ZX81 and a Commorore C64
READY.
poke 53280,0
poke 53281,0
* Includes some opensource code from https://github.com/birdslikewires/hubitat
On how to control Iris devices. Much has been rewritten but some orginal
code is still contained in these routines. This would have not been possible
without this code.
* Used info from IRIS V2 source code in another language. Now called Arcus
This code would not work here and was very hard to follow through many subroutines.
Much of it was never decyphered. But gained sound control cmds.
https://github.com/arcus-smart-home/arcusplatform/
This code helped with controling tones setting OFF on buttons.
GNU General Public License v3.0
Permissions of this strong copyleft license are conditioned on making available
complete source code of licensed works and modifications, which include larger
works using a licensed work, under the same license. Copyright and license
notices must be preserved. Contributors provide an express grant of patent rights.
*/
def clientVersion() {
TheVersion="7.0.3"
if (state.version != TheVersion){
state.version = TheVersion
configure()
}
}
import hubitat.helper.HexUtils
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
metadata {
definition (name: "Iris v1 Keypad", namespace: "tmastersmart", author: "Tmaster", importUrl: "https://raw.githubusercontent.com/tmastersmart/hubitat-code/main/iris_v1_keypad.groovy") {
capability "Battery"
capability "Configuration"
capability "Initialize"
capability "PresenceSensor"
capability "Refresh"
capability "Sensor"
capability "SignalStrength"
capability "Security Keypad"
capability "PushableButton"
capability "TamperAlert"
capability "Tone"
capability "ShockSensor"
capability "Chime"
capability "Alarm"
capability "Switch"
command "checkPresence"
command "normalMode"
command "rangeAndRefresh"
command "entry"
command "SendState"
command "getStatus"
command "unschedule"
command "installed"
attribute "armingIn", "NUMBER"
attribute "batteryState", "string"
attribute "lastCodeName", "string"
attribute "lastCodePIN", "string"
attribute "batteryVoltage", "string"
attribute "panic", "string"
attribute "code1", "string"
attribute "code1n", "string"
attribute "code2", "string"
attribute "code2n", "string"
attribute "code3", "string"
attribute "code3n", "string"
attribute "code4", "string"
attribute "code4n", "string"
attribute "code5", "string"
attribute "code5n", "string"
attribute "code6", "string"
attribute "code6n", "string"
attribute "code7", "string"
attribute "code7n", "string"
attribute "code8", "string"
attribute "code8n", "string"
attribute "code9", "string"
attribute "code9n", "string"
attribute "code10", "string"
attribute "code10n", "string"
attribute "lockCodes", "string"
// HUB has hardwired any iris device with 00C0 as a care fob so we have to fake carefob fingerprint.
fingerprint profileId: "C216", endpointId:"02", inClusters:"00F0,00C0", outClusters: "00C0", manufacturer: "Iris/AlertMe", model: "KeyPad Device", deviceJoinName: "Iris V1 Keypad"
fingerprint profileId: "C216", endpointId:"02", inClusters:"00F0,00C0,00F3,00F5", outClusters: "00C0", manufacturer: "Iris/AlertMe", model: "KeyPad Device", deviceJoinName: "Iris V1 Keypad"
}
}
preferences {
input name: "infoLogging", type: "bool", title: "Enable info logging", description: "Recomended low level" ,defaultValue: true, required: true
input name: "debugLogging", type: "bool", title: "Enable debug logging", description: "MED level Debug" ,defaultValue: false, required: true
input name: "traceLogging", type: "bool", title: "Enable trace logging", description: "Insane HIGH level", defaultValue: false, required: true
input name: "tamperPIN", type: "bool", title: "Press Tamper on BAD PIN (off use shock)", defaultValue: true
input name: "requirePIN", type: "bool", title: "Require Valid PIN to ARM", defaultValue: false, required: true
input name: "detectBadBat", type: "bool", title: "Automatic dead battery detection", defaultValue: true, required: true
input name: "SilentArmHome", type: "bool", title: "Silent Arming Home", description: "No beep while arming", defaultValue: false
input name: "SilentArmAway", type: "bool", title: "Silent Arming Away", description: "No beep while arming", defaultValue: false
input name: "SilentArmNight",type: "bool", title: "Silent Arming Night",description: "No beep while arming", defaultValue: false
input name: "PartSet", type: "enum", title: "Partial Button", description: "Customize Partial Button", options: ["Arm Night", "Arm Home"], defaultValue: "Arm Night",required: true
input name: "PoundSet",type: "enum", title: "# Button", description: "Customize Pound Button", options: ["Disabled","Arm Night", "Arm Home", "Arm Away"], defaultValue: "Arm Home",required: true
input name: "StarSet" ,type: "enum", title: "* Button", description: "Customize Star Button", options: ["Disabled","Arm Night", "Arm Home", "Arm Away"], defaultValue: "Disabled",required: true
input name: "BatType", type: "enum", title: "Battery Type", options: ["Lithium", "Alkaline", "NiMH", "NiCad"], defaultValue: "Alkaline",required: true
input name: "AlarmTone",type:"enum", title: "Alarm Tone",description: "Customize Alarm Tone. Some firmware may only work with STROBE", options: ["STROBE","KEYCLICK","LOSTHUB","ARMING","ARMED","HOME","NIGHT","ALARM","PANIC","OPENDOOR","LOCKED","BADPIN","GAME","CPU"], defaultValue: "STROBE",required: true
input name: "BadPinTone",type:"enum",title: "Bad Pin Tone",description: "Customize Bad Pin Tone. some firmware may not play all tones", options: ["ERROR","BADPIN","GAME","CPU","LOCKED","LOSTHUB"], defaultValue: "ERROR",required: true
input("chimeTime", "number", title: "Chime Timeout", description: "Chime Timeout timer. Sends stop in ms 0=disable",defaultValue: 5000,required: true)
input("secure", "text", title: "Master password", description: "4 to 11 digit Overide PIN. Not stored in Lock Code Manager Database 0=disable",defaultValue: 0,required: false)
}
def installed() { // Runs after first pairing.
infoLogging=true
debugLogging=false
traceLogging=false
logging("Paired!", "info")
loggingUpdate()
initialize()
getStatus()
}
def initialize() {
/// Runs on reboot also
logging("initialize", "info")
// Set defaults they will be updated by HSM
// Survive a reboot
if (!state.armNightDelay){state.armNightDelay = 30}
if (!state.armHomeDelay){state.armHomeDelay = 30}
if (!state.delayEntry){state.delayEntry = 30}
if (!state.delayExit){state.delayExit = 30}
if (!state.Command){state.Command = "unknown"}
state.delay = 40
state.waiting = 0
state.message = "Enable [${device}] in HSM"
state.batteryOkay = true
state.Panic = false
state.presenceUpdated = 0
state.rangingPulses = 0
state.validPIN = false
state.PinName = "NA"
state.PIN = "NA"
state.message = "Keypad supports 14 diffrent chimes under play command. Not supported on all Firmware"
sendEvent(name: "operation", value: "normal", isStateChange: false)
sendEvent(name: "presence", value: "present", isStateChange: false)
sendEvent(name: "numberOfButtons", value: "12", isStateChange: false)
sendEvent(name: "maxCodes", value:10)
sendEvent(name: "codeLength", value:15)
sendEvent(name: "tamper", value: "clear")
sendEvent(name: "status", value: "ok")
offEvents()
state.remove("uptime")
state.remove("logo")
state.remove("irisKeyPad")
state.remove("iriscmd")
state.remove("alertST")
state.remove("reportToDev")
state.remove("iriscmd")
state.remove("alertST")
state.remove("armingMode")
state.remove("waitForGetInfo")
state.remove("AltTones")
removeDataValue("image")
device.deleteCurrentState("alarm")
device.deleteCurrentState("pushed")
device.deleteCurrentState("pin")
device.deleteCurrentState("lockCodes")
device.deleteCurrentState("HSMAlert")
// Stagger init refreshes On reboot
randomSixty = Math.abs(new Random().nextInt() % 60)
logging("refresh in ${randomSixty}sec", "info")
runIn(randomSixty,refresh)
randomSixty = Math.abs(new Random().nextInt() % 60)
logging("getStatus in ${randomSixty}sec", "info")
runIn(randomSixty,getStatus)
randomSixty = Math.abs(new Random().nextInt() % 60)
logging("getCodes in ${randomSixty}sec", "info")
runIn(randomSixty,getCodes)
//clientVersion()
}
def configure() {
initialize()
state.Config = false
state.remove("operatingMode")
state.remove("LQI")
state.remove("batteryOkay")
state.remove("batteryState")
state.remove("armMode")
// updateDataValue("inClusters", "00F0,00C0,00F3,00F5")
// updateDataValue("outClusters", "00C0")
unschedule()
// Schedule random ranging in hrs
randomSixty = Math.abs(new Random().nextInt() % 60)
randomTwentyFour = Math.abs(new Random().nextInt() % 24)
schedule("${randomSixty} ${randomSixty} ${randomTwentyFour}/${8} * * ? *", rangeAndRefresh)
logging("Configure - Ranging Every 8hrs starting at ${randomTwentyFour}:${randomSixty}:${randomSixty} ", "info")
// Check presence in hrs
randomSixty = Math.abs(new Random().nextInt() % 60)
randomTwentyFour = Math.abs(new Random().nextInt() % 24)
schedule("${randomSixty} ${randomSixty} ${randomTwentyFour}/${1} * * ? *", checkPresence)
logging("Configure - checkPresence Every hr starting at ${randomTwentyFour}:${randomSixty}:${randomSixty} ", "info")
runIn(randomSixty,rangeAndRefresh)
// runIn(12,normalMode)
}
def updated() {
// Runs whenever preferences are saved.
clientVersion()
loggingUpdate()
getIcons()
refresh()
}
// Sample Hubitat pin store code is not opensource
// My custom pin store code
def setCode(code,pinCode,userCode){
size = pinCode.size()
if (size < 4 || size >15){
logging( "Invalid PIN size :${size} Rejected","warn")
return
}
if (code == 1){ save= "code1";}
if (code == 2){ save= "code2";}
if (code == 3){ save= "code3";}
if (code == 4){ save= "code4";}
if (code == 5){ save= "code5";}
if (code == 6){ save= "code6";}
if (code == 7){ save= "code7";}
if (code == 8){ save= "code8";}
if (code == 9){ save= "code9";}
if (code == 10){save= "code10";}
if (code < 11){
saveit = true
// stop dupes from lock manager
if (device.currentValue("code1") == pinCode){saveit = false}
if (device.currentValue("code2") == pinCode){saveit = false}
if (device.currentValue("code3") == pinCode){saveit = false}
if (device.currentValue("code4") == pinCode){saveit = false}
if (device.currentValue("code5") == pinCode){saveit = false}
if (device.currentValue("code6") == pinCode){saveit = false}
if (device.currentValue("code7") == pinCode){saveit = false}
if (device.currentValue("code8") == pinCode){saveit = false}
if (device.currentValue("code9") == pinCode){saveit = false}
if (device.currentValue("code10") == pinCode){saveit = false}
logging( "ADD code#${code} PIN:${pinCode} User:${userCode} [OK to save:${saveit}]","debug")
logging( "ADD code#${code} PIN:XXXX User:${userCode}","info")
if (saveit){
logging( "Saving ...${save}...","debug")
logging( "Saving User:${userCode}","info")
sendEvent(name: "${save}", value: pinCode)
sendEvent(name: "${save}n",value: userCode)
}
}
pauseExecution(3000) // wait for database
getCodes()
sendEvent(name:"codeChanged",value:"added",data:"${codeStore}", isStateChange: true, descriptionText: "code:${pinCode} name:${userCode}" )
pauseExecution(3000) // wait for database
getCodes()
}
private upgradeCodes(code){
store1 = device.currentValue("code1")
store1n= device.currentValue("code1n")
store2 = device.currentValue("code2")
store2n= device.currentValue("code2n")
store3 = device.currentValue("code3")
store3n= device.currentValue("code3n")
store4 = device.currentValue("code4")
store4n= device.currentValue("code4n")
store5 = device.currentValue("code5")
store5n= device.currentValue("code5n")
store6 = device.currentValue("code6")
store6n= device.currentValue("code6n")
store7 = device.currentValue("code7")
store7n= device.currentValue("code7n")
store8 = device.currentValue("code8")
store8n= device.currentValue("code8n")
store9 = device.currentValue("code9")
store9n= device.currentValue("code9n")
store10 = device.currentValue("code10")
store10n= device.currentValue("code10n")
}
def deleteCode(code) {
if (code == 1){ save= "code1"}
if (code == 2){ save= "code2"}
if (code == 3){ save= "code3"}
if (code == 4){ save= "code4"}
if (code == 5){ save= "code5"}
if (code == 6){ save= "code6"}
if (code == 7){ save= "code7"}
if (code == 8){ save= "code8"}
if (code == 9){ save= "code9"}
if (code == 10){ save= "code10"}
thecode = device.currentValue("${save}")
thename = device.currentValue("${save}n")
logging ("deleteCode #${code} code:${thecode} name:${thename}","debug")
logging ("deleteCode #${code} code:XXXX name:${thename}","info")
if (code < 11) {
device.deleteCurrentState("${save}")
device.deleteCurrentState("${save}n")
pauseExecution(3000) // wait for database
getCodes()
sendEvent(name:"codeChanged",value:"deleted",data:"${codeStore}", isStateChange: true, descriptionText: "code:${thecode} name:${thename} ")
pauseExecution(3000) // wait for database
getCodes()
}
}
// Scan all the pins and return stat
void checkThePin(code)
{
state.validPIN = false
state.PinName = "none"
state.pinN = 0
if (device.currentValue("code1") == state.PIN){
state.PinName = device.currentValue("code1n")
state.validPIN = true
state.pinN = 1
}
if (device.currentValue("code2") == state.PIN){
state.PinName = device.currentValue("code2n")
state.validPIN = true
state.pinN = 2
}
if (device.currentValue("code3") == state.PIN){
state.PinName = device.currentValue("code3n")
state.validPIN = true
state.pinN = 3
}
if (device.currentValue("code4") == state.PIN){
state.PinName = device.currentValue("code4n")
state.validPIN = true
state.pinN = 4
}
if (device.currentValue("code5") == state.PIN){
state.name = device.currentValue("code5n")
state.validPIN = true
state.pinN = 5
}
if (device.currentValue("code6") == state.PIN){
state.PinName= device.currentValue("code6n")
state.validPIN = true
state.pinN = 6
}
if (device.currentValue("code7") == state.PIN){
state.PinName = device.currentValue("code7n")
state.validPIN = true
state.pinN = 7
}
if (device.currentValue("code8") == state.PIN){
state.PinName = device.currentValue("code8n")
state.validPIN = true
state.pinN = 8
}
if (device.currentValue("code9") == state.PIN){
state.PinName = device.currentValue("code9n")
state.validPIN = true
state.pinN = 9
}
if (device.currentValue("code10") == state.PIN){
state.PinName = device.currentValue("code10n")
state.validPIN = true
state.pinN = 10
}
if (secure == state.PIN){
state.PinName ="master"
state.validPIN = true
state.pinN = 100
}
}
// Create jason code for lock manager
def getCodes(){
qt= '"'
needsComma = false
if (device.currentValue("code1")) {
code = device.currentValue("code1")
name = device.currentValue("code1n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode1 = "${qt}1${end}"
needsComma = true
}
if (device.currentValue("code2")) {
code = device.currentValue("code2")
name = device.currentValue("code2n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode2 = "${qt}2${end}"
if (needsComma == true){ setCode2 = ",${setCode2}"}
needsComma = true
}
if (device.currentValue("code3")) {
code = device.currentValue("code3")
name = device.currentValue("code3n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode3 = "${qt}3${end}"
if (needsComma == true){ setCode3 = ",${setCode3}"}
needsComma = true
}
if (device.currentValue("code4")) {
code = device.currentValue("code4")
name = device.currentValue("code4n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode4 = "${qt}4${end}"
if (needsComma== true){ setCode4 = ",${setCode4}"}
needsComma = true
}
if (device.currentValue("code5")) {
code = device.currentValue("code5")
name = device.currentValue("code5n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode5 = "${qt}5${end}"
if (needsComma == true){ setCode5 = ",${setCode5}"}
needsComma = true
}
if (device.currentValue("code6")) {
code = device.currentValue("code6")
name = device.currentValue("code6n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode6 = "${qt}6${end}"
if (needsComma == true){ setCode6 = ",${setCode6}"}
needsComma = true
}
if (device.currentValue("code7")) {
code = device.currentValue("code7")
name = device.currentValue("code7n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode7 = "${qt}7${end}"
if (needsComma == true){ setCode7 = ",${setCode7}"}
needsComma = true
}
if (device.currentValue("code8")) {
code = device.currentValue("code8")
name = device.currentValue("code8n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode8 = "${qt}8${end}"
if (needsComma == true){ setCode8 = ",${setCode8}"}
needsComma = true
}
if (device.currentValue("code9")) {
code = device.currentValue("code9")
name = device.currentValue("code9n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode9 = "${qt}9${end}"
if (needsComma== true){ setCode9 = ",${setCode9}"}
needsComma = true
}
if (device.currentValue("code10")) {
code = device.currentValue("code10")
name = device.currentValue("code10n")
end = "${qt}:{${qt}name${qt}:${qt}${name}${qt},${qt}code${qt}:${qt}${code}${qt}}"
setCode10 = "${qt}10${end}"
if (needsComma == true){ setCode10 = ",${setCode10}"}
}
codeStore= "{"
if (setCode1) { codeStore = "${codeStore}${setCode1}" }
if (setCode2) { codeStore = "${codeStore}${setCode2}" }
if (setCode3) { codeStore = "${codeStore}${setCode3}" }
if (setCode4) { codeStore = "${codeStore}${setCode4}" }
if (setCode5) { codeStore = "${codeStore}${setCode5}" }
if (setCode6) { codeStore = "${codeStore}${setCode6}" }
if (setCode7) { codeStore = "${codeStore}${setCode7}" }
if (setCode8) { codeStore = "${codeStore}${setCode8}" }
if (setCode9) { codeStore = "${codeStore}${setCode9}" }
if (setCode10){ codeStore = "${codeStore}${setCode10}"}
codeStore = "${codeStore}}"
sendEvent(name: "lockCodes",value: codeStore)
// Dont show codes in normal log for security
logging("lockCode Database ${codeStore}", "trace")
logging("getCodes (Lockcode Database rebuilt)", "info")
}
// using state.delayExit
void setExitDelay(Map delays){
state.delayExit = (delays?.awayDelay ?: 0).toInteger()
state.armNightDelay = (delays?.nightDelay ?: 0).toInteger()
state.armHomeDelay = (delays?.homeDelay ?: 0).toInteger()
state.delay = state.delayExit
logging("setExitDelay ${delays}", "info")
}
def setEntryDelay(cmd){
state.delayEntry = (cmd ?: 0).toInteger()
logging("setEntryDelay ${cmd}", "info")
}
def setExitDelay(cmd){
logging("setExitDelay ${cmd} Not used", "debug")
}
def setCodeLength(cmd){
logging("setCodeLength ${cmd} ignored we us 15", "debug")
}
// Arming commands
//hsmSetArm = armAway ,armHome,armNight,disarm,disarmAll,armAll,CancelAlerts
//subscribe (location, "hsmStatus", statusHandler)
//subscribe (location, "hsmAlerts", alertHandler)
// For calling delayed arming.
// if disarmed during countdown dont arm.
def setAway(){
if (state.Command == "off"){
logging ("Disarmed while arming. Abort","warn")
SendState()
runIn(1,getSoftStatus)
return}
state.Command = "away"
SendState()
runIn(40,getSoftStatus)
}
def setHome(){
if (state.Command == "off"){
logging ("Disarmed while arming. Abort","warn")
SendState()
runIn(1,getSoftStatus)
return}
state.Command = "home"
SendState()
runIn(40,getSoftStatus)
}
def setNight(){
if (state.Command == "off"){
logging ("Disarmed while arming. Abort","warn")
SendState()
runIn(1,getSoftStatus)
return}
state.Command = "night"
SendState()
runIn(40,getSoftStatus)
}
void setPartialFunction(cmd){
logging ("HSM sent >> ${cmd}","warn")
}
// =====================Incomming command==HSM RECEIVED =======================================
def armAway(cmd){
delay = (cmd ?: 0).toInteger()
if (delay != state.delayExit){
state.delayExit = delay
logging ("Received >> new Delay:${state.delayExit} for delayExit", "info")
}
state.received = true
if (state.Command == "armingAway" | state.Command == "away" ){
logging ("Ignored HSM CMD [ArmAWAY] State:${state.Command}","info")
return
}
MakeLockCodeIN()
state.delay = state.delayExit // state.delay used by the timeout loop also
sendEvent(name: "securityKeypad",value: "armed away",data: lockCode, type: "digital",descriptionText: "armed away [digital] Delay:${state.delayExit}")
logging ("Received >> [ArmAWAY] Delay:${state.delayExit} Our State:${state.Command} [digital] SilentArm${SilentArmAway}", "info")
state.Command = "armingAway"
if (SilentArmAway == false){SendState()}
runIn(state.delay,setAway)
}
def armHome(cmd){
delay = (cmd ?: 0).toInteger()
if (delay != state.armHomeDelay){
state.armHomeDelay = delay
logging ("Received >> new Delay:${state.armHomeDelay} for armHomeDelay", "info")
}
state.received = true
if (state.Command == "armingHome" | state.Command == "home"){
logging ("Ignored HSM CMD [ArmHOME] State:${state.Command}","info")
return
}
MakeLockCodeIN()
state.delay = state.armHomeDelay
sendEvent(name: "securityKeypad",value: "armed home",data: lockCode, type: "digital",descriptionText: "armed home [digital] Delay:${state.armHomeDelay}")
logging ("Received >> [ArmHome] Delay:${state.armHomeDelay} Our State:${state.Command} [digital] SilentArm${SilentArmHome}", "info")
state.Command = "armingHome"
if (SilentArmHome == false){SendState()}
runIn(state.delay,setHome)
return
}
def armNight(cmd){
delay = (cmd ?: 0).toInteger()
if (delay != state.armNightDelay){
state.armNightDelay = delay
logging ("Received >> new Delay:${state.armNightDelay} for armNightDelay", "info")
}
state.received = true
if (state.Command == "armingNight" | state.Command == "night"){
logging ("Ignored HSM CMD [ArmNight] State:${state.Command}","info")
return
}
MakeLockCodeIN()
state.delay = state.armNightDelay // state.delay used by the timeout loop also
sendEvent(name: "securityKeypad",value: "armed night",data: lockCode, type: "digital",descriptionText: "armed night [digital] Delay:${state.armNightDelay}")
logging ("Received >> [ArmNight] Delay:${state.armNightDelay} Our State:${state.Command} [digital] SilentArm${SilentArmNight}", "info")
state.Command = "armingNight"
if (SilentArmNight == false){SendState()}
runIn(state.delay,setNight)
}
// HUB says DISARM
def disarm(cmd) {
cmd = 0
state.received = true
offEvents()
if (state.Command == "off" ){ // Ignore dupes cause a beep
logging ("HSM CMD [disarm] received but we are State:${state.Command}","info")
return
}
MakeLockCodeIN()
sendEvent(name: "securityKeypad",value: "disarmed",data: lockCode, type: "digital",descriptionText: "disarmed [digital]")
logging ("Received >> [disarm] Our State:${state.Command} [digital] ", "info")
state.Command = "off"
SendState()
runIn(15,getSoftStatus)
}
def offEvents(){
alarmTest = device.currentValue("alarm")
if(alarmTest != "off"){sendEvent(name: "alarm", value: "off")}
alarmTest = device.currentValue("siren")
if(alarmTest != "off"){sendEvent(name: "siren", value: "off")}
alarmTest = device.currentValue("strobe")
if(alarmTest != "off"){sendEvent(name: "strobe", value: "off")}
alarmTest = device.currentValue("panic")
if(alarmTest != "off"){sendEvent(name: "panic", value: "off")}
alarmTest = device.currentValue("switch")
if(alarmTest != "off"){sendEvent(name: "switch", value: "off")}
sendEvent(name: "status", value: "off")
}
def softOFF(){
logging ("Alarm OFF ","info")
offEvents()
getStatus() // Are we armed or not Reset state
}
def setNA(){// Alarm Part button
if (state.Command == "off"){
logging ("Disarmed during Entry. Abort","warn")
SendState()
runIn(1,getSoftStatus)
return
}
state.Command ="alarmingNight"
SendState()
logging ("Alarm on ","info")
sendEvent(name: "strobe",value: "on", displayed: true)
sendEvent(name: "alarm", value: "on", displayed: true)
sendEvent(name: "switch",value: "on", displayed: true)
runIn(60,softOFF) // Times out the alarm to save bat. 1 min
}
def setAA(){// Alarm ON button
if (state.Command == "off"){
logging ("Disarmed during Entry. Abort","warn")
SendState()
runIn(1,getSoftStatus)
return}
state.Command ="alarmingAway"
SendState()
logging ("Alarm on ","info")
sendEvent(name: "strobe",value: "on", displayed: true)
sendEvent(name: "alarm", value: "on", displayed: true)
sendEvent(name: "switch",value: "on", displayed: true)
runIn(60,softOFF) // Times out the alarm to save bat. 1 min
}
//=========================================ENTRY====================================================
def entry(cmd){
delay = (cmd ?: 0).toInteger()
if (delay != state.delayEntry){
state.delayEntry = delay
logging ("Received >> new Delay:${state.delayEntry} for delayEntry", "info")
}
sendEvent(name: "securityKeypad",value: "Entry",data: lockCode, type: "digital",descriptionText: "Entry delay:${state.delayEntry} state:${state.Command}")
if (state.Command == "night"){
state.Command = "armingNight"
if (state.delayEntry >5){SendState()}//dont do a short countdown
runIn(state.delayEntry+1,setNA) // Night ALARM
}
if (state.Command == "home"){
state.Command = "armingHome"
if (state.delayEntry >5){SendState()}//dont do a short countdown
runIn(state.delayEntry+1,setAA)// ALARM
}
if (state.Command == "away" | state.Command == "off"){//assume away even if we are off
state.Command = "armingAway"
if (state.delayEntry >5){SendState()}
runIn(state.delayEntry+1,setAA)// ALARM
}
logging ("ENTRY in progress delay:${state.delayEntry} state:${state.Command} ","warn")
}
/* Old direct HSM cmds no longer needed
sendEvent(name:"armingIn", value: value,data:[armMode:getArmText(armRequest),armCmd:getArmCmd(armRequest)], isStateChange:true)
case "00": return "disarm"
case "01": return "armHome"
case "02": return "armNight"
case "03": return "armAway"
input name: "DirectHSMcmd", type: "bool", title: "Send direct HSM cmd", defaultValue: true, required: true
, type: "physical", type: "digital"
*/
// My arming commands
private MakeLockCode(cmd){
// more compatibility code
def isInitiator = true
def lockCode = JsonOutput.toJson(["${state.pinN}":["name":"${state.PinName}", "code":"${state.PIN}", "isInitiator":"${isInitiator}"]] )
logging ("lockCode:${lockCode}]","trace")
}
private defaultLockCode(){
// more compatibility code NO PIN
state.PIN = "0000"
state.PinName = "not required"
state.pinN = -1