Skip to content

Commit 5b6d5bb

Browse files
committed
Moderate changes and fixes
### UPDATED - Syncing the `.editorconfig` file. - `parseSensorsTable()` will now skip devices that have a "System/Supervisory" device type. - Renamed the detector functions to match where should they be called from (Api or Platform). - Detector reporting url. - Re-wrote the detector reminder and moved it to after the content. ### FIXED - Incorrect detection of "Status Tampered" in connection with "Trouble" status. - Headers for `test-api.ts` and `repl.ts` files. - `generateFakeReadyButtons()` should not be adding an Arm Night button because this is not available in the portal. - Type for `StackTracerError` was incorrectly defined. ### ADDED - Sensor status support for "Tampered". - Function name type for `detectApiDebugParser()`. ### REMOVED - Support for "System/Supervisory" because it does not show a status in the summary page.
1 parent 2fb1cd5 commit 5b6d5bb

16 files changed

+620
-304
lines changed

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ ij_html_text_wrap = off
4848
[*.php]
4949
indent_size = 4
5050
indent_style = tab
51+
ij_php_indent_code_in_php_tags = true
52+
ij_php_method_brace_style = end_of_line
53+
ij_php_new_line_after_php_opening_tag = true
5154

5255
[{*.markdown,*.md}]
5356
ij_markdown_max_lines_around_block_elements = 0

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ This plugin can expose these devices (in read-only mode) based on your configura
6666
6. `heat` - Heat (Rate-of-Rise) Detector
6767
7. `motion` - Motion Sensor __::__ Motion Sensor (Notable Events Only)
6868
8. `shock` - Shock Sensor
69-
9. `supervisory` - System/Supervisory
70-
10. `temperature` - Temperature Sensor
69+
9. `temperature` - Temperature Sensor
7170

7271
Due to implementation complexity and platform instability, all Z-Wave accessories connected to the ADT Pulse gateway will not be planned for development or be supported overall. Consider purchasing the [Hubitat Hub](https://hubitat.com) for a seamless setup experience, or read about the [Home Assistant Z-Wave](https://www.home-assistant.io/integrations/zwave_js/) integration.
7372

config.schema.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,6 @@
205205
"shock"
206206
]
207207
},
208-
{
209-
"title": "System/Supervisory",
210-
"enum": [
211-
"supervisory"
212-
]
213-
},
214208
{
215209
"title": "Temperature Sensor",
216210
"enum": [

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "homebridge-adt-pulse",
33
"displayName": "Homebridge ADT Pulse",
4-
"version": "3.0.0",
4+
"version": "3.0.1",
55
"description": "Homebridge security system platform for ADT Pulse",
66
"main": "./build/src/index.js",
77
"exports": "./build/src/index.js",

src/lib/accessory.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,6 @@ export class ADTPulseAccessory {
208208
case 'shock':
209209
this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
210210
break;
211-
case 'supervisory':
212-
this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
213-
break;
214211
case 'temperature':
215212
this.#services.Primary = this.#accessory.getService(service.TemperatureSensor) ?? this.#accessory.addService(service.TemperatureSensor);
216213
break;
@@ -327,10 +324,6 @@ export class ADTPulseAccessory {
327324
this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
328325
.updateValue(this.getSensorStatus('status'));
329326
break;
330-
case 'supervisory':
331-
this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
332-
.updateValue(this.getSensorStatus('status'));
333-
break;
334327
case 'temperature':
335328
this.#services.Primary.getCharacteristic(this.#characteristic.CurrentTemperature)
336329
.updateValue(this.getSensorStatus('status'));
@@ -349,7 +342,6 @@ export class ADTPulseAccessory {
349342
case 'heat':
350343
case 'motion':
351344
case 'shock':
352-
case 'supervisory':
353345
case 'temperature':
354346
this.#services.Primary.getCharacteristic(this.#characteristic.StatusActive)
355347
.updateValue(this.getSensorStatus('active'));
@@ -428,6 +420,7 @@ export class ADTPulseAccessory {
428420
if (
429421
statuses.includes('ALARM')
430422
|| statuses.includes('Bypassed')
423+
|| statuses.includes('Trouble')
431424
|| icon === 'devStatAlarm'
432425
) {
433426
return this.#characteristic.StatusFault.GENERAL_FAULT;
@@ -453,7 +446,7 @@ export class ADTPulseAccessory {
453446
if (mode === 'tamper') {
454447
// If status or icon includes these, the sensor is tampered.
455448
if (
456-
statuses.includes('Trouble')
449+
statuses.includes('Tampered')
457450
|| icon === 'devStatTamper'
458451
) {
459452
return this.#characteristic.StatusTampered.TAMPERED;
@@ -533,9 +526,6 @@ export class ADTPulseAccessory {
533526
case 'shock':
534527
break;
535528
// TODO Device type needs to be manually tested and confirmed first.
536-
case 'supervisory':
537-
break;
538-
// TODO Device type needs to be manually tested and confirmed first.
539529
case 'temperature':
540530
/**
541531
* Since sensors from ADT do not show exact temperatures

src/lib/api.ts

Lines changed: 133 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import { serializeError } from 'serialize-error';
66
import { CookieJar } from 'tough-cookie';
77

88
import {
9-
detectedNewDoSubmitHandlers,
10-
detectedNewGatewayInformation,
11-
detectedNewOrbSecurityButtons,
12-
detectedNewPanelInformation,
13-
detectedNewPanelStatus,
14-
detectedNewPortalVersion,
15-
detectedNewSensorsInformation,
16-
detectedNewSensorsStatus,
9+
detectApiDebugParser,
10+
detectApiDoSubmitHandlers,
11+
detectApiGatewayInformation,
12+
detectApiOrbSecurityButtons,
13+
detectApiPanelInformation,
14+
detectApiPanelStatus,
15+
detectApiPortalVersion,
16+
detectApiSensorsInformation,
17+
detectApiSensorsStatus,
1718
} from '@/lib/detect.js';
1819
import {
1920
paramNetworkId,
@@ -41,6 +42,7 @@ import {
4142
generateDynatracePCHeaderValue,
4243
generateFakeReadyButtons,
4344
generateHash,
45+
isEmptyOrbTextSummary,
4446
isPortalSyncCode,
4547
parseArmDisarmMessage,
4648
parseDoSubmitHandlers,
@@ -864,6 +866,20 @@ export class ADTPulse {
864866
*/
865867
await this.newInformationDispatcher('gateway-information', gatewayInformation);
866868

869+
// If the parsing function may be parsing data incorrectly.
870+
if (Object.keys(fetchedTableCells).length !== 18) {
871+
if (this.#internal.debug) {
872+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getGatewayInformation()', 'warn', 'The fetchTableCells() function may be parsing the gateway information incorrectly');
873+
}
874+
875+
await this.newInformationDispatcher('debug-parser', {
876+
parserName: 'fetchTableCells()',
877+
parserReason: 'length does not equal to 18',
878+
parserResponse: fetchedTableCells,
879+
rawData: sessions.axiosSystemGateway.data,
880+
});
881+
}
882+
867883
if (this.#internal.debug) {
868884
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getGatewayInformation()', 'success', `Successfully retrieved gateway information from "${this.#internal.baseUrl}"`);
869885
}
@@ -1062,6 +1078,20 @@ export class ADTPulse {
10621078
*/
10631079
await this.newInformationDispatcher('panel-information', panelInformation);
10641080

1081+
// If the parsing function may be parsing data incorrectly.
1082+
if (Object.keys(fetchedTableCells).length !== 5) {
1083+
if (this.#internal.debug) {
1084+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getPanelInformation()', 'warn', 'The fetchTableCells() function may be parsing the panel information incorrectly');
1085+
}
1086+
1087+
await this.newInformationDispatcher('debug-parser', {
1088+
parserName: 'fetchTableCells()',
1089+
parserReason: 'length does not equal to 5',
1090+
parserResponse: fetchedTableCells,
1091+
rawData: sessions.axiosSystemDeviceId1.data,
1092+
});
1093+
}
1094+
10651095
if (this.#internal.debug) {
10661096
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getPanelInformation()', 'success', `Successfully retrieved panel information from "${this.#internal.baseUrl}"`);
10671097
}
@@ -1277,6 +1307,20 @@ export class ADTPulse {
12771307
*/
12781308
await this.newInformationDispatcher('panel-status', parsedOrbTextSummary);
12791309

1310+
// If the parsing function may be parsing data incorrectly.
1311+
if (isEmptyOrbTextSummary(parsedOrbTextSummary)) {
1312+
if (this.#internal.debug) {
1313+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getPanelStatus()', 'warn', 'The parseOrbTextSummary() function may be parsing sensors information incorrectly');
1314+
}
1315+
1316+
await this.newInformationDispatcher('debug-parser', {
1317+
parserName: 'parseOrbTextSummary()',
1318+
parserReason: 'empty response',
1319+
parserResponse: parsedOrbTextSummary,
1320+
rawData: sessions.axiosSummary.data,
1321+
});
1322+
}
1323+
12801324
if (this.#internal.debug) {
12811325
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getPanelStatus()', 'success', `Successfully retrieved panel status from "${this.#internal.baseUrl}"`);
12821326
}
@@ -1593,6 +1637,20 @@ export class ADTPulse {
15931637
*/
15941638
await this.newInformationDispatcher('orb-security-buttons', parsedOrbSecurityButtons);
15951639

1640+
// If the parsing function may be parsing data incorrectly.
1641+
if (parsedOrbSecurityButtons.length < 1 || parsedOrbSecurityButtons.length > 3) {
1642+
if (this.#internal.debug) {
1643+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.setPanelStatus()', 'warn', 'The parseOrbSecurityButtons() function may be parsing the orb security buttons incorrectly');
1644+
}
1645+
1646+
await this.newInformationDispatcher('debug-parser', {
1647+
parserName: 'parseOrbSecurityButtons()',
1648+
parserReason: 'length is not between 1 to 3',
1649+
parserResponse: parsedOrbSecurityButtons,
1650+
rawData: sessions.axiosSummary.data,
1651+
});
1652+
}
1653+
15961654
// Only keep all ready (enabled) orb security buttons.
15971655
let readyButtons = parsedOrbSecurityButtons.filter((parsedOrbSecurityButton): parsedOrbSecurityButton is ADTPulseSetPanelStatusReadyButton => !parsedOrbSecurityButton.buttonDisabled);
15981656

@@ -1923,7 +1981,6 @@ export class ADTPulse {
19231981
* 'Motion Sensor'
19241982
* 'Motion Sensor (Notable Events Only)'
19251983
* 'Shock Sensor'
1926-
* 'System/Supervisory'
19271984
* 'Temperature Sensor'
19281985
* 'Water/Flood Sensor'
19291986
* 'Window Sensor'
@@ -1937,6 +1994,20 @@ export class ADTPulse {
19371994
*/
19381995
await this.newInformationDispatcher('sensors-information', parsedSensorsTable);
19391996

1997+
// If the parsing function may be parsing data incorrectly.
1998+
if (parsedSensorsTable.length < 1) {
1999+
if (this.#internal.debug) {
2000+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getSensorsInformation()', 'warn', 'The parseSensorsTable() function may be parsing the sensors table incorrectly');
2001+
}
2002+
2003+
await this.newInformationDispatcher('debug-parser', {
2004+
parserName: 'parseSensorsTable()',
2005+
parserReason: 'length is not 1 or more',
2006+
parserResponse: parsedSensorsTable,
2007+
rawData: sessions.axiosSystem.data,
2008+
});
2009+
}
2010+
19402011
if (this.#internal.debug) {
19412012
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getSensorsInformation()', 'success', `Successfully retrieved sensors information from "${this.#internal.baseUrl}"`);
19422013
}
@@ -2175,6 +2246,20 @@ export class ADTPulse {
21752246
*/
21762247
await this.newInformationDispatcher('sensors-status', parsedOrbSensors);
21772248

2249+
// If the parsing function may be parsing data incorrectly.
2250+
if (parsedOrbSensors.length < 1) {
2251+
if (this.#internal.debug) {
2252+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getSensorsStatus()', 'warn', 'The parseOrbSensors() function may be parsing the orb sensors incorrectly');
2253+
}
2254+
2255+
await this.newInformationDispatcher('debug-parser', {
2256+
parserName: 'parseOrbSensors()',
2257+
parserReason: 'length is not 1 or more',
2258+
parserResponse: parsedOrbSensors,
2259+
rawData: sessions.axiosSummary.data,
2260+
});
2261+
}
2262+
21782263
if (this.#internal.debug) {
21792264
debugLog(this.#internal.logger, 'api.ts / ADTPulse.getSensorsStatus()', 'success', `Successfully retrieved sensors status from "${this.#internal.baseUrl}"`);
21802265
}
@@ -2888,6 +2973,20 @@ export class ADTPulse {
28882973
*/
28892974
await this.newInformationDispatcher('orb-security-buttons', parsedOrbSecurityButtons);
28902975

2976+
// If the parsing function may be parsing data incorrectly.
2977+
if (parsedOrbSecurityButtons.length < 1 || parsedOrbSecurityButtons.length > 3) {
2978+
if (this.#internal.debug) {
2979+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'warn', 'The parseOrbSecurityButtons() function may be parsing the orb security buttons incorrectly');
2980+
}
2981+
2982+
await this.newInformationDispatcher('debug-parser', {
2983+
parserName: 'parseOrbSecurityButtons()',
2984+
parserReason: 'length is not between 1 to 3',
2985+
parserResponse: parsedOrbSecurityButtons,
2986+
rawData: sessions.axiosSummary.data,
2987+
});
2988+
}
2989+
28912990
let readyButtons = parsedOrbSecurityButtons.filter((parsedOrbSecurityButton): parsedOrbSecurityButton is ADTPulseArmDisarmHandlerReadyButton => !parsedOrbSecurityButton.buttonDisabled);
28922991

28932992
// Generate "fake" ready buttons if arming tasks become stuck.
@@ -3050,6 +3149,20 @@ export class ADTPulse {
30503149
*/
30513150
await this.newInformationDispatcher('do-submit-handlers', parsedDoSubmitHandlers);
30523151

3152+
// If the parsing function may be parsing data incorrectly.
3153+
if (parsedDoSubmitHandlers.length !== 2) {
3154+
if (this.#internal.debug) {
3155+
debugLog(this.#internal.logger, 'api.ts / ADTPulse.armDisarmHandler()', 'warn', 'The parseDoSubmitHandlers() function may be parsing the do submit handlers incorrectly');
3156+
}
3157+
3158+
await this.newInformationDispatcher('debug-parser', {
3159+
parserName: 'parseDoSubmitHandlers()',
3160+
parserReason: 'length does not equal to 2',
3161+
parserResponse: parsedDoSubmitHandlers,
3162+
rawData: response.data,
3163+
});
3164+
}
3165+
30533166
// Check if there are no force arm buttons available.
30543167
if (
30553168
parsedDoSubmitHandlers.length === 0
@@ -3314,29 +3427,32 @@ export class ADTPulse {
33143427

33153428
// Determine what information needs to be checked.
33163429
switch (type) {
3430+
case 'debug-parser':
3431+
detectedNew = await detectApiDebugParser(data as ADTPulseNewInformationDispatcherData<'debug-parser'>, this.#internal.logger, this.#internal.debug);
3432+
break;
33173433
case 'do-submit-handlers':
3318-
detectedNew = await detectedNewDoSubmitHandlers(data as ADTPulseNewInformationDispatcherData<'do-submit-handlers'>, this.#internal.logger, this.#internal.debug);
3434+
detectedNew = await detectApiDoSubmitHandlers(data as ADTPulseNewInformationDispatcherData<'do-submit-handlers'>, this.#internal.logger, this.#internal.debug);
33193435
break;
33203436
case 'gateway-information':
3321-
detectedNew = await detectedNewGatewayInformation(data as ADTPulseNewInformationDispatcherData<'gateway-information'>, this.#internal.logger, this.#internal.debug);
3437+
detectedNew = await detectApiGatewayInformation(data as ADTPulseNewInformationDispatcherData<'gateway-information'>, this.#internal.logger, this.#internal.debug);
33223438
break;
33233439
case 'orb-security-buttons':
3324-
detectedNew = await detectedNewOrbSecurityButtons(data as ADTPulseNewInformationDispatcherData<'orb-security-buttons'>, this.#internal.logger, this.#internal.debug);
3440+
detectedNew = await detectApiOrbSecurityButtons(data as ADTPulseNewInformationDispatcherData<'orb-security-buttons'>, this.#internal.logger, this.#internal.debug);
33253441
break;
33263442
case 'panel-information':
3327-
detectedNew = await detectedNewPanelInformation(data as ADTPulseNewInformationDispatcherData<'panel-information'>, this.#internal.logger, this.#internal.debug);
3443+
detectedNew = await detectApiPanelInformation(data as ADTPulseNewInformationDispatcherData<'panel-information'>, this.#internal.logger, this.#internal.debug);
33283444
break;
33293445
case 'panel-status':
3330-
detectedNew = await detectedNewPanelStatus(data as ADTPulseNewInformationDispatcherData<'panel-status'>, this.#internal.logger, this.#internal.debug);
3446+
detectedNew = await detectApiPanelStatus(data as ADTPulseNewInformationDispatcherData<'panel-status'>, this.#internal.logger, this.#internal.debug);
33313447
break;
33323448
case 'portal-version':
3333-
detectedNew = await detectedNewPortalVersion(data as ADTPulseNewInformationDispatcherData<'portal-version'>, this.#internal.logger, this.#internal.debug);
3449+
detectedNew = await detectApiPortalVersion(data as ADTPulseNewInformationDispatcherData<'portal-version'>, this.#internal.logger, this.#internal.debug);
33343450
break;
33353451
case 'sensors-information':
3336-
detectedNew = await detectedNewSensorsInformation(data as ADTPulseNewInformationDispatcherData<'sensors-information'>, this.#internal.logger, this.#internal.debug);
3452+
detectedNew = await detectApiSensorsInformation(data as ADTPulseNewInformationDispatcherData<'sensors-information'>, this.#internal.logger, this.#internal.debug);
33373453
break;
33383454
case 'sensors-status':
3339-
detectedNew = await detectedNewSensorsStatus(data as ADTPulseNewInformationDispatcherData<'sensors-status'>, this.#internal.logger, this.#internal.debug);
3455+
detectedNew = await detectApiSensorsStatus(data as ADTPulseNewInformationDispatcherData<'sensors-status'>, this.#internal.logger, this.#internal.debug);
33403456
break;
33413457
default:
33423458
break;

0 commit comments

Comments
 (0)