homebridge-adt-pulse 3.0.0-beta.4 → 3.0.0-beta.5

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.
@@ -1,300 +0,0 @@
1
- import chalk from 'chalk';
2
- import repl from 'node:repl';
3
-
4
- import { ADTPulse } from '@/lib/api.js';
5
- import type {
6
- ADTPulseDisplayHelpHeaderReturns,
7
- ADTPulseDisplayHelpMenuReturns,
8
- ADTPulseDisplayStartupHeaderReturns,
9
- ADTPulseReplApi,
10
- ADTPulseReplColorLogMessage,
11
- ADTPulseReplColorLogReturns,
12
- ADTPulseReplColorLogType,
13
- ADTPulseReplReplServer,
14
- ADTPulseReplSetInstanceFingerprint,
15
- ADTPulseReplSetInstancePassword,
16
- ADTPulseReplSetInstanceReturns,
17
- ADTPulseReplSetInstanceSubdomain,
18
- ADTPulseReplSetInstanceUsername,
19
- ADTPulseReplStartReplReturns,
20
- } from '@/types/index.d.ts';
21
-
22
- /**
23
- * ADT Pulse Repl.
24
- *
25
- * @since 1.0.0
26
- */
27
- class ADTPulseRepl {
28
- /**
29
- * ADT Pulse Repl - Api.
30
- *
31
- * @private
32
- *
33
- * @since 1.0.0
34
- */
35
- #api: ADTPulseReplApi;
36
-
37
- /**
38
- * ADT Pulse Repl - Repl server.
39
- *
40
- * @private
41
- *
42
- * @since 1.0.0
43
- */
44
- #replServer: ADTPulseReplReplServer;
45
-
46
- /**
47
- * ADT Pulse Repl - Start repl.
48
- *
49
- * @returns {ADTPulseReplStartReplReturns}
50
- *
51
- * @since 1.0.0
52
- */
53
- async startRepl(): ADTPulseReplStartReplReturns {
54
- ADTPulseRepl.displayStartupHeader();
55
- ADTPulseRepl.displayHelpMenu();
56
-
57
- // Start the REPL server.
58
- this.#replServer = repl.start({
59
- ignoreUndefined: true,
60
- prompt: '> ',
61
- });
62
-
63
- // Set the REPL server context on start-up.
64
- this.#replServer.context.repl = this;
65
-
66
- // Replace the default ".break" command.
67
- this.#replServer.defineCommand('break', {
68
- help: 'Sometimes you get stuck, this gets you out',
69
- action() {
70
- ADTPulseRepl.colorLog('error', 'The ".break" command is not allowed.');
71
- this.displayPrompt();
72
- },
73
- });
74
-
75
- // Replace the default ".clear" command.
76
- this.#replServer.defineCommand('clear', {
77
- help: 'Break, and also clear the local context',
78
- action() {
79
- ADTPulseRepl.colorLog('error', 'The ".clear" command is not allowed.');
80
- this.displayPrompt();
81
- },
82
- });
83
-
84
- // Replace the default ".editor" command.
85
- this.#replServer.defineCommand('editor', {
86
- help: 'Enter editor mode',
87
- action() {
88
- ADTPulseRepl.colorLog('error', 'The ".editor" command is not allowed.');
89
- this.displayPrompt();
90
- },
91
- });
92
-
93
- // Replace the default ".help" command.
94
- this.#replServer.defineCommand('help', {
95
- help: 'Print this help message',
96
- action() {
97
- ADTPulseRepl.displayHelpHeader();
98
- ADTPulseRepl.displayHelpMenu();
99
- this.displayPrompt();
100
- },
101
- });
102
-
103
- // Replace the default ".load" command.
104
- this.#replServer.defineCommand('load', {
105
- help: 'Load JS from a file into the REPL session',
106
- action() {
107
- ADTPulseRepl.colorLog('error', 'The ".load" command is not allowed.');
108
- this.displayPrompt();
109
- },
110
- });
111
-
112
- // Replace the default ".save" command.
113
- this.#replServer.defineCommand('save', {
114
- help: 'Save all evaluated commands in this REPL session to a file',
115
- action() {
116
- ADTPulseRepl.colorLog('error', 'The ".save" command is not allowed.');
117
- this.displayPrompt();
118
- },
119
- });
120
- }
121
-
122
- /**
123
- * ADT Pulse Repl - Set instance.
124
- *
125
- * @param {ADTPulseReplSetInstanceSubdomain} subdomain - Subdomain.
126
- * @param {ADTPulseReplSetInstanceUsername} username - Username.
127
- * @param {ADTPulseReplSetInstancePassword} password - Password.
128
- * @param {ADTPulseReplSetInstanceFingerprint} fingerprint - Fingerprint.
129
- *
130
- * @returns {ADTPulseReplSetInstanceReturns}
131
- *
132
- * @since 1.0.0
133
- */
134
- setInstance(subdomain: ADTPulseReplSetInstanceSubdomain, username: ADTPulseReplSetInstanceUsername, password: ADTPulseReplSetInstancePassword, fingerprint: ADTPulseReplSetInstanceFingerprint): ADTPulseReplSetInstanceReturns {
135
- if (subdomain !== 'portal' && subdomain !== 'portal-ca') {
136
- ADTPulseRepl.colorLog('error', 'Invalid subdomain specified. Valid values are either "portal" or "portal-ca".');
137
-
138
- return;
139
- }
140
-
141
- if (typeof username !== 'string' || username === '') {
142
- ADTPulseRepl.colorLog('error', 'Username must be a string and cannot be empty.');
143
-
144
- return;
145
- }
146
-
147
- if (typeof password !== 'string' || password === '') {
148
- ADTPulseRepl.colorLog('error', 'Password must be a string and cannot be empty.');
149
-
150
- return;
151
- }
152
-
153
- if (typeof fingerprint !== 'string' || fingerprint === '') {
154
- ADTPulseRepl.colorLog('error', 'Fingerprint must be a string and cannot be empty.');
155
-
156
- return;
157
- }
158
-
159
- // If the values are valid, set a new instance.
160
- this.#api = new ADTPulse({
161
- platform: 'ADTPulse',
162
- subdomain,
163
- username,
164
- password,
165
- fingerprint,
166
- sensors: [],
167
- }, {
168
- debug: true,
169
- });
170
-
171
- // Check if "this.#replServer" was properly set during startup.
172
- if (this.#replServer === undefined) {
173
- ADTPulseRepl.colorLog('error', 'Failed to set context because "this.#replServer" is undefined.');
174
-
175
- return;
176
- }
177
-
178
- // Set the REPL server context after setting the instance.
179
- this.#replServer.context.api = this.#api;
180
-
181
- ADTPulseRepl.colorLog('info', 'Instance has been successfully set.');
182
- ADTPulseRepl.colorLog('info', 'You may now use the available API methods to test the system!');
183
- ADTPulseRepl.colorLog('info', '\n');
184
- }
185
-
186
- /**
187
- * ADT Pulse Repl - Color log.
188
- *
189
- * @param {ADTPulseReplColorLogType} type - Type.
190
- * @param {ADTPulseReplColorLogMessage} message - Message.
191
- *
192
- * @private
193
- *
194
- * @returns {ADTPulseReplColorLogReturns}
195
- *
196
- * @since 1.0.0
197
- */
198
- private static colorLog(type: ADTPulseReplColorLogType, message: ADTPulseReplColorLogMessage): ADTPulseReplColorLogReturns {
199
- switch (type) {
200
- case 'error':
201
- console.error(chalk.redBright(message));
202
- break;
203
- case 'info':
204
- console.info(chalk.greenBright(message));
205
- break;
206
- default:
207
- break;
208
- }
209
- }
210
-
211
- /**
212
- * ADT Pulse Repl - Display help header.
213
- *
214
- * @returns {ADTPulseDisplayHelpHeaderReturns}
215
- *
216
- * @since 1.0.0
217
- */
218
- private static displayHelpHeader(): ADTPulseDisplayHelpHeaderReturns {
219
- console.info([
220
- chalk.cyanBright('########################################################'),
221
- chalk.cyanBright('#### ADT Pulse for Homebridge Plugin REPL Help Menu ####'),
222
- chalk.cyanBright('########################################################'),
223
- '',
224
- 'This is the help menu on how to use this REPL interface. If you have questions on how',
225
- 'to use this, please refer to the documentation using the link below:',
226
- '',
227
- 'https://github.com/mrjackyliang/homebridge-adt-pulse',
228
- ].join('\n'));
229
- }
230
-
231
- /**
232
- * ADT Pulse Repl - Display help menu.
233
- *
234
- * @returns {ADTPulseDisplayHelpMenuReturns}
235
- *
236
- * @since 1.0.0
237
- */
238
- private static displayHelpMenu(): ADTPulseDisplayHelpMenuReturns {
239
- console.info([
240
- '',
241
- chalk.bold('Method parameter documentation:'),
242
- ` {'portal' | 'portal-ca'} ${chalk.magentaBright('subdomain')} - Set the domain for either USA or Canada subscribers`,
243
- ` {string} ${chalk.magentaBright('username')} - The username for logging in to ADT Pulse portal`,
244
- ` {string} ${chalk.magentaBright('password')} - The password for logging in to ADT Pulse portal`,
245
- ` {string} ${chalk.magentaBright('fingerprint')} - The fingerprint for logging in to ADT Pulse portal`,
246
- ` {'arm' | 'night' | 'off' | 'stay'} ${chalk.magentaBright('armTo')} - Available methods to arm the system`,
247
- '',
248
- chalk.bold('Before you use the API, set the instance using this command:'),
249
- ` ${chalk.yellowBright(`repl.setInstance(${chalk.magentaBright('subdomain')}, ${chalk.magentaBright('username')}, ${chalk.magentaBright('password')}, ${chalk.magentaBright('fingerprint')});`)}`,
250
- '',
251
- chalk.bold('Once an instance is set, interact with the portal using these methods:'),
252
- ` ${chalk.yellowBright('await api.login();')}`,
253
- ` ${chalk.yellowBright('await api.logout();')}`,
254
- ` ${chalk.yellowBright('await api.getGatewayInformation();')}`,
255
- ` ${chalk.yellowBright('await api.getPanelInformation();')}`,
256
- ` ${chalk.yellowBright('await api.getPanelStatus();')}`,
257
- ` ${chalk.yellowBright(`await api.setPanelStatus(${chalk.magentaBright('armTo')});`)}`,
258
- ` ${chalk.yellowBright('await api.getSensorsInformation();')}`,
259
- ` ${chalk.yellowBright('await api.getSensorsStatus();')}`,
260
- ` ${chalk.yellowBright('await api.performSyncCheck();')}`,
261
- ` ${chalk.yellowBright('await api.performKeepAlive();')}`,
262
- ` ${chalk.yellowBright(' api.isAuthenticated();')}`,
263
- '',
264
- chalk.bold('You may also wrap the above methods with this to see the entire response:'),
265
- ` ${chalk.yellowBright(`console.log(util.inspect(${chalk.magentaBright('replace me without the ending semi-colon')}, false, null, true));`)}`,
266
- chalk.bold('A small reference for REPL commands:'),
267
- ` ${chalk.yellowBright('.exit')}`,
268
- ` ${chalk.yellowBright('.help')}`,
269
- '',
270
- ].join('\n'));
271
- }
272
-
273
- /**
274
- * ADT Pulse Repl - Display startup header.
275
- *
276
- * @returns {ADTPulseDisplayStartupHeaderReturns}
277
- *
278
- * @since 1.0.0
279
- */
280
- private static displayStartupHeader(): ADTPulseDisplayStartupHeaderReturns {
281
- console.info([
282
- chalk.cyanBright('##############################################################'),
283
- chalk.cyanBright('#### ADT Pulse for Homebridge Plugin REPL ####'),
284
- chalk.cyanBright('#### https://github.com/mrjackyliang/homebridge-adt-pulse ####'),
285
- chalk.cyanBright('#### ####'),
286
- chalk.cyanBright('#### Copyright (c) 2023 Jacky Liang. ISC License. ####'),
287
- chalk.cyanBright('##############################################################'),
288
- '',
289
- 'Welcome to the REPL interface for ADT Pulse for Homebridge. This interface',
290
- 'allows you to interact with the ADT Pulse portal via the included API and is designed',
291
- `for advanced users only. ${chalk.redBright('PLEASE USE WITH CAUTION, NO WARRANTY IS PROVIDED.')}`,
292
- '',
293
- `${chalk.bold.yellowBright('NOTICE')}: The API gathers anonymous analytics to detect potential bugs or issues.`,
294
- ' All personally identifiable information redacted. You will see exactly what will be sent out.',
295
- ].join('\n'));
296
- }
297
- }
298
-
299
- const adtPulseRepl = new ADTPulseRepl();
300
- await adtPulseRepl.startRepl();
@@ -1,278 +0,0 @@
1
- import chalk from 'chalk';
2
- import _ from 'lodash';
3
- import { readFileSync } from 'node:fs';
4
- import os from 'node:os';
5
- import { exit, stdin, stdout } from 'node:process';
6
- import readline from 'node:readline';
7
- import util from 'node:util';
8
-
9
- import { ADTPulse } from '@/lib/api.js';
10
- import { platformConfig } from '@/lib/schema.js';
11
- import { debugLog, isForwardSlashOS } from '@/lib/utility.js';
12
- import type {
13
- ADTPulseTestAskQuestionMode,
14
- ADTPulseTestAskQuestionReturns,
15
- ADTPulseTestFindConfigParsedFile,
16
- ADTPulseTestFindConfigPossibleLocations,
17
- ADTPulseTestFindConfigReturns,
18
- ADTPulseTestPrintTestOutputIsSuccess,
19
- ADTPulseTestPrintTestOutputReturns,
20
- ADTPulseTestSelectedConfigLocation,
21
- ADTPulseTestSelectedPlatform,
22
- ADTPulseTestStartTestReturns,
23
- } from '@/types/index.d.ts';
24
-
25
- /**
26
- * ADT Pulse Test.
27
- *
28
- * @since 1.0.0
29
- */
30
- class ADTPulseTest {
31
- /**
32
- * ADT Pulse Test - Selected config location.
33
- *
34
- * @private
35
- *
36
- * @since 1.0.0
37
- */
38
- #selectedConfigLocation: ADTPulseTestSelectedConfigLocation;
39
-
40
- /**
41
- * ADT Pulse Test - Selected platform.
42
- *
43
- * @private
44
- *
45
- * @since 1.0.0
46
- */
47
- #selectedPlatform: ADTPulseTestSelectedPlatform;
48
-
49
- /**
50
- * ADT Pulse Test - Start test.
51
- *
52
- * @returns {ADTPulseTestStartTestReturns}
53
- *
54
- * @since 1.0.0
55
- */
56
- async startTest(): ADTPulseTestStartTestReturns {
57
- try {
58
- const userAcceptedDisclaimer = await ADTPulseTest.askQuestion('disclaimer');
59
-
60
- if (!userAcceptedDisclaimer) {
61
- exit(0);
62
- }
63
-
64
- // Used to pad the user input to the next line.
65
- console.info('\r');
66
-
67
- const configFoundAndSet = this.findConfig();
68
-
69
- if (!configFoundAndSet || this.#selectedPlatform === undefined) {
70
- ADTPulseTest.printTestOutput(false);
71
-
72
- exit(1);
73
- }
74
-
75
- const instance = new ADTPulse(
76
- this.#selectedPlatform,
77
- {
78
- debug: true,
79
- testMode: {
80
- enabled: true,
81
- },
82
- },
83
- );
84
- const instanceFunctions = [
85
- instance.login.bind(instance),
86
- instance.getGatewayInformation.bind(instance),
87
- instance.getPanelInformation.bind(instance),
88
- instance.getPanelStatus.bind(instance),
89
- instance.setPanelStatus.bind(instance, 'away'),
90
- instance.setPanelStatus.bind(instance, 'stay'),
91
- instance.setPanelStatus.bind(instance, 'night'),
92
- instance.setPanelStatus.bind(instance, 'off'),
93
- instance.getSensorsInformation.bind(instance),
94
- instance.getSensorsStatus.bind(instance),
95
- instance.performSyncCheck.bind(instance),
96
- instance.performKeepAlive.bind(instance),
97
- instance.logout.bind(instance),
98
- ];
99
-
100
- for (let i = 0; i < instanceFunctions.length; i += 1) {
101
- const response = await instanceFunctions[i]();
102
-
103
- // If response is not successful, end the test.
104
- if (!response.success) {
105
- ADTPulseTest.printTestOutput(false);
106
-
107
- exit(1);
108
- }
109
-
110
- // Print success responses.
111
- console.info(util.inspect(response, {
112
- showHidden: false,
113
- depth: Infinity,
114
- colors: true,
115
- }));
116
- }
117
-
118
- ADTPulseTest.printTestOutput(true);
119
-
120
- exit(0);
121
- } catch {
122
- ADTPulseTest.printTestOutput(false);
123
-
124
- exit(1);
125
- }
126
- }
127
-
128
- /**
129
- * ADT Pulse Test - Find config.
130
- *
131
- * @private
132
- *
133
- * @returns {ADTPulseTestFindConfigReturns}
134
- *
135
- * @since 1.0.0
136
- */
137
- private findConfig(): ADTPulseTestFindConfigReturns {
138
- const possibleLocations: ADTPulseTestFindConfigPossibleLocations = [
139
- ...(isForwardSlashOS()) ? [
140
- '/homebridge/config.json', // "homebridge" Docker.
141
- '/var/lib/homebridge/config.json', // Debian or Raspbian.
142
- `${os.homedir()}/.homebridge/config.json`, // macOS.
143
- ] : [],
144
- ...(!isForwardSlashOS()) ? [
145
- `${os.homedir()}\\.homebridge\\config.json`, // Windows.
146
- ] : [],
147
- ];
148
-
149
- for (let i = 0; i < possibleLocations.length; i += 1) {
150
- // Don't run again if config location and platform have been selected.
151
- if (this.#selectedConfigLocation !== undefined && this.#selectedPlatform !== undefined) {
152
- break;
153
- }
154
-
155
- debugLog(null, 'test-api.ts', 'info', `Attempt ${i + 1}: Finding the Homebridge config file in "${possibleLocations[i]}"`);
156
-
157
- try {
158
- const rawFile = readFileSync(possibleLocations[i], 'utf-8');
159
- const parsedFile: ADTPulseTestFindConfigParsedFile = JSON.parse(rawFile);
160
- const platforms = _.get(parsedFile, ['platforms']);
161
- const adtPlatform = _.find(platforms, (platform) => _.get(platform, ['platform']) === 'ADTPulse');
162
-
163
- if (adtPlatform !== undefined) {
164
- const validAdtPlatform = platformConfig.safeParse(adtPlatform);
165
-
166
- if (validAdtPlatform.success) {
167
- this.#selectedConfigLocation = possibleLocations[i];
168
- this.#selectedPlatform = validAdtPlatform.data;
169
- }
170
- }
171
- } catch {
172
- this.#selectedConfigLocation = undefined;
173
- this.#selectedPlatform = undefined;
174
- }
175
- }
176
-
177
- if (this.#selectedConfigLocation === undefined || this.#selectedPlatform === undefined) {
178
- debugLog(null, 'test-api.ts', 'error', 'Unable to find a parsable Homebridge config file with a validated "ADTPulse" platform');
179
-
180
- return false;
181
- }
182
-
183
- debugLog(null, 'test-api.ts', 'success', `Found valid Homebridge config in "${this.#selectedConfigLocation}"`);
184
-
185
- return true;
186
- }
187
-
188
- /**
189
- * ADT Pulse Test - Ask question.
190
- *
191
- * @param {ADTPulseTestAskQuestionMode} mode - Mode.
192
- *
193
- * @private
194
- *
195
- * @returns {ADTPulseTestAskQuestionReturns}
196
- *
197
- * @since 1.0.0
198
- */
199
- private static async askQuestion(mode: ADTPulseTestAskQuestionMode): ADTPulseTestAskQuestionReturns {
200
- const rlInterface = readline.createInterface({
201
- input: stdin,
202
- output: stdout,
203
- });
204
- const questions = {
205
- disclaimer: [
206
- chalk.cyanBright('##############################################################'),
207
- chalk.cyanBright('#### ADT Pulse for Homebridge Plugin Test ####'),
208
- chalk.cyanBright('#### https://github.com/mrjackyliang/homebridge-adt-pulse ####'),
209
- chalk.cyanBright('#### ####'),
210
- chalk.cyanBright('#### Copyright (c) 2023 Jacky Liang. ISC License. ####'),
211
- chalk.cyanBright('##############################################################'),
212
- 'Before you begin, please make sure of the following:',
213
- '',
214
- '1. You have the proper authorization to carry out system testing.',
215
- '2. You are currently ON THE PROPERTY where the test is being conducted.',
216
- '3. You have disarmed the system and have >= 1 door/window open.',
217
- '4. You have access to MyADT and have placed the system in test mode.',
218
- '',
219
- `${chalk.redBright('WARNING')}: If you DO NOT have access to MyADT or CANNOT place the system into`,
220
- 'test mode, please DO NOT PROCEED. The author is NOT RESPONSIBLE if the test causes',
221
- 'an accidental trigger or if ADT agents/local authorities become involved.',
222
- '',
223
- `${chalk.bold.yellowBright('NOTICE')}: The API gathers anonymous analytics to detect potential bugs or issues.`,
224
- ' All personally identifiable information redacted. You will see exactly what will be sent out.',
225
- '',
226
- chalk.yellowBright('Type "I Agree" (without quotes) to fully acknowledge that you have read through'),
227
- chalk.yellowBright('and understood the instructions, and agree to the disclaimer above ...'),
228
- '➜ ',
229
- ].join('\n'),
230
- };
231
-
232
- return new Promise((resolve) => {
233
- rlInterface.question(questions[mode], (input) => {
234
- if (input !== 'I Agree') {
235
- resolve(false);
236
- }
237
-
238
- resolve(true);
239
- });
240
- });
241
- }
242
-
243
- /**
244
- * ADT Pulse Test - Print test output.
245
- *
246
- * @param {ADTPulseTestPrintTestOutputIsSuccess} isSuccess - Is success.
247
- *
248
- * @private
249
- *
250
- * @returns {ADTPulseTestPrintTestOutputReturns}
251
- *
252
- * @since 1.0.0
253
- */
254
- private static printTestOutput(isSuccess: ADTPulseTestPrintTestOutputIsSuccess): ADTPulseTestPrintTestOutputReturns {
255
- if (!isSuccess) {
256
- console.info([
257
- '',
258
- chalk.redBright('########################################################################'),
259
- chalk.redBright('##### Test has failed! Please check the error response #####'),
260
- chalk.redBright('##### above, attempt to resolve them, then run this tester again #####'),
261
- chalk.redBright('########################################################################'),
262
- ].join('\n'));
263
-
264
- return;
265
- }
266
-
267
- console.info([
268
- '',
269
- chalk.greenBright('########################################################################'),
270
- chalk.greenBright('##### Test has completed! If you find my plugin useful #####'),
271
- chalk.greenBright('##### please consider donating to my efforts via GitHub Sponsors #####'),
272
- chalk.greenBright('########################################################################'),
273
- ].join('\n'));
274
- }
275
- }
276
-
277
- const instance = new ADTPulseTest();
278
- await instance.startTest();