homebridge-adt-pulse 3.0.0-beta.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,8 +5,8 @@ import _ from 'lodash';
5
5
  import { serializeError } from 'serialize-error';
6
6
  import { CookieJar } from 'tough-cookie';
7
7
  import { detectedNewDoSubmitHandlers, detectedNewGatewayInformation, detectedNewOrbSecurityButtons, detectedNewPanelInformation, detectedNewPanelStatus, detectedNewPortalVersion, detectedNewSensorsInformation, detectedNewSensorsStatus, } from './detect.js';
8
- import { paramNetworkId, paramSat, requestPathAccessSignIn, requestPathAccessSignInENsPartnerAdt, requestPathAccessSignInNetworkIdXxPartnerAdt, requestPathAjaxSyncCheckServTXx, requestPathKeepAlive, requestPathMfaMfaSignInWorkflowChallenge, requestPathQuickControlArmDisarm, requestPathQuickControlServRunRraCommand, requestPathSummarySummary, requestPathSystemDeviceId1, requestPathSystemGateway, requestPathSystemSystem, textPanelEmergencyKeys, } from './regex.js';
9
- import { debugLog, fetchErrorMessage, fetchMissingSatCode, fetchTableCells, findNullKeys, generateDynatracePCHeaderValue, generateHash, isPortalSyncCode, parseArmDisarmMessage, parseDoSubmitHandlers, parseOrbSecurityButtons, parseOrbSensors, parseOrbTextSummary, parseSensorsTable, sleep, stackTracer, } from './utility.js';
8
+ import { paramNetworkId, paramSat, requestPathAccessSignIn, requestPathAccessSignInEXxPartnerAdt, requestPathAccessSignInNetworkIdXxPartnerAdt, requestPathAjaxSyncCheckServTXx, requestPathKeepAlive, requestPathMfaMfaSignInWorkflowChallenge, requestPathQuickControlArmDisarm, requestPathQuickControlServRunRraCommand, requestPathSummarySummary, requestPathSystemDeviceId1, requestPathSystemGateway, requestPathSystemSystem, textPanelEmergencyKeys, } from './regex.js';
9
+ import { debugLog, fetchErrorMessage, fetchMissingSatCode, fetchTableCells, findNullKeys, generateDynatracePCHeaderValue, generateFakeReadyButtons, generateHash, isPortalSyncCode, parseArmDisarmMessage, parseDoSubmitHandlers, parseOrbSecurityButtons, parseOrbSensors, parseOrbTextSummary, parseSensorsTable, sleep, stackTracer, } from './utility.js';
10
10
  export class ADTPulse {
11
11
  #credentials;
12
12
  #internal;
@@ -25,19 +25,39 @@ export class ADTPulse {
25
25
  reportedHashes: [],
26
26
  testMode: {
27
27
  enabled: internalConfig.testMode?.enabled ?? false,
28
- isDisarmChecked: internalConfig.testMode?.isDisarmChecked ?? false,
28
+ isSystemDisarmedBeforeTest: internalConfig.testMode?.isSystemDisarmedBeforeTest ?? false,
29
29
  },
30
+ waitTimeAfterArm: 5000,
30
31
  };
31
32
  this.#session = {
32
33
  backupSatCode: null,
33
34
  httpClient: wrapper(axios.create({
34
35
  jar: new CookieJar(),
36
+ validateStatus: () => true,
35
37
  })),
36
38
  isAuthenticated: false,
37
39
  isCleanState: true,
38
40
  networkId: null,
39
41
  portalVersion: null,
40
42
  };
43
+ if (config.speed !== 1) {
44
+ if (this.#internal.debug) {
45
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.constructor()', 'warn', `Plugin is now running under ${config.speed}x operational speed. You may see slower device updates`);
46
+ }
47
+ switch (config.speed) {
48
+ case 0.75:
49
+ this.#internal.waitTimeAfterArm = 6000;
50
+ break;
51
+ case 0.5:
52
+ this.#internal.waitTimeAfterArm = 7000;
53
+ break;
54
+ case 0.25:
55
+ this.#internal.waitTimeAfterArm = 8000;
56
+ break;
57
+ default:
58
+ break;
59
+ }
60
+ }
41
61
  }
42
62
  async login() {
43
63
  let errorObject;
@@ -45,15 +65,7 @@ export class ADTPulse {
45
65
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.login()', 'info', `Attempting to login to "${this.#internal.baseUrl}"`);
46
66
  }
47
67
  try {
48
- const internet = await this.isPortalAccessible();
49
68
  const sessions = {};
50
- if (!internet.success) {
51
- return {
52
- action: 'LOGIN',
53
- success: false,
54
- info: internet.info,
55
- };
56
- }
57
69
  if (this.isAuthenticated()) {
58
70
  if (this.#internal.debug) {
59
71
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.login()', 'info', [
@@ -224,15 +236,7 @@ export class ADTPulse {
224
236
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.logout()', 'info', `Attempting to logout of "${this.#internal.baseUrl}"`);
225
237
  }
226
238
  try {
227
- const internet = await this.isPortalAccessible();
228
239
  const sessions = {};
229
- if (!internet.success) {
230
- return {
231
- action: 'LOGOUT',
232
- success: false,
233
- info: internet.info,
234
- };
235
- }
236
240
  if (!this.isAuthenticated()) {
237
241
  if (this.#internal.debug) {
238
242
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.logout()', 'info', [
@@ -341,15 +345,7 @@ export class ADTPulse {
341
345
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.getGatewayInformation()', 'info', `Attempting to retrieve gateway information from "${this.#internal.baseUrl}"`);
342
346
  }
343
347
  try {
344
- const internet = await this.isPortalAccessible();
345
348
  const sessions = {};
346
- if (!internet.success) {
347
- return {
348
- action: 'GET_GATEWAY_INFORMATION',
349
- success: false,
350
- info: internet.info,
351
- };
352
- }
353
349
  sessions.axiosSystemGateway = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/system/gateway.jsp`, this.getRequestConfig({
354
350
  headers: {
355
351
  Referer: `${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/system/system.jsp`,
@@ -429,10 +425,10 @@ export class ADTPulse {
429
425
  ], 1, 1);
430
426
  const gatewayInformation = {
431
427
  communication: {
432
- primaryConnectionType: _.get(fetchedTableCells, ['Primary Connection Type:', 0], null),
433
428
  broadbandConnectionStatus: _.get(fetchedTableCells, ['Broadband Connection Status:', 0], null),
434
429
  cellularConnectionStatus: _.get(fetchedTableCells, ['Cellular Connection Status:', 0], null),
435
430
  cellularSignalStrength: _.get(fetchedTableCells, ['Cellular Signal Strength:', 0], null),
431
+ primaryConnectionType: _.get(fetchedTableCells, ['Primary Connection Type:', 0], null),
436
432
  },
437
433
  manufacturer: _.get(fetchedTableCells, ['Manufacturer:', 0], null),
438
434
  model: _.get(fetchedTableCells, ['Model:', 0], null),
@@ -492,15 +488,7 @@ export class ADTPulse {
492
488
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.getPanelInformation()', 'info', `Attempting to retrieve panel information from "${this.#internal.baseUrl}"`);
493
489
  }
494
490
  try {
495
- const internet = await this.isPortalAccessible();
496
491
  const sessions = {};
497
- if (!internet.success) {
498
- return {
499
- action: 'GET_PANEL_INFORMATION',
500
- success: false,
501
- info: internet.info,
502
- };
503
- }
504
492
  sessions.axiosSystemDeviceId1 = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/system/device.jsp?id=1`, this.getRequestConfig({
505
493
  headers: {
506
494
  Referer: `${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/system/system.jsp`,
@@ -565,13 +553,13 @@ export class ADTPulse {
565
553
  'Type/Model:',
566
554
  ], 1, 1);
567
555
  const emergencyKeys = _.get(fetchedTableCells, ['Emergency Keys:', 0], null);
568
- const parsedEmergencyKeys = (typeof emergencyKeys === 'string') ? emergencyKeys.match(textPanelEmergencyKeys) : null;
556
+ const parsedEmergencyKeys = (emergencyKeys !== null) ? emergencyKeys.match(textPanelEmergencyKeys) : null;
569
557
  const manufacturerProvider = _.get(fetchedTableCells, ['Manufacturer/Provider:', 0], null);
570
- const parsedManufacturer = (typeof manufacturerProvider === 'string') ? manufacturerProvider.split(' - ')[0] ?? null : null;
571
- const parsedProvider = (typeof manufacturerProvider === 'string') ? manufacturerProvider.split(' - ')[1] ?? null : null;
558
+ const parsedManufacturer = (manufacturerProvider !== null) ? manufacturerProvider.split(' - ')[0] ?? null : null;
559
+ const parsedProvider = (manufacturerProvider !== null) ? manufacturerProvider.split(' - ')[1] ?? null : null;
572
560
  const typeModel = _.get(fetchedTableCells, ['Type/Model:', 0], null);
573
- const parsedType = (typeof typeModel === 'string') ? typeModel.split(' - ')[0] ?? null : null;
574
- const parsedModel = (typeof typeModel === 'string') ? typeModel.split(' - ')[1] ?? null : null;
561
+ const parsedType = (typeModel !== null) ? typeModel.split(' - ')[0] ?? null : null;
562
+ const parsedModel = (typeModel !== null) ? typeModel.split(' - ')[1] ?? null : null;
575
563
  const panelInformation = {
576
564
  emergencyKeys: parsedEmergencyKeys,
577
565
  manufacturer: parsedManufacturer,
@@ -612,15 +600,7 @@ export class ADTPulse {
612
600
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.getPanelStatus()', 'info', `Attempting to retrieve panel status from "${this.#internal.baseUrl}"`);
613
601
  }
614
602
  try {
615
- const internet = await this.isPortalAccessible();
616
603
  const sessions = {};
617
- if (!internet.success) {
618
- return {
619
- action: 'GET_PANEL_STATUS',
620
- success: false,
621
- info: internet.info,
622
- };
623
- }
624
604
  sessions.axiosSummary = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`, this.getRequestConfig({
625
605
  headers: {
626
606
  Referer: `${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`,
@@ -712,10 +692,22 @@ export class ADTPulse {
712
692
  },
713
693
  };
714
694
  }
715
- async setPanelStatus(armTo) {
695
+ async setPanelStatus(armFrom, armTo, isAlarmActive) {
716
696
  let errorObject;
717
697
  if (this.#internal.debug) {
718
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'info', `Attempting to update panel status to "${armTo}" at "${this.#internal.baseUrl}"`);
698
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'info', `Attempting to update panel status from "${armFrom}" to "${armTo}" at "${this.#internal.baseUrl}"`);
699
+ }
700
+ if (armFrom !== 'away'
701
+ && armFrom !== 'night'
702
+ && armFrom !== 'off'
703
+ && armFrom !== 'stay') {
704
+ return {
705
+ action: 'SET_PANEL_STATUS',
706
+ success: false,
707
+ info: {
708
+ message: `"${armFrom}" is an invalid arm from state`,
709
+ },
710
+ };
719
711
  }
720
712
  if (armTo !== 'away'
721
713
  && armTo !== 'night'
@@ -729,16 +721,41 @@ export class ADTPulse {
729
721
  },
730
722
  };
731
723
  }
724
+ if (typeof isAlarmActive !== 'boolean') {
725
+ return {
726
+ action: 'SET_PANEL_STATUS',
727
+ success: false,
728
+ info: {
729
+ message: 'You must specify if the system\'s alarm is currently ringing (true) or not (false)',
730
+ },
731
+ };
732
+ }
733
+ if ((armFrom === 'away'
734
+ && armTo === 'away')
735
+ || (armFrom === 'night'
736
+ && armTo === 'night')
737
+ || (armFrom === 'stay'
738
+ && armTo === 'stay')
739
+ || (armFrom === 'off'
740
+ && armTo === 'off'
741
+ && !isAlarmActive)) {
742
+ if (this.#internal.debug) {
743
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'info', `No need to change arm state from "${armFrom}" to "${armTo}" due to its equivalence`);
744
+ }
745
+ return {
746
+ action: 'SET_PANEL_STATUS',
747
+ success: true,
748
+ info: {
749
+ forceArmRequired: false,
750
+ },
751
+ };
752
+ }
753
+ if (this.#internal.debug && isAlarmActive) {
754
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'warn', `Alarm is currently ringing and arm state is being changed from "${armFrom}" to "${armTo}"`);
755
+ }
732
756
  try {
733
- const internet = await this.isPortalAccessible();
734
757
  const sessions = {};
735
- if (!internet.success) {
736
- return {
737
- action: 'SET_PANEL_STATUS',
738
- success: false,
739
- info: internet.info,
740
- };
741
- }
758
+ let isAlarmCurrentlyActive = isAlarmActive;
742
759
  sessions.axiosSummary = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`, this.getRequestConfig({
743
760
  headers: {
744
761
  Referer: `${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`,
@@ -806,34 +823,33 @@ export class ADTPulse {
806
823
  const jsdomSummaryOrbSecurityButtons = sessions.jsdomSummary.window.document.querySelectorAll('#divOrbSecurityButtons input');
807
824
  const parsedOrbSecurityButtons = parseOrbSecurityButtons(jsdomSummaryOrbSecurityButtons);
808
825
  await this.newInformationDispatcher('orb-security-buttons', parsedOrbSecurityButtons);
809
- const armingNightButtonIndex = parsedOrbSecurityButtons.findIndex((parsedOrbSecurityButton) => {
810
- const parsedOrbSecurityButtonButtonDisabled = parsedOrbSecurityButton.buttonDisabled;
811
- const parsedOrbSecurityButtonButtonText = parsedOrbSecurityButton.buttonText;
812
- return (parsedOrbSecurityButtonButtonDisabled && parsedOrbSecurityButtonButtonText === 'Arming Night');
813
- });
814
- if (this.#session.backupSatCode !== null
815
- && armingNightButtonIndex >= 0) {
816
- if (this.#internal.debug) {
817
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'warn', 'Replacing the stuck "Arming Night" button with a fake "Disarm" button');
818
- }
819
- parsedOrbSecurityButtons[armingNightButtonIndex] = {
820
- buttonDisabled: false,
821
- buttonId: 'security_button_0',
822
- buttonIndex: 0,
823
- buttonText: 'Disarm',
824
- changeAccessCode: false,
825
- loadingText: 'Disarming',
826
+ let readyButtons = parsedOrbSecurityButtons.filter((parsedOrbSecurityButton) => !parsedOrbSecurityButton.buttonDisabled);
827
+ if (readyButtons.length === 0 && this.#session.backupSatCode !== null) {
828
+ readyButtons = generateFakeReadyButtons(parsedOrbSecurityButtons, this.#session.isCleanState, {
826
829
  relativeUrl: 'quickcontrol/armDisarm.jsp',
827
- totalButtons: 1,
828
- urlParams: {
829
- arm: 'off',
830
- armState: (this.#session.isCleanState) ? 'night' : 'night+stay',
831
- href: 'rest/adt/ui/client/security/setArmState',
832
- sat: this.#session.backupSatCode,
830
+ href: 'rest/adt/ui/client/security/setArmState',
831
+ sat: this.#session.backupSatCode,
832
+ });
833
+ if (this.#internal.debug) {
834
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'warn', 'No security buttons were found. Replacing stuck orb security buttons with fake buttons');
835
+ stackTracer('fake-ready-buttons', {
836
+ before: parsedOrbSecurityButtons,
837
+ after: readyButtons,
838
+ });
839
+ }
840
+ }
841
+ if (readyButtons.length === 0 && this.#session.backupSatCode === null) {
842
+ if (this.#internal.debug) {
843
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'error', 'No security buttons were found and replacement failed because no backup sat code exists');
844
+ }
845
+ return {
846
+ action: 'SET_PANEL_STATUS',
847
+ success: false,
848
+ info: {
849
+ message: 'No security buttons were found and replacement failed because no backup sat code exists',
833
850
  },
834
851
  };
835
852
  }
836
- let readyButtons = parsedOrbSecurityButtons.filter((parsedOrbSecurityButton) => !parsedOrbSecurityButton.buttonDisabled);
837
853
  if (readyButtons.length < 1) {
838
854
  if (this.#internal.debug) {
839
855
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'error', 'Security buttons are not found on the summary page');
@@ -847,7 +863,7 @@ export class ADTPulse {
847
863
  };
848
864
  }
849
865
  if (this.#internal.testMode.enabled
850
- && !this.#internal.testMode.isDisarmChecked) {
866
+ && !this.#internal.testMode.isSystemDisarmedBeforeTest) {
851
867
  if (!['off', 'disarmed'].includes(readyButtons[0].urlParams.armState)) {
852
868
  if (this.#internal.debug) {
853
869
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'error', 'Test mode is active and system is not disarmed');
@@ -860,10 +876,16 @@ export class ADTPulse {
860
876
  },
861
877
  };
862
878
  }
863
- this.#internal.testMode.isDisarmChecked = true;
879
+ this.#internal.testMode.isSystemDisarmedBeforeTest = true;
864
880
  }
865
- while (!['off', 'disarmed'].includes(readyButtons[0].urlParams.armState)) {
866
- const armDisarmResponse = await this.armDisarmHandler(readyButtons[0].relativeUrl, readyButtons[0].urlParams.href, readyButtons[0].urlParams.armState, 'off', readyButtons[0].urlParams.sat);
881
+ while (isAlarmCurrentlyActive || !['off', 'disarmed'].includes(readyButtons[0].urlParams.armState)) {
882
+ const armDisarmResponse = await this.armDisarmHandler(isAlarmCurrentlyActive, {
883
+ relativeUrl: readyButtons[0].relativeUrl,
884
+ href: readyButtons[0].urlParams.href,
885
+ armState: readyButtons[0].urlParams.armState,
886
+ arm: 'off',
887
+ sat: readyButtons[0].urlParams.sat,
888
+ });
867
889
  if (!armDisarmResponse.success) {
868
890
  if (this.#internal.debug) {
869
891
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'error', 'An error occurred in the arm disarm handler (while disarming)');
@@ -887,10 +909,19 @@ export class ADTPulse {
887
909
  };
888
910
  }
889
911
  readyButtons = armDisarmResponse.info.readyButtons;
912
+ if (isAlarmCurrentlyActive) {
913
+ isAlarmCurrentlyActive = false;
914
+ }
890
915
  }
891
916
  let forceArmRequired = false;
892
917
  if (armTo !== 'off') {
893
- const armDisarmResponse = await this.armDisarmHandler(readyButtons[0].relativeUrl, readyButtons[0].urlParams.href, readyButtons[0].urlParams.armState, armTo, readyButtons[0].urlParams.sat);
918
+ const armDisarmResponse = await this.armDisarmHandler(false, {
919
+ relativeUrl: readyButtons[0].relativeUrl,
920
+ href: readyButtons[0].urlParams.href,
921
+ armState: readyButtons[0].urlParams.armState,
922
+ arm: armTo,
923
+ sat: readyButtons[0].urlParams.sat,
924
+ });
894
925
  if (!armDisarmResponse.success) {
895
926
  if (this.#internal.debug) {
896
927
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'error', 'An error occurred in the arm disarm handler (while arming)');
@@ -904,7 +935,7 @@ export class ADTPulse {
904
935
  forceArmRequired = armDisarmResponse.info.forceArmRequired;
905
936
  }
906
937
  if (this.#internal.debug) {
907
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'success', `Successfully updated panel status to "${armTo}" at "${this.#internal.baseUrl}"`);
938
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'success', `Successfully updated panel status from "${armFrom}" to "${armTo}" at "${this.#internal.baseUrl}"`);
908
939
  }
909
940
  return {
910
941
  action: 'SET_PANEL_STATUS',
@@ -935,15 +966,7 @@ export class ADTPulse {
935
966
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.getSensorsInformation()', 'info', `Attempting to retrieve sensors information from "${this.#internal.baseUrl}"`);
936
967
  }
937
968
  try {
938
- const internet = await this.isPortalAccessible();
939
969
  const sessions = {};
940
- if (!internet.success) {
941
- return {
942
- action: 'GET_SENSORS_INFORMATION',
943
- success: false,
944
- info: internet.info,
945
- };
946
- }
947
970
  sessions.axiosSystem = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/system/system.jsp`, this.getRequestConfig({
948
971
  headers: {
949
972
  Referer: `${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`,
@@ -999,7 +1022,7 @@ export class ADTPulse {
999
1022
  contentType: 'text/html',
1000
1023
  pretendToBeVisual: true,
1001
1024
  });
1002
- const jsdomSystemSensorsTable = sessions.jsdomSystem.window.document.querySelectorAll('#systemContentList tr[onclick^="goToUrl(\'device.jsp?id="]');
1025
+ const jsdomSystemSensorsTable = sessions.jsdomSystem.window.document.querySelectorAll('#systemContentList tr[class^=\'p_row\'] tr.p_listRow');
1003
1026
  const parsedSensorsTable = parseSensorsTable(jsdomSystemSensorsTable);
1004
1027
  await this.newInformationDispatcher('sensors-information', parsedSensorsTable);
1005
1028
  if (this.#internal.debug) {
@@ -1034,15 +1057,7 @@ export class ADTPulse {
1034
1057
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.getSensorsStatus()', 'info', `Attempting to retrieve sensors status from "${this.#internal.baseUrl}"`);
1035
1058
  }
1036
1059
  try {
1037
- const internet = await this.isPortalAccessible();
1038
1060
  const sessions = {};
1039
- if (!internet.success) {
1040
- return {
1041
- action: 'GET_SENSORS_STATUS',
1042
- success: false,
1043
- info: internet.info,
1044
- };
1045
- }
1046
1061
  sessions.axiosSummary = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`, this.getRequestConfig({
1047
1062
  headers: {
1048
1063
  Referer: `${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`,
@@ -1142,15 +1157,7 @@ export class ADTPulse {
1142
1157
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.performSyncCheck()', 'info', `Attempting to perform a sync check from "${this.#internal.baseUrl}"`);
1143
1158
  }
1144
1159
  try {
1145
- const internet = await this.isPortalAccessible();
1146
1160
  const sessions = {};
1147
- if (!internet.success) {
1148
- return {
1149
- action: 'PERFORM_SYNC_CHECK',
1150
- success: false,
1151
- info: internet.info,
1152
- };
1153
- }
1154
1161
  sessions.axiosSyncCheck = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/Ajax/SyncCheckServ?t=${Date.now()}`, this.getRequestConfig({
1155
1162
  headers: {
1156
1163
  Accept: '*/*',
@@ -1249,15 +1256,7 @@ export class ADTPulse {
1249
1256
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.performKeepAlive()', 'info', `Attempting to perform a keep alive from "${this.#internal.baseUrl}"`);
1250
1257
  }
1251
1258
  try {
1252
- const internet = await this.isPortalAccessible();
1253
1259
  const sessions = {};
1254
- if (!internet.success) {
1255
- return {
1256
- action: 'PERFORM_KEEP_ALIVE',
1257
- success: false,
1258
- info: internet.info,
1259
- };
1260
- }
1261
1260
  sessions.axiosKeepAlive = await this.#session.httpClient.post(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/KeepAlive`, '', this.getRequestConfig({
1262
1261
  headers: {
1263
1262
  Accept: '*/*',
@@ -1330,16 +1329,40 @@ export class ADTPulse {
1330
1329
  isAuthenticated() {
1331
1330
  return this.#session.isAuthenticated;
1332
1331
  }
1333
- async armDisarmHandler(relativeUrl, href, armState, arm, sat) {
1332
+ resetSession() {
1333
+ this.#session = {
1334
+ backupSatCode: null,
1335
+ httpClient: wrapper(axios.create({
1336
+ jar: new CookieJar(),
1337
+ validateStatus: () => true,
1338
+ })),
1339
+ isAuthenticated: false,
1340
+ isCleanState: true,
1341
+ networkId: null,
1342
+ portalVersion: null,
1343
+ };
1344
+ }
1345
+ async armDisarmHandler(isAlarmActive, options) {
1334
1346
  let errorObject;
1335
1347
  if (this.#internal.debug) {
1336
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'info', `Attempting to update arm state from "${armState}" to "${arm}" on "${this.#internal.baseUrl}"`);
1348
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'info', `Attempting to update arm state from "${options.armState}" to "${options.arm}" on "${this.#internal.baseUrl}"`);
1337
1349
  }
1338
- if (armState === arm
1339
- || (armState === 'disarmed'
1340
- && arm === 'off')) {
1350
+ if ((options.armState === 'away'
1351
+ && options.arm === 'away')
1352
+ || (options.armState === 'night'
1353
+ && options.arm === 'night')
1354
+ || (options.armState === 'night+stay'
1355
+ && options.arm === 'night')
1356
+ || (options.armState === 'stay'
1357
+ && options.arm === 'stay')
1358
+ || (options.armState === 'disarmed'
1359
+ && options.arm === 'off'
1360
+ && !isAlarmActive)
1361
+ || (options.armState === 'off'
1362
+ && options.arm === 'off'
1363
+ && !isAlarmActive)) {
1341
1364
  if (this.#internal.debug) {
1342
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'info', `No need to change arm state from "${armState}" to "${arm}" due to its equivalence`);
1365
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'info', `No need to change arm state from "${options.armState}" to "${options.arm}" due to its equivalence`);
1343
1366
  }
1344
1367
  return {
1345
1368
  action: 'ARM_DISARM_HANDLER',
@@ -1351,21 +1374,13 @@ export class ADTPulse {
1351
1374
  };
1352
1375
  }
1353
1376
  try {
1354
- const internet = await this.isPortalAccessible();
1355
1377
  const sessions = {};
1356
- if (!internet.success) {
1357
- return {
1358
- action: 'ARM_DISARM_HANDLER',
1359
- success: false,
1360
- info: internet.info,
1361
- };
1362
- }
1363
1378
  const armDisarmForm = new URLSearchParams();
1364
- armDisarmForm.append('href', href);
1365
- armDisarmForm.append('armstate', armState);
1366
- armDisarmForm.append('arm', arm);
1367
- armDisarmForm.append('sat', sat);
1368
- sessions.axiosSetArmMode = await this.#session.httpClient.post(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/${relativeUrl}`, armDisarmForm, this.getRequestConfig({
1379
+ armDisarmForm.append('href', options.href);
1380
+ armDisarmForm.append('armstate', options.armState);
1381
+ armDisarmForm.append('arm', options.arm);
1382
+ armDisarmForm.append('sat', options.sat);
1383
+ sessions.axiosSetArmMode = await this.#session.httpClient.post(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/${options.relativeUrl}`, armDisarmForm, this.getRequestConfig({
1369
1384
  headers: {
1370
1385
  'Cache-Control': 'max-age=0',
1371
1386
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -1409,8 +1424,8 @@ export class ADTPulse {
1409
1424
  };
1410
1425
  }
1411
1426
  let forceArmRequired = false;
1412
- if (arm !== 'off') {
1413
- const forceArmResponse = await this.forceArmHandler(sessions.axiosSetArmMode, relativeUrl);
1427
+ if (options.arm !== 'off') {
1428
+ const forceArmResponse = await this.forceArmHandler(sessions.axiosSetArmMode, options.relativeUrl);
1414
1429
  if (!forceArmResponse.success) {
1415
1430
  if (this.#internal.debug) {
1416
1431
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'error', 'An error occurred in the force arm handler');
@@ -1424,7 +1439,7 @@ export class ADTPulse {
1424
1439
  forceArmRequired = forceArmResponse.info.forceArmRequired;
1425
1440
  }
1426
1441
  this.#session.isCleanState = false;
1427
- await sleep(6000);
1442
+ await sleep(this.#internal.waitTimeAfterArm);
1428
1443
  sessions.axiosSummary = await this.#session.httpClient.get(`${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`, this.getRequestConfig({
1429
1444
  headers: {
1430
1445
  Referer: `${this.#internal.baseUrl}/myhome/${this.#session.portalVersion}/summary/summary.jsp`,
@@ -1493,30 +1508,22 @@ export class ADTPulse {
1493
1508
  const parsedOrbSecurityButtons = parseOrbSecurityButtons(jsdomSummaryOrbSecurityButtons);
1494
1509
  await this.newInformationDispatcher('orb-security-buttons', parsedOrbSecurityButtons);
1495
1510
  let readyButtons = parsedOrbSecurityButtons.filter((parsedOrbSecurityButton) => !parsedOrbSecurityButton.buttonDisabled);
1496
- if (['disarmed', 'off'].includes(armState)
1497
- && ['night'].includes(arm)
1498
- && readyButtons.length === 0) {
1499
- readyButtons = [
1500
- {
1501
- buttonDisabled: false,
1502
- buttonId: 'security_button_0',
1503
- buttonIndex: 0,
1504
- buttonText: 'Disarm',
1505
- changeAccessCode: false,
1506
- loadingText: 'Disarming',
1507
- relativeUrl,
1508
- totalButtons: 1,
1509
- urlParams: {
1510
- arm: 'off',
1511
- armState: (this.#session.isCleanState) ? 'night' : 'night+stay',
1512
- href,
1513
- sat,
1514
- },
1515
- },
1516
- ];
1511
+ if (readyButtons.length === 0) {
1512
+ readyButtons = generateFakeReadyButtons(parsedOrbSecurityButtons, this.#session.isCleanState, {
1513
+ relativeUrl: options.relativeUrl,
1514
+ href: options.href,
1515
+ sat: options.sat,
1516
+ });
1517
+ if (this.#internal.debug) {
1518
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'warn', 'No security buttons were found. Replacing stuck orb security buttons with fake buttons');
1519
+ stackTracer('fake-ready-buttons', {
1520
+ before: parsedOrbSecurityButtons,
1521
+ after: readyButtons,
1522
+ });
1523
+ }
1517
1524
  }
1518
1525
  if (this.#internal.debug) {
1519
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'success', `Successfully updated arm state from "${armState}" to "${arm}" on "${this.#internal.baseUrl}"`);
1526
+ debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'success', `Successfully updated arm state from "${options.armState}" to "${options.arm}" on "${this.#internal.baseUrl}"`);
1520
1527
  }
1521
1528
  return {
1522
1529
  action: 'ARM_DISARM_HANDLER',
@@ -1548,15 +1555,7 @@ export class ADTPulse {
1548
1555
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.forceArmHandler()', 'info', `Attempting to force arm on "${this.#internal.baseUrl}"`);
1549
1556
  }
1550
1557
  try {
1551
- const internet = await this.isPortalAccessible();
1552
1558
  const sessions = {};
1553
- if (!internet.success) {
1554
- return {
1555
- action: 'FORCE_ARM_HANDLER',
1556
- success: false,
1557
- info: internet.info,
1558
- };
1559
- }
1560
1559
  if (typeof response.data !== 'string') {
1561
1560
  if (this.#internal.debug) {
1562
1561
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.forceArmHandler()', 'error', 'The response body of the arm disarm page is not of type "string"');
@@ -1731,49 +1730,6 @@ export class ADTPulse {
1731
1730
  },
1732
1731
  };
1733
1732
  }
1734
- async isPortalAccessible() {
1735
- let errorObject;
1736
- if (this.#internal.debug) {
1737
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.isPortalAccessible()', 'info', `Attempting to check if "${this.#internal.baseUrl}" is accessible`);
1738
- }
1739
- try {
1740
- const response = await axios.head(this.#internal.baseUrl, this.getRequestConfig());
1741
- if (response.status !== 200 || response.statusText !== 'OK') {
1742
- if (this.#internal.debug) {
1743
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.isPortalAccessible()', 'error', `The portal at "${this.#internal.baseUrl}" is not accessible`);
1744
- }
1745
- return {
1746
- action: 'IS_PORTAL_ACCESSIBLE',
1747
- success: false,
1748
- info: {
1749
- message: `The portal at "${this.#internal.baseUrl}" is not accessible`,
1750
- },
1751
- };
1752
- }
1753
- if (this.#internal.debug) {
1754
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.isPortalAccessible()', 'success', `Successfully checked if "${this.#internal.baseUrl}" is accessible`);
1755
- }
1756
- return {
1757
- action: 'IS_PORTAL_ACCESSIBLE',
1758
- success: true,
1759
- info: null,
1760
- };
1761
- }
1762
- catch (error) {
1763
- errorObject = serializeError(error);
1764
- }
1765
- if (this.#internal.debug) {
1766
- debugLog(this.#internal.logger, 'api.ts / ADTPulse.isPortalAccessible()', 'error', 'Method encountered an error during execution');
1767
- stackTracer('serialize-error', errorObject);
1768
- }
1769
- return {
1770
- action: 'IS_PORTAL_ACCESSIBLE',
1771
- success: false,
1772
- info: {
1773
- error: errorObject,
1774
- },
1775
- };
1776
- }
1777
1733
  async newInformationDispatcher(type, data) {
1778
1734
  const dataHash = generateHash(`${type}: ${JSON.stringify(data)}`);
1779
1735
  if (this.#internal.reportedHashes.find((reportedHash) => dataHash === reportedHash) === undefined) {
@@ -1818,8 +1774,10 @@ export class ADTPulse {
1818
1774
  Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
1819
1775
  'Accept-Encoding': 'gzip, deflate, br',
1820
1776
  'Accept-Language': 'en-US,en;q=0.9',
1777
+ 'Cache-Control': 'no-cache',
1821
1778
  Connection: 'keep-alive',
1822
1779
  Host: `${this.#credentials.subdomain}.adtpulse.com`,
1780
+ Pragma: 'no-cache',
1823
1781
  'Sec-Fetch-Dest': 'document',
1824
1782
  'Sec-Fetch-Mode': 'navigate',
1825
1783
  'Sec-Fetch-Site': 'none',
@@ -1831,7 +1789,6 @@ export class ADTPulse {
1831
1789
  'sec-ch-ua-platform': '"macOS"',
1832
1790
  },
1833
1791
  timeout: 15000,
1834
- validateStatus: undefined,
1835
1792
  };
1836
1793
  if (extraConfig === undefined) {
1837
1794
  return defaultConfig;
@@ -1843,11 +1800,11 @@ export class ADTPulse {
1843
1800
  return;
1844
1801
  }
1845
1802
  if (requestPathAccessSignIn.test(requestPath)
1846
- || requestPathAccessSignInENsPartnerAdt.test(requestPath)
1803
+ || requestPathAccessSignInEXxPartnerAdt.test(requestPath)
1847
1804
  || requestPathMfaMfaSignInWorkflowChallenge.test(requestPath)) {
1848
1805
  if (this.#internal.debug) {
1849
1806
  const errorMessage = fetchErrorMessage(session);
1850
- if (requestPathAccessSignIn.test(requestPath) || requestPathAccessSignInENsPartnerAdt.test(requestPath)) {
1807
+ if (requestPathAccessSignIn.test(requestPath) || requestPathAccessSignInEXxPartnerAdt.test(requestPath)) {
1851
1808
  debugLog(this.#internal.logger, 'api.ts / ADTPulse.handleLoginFailure()', 'error', 'Either the username or password is incorrect, fingerprint format is invalid, or was signed out due to inactivity');
1852
1809
  }
1853
1810
  if (requestPathMfaMfaSignInWorkflowChallenge.test(requestPath)) {
@@ -1860,17 +1817,5 @@ export class ADTPulse {
1860
1817
  this.resetSession();
1861
1818
  }
1862
1819
  }
1863
- resetSession() {
1864
- this.#session = {
1865
- backupSatCode: null,
1866
- httpClient: wrapper(axios.create({
1867
- jar: new CookieJar(),
1868
- })),
1869
- isAuthenticated: false,
1870
- isCleanState: true,
1871
- networkId: null,
1872
- portalVersion: null,
1873
- };
1874
- }
1875
1820
  }
1876
1821
  //# sourceMappingURL=api.js.map