-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathindex.js
More file actions
1762 lines (1581 loc) · 73.5 KB
/
index.js
File metadata and controls
1762 lines (1581 loc) · 73.5 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
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
// Requires
var net = require('net');
var mqtt = require('mqtt');
// Global variables
var loggedin = false; // indcates if logged in successful
var busyloggingin = false;
var client;
var mqttclient;
var mqttenabled = false;
//var alarmstatus = 'Disarmed'; // Current Alarm state
//var alarmstatus_p2 = 'Disarmed'; // Current Alarm state
var receivebuffer = Buffer.alloc(1024, 0x00); // Data received from alarm is stored here
var zonestatus = Buffer.alloc(32, 0x00); // Current 32 zone status is stored here
var gettingstatus = false; // Indicates if status get is in progress
var controlAlarmstate = false; // Indicates if conreolling of alarm is in progress
var controlPGMstate = false; // Indicates if controlling of PGMs are in progress
var loginresult = 0; // Flag used to ignre login messages causing zone status messages
var muteStatus = false; // Mute flag to allow sending commands to Paradox. This flag mutes the Zone and Alarm status polling.
var PanelProduct = 'SP5500';
// Global Zones status array
// Each Zone stores :
// status : either on or off
// accessory : store the accessory so that it can be accessed when a change occurs
// Type : either GarageDoorOpener, MotionSensor, ContactSensor or SmokeSensor
var zones = new Array();
// Global alarmstate
// status: is either Armed Away, Armed Perimeter, Armed Sleep, or Disarmed
// accessory : store the accessory so that it can be accessed when a change occurs
//var alarmstate = {
// status: "Disarmed",
// accessory: null
//};
var alarm = new Array();
var alarmstatus = new Array();
var PanelFirmware = new Array();
var alarm_ip_address = "192.168.1.0"; // Alarm IP address on local LAN
var alarm_port = 10000; // Alarm Port used
var alarm_password = "password"; // Store alarm password in here
var message_count = 0; // Count number of received status messages
var status_valid = false; // Flag indicating valid status received
var connected = true; // Flag to disable alarm connection for 3rd party access
// Global constants
const LOGIN_MSG1 = [0xAA, 0x08, 0x00, 0x03, 0x08, 0xF0, 0x00, 0x0A, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE];
const LOGIN_MSG2 = [0xAA, 0x08, 0x00, 0x03, 0x08, 0xF0, 0x00, 0x0A, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE];
const LOGIN_MSG3 = '\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const LOGIN_MSG4 = '\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const LOGIN_MSG5 = '\x5f\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const LOGIN_MSG6 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00];
const LOGIN_MSG7 = '\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const LOGIN_MSG8 = '\x50\x00\x0e\x52\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const STATUS_MSG1 = [0xAA, 0x25, 0x00, 0x04, 0x08, 0x00, 0x00, 0x14, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x50, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE];
const STATUS_MSG2 = [0xAA, 0x25, 0x00, 0x04, 0x08, 0x00, 0x00, 0x14, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x50, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE];
const CONTROLALARM_MSG1 = [0xAA, 0x25, 0x00, 0x04, 0x08, 0x00, 0x00, 0x14, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE];
const CONTROLALARM_ARM_P0_MSG = '\x40\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLALARM_DISARM_P0_MSG = '\x40\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLALARM_SLEEP_P0_MSG = '\x40\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLALARM_STAY_P0_MSG = '\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLALARM_ARM_P1_MSG = '\x40\x00\x04\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLALARM_DISARM_P1_MSG = '\x40\x00\x05\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLALARM_SLEEP_P1_MSG = '\x40\x00\x03\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLALARM_STAY_P1_MSG = '\x40\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CONTROLPGM_MSG1 = [0xAA, 0x25, 0x00, 0x04, 0x08, 0x00, 0x00, 0x14, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE];
const CONTROLPGM_MSG2 = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
const CLOSECONNECTION_MSG = '\x70\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00';
var eventMap = {
0: "Zone OK",
1: "Zone open",
2: "Partition status",
3: "Bell status (Partition 1)",
5: "Non-Reportable Event",
6: "Non-reportable event",
7: "PGM Activation",
8: "Button B pressed on remote",
9: "Button C pressed on remote",
10: "Button D pressed on remote",
11: "Button E pressed on remote",
12: "Cold start wireless zone",
13: "Cold start wireless module (Partition 1)",
14: "Bypass programming",
15: "User code activated output (Partition 1)",
16: "Wireless smoke maintenance signal",
17: "Delay zone alarm transmission",
18: "Zone signal strength weak 1 (Partition 1)",
19: "Zone signal strength weak 2 (Partition 1)",
20: "Zone signal strength weak 3 (Partition 1)",
21: "Zone signal strength weak 4 (Partition 1)",
22: "Button 5 pressed on remote",
23: "Button 6 pressed on remote",
24: "Fire delay started",
25: "N/A",
26: "Software access",
27: "Bus module event",
28: "StayD pass acknowledged",
29: "Arming with user",
30: "Special arming",
31: "Disarming with user",
32: "Disarming after alarm with user",
33: "Alarm cancelled with user",
34: "Special disarming",
35: "Zone bypassed",
36: "Zone in alarm",
37: "Fire alarm",
38: "Zone alarm restore",
39: "Fire alarm restore",
40: "Special alarm",
41: "Zone shutdown",
42: "Zone tampered",
43: "Zone tamper restore",
44: "New trouble (Partition 1:both for sub event 7",
45: "Trouble restored ",
46: "Bus / EBus / Wireless module new trouble (Partition 1)",
47: "Bus / EBus / Wireless module trouble restored (Partition 1)",
48: "Special (Partition 1)",
49: "Low battery on zone",
50: "Low battery on zone restore",
51: "Zone supervision trouble",
52: "Zone supervision restore",
53: "Wireless module supervision trouble (Partition 1)",
54: "Wireless module supervision restore (Partition 1)",
55: "Wireless module tamper trouble (Partition 1)",
56: "Wireless module tamper restore (Partition 1)",
57: "Non-medical alarm (paramedic)",
58: "Zone forced",
59: "Zone included",
64: "System Status"
};
var partitionStatus = {
0:"N/A" ,
1:"N/A" ,
2:"Silent alarm" ,
3:"Buzzer alarm" ,
4:"Steady alarm" ,
5:"Pulse alarm" ,
6:"Strobe" ,
7:"Alarm stopped" ,
8:"Squawk ON (Partition 1)" ,
9:"Squawk OFF (Partition 1)" ,
10:"Ground Start (Partition 1)" ,
11:"Disarm partition" ,
12:"Arm partition" ,
13:"Entry delay started" ,
14:"Exit delay started" ,
15:"Pre-alarm delay" ,
16:"Report confirmation" ,
99:"Any partition status event"
};
var bellStatus = {
0:" Bell OFF" ,
1:" Bell ON" ,
2:" Bell squawk arm" ,
3:" Bell squawk disarm" ,
99:"Any bell status event"
};
var nonReportableEvents = {
0:"Telephone line trouble" ,
1:"[ENTER]/[CLEAR]/[POWER] key was pressed (Partition 1 only)" ,
2:"N/A" ,
3:"Arm in stay mode" ,
4:"Arm in sleep mode" ,
5:"Arm in force mode" ,
6:"Full arm when armed in stay mode" ,
7:"PC fail to communicate (Partition 1)" ,
8:"Utility Key 1 pressed (keys [1] and [2]) (Partition 1)" ,
9:"Utility Key 2 pressed (keys [4] and [5]) (Partition 1)" ,
10:"Utility Key 3 pressed (keys [7] and [8]) (Partition 1)" ,
11:"Utility Key 4 pressed (keys [2] and [3]) (Partition 1)" ,
12:"Utility Key 5 pressed (keys [5] and [6]) (Partition 1)" ,
13:"Utility Key 6 pressed (keys [8] and [9]) (Partition 1)" ,
14:"Tamper generated alarm" ,
15:"Supervision loss generated alarm" ,
16:"N/A" ,
17:"N/A" ,
18:"N/A" ,
19:"N/A" ,
20:"Full arm when armed in sleep mode" ,
21:"Firmware upgrade -Partition 1 only (non-PGM event)" ,
22:"N/A" ,
23:"StayD mode activated" ,
24:"StayD mode deactivated" ,
25:"IP Registration status change" ,
26:"GPRS Registration status change" ,
99:"Any non-reportable event"
};
newTrouble = {
0:"N/A" ,
1:"AC failure" ,
2:"Battery failure" ,
3:"Auxiliary current overload" ,
4:"Bell current overload" ,
5:"Bell disconnected" ,
6:"Clock loss" ,
7:"Fire loop trouble" ,
8:"Fail to communicate to monitoring station telephone #1" ,
9:"Fail to communicate to monitoring station telephone #2" ,
11:"Fail to communicate to voice report" ,
12:"RF jamming" ,
13:"GSM RF jamming" ,
14:"GSM no service" ,
15:"GSM supervision lost" ,
16:"Fail To Communicate IP Receiver 1 (GPRS)" ,
17:"Fail To Communicate IP Receiver 2 (GPRS)" ,
18:"IP Module No Service" ,
19:"IP Module Supervision Loss" ,
20:"Fail To Communicate IP Receiver 1 (IP)" ,
21:"Fail To Communicate IP Receiver 2 (IP)" ,
99:"Any new trouble event"
};
var troubleRestored = {
0:"Telephone line restore" ,
1:"AC failure restore" ,
2:"Battery failure restore" ,
3:"Auxiliary current overload restore" ,
4:"Bell current overload restore" ,
5:"Bell disconnected restore" ,
6:"Clock loss restore" ,
7:"Fire loop trouble restore" ,
8:"Fail to communicate to monitoring station telephone #1 restore" ,
9:"Fail to communicate to monitoring station telephone #2 restore" ,
11:"Fail to communicate to voice report restore" ,
12:"RF jamming restore" ,
13:"GSM RF jamming restore" ,
14:"GSM no service restore" ,
15:"GSM supervision lost restore" ,
16:"Fail To Communicate IP Receiver 1 (GPRS) restore" ,
17:"Fail To Communicate IP Receiver 2 (GPRS) restore" ,
18:"IP Module No Service restore" ,
19:"IP Module Supervision Loss restore" ,
20:"Fail To Communicate IP Receiver 1 (IP) restore" ,
21:"Fail To Communicate IP Receiver 2 (IP) restore" ,
99:"Any trouble event restore"
};
var specialArming = {
0:"Auto-arming (on time/no movement)" ,
1:"Late to close" ,
2:"No movement arming" ,
3:"Partial arming" ,
4:"Quick arming" ,
5:"Arming through WinLoad" ,
6:"Arming with keyswitch" ,
99:"Any special arming"
};
var specialDisarming = {
0:"Auto-arm cancelled (on time/no movement)" ,
1:"Disarming through WinLoad" ,
2:"Disarming through WinLoad after alarm" ,
3:"Alarm cancelled through WinLoad" ,
4:"Paramedical alarm cancelled" ,
5:"Disarm with keyswitch" ,
6:"Disarm with keyswitch after an alarm" ,
7:"Alarm cancelled with keyswitch" ,
99:"Any special disarming"
};
var specialAlarm = {
0:"Panic non-medical emergency" ,
1:"Panic medical" ,
2:"Panic fire" ,
3:"Recent closing" ,
4:"Global shutdown" ,
5:"Duress alarm" ,
6:"Keypad lockout (Partition 1)" ,
99:"Any special alarm event"
};
var softwareAccess = {
0:"Non-valid source ID" ,
1:"WinLoad direct" ,
2:"WinLoad through IP module" ,
3:"WinLoad through GSM module" ,
4:"WinLoad through modem" ,
9:"IP150 direct" ,
10:"VDMP3 direct" ,
11:"Voice through GSM module" ,
12:"Remote access" ,
13:"SMS through GSM module" ,
99:"Any software access"
};
var busModuleEvent = {
0:"A bus module was added" ,
1:"A bus module was removed" ,
2:"2-way RF Module Communication Failure" ,
3:"2-way RF Module Communication Restored"
};
var moduleTrouble = {
0:"Bus / EBus / Wireless module communication fault" ,
1:"Tamper trouble" ,
2:"Power fail" ,
3:"Battery failure" ,
99:"Any bus module new trouble event"
};
var moduleTroubleRestore = {
0:"Bus / EBus / Wireless module communication fault restore" ,
1:"Tamper trouble restore" ,
2:"Power fail restore" ,
3:"Battery failure restore" ,
99:"Any bus module trouble restored event"
};
var special = {
0:"System power up" ,
1:"Reporting test" ,
2:"Software log on" ,
3:"Software log off" ,
4:"Installer in programming mode" ,
5:"Installer exited programming mode" ,
6:"Maintenance in programming mode" ,
7:"Maintenance exited programming mode" ,
8:"Closing delinquency delay elapsed" ,
99:"Any special event"
};
var systemStatus = {
0:"Follow Arm LED status" ,
1:"PGM pulse fast in alarm" ,
2:"PGM pulse fast in exit delay below 10 sec." ,
3:"PGM pulse slow in exit delay over 10 sec." ,
4:"PGM steady ON if armed" ,
5:"PGM OFF if disarmed"
};
//const DOOROPENTIME = 16000;
var LOGINDELAY = 3800;
var POLL_DELAY = 5000;
var WAIT_AFTER_LOGIN = 600;
var DELAY_BETWEEN_CMDS = 250;
var LOGOUT_DELAY = 500;
var LOGIN_DELAY_AFTER_RECONNECT = 1000;
var DEBOUNCE_DELAY = 600;
const FIRMWARE = '\x00\x00\x00';
"use strict";
var Characteristic, Service, DoorState;
// Initialise firmware version
for (i=0; i < 3; i++) {
PanelFirmware[i] = 0;
}
// Initialise zones
for (i = 0; i < 32; i++) {
zones.push({status: "off", accessory: null, type: null, doorOpensInSeconds: null, debounce: false, debounceDelay: 0
});
}
// Initialise alarms
for (i = 0; i < 2; i++) {
alarm.push({status: "Disarmed", accessory: null, partition: i});
}
// Initialise alarms
for (i = 0; i < 2; i++) {
alarmstatus.push({status: "Disarmed"});
}
//function _byte_xor(chks, byte) {
//
// var tmp1;
// var tmp2;
//
// for (i = 0; i < 8 ; i++)
// {
// tmp1 = byte && (0x01 << i); // Mask bit i
// tmp1 = tmp1 >> i; // Get it to bit 0
// tmp2 = chks && 0x01; // Get checksum bit 0
// tmp2 = tmp1 ^ tmp2; // XOR bits 0
// chks = (chks && 0xFE) && tmp2; // Put the XOR result in checksum bit 0
// tmp1 = (chks && 0x08) ^ (tmp2 << 3); // XOR bits 3
// chks = (chks && 0xF7) && tmp1; // Put the XOR result in checksum bit 3
// tmp1 = (chks && 0x10) ^ (tmp2 << 4); // XOR Bit 4
// chks = (chks && 0xEF) && tmp1; // Put the XOR result in checksum bit 4
// tmp2 = chks && 0x01; // Get checksum bit 0
// tmp2 = tmp2 << 7; // Move it to bit 7
// chks = chks >> 1; // Shift checksum right 1 bit
// chks = chks && tmp2; // Rotate calculated bit 0 into bit 7
// }
// return chks;
//}
function _checksum() {
var checksum = 0;
for (i = 0; i < 36; i++)
checksum += receivebuffer[i+16];
checksum = checksum % 256;
if (checksum === receivebuffer[52])
return true;
else return false;
}
function _debounce(_zone) {
zones[_zone].accessory.log("zone :");
zones[_zone].accessory.log(_zone);
zones[_zone].debounce = false;
zones[_zone].accessory.log('Stopping debounce');
}
//
// Function to retrieve alram status and zone status from buffer data received from alarm.
// This is used in periodic status pole as well as in alarm control and pgm control functions
function _parsestatus(acc, cl) {
if (_checksum()) {
acc.log('Checksum OK');
// for (i = 0; i < 36; i++)
// acc.log(receivebuffer[i]);
if (receivebuffer[16] === 0x02) {
switch (receivebuffer[20]) {
case 0x15:
PanelProduct = 'SP5500';
break;
case 0x16:
PanelProduct = 'SP6000';
break;
case 0x17:
PanelProduct = 'SP7000';
break;
case 0x40:
PanelProduct = 'MG5000';
break;
case 0x42:
PanelProduct = 'MG5050';
break;
}
for (i=0;i < 3; i++) {
PanelFirmware[i] = receivebuffer[21+i];
}
var Firmware = PanelFirmware[0] + PanelFirmware[1] + PanelFirmware[2];
var str = toString(Firmware);
acc.informationService
.setCharacteristic(Characteristic.SerialNumber, PanelProduct)
.setCharacteristic(Characteristic.FirmwareRevision, str);
}
if (receivebuffer[16] === 0xE2) {
var state;
// acc.log(receivebuffer[23]);
acc.log(eventMap[receivebuffer[23]]);
if (receivebuffer[24] > 0 && receivebuffer[24] < 33) {
switch (receivebuffer[23]) {
case 0:
// "Zone OK",
if (zones[receivebuffer[24]-1].accessory !== null && !zones[receivebuffer[24]-1].debounce)
{
zones[receivebuffer[24]-1].status = 'off';
}
case 1:
// "Zone open",
if (zones[receivebuffer[24]-1].accessory !== null && !zones[receivebuffer[24]-1].debounce) {
if (receivebuffer[23] === 1)
{
zones[receivebuffer[24]-1].status = 'on';
}
setTimeout(_debounce, zones[receivebuffer[24]-1].debounceDelay, receivebuffer[24]-1);
}
var state;
if (zones[receivebuffer[24]-1].accessory !== null && !zones[receivebuffer[24]-1].debounce) {
zones[receivebuffer[24]-1].debounce = true;
zones[receivebuffer[24]-1].accessory.log('Starting debounce delay:');
zones[receivebuffer[24]-1].accessory.log(zones[receivebuffer[24]-1].debounceDelay);
switch (zones[receivebuffer[24]-1].type) {
case 'Garage Door':
var isClosed;
if (zones[receivebuffer[24]-1].status === 'off') {
isClosed = true;
state = DoorState.CLOSED;
} else {
isClosed = false;
state = DoorState.OPEN;
}
if (isClosed !== zones[receivebuffer[24]-1].accessory.wasClosed) {
if (!zones[receivebuffer[24]-1].accessory.operating) {
zones[receivebuffer[24]-1].accessory.log('Door state changed');
zones[receivebuffer[24]-1].accessory.wasClosed = isClosed;
zones[receivebuffer[24]-1].accessory.garagedooropenerService.getCharacteristic(DoorState).updateValue(state);
zones[receivebuffer[24]-1].accessory.garagedooropenerService.getCharacteristic(Characteristic.TargetDoorState).setValue(state);
zones[receivebuffer[24]-1].accessory.targetState = state;
}
}
break;
case 'Alarm':
break;
case 'Contact Sensor':
if (zones[receivebuffer[24]-1].status === 'off') {
state = Characteristic.ContactSensorState.CONTACT_DETECTED;
} else {
state = Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
}
zones[receivebuffer[24]-1].accessory.contactsensorService.getCharacteristic(Characteristic.ContactSensorState).setValue(state);
break;
case 'Motion Sensor':
if (zones[receivebuffer[24]-1].status === 'off') {
state = false;
} else {
state = true;
}
zones[receivebuffer[24]-1].accessory.motionsensorService.getCharacteristic(Characteristic.MotionDetected).setValue(state);
break;
case 'Smoke Sensor':
if (zones[receivebuffer[24]-1].status === 'off') {
state = Characteristic.SmokeDetected.SMOKE_NOT_DETECTED;
} else {
state = Characteristic.SmokeDetected.SMOKE_DETECTED;
}
zones[receivebuffer[24]-1].accessory.smokesensorService.getCharacteristic(Characteristic.SmokeDetected).setValue(state);
break;
}
}
if (zones[receivebuffer[24]-1].accessory !== null) {
zones[receivebuffer[24]-1].accessory.log('Zone ' + (receivebuffer[24]-1).toString() + ' ' + zones[receivebuffer[24]-1].status + ' (' + zones[receivebuffer[24]-1].accessory.name + ')');
if (mqttenabled) {
mqttclient.publish(zones[receivebuffer[24]-1].topic, zones[receivebuffer[24]-1].status, this.publish_options);
}
acc.log('Zone:' + zones[receivebuffer[24]-1].accessory.name);
}
break;
case 2:
// "Partition status"
//0:"N/A" ,
//1:"N/A" ,
//2:"Silent alarm" ,
//3:"Buzzer alarm" ,
//4:"Steady alarm" ,
//5:"Pulse alarm" ,
//6:"Strobe" ,
//7:"Alarm stopped" ,
//8:"Squawk ON (Partition 1)" ,
//9:"Squawk OFF (Partition 1)" ,
//10:"Ground Start (Partition 1)" ,
//11:"Disarm partition" ,
//12:"Arm partition" ,
//13:"Entry delay started" ,
//14:"Exit delay started" ,
//15:"Pre-alarm delay" ,
//16:"Report confirmation" ,
//99:"Any partition status event"
acc.log(partitionStatus[receivebuffer[24]]);
break;
case 3:
// "Bell status (Partition 1)"
acc.log(bellStatus[receivebuffer[24]]);
break;
case 5:
case 6:
acc.log(nonReportableEvents[receivebuffer[24]]);
break;
case 26:
acc.log(softwareAccess[receivebuffer[24]]);
break;
case 27:
acc.log(busModuleEvent[receivebuffer[24]]);
break;
case 30:
acc.log(specialArming[receivebuffer[24]]);
break;
case 34:
acc.log(specialDisarming[receivebuffer[24]]);
break;
case 36:
// "Zone in alarm"
if (zones[receivebuffer[24]-1].accessory !== null && alarm[receivebuffer[25]].accessory !== null) {
zones[receivebuffer[24]-1].accessory.log('Zone:' + zones[receivebuffer[24]-1].accessory.name + ' in alarm.');
alarm[receivebuffer[25]].accessory.securitysystemService.getCharacteristic(Characteristic.SecuritySystemCurrentState).setValue(Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED);
alarm[receivebuffer[25]].accessory.log('Alarmstatus :' + alarm[receivebuffer[25]].status);
if (mqttenabled) {
mqttclient.publish(alarm[receivebuffer[25]].topic, alarm[receivebuffer[25]].status, acc.publish_options);
}
}
break;
case 38:
// "Zone alarm restore"
if (zones[receivebuffer[24]-1].accessory !== null && alarm[receivebuffer[25]].accessory !== null) {
zones[receivebuffer[24]-1].accessory.log('Zone:' + zones[receivebuffer[24]-1].accessory.name + ' alarm restored.');
// alarm[receivebuffer[25]].accessory.securitysystemService.setCharacteristic(Characteristic.SecuritySystemCurrentState, Characteristic.SecuritySystemCurrentState.DISARMED);
alarm[receivebuffer[25]].accessory.log('Alarmstatus :' + alarm[receivebuffer[25]].status);
if (mqttenabled) {
mqttclient.publish(alarm[receivebuffer[25]].topic, alarm[receivebuffer[25]].status, acc.publish_options);
}
}
break;
case 40:
acc.log(specialAlarm[receivebuffer[24]]);
break;
case 42:
// "Trouble restored "
acc.log([receivebuffer[24]]);
break;
case 44:
// "New trouble (Partition 1:both for sub event 7"
// SecuritySystem
// // Optional Characteristics
// this.addOptionalCharacteristic(Characteristic.StatusFault);
acc.log(newTrouble[receivebuffer[24]]);
break;
case 45:
// "Trouble restored "
acc.log(troubleRestored[receivebuffer[24]]);
break;
case 46:
acc.log(moduleTrouble[receivebuffer[24]]);
break;
case 47:
acc.log(moduleTroubleRestore[receivebuffer[24]]);
break;
case 48:
acc.log(special[receivebuffer[24]]);
break;
// 42: "Zone tampered",
// 43: "Zone tamper restore",
// 49: "Low battery on zone",
// ContacSensor
// // Optional Characteristics
// this.addOptionalCharacteristic(Characteristic.StatusTampered);
// this.addOptionalCharacteristic(Characteristic.StatusLowBattery);
//
// MotionSensor
// // Optional Characteristics
// this.addOptionalCharacteristic(Characteristic.StatusTampered);
// this.addOptionalCharacteristic(Characteristic.StatusLowBattery);
case 64:
acc.log(systemStatus[receivebuffer[24]]);
break;
}
}
}
if (receivebuffer[16] === 0x52) {
if (receivebuffer[19] === 0x01) {
// Alarm status
// acc.log('Alarm State received');
status_valid = true;
if (receivebuffer[33] > 0x10) {
alarmstatus[0] = "In Alarm";
} else {
switch (receivebuffer[33]) {
case 0x00:
alarmstatus[0] = "Disarmed";
break;
case 0x01:
alarmstatus[0] = "Armed Away";
break;
case 0x02:
alarmstatus[0] = "Armed Sleep";
break;
case 0x03:
alarmstatus[0] = "Armed Sleep";
break;
case 0x06:
alarmstatus[0] = "Armed Sleep";
break;
case 0x04:
alarmstatus[0] = "Armed Perimeter";
break;
case 0x05:
alarmstatus[0] = "Armed Perimeter";
break;
case 0x08:
alarmstatus[0] = "Instant Armed";
break;
case 0x09:
alarmstatus[0] = "Instant Armed";
break;
default:
alarmstatus[0] = "Unknown";
}
}
if (receivebuffer[37] > 0x10) {
alarmstatus[1] = "In Alarm";
} else {
switch (receivebuffer[37]) {
case 0x00:
alarmstatus[1] = "Disarmed";
break;
case 0x01:
alarmstatus[1] = "Armed Away";
break;
case 0x02:
alarmstatus[1] = "Armed Sleep";
break;
case 0x03:
alarmstatus[1] = "Armed Sleep";
break;
case 0x06:
alarmstatus[1] = "Armed Sleep";
break;
case 0x04:
alarmstatus[1] = "Armed Perimeter";
break;
case 0x05:
alarmstatus[1] = "Armed Perimeter";
break;
case 0x08:
alarmstatus[1] = "Instant Armed";
break;
case 0x09:
alarmstatus[1] = "Instant Armed";
break;
default:
alarmstatus[1] = "Unknown";
}
}
}
if (receivebuffer[19] === 0x00) {
// Zone status
if (loginresult === 0) { // only get zone status if this message is not as a result of a login message sent to alarm
// acc.log('Zone State received');
for (i = 0; i < 4; i++) {
for (j = 0; j < 8; j++) {
if (zones[j + i * 8].accessory !== null) {
if (zones[j + i * 8].accessory.operating !== true) {
if (receivebuffer[i + 35] & 0x01 << j) {
zones[j + i * 8].status = "on";
} else {
zones[j + i * 8].status = "off";
}
}
}
}
}
}
}
}
} else {
acc.log('Checksum not OK');
}
}
//
// This function formats the message sent to the alarm by ensuring it is 36 bytes in length and then adding a checksum byte to the end that results in a 37 byte message
function format37ByteMessage(message) {
var checksum = 0;
if (message.length % 37 !== 0) {
for (i = 0; i < message.length; i++)
checksum += message.charCodeAt(i);
while (checksum > 255)
checksum = checksum - (checksum / 256) * 256;
buf2 = Buffer.from([checksum]);
buf1 = Buffer.from(message);
buf3 = Buffer.concat([buf1, buf2], buf1.length + buf2.length);
buf4 = Buffer.alloc((Math.round(buf3.length / 16) + 1) * 16, 0xEE);
buf3.copy(buf4);
message = buf4.toString('hex');
}
return message;
}
//
// This is the login function to the alarm. It takes the alarm password, the socket handle, and the accessory in order to be able to log message for the ccessory
function _login(password, cl, acc) {
var byte1 = Buffer.from(LOGIN_MSG1);
var byte2 = Buffer.alloc(16,0xEE); // Please not : currently only cater for passwords shorter than 16 characters
var byte3 = Buffer.from(password);
byte3.copy(byte2,0);
byte1[1]=byte3.length; // Cater for password length in header
var totalLength = byte1.length + byte2.length;
var buf = Buffer.concat([byte1, byte2], totalLength);
loginresult = 1;
acc.log('Logging in');
cl.write(buf);
setTimeout(function () {
if (receivebuffer[4] === 0x38) {
acc.log('Log in successfull');
buf = Buffer.from(LOGIN_MSG2);
buf[1] = 0x00;
buf[5] = 0xF2;
cl.write(buf);
setTimeout(function () {
acc.log('Step 1');
buf[5] = 0xF3;
cl.write(buf);
setTimeout(function () {
acc.log('Step 2');
buf[1] = 0x25;
buf[3] = 0x04;
buf[5] = 0x00;
var message = LOGIN_MSG3;
message = format37ByteMessage(message);
buf2 = Buffer.from(message, 'hex');
totalLength = buf.length + buf2.length;
var buf3 = Buffer.concat([buf, buf2], totalLength);
cl.write(buf3);
setTimeout(function () {
acc.log('Step 3');
buf[1] = 0x26;
buf[3] = 0x03;
buf[5] = 0xF8;
message = LOGIN_MSG4;
message = format37ByteMessage(message);
buf2 = Buffer.from(message, 'hex');
buf2[2] = 0x80; // Weird bug that adds c2 whenever there is 0x80 in string so fix it manually
totalLength = buf.length + buf2.length;
buf3 = Buffer.concat([buf, buf2], totalLength);
cl.write(buf3);
setTimeout(function () {
buf[1] = 0x25;
buf[3] = 0x04;
buf[5] = 0x00;
message = LOGIN_MSG5;
message = format37ByteMessage(message);
buf2 = Buffer.from(message, 'hex');
totalLength = buf.length + buf2.length;
buf3 = Buffer.concat([buf, buf2], totalLength);
cl.write(buf3);
setTimeout(function () {
// add code here to extract product id and firmware version to information service
buf[7] = 0x14;
buftemp = Buffer.alloc(23, 0x00);
receivebuffer.copy(buftemp, 0, 16, 26);
receivebuffer.copy(buftemp, 10, 24, 26);
receivebuffer.copy(buftemp, 15, 31, 39);
buftemp[12] = 0x19;
buftemp[13] = 0x00;
buftemp[14] = 0x00;
buf2 = Buffer.from(LOGIN_MSG6);
totalLength = buftemp.length + buf2.length;
buf3 = Buffer.concat([buftemp, buf2], totalLength);
var checksum = 0;
for (i = 0; i < buf3.length; i++) {
checksum += buf3[i];
}
while (checksum > 255) {
checksum = checksum - Math.trunc(checksum / 256) * 256;
}
buf4 = Buffer.from([checksum]);
buf5 = Buffer.concat([buf3, buf4], buf3.length + buf4.length);
buf6 = Buffer.alloc((Math.round(buf5.length / 16) + 1) * 16, 0xEE);
buf5.copy(buf6);
totalLength = buf.length + buf6.length;
buf7 = Buffer.concat([buf, buf6], totalLength);
cl.write(buf7);
setTimeout(function () {
buf[1] = 0x25;
buf[3] = 0x04;
buf[5] = 0x00;
buf[7] = 0x14;
message = LOGIN_MSG7;
message = format37ByteMessage(message);
buf2 = Buffer.from(message, 'hex');
totalLength = buf.length + buf2.length;
buf3 = Buffer.concat([buf, buf2], totalLength);
cl.write(buf3);
setTimeout(function () {
buf[1] = 0x25;
buf[3] = 0x04;
buf[5] = 0x00;
buf[7] = 0x14;
message = LOGIN_MSG8;
message = format37ByteMessage(message);
buf2 = Buffer.from(message, 'hex');
totalLength = buf.length + buf2.length;
buf3 = Buffer.concat([buf, buf2], totalLength);
cl.write(buf3);
setTimeout(function () {
loggedin = true;
busyloggingin = false;
acc.log('Done logging in');
}, LOGINDELAY);
}, DELAY_BETWEEN_CMDS);
}, DELAY_BETWEEN_CMDS);
}, DELAY_BETWEEN_CMDS);
}, DELAY_BETWEEN_CMDS);
}, DELAY_BETWEEN_CMDS);
}, DELAY_BETWEEN_CMDS);
}, DELAY_BETWEEN_CMDS);
} else {
acc.log('Error logging in');
cl.end();
loggedin = false;
busyloggingin = false;
}
}, WAIT_AFTER_LOGIN);
}
function _logout(cl, acc) {
acc.log('Creating close message');
var buf = Buffer.from(CONTROLALARM_MSG1);
message1 = CLOSECONNECTION_MSG;
message1 = format37ByteMessage(message1);
var buf2 = Buffer.from(message1, 'hex');
var totalLength = buf.length + buf2.length;
var buf3 = Buffer.concat([buf, buf2], totalLength);
loginresult = 0;
loggedin = false;
acc.log('Close alarm connection');
cl.write(buf3);
setTimeout(function() {
cl.end();
}, LOGOUT_DELAY);
}
//
// This is an internal function that sends the status request messages to the alarm in order to retrieve the alarm and zone status
// It takes the socket handle to communicate the message to the alarm and accessory handle in order to log messages for the accessory
function _getalarmstatus(cl, acc) {
if (loggedin) {
acc.log('Geting Status...');
loginresult = 0;
buf = Buffer.from(STATUS_MSG1);
cl.write(buf);
setTimeout(function () {
buf = Buffer.from(STATUS_MSG2);
cl.write(buf);
setTimeout(function () {
acc.log("Statusses:");
acc.log('Area 1 - ' + alarmstatus[0]);
acc.log('Area 2 - ' + alarmstatus[1]);
}, DELAY_BETWEEN_CMDS);
}, DELAY_BETWEEN_CMDS);
} else {
acc.log('Cannot get status - not logged in');
}
}
//
// Function that handles the full status get cycle. It logs in, sends status requets message and retrieves status info form data received from alarm
// It takes accessory as input in order to be able to log messages for it
function getAlarmStatus(acc) {
// self = this;
var returnvalue = false;
if (controlPGMstate || controlAlarmstate || !connected) {
// acc.log('Busy with alarm now - not getting status');
// status_valid = false;
} else {
message_count = 0;
status_valid = false;
_getalarmstatus(client, acc);
status_valid = true;
returnvalue = true;
}
return(returnvalue);
}
//
// Function to control alarm
// It takes input as the state the alarm must be set to, the partition in which the zone is, the accessory in order to log messages and the socket handle to be able to talk to alarm
function controlAlarm(state, partition, acc, cl) {
if (loggedin) {
var message1 = '';
acc.log('Controlling Alarm State...');
buf = Buffer.from(CONTROLALARM_MSG1);
if (partition === 0) {
switch (state) {
case "ARM" :
message1 = CONTROLALARM_ARM_P0_MSG;
break;
case "DISARM" :