Skip to content

Commit 2efa519

Browse files
committed
New features
### FIXED - Label for `test-api-logs` in `BUG-REPORT.yml` did not convert to markdown properly since it is unsupported. ### ADDED - Advanced options to disable the "Alarm Ringing" switch and to "Ignore Sensor Problem Status". ### PLEASE READ - The configuration has changed. Please add `"options": [],` to the configuration before upgrading or you will not be able to start the plugin.
1 parent 89e4ac6 commit 2efa519

File tree

10 files changed

+145
-29
lines changed

10 files changed

+145
-29
lines changed

.github/ISSUE_TEMPLATE/BUG-REPORT.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ body:
7171
- type: textarea
7272
id: test-api-logs
7373
attributes:
74-
label: Log output of the `test-api` command
74+
label: Log output of the "test-api" command
7575
description: From the Homebridge plugin path, most likely will be `/var/lib/homebridge/node_modules`, run this command `cd homebridge-adt-pulse && npm run test-api` and paste in the results below. __Do not include logs from other commands.__ This block will be automatically formatted into code, so __no need for backticks__.
7676
render: Shell
7777
validations:

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Here is an example of how the `config.json` file for this plugin should be confi
3232
"fingerprint": "VGhpc0lzQVNlY3VyZVBhc3N3b3JkMTIzIQ==",
3333
"mode": "normal",
3434
"speed": 1,
35+
"options": [],
3536
"sensors": [
3637
{
3738
"name": "Family Room Couch Window 1",
@@ -111,6 +112,20 @@ However, for certain consumer routers, this plugin may induce a network slowdown
111112

112113
If the plugin does not operate under "Normal" mode, a warning will be issued on every startup, and this warning cannot be disabled.
113114

115+
## Specifying Advanced Options
116+
Each alarm system is uniquely designed, and at times, functionalities may not align with your preferences.
117+
118+
The options provided give you the flexibility to deactivate specific aspects of the plugin; however, please exercise caution, as doing so may result in the loss of expected functionality.
119+
120+
- __To disable the "Alarm Ringing" switch:__
121+
- Include the `"disableAlarmRingingSwitch"` value in the `options` array.
122+
- ⚠️ Enabling this option will prevent you from being able to silence a ringing alarm when the system is in "Disarmed" mode.
123+
- __To ignore "Sensor Problem" statuses:__
124+
- Include the `"ignoreSensorProblemStatus"` value in the `options` array.
125+
- ⚠️ Enabling this option will prevent you from being able to silence a ringing alarm triggered by a "Sensor Problem" or "Sensor Problems" status.
126+
127+
If the `options` array is not empty, a warning will be displayed upon every startup for every enabled option, and this warning cannot be disabled.
128+
114129
## Specifying the Sensors
115130
In the past, this plugin would automatically detect sensors and dynamically manage their addition and removal based on its observations.
116131

@@ -158,6 +173,24 @@ Consumers would enable debug mode, but forget to also enable Homebridge debug mo
158173

159174
To improve this, debug mode is now activated __ONLY when debug mode is enabled on Homebridge__ itself. This approach promotes isolation (logs can be separated for each bridge) and helps enhance the troubleshooting experience in case any issues arise.
160175

176+
## API Test and REPL Playground Scripts
177+
If any unusual occurrences arise, utilize the provided `test-api` or `repl` commands within this plugin to troubleshoot potential issues.
178+
179+
- To confirm if the plugin is communicating with the portal correctly, use the command `npm run test-api`.
180+
- To access the playground (Read-eval-print loop mode), use the command `npm run repl`.
181+
182+
Ensure you are inside the `node_modules/homebridge-adt-pulse` directory when attempting to access these commands. The location of `node_modules` may vary based on the system you are using:
183+
- [Raspbian](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Raspbian#configuration-reference)
184+
- [Debian or Ubuntu Linux](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Debian-or-Ubuntu-Linux#configuration-reference)
185+
- [Red Hat, CentOS or Fedora Linux](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Red-Hat%2C-CentOS-or-Fedora-Linux#configuration-reference)
186+
- [Arch Linux](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Arch-Linux#configuration-reference)
187+
- [macOS](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-macOS#configuration-reference)
188+
- [Windows 10 Using Hyper V](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Windows-10-Using-Hyper-V#configuration-reference)
189+
- [Docker](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Docker#configuration-reference)
190+
- [Unraid](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-Unraid#configuration-reference)
191+
- [TrueNAS Scale](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-TrueNAS-Scale#configuration-reference)
192+
- [Synology DSM](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Synology-DSM#configuration-reference)
193+
161194
## Temperature Sensors in HAP Protocol
162195
The Temperature Sensor (`temperature`) functions differently compared to standard contact sensors when it comes to processing sensor statuses.
163196

config.schema.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,19 @@
125125
],
126126
"default": 1
127127
},
128+
"options": {
129+
"title": "Advanced Options",
130+
"type": "array",
131+
"required": true,
132+
"description": "Customize the features of this plugin. Please note these advanced options will disable expected functionality. Only enable them if necessary.",
133+
"items": {
134+
"type": "string",
135+
"enum": [
136+
"disableAlarmRingingSwitch",
137+
"ignoreSensorProblemStatus"
138+
]
139+
}
140+
},
128141
"sensors": {
129142
"title": "Sensors",
130143
"type": "array",
@@ -248,6 +261,20 @@
248261
{
249262
"key": "speed",
250263
"type": "select"
264+
},
265+
{
266+
"key": "options",
267+
"type": "checkboxes",
268+
"titleMap": [
269+
{
270+
"value": "disableAlarmRingingSwitch",
271+
"name": "Disable \"Alarm Ringing\" switch"
272+
},
273+
{
274+
"value": "ignoreSensorProblemStatus",
275+
"name": "Ignore Sensor Problem Status"
276+
}
277+
]
251278
}
252279
]
253280
},

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.6",
4+
"version": "3.1.0",
55
"description": "Homebridge security system platform for ADT Pulse",
66
"main": "./build/index.js",
77
"exports": "./build/index.js",

src/lib/accessory.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ import type {
1212
ADTPulseAccessoryActivity,
1313
ADTPulseAccessoryApi,
1414
ADTPulseAccessoryCharacteristic,
15+
ADTPulseAccessoryConfig,
1516
ADTPulseAccessoryConstructorAccessory,
1617
ADTPulseAccessoryConstructorApi,
1718
ADTPulseAccessoryConstructorCharacteristic,
19+
ADTPulseAccessoryConstructorConfig,
1820
ADTPulseAccessoryConstructorInstance,
1921
ADTPulseAccessoryConstructorLog,
2022
ADTPulseAccessoryConstructorService,
@@ -77,6 +79,15 @@ export class ADTPulseAccessory {
7779
*/
7880
readonly #characteristic: ADTPulseAccessoryCharacteristic;
7981

82+
/**
83+
* ADT Pulse Accessory - Config.
84+
*
85+
* @private
86+
*
87+
* @since 1.0.0
88+
*/
89+
#config: ADTPulseAccessoryConfig;
90+
8091
/**
8192
* ADT Pulse Accessory - Instance.
8293
*
@@ -118,6 +129,7 @@ export class ADTPulseAccessory {
118129
*
119130
* @param {ADTPulseAccessoryConstructorAccessory} accessory - Accessory.
120131
* @param {ADTPulseAccessoryConstructorState} state - State.
132+
* @param {ADTPulseAccessoryConstructorConfig} config - Config.
121133
* @param {ADTPulseAccessoryConstructorInstance} instance - Instance.
122134
* @param {ADTPulseAccessoryConstructorService} service - Service.
123135
* @param {ADTPulseAccessoryConstructorCharacteristic} characteristic - Characteristic.
@@ -126,7 +138,7 @@ export class ADTPulseAccessory {
126138
*
127139
* @since 1.0.0
128140
*/
129-
public constructor(accessory: ADTPulseAccessoryConstructorAccessory, state: ADTPulseAccessoryConstructorState, instance: ADTPulseAccessoryConstructorInstance, service: ADTPulseAccessoryConstructorService, characteristic: ADTPulseAccessoryConstructorCharacteristic, api: ADTPulseAccessoryConstructorApi, log: ADTPulseAccessoryConstructorLog) {
141+
public constructor(accessory: ADTPulseAccessoryConstructorAccessory, state: ADTPulseAccessoryConstructorState, config: ADTPulseAccessoryConstructorConfig, instance: ADTPulseAccessoryConstructorInstance, service: ADTPulseAccessoryConstructorService, characteristic: ADTPulseAccessoryConstructorCharacteristic, api: ADTPulseAccessoryConstructorApi, log: ADTPulseAccessoryConstructorLog) {
130142
this.#accessory = accessory;
131143
this.#activity = {
132144
isBusy: false,
@@ -136,6 +148,7 @@ export class ADTPulseAccessory {
136148
};
137149
this.#api = api;
138150
this.#characteristic = characteristic;
151+
this.#config = config;
139152
this.#instance = instance;
140153
this.#log = log;
141154
this.#services = {};
@@ -613,7 +626,7 @@ export class ADTPulseAccessory {
613626

614627
// Find the state for "Security System Alarm Type" (optional characteristic).
615628
if (mode === 'alarmType') {
616-
if (isPanelAlarmActive(panelStatuses)) {
629+
if (isPanelAlarmActive(panelStatuses, this.#config?.options.includes('ignoreSensorProblemStatus') ?? false)) {
617630
return 1;
618631
}
619632

@@ -649,7 +662,7 @@ export class ADTPulseAccessory {
649662
switch (true) {
650663
case mode === 'current' && this.#activity.isBusy && this.#activity.setCurrentValue !== null:
651664
return this.#activity.setCurrentValue;
652-
case mode === 'current' && isPanelAlarmActive(panelStatuses):
665+
case mode === 'current' && isPanelAlarmActive(panelStatuses, this.#config?.options.includes('ignoreSensorProblemStatus') ?? false):
653666
return this.#characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED;
654667
case mode === 'current' && panelStates.includes('Armed Stay'):
655668
return this.#characteristic.SecuritySystemCurrentState.STAY_ARM;
@@ -735,7 +748,7 @@ export class ADTPulseAccessory {
735748
}
736749

737750
// Only show as "On" if alarm is ringing.
738-
return isPanelAlarmActive(panelStatuses);
751+
return isPanelAlarmActive(panelStatuses, this.#config?.options.includes('ignoreSensorProblemStatus') ?? false);
739752
}
740753

741754
/**
@@ -785,7 +798,7 @@ export class ADTPulseAccessory {
785798
const { panelStates } = this.#state.data.panelStatus;
786799

787800
const condensedPanelStates = condensePanelStates(this.#characteristic, panelStates);
788-
const isAlarmActive = isPanelAlarmActive(this.#state.data.panelStatus.panelStatuses);
801+
const isAlarmActive = isPanelAlarmActive(this.#state.data.panelStatus.panelStatuses, this.#config?.options.includes('ignoreSensorProblemStatus') ?? false);
789802

790803
// If panel status cannot be found or most likely "Status Unavailable".
791804
if (condensedPanelStates === undefined) {
@@ -924,7 +937,7 @@ export class ADTPulseAccessory {
924937
const { panelStates } = this.#state.data.panelStatus;
925938

926939
const condensedPanelStates = condensePanelStates(this.#characteristic, panelStates);
927-
const isAlarmActive = isPanelAlarmActive(this.#state.data.panelStatus.panelStatuses);
940+
const isAlarmActive = isPanelAlarmActive(this.#state.data.panelStatus.panelStatuses, this.#config?.options.includes('ignoreSensorProblemStatus') ?? false);
928941

929942
// If panel status cannot be found or most likely "Status Unavailable".
930943
if (condensedPanelStates === undefined) {

src/lib/platform.ts

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ export class ADTPulsePlatform implements ADTPulsePlatformPlugin {
234234
// Check for a valid platform configuration before initializing.
235235
if (!parsedConfig.success) {
236236
this.#log.error('Plugin is unable to initialize due to an invalid platform configuration.');
237-
this.#log.warn('If you just upgraded from v2 to v3, please update your configuration structure.');
237+
this.#log.warn('If you just upgraded from v2 to v3 / v3.1, please update your configuration structure.');
238238
stackTracer('zod-error', parsedConfig.error.errors);
239239

240240
return;
@@ -314,6 +314,16 @@ export class ADTPulsePlatform implements ADTPulsePlatformPlugin {
314314
this.#constants.intervalTimestamps.synchronize *= (1 / this.#config.speed);
315315
}
316316

317+
// If the config specifies that the plugin should disable the "Alarm Ringing" switch.
318+
if (this.#config.options.includes('disableAlarmRingingSwitch')) {
319+
this.#log.warn('Plugin accessory for "Alarm Ringing" is disabled. You will NOT be able to silence a ringing alarm when the system is in "Disarmed" mode.');
320+
}
321+
322+
// If the config specifies that the plugin should ignore "Sensor Problem" and "Sensor Problems" statuses.
323+
if (this.#config.options.includes('ignoreSensorProblemStatus')) {
324+
this.#log.warn('Plugin ignoring "Sensor Problem" and "Sensor Problems" statuses. You will not be able to silence a ringing alarm triggered by a "Sensor Problem" or "Sensor Problems" status.');
325+
}
326+
317327
// Initialize the API instance.
318328
this.#instance = new ADTPulse(
319329
this.#config,
@@ -391,6 +401,7 @@ export class ADTPulsePlatform implements ADTPulsePlatformPlugin {
391401
this.#handlers[device.id] = new ADTPulseAccessory(
392402
typedAccessory,
393403
this.#state,
404+
this.#config,
394405
this.#instance,
395406
this.#service,
396407
this.#characteristic,
@@ -453,6 +464,7 @@ export class ADTPulsePlatform implements ADTPulsePlatformPlugin {
453464
this.#handlers[device.id] = new ADTPulseAccessory(
454465
value,
455466
this.#state,
467+
this.#config,
456468
this.#instance,
457469
this.#service,
458470
this.#characteristic,
@@ -1088,21 +1100,23 @@ export class ADTPulsePlatform implements ADTPulsePlatformPlugin {
10881100
});
10891101

10901102
// A separate switch designed to turn off ringing alarm while in "Disarmed" state.
1091-
devices.push({
1092-
id: idSwitch,
1093-
name: 'Alarm Ringing',
1094-
originalName: 'Alarm Ringing',
1095-
type: 'panelSwitch',
1096-
zone: null,
1097-
category: 'SWITCH',
1098-
manufacturer: 'ADT Pulse for Homebridge',
1099-
model: 'N/A',
1100-
serial: 'N/A',
1101-
firmware: null,
1102-
hardware: null,
1103-
software: getPackageVersion(),
1104-
uuid: this.#api.hap.uuid.generate(idSwitch),
1105-
});
1103+
if (this.#config !== null && !this.#config.options.includes('disableAlarmRingingSwitch')) {
1104+
devices.push({
1105+
id: idSwitch,
1106+
name: 'Alarm Ringing',
1107+
originalName: 'Alarm Ringing',
1108+
type: 'panelSwitch',
1109+
zone: null,
1110+
category: 'SWITCH',
1111+
manufacturer: 'ADT Pulse for Homebridge',
1112+
model: 'N/A',
1113+
serial: 'N/A',
1114+
firmware: null,
1115+
hardware: null,
1116+
software: getPackageVersion(),
1117+
uuid: this.#api.hap.uuid.generate(idSwitch),
1118+
});
1119+
}
11061120
}
11071121

11081122
// Add sensors as an accessory.
@@ -1156,11 +1170,16 @@ export class ADTPulsePlatform implements ADTPulsePlatformPlugin {
11561170

11571171
// Check if accessories were removed from config.
11581172
if (this.#config !== null) {
1159-
const { sensors } = this.#config;
1173+
const { options, sensors } = this.#config;
11601174

11611175
for (let i = this.#accessories.length - 1; i >= 0; i -= 1) {
11621176
const { originalName, type, zone } = this.#accessories[i].context;
11631177

1178+
// Remove the "panelSwitch" since the user disabled it.
1179+
if (type === 'panelSwitch' && options.includes('disableAlarmRingingSwitch')) {
1180+
this.removeAccessory(this.#accessories[i], 'user disabled this feature');
1181+
}
1182+
11641183
// If current accessory is a "gateway", "panel", or "panelSwitch", skip check.
11651184
if (type === 'gateway' || type === 'panel' || type === 'panelSwitch') {
11661185
continue;

src/lib/schema.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ export const platformConfig = z.object({
2626
z.literal(0.5),
2727
z.literal(0.25),
2828
]),
29+
options: z.array(z.union([
30+
z.literal('disableAlarmRingingSwitch'),
31+
z.literal('ignoreSensorProblemStatus'),
32+
])),
2933
sensors: z.array(z.object({
3034
name: z.string().min(1).max(50).optional(),
3135
adtName: z.string().min(1).max(100),

src/lib/utility.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import type {
8181
IsEmptyOrbTextSummaryMatch,
8282
IsEmptyOrbTextSummaryReturns,
8383
IsForwardSlashOSReturns,
84+
IsPanelAlarmActiveIgnoreSensorProblem,
8485
IsPanelAlarmActivePanelStatuses,
8586
IsPanelAlarmActiveReturns,
8687
IsPluginOutdatedReturns,
@@ -861,19 +862,26 @@ export function isForwardSlashOS(): IsForwardSlashOSReturns {
861862
/**
862863
* Is panel alarm active.
863864
*
864-
* @param {IsPanelAlarmActivePanelStatuses} panelStatuses - Panel statuses.
865+
* @param {IsPanelAlarmActivePanelStatuses} panelStatuses - Panel statuses.
866+
* @param {IsPanelAlarmActiveIgnoreSensorProblem} ignoreSensorProblem - Ignore sensor problem.
865867
*
866868
* @returns {IsPanelAlarmActiveReturns}
867869
*
868870
* @since 1.0.0
869871
*/
870-
export function isPanelAlarmActive(panelStatuses: IsPanelAlarmActivePanelStatuses): IsPanelAlarmActiveReturns {
872+
export function isPanelAlarmActive(panelStatuses: IsPanelAlarmActivePanelStatuses, ignoreSensorProblem: IsPanelAlarmActiveIgnoreSensorProblem): IsPanelAlarmActiveReturns {
871873
return (
872874
panelStatuses.includes('BURGLARY ALARM')
873875
|| panelStatuses.includes('Carbon Monoxide Alarm')
874876
|| panelStatuses.includes('FIRE ALARM')
875-
|| panelStatuses.includes('Sensor Problem') // User must fix the sensor issue before "Triggered" in Home app will go away.
876-
|| panelStatuses.includes('Sensor Problems') // User must fix the sensor issue before "Triggered" in Home app will go away.
877+
|| (
878+
panelStatuses.includes('Sensor Problem')
879+
&& !ignoreSensorProblem
880+
)
881+
|| (
882+
panelStatuses.includes('Sensor Problems')
883+
&& !ignoreSensorProblem
884+
)
877885
|| panelStatuses.includes('Uncleared Alarm')
878886
|| panelStatuses.includes('WATER ALARM')
879887
);

src/scripts/repl.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ class ADTPulseRepl {
166166
fingerprint,
167167
mode: 'normal',
168168
speed: 1,
169+
options: [],
169170
sensors: [],
170171
}, {
171172
debug: true,

src/types/index.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,13 @@ export type ADTPulseAccessoryApi = API;
534534
*/
535535
export type ADTPulseAccessoryCharacteristic = typeof Characteristic;
536536

537+
/**
538+
* ADT Pulse Accessory - Config.
539+
*
540+
* @since 1.0.0
541+
*/
542+
export type ADTPulseAccessoryConfig = ADTPulsePlatformConfig;
543+
537544
/**
538545
* ADT Pulse Accessory - Constructor.
539546
*
@@ -543,6 +550,8 @@ export type ADTPulseAccessoryConstructorAccessory = PlatformAccessory<Device>;
543550

544551
export type ADTPulseAccessoryConstructorState = ADTPulsePlatformState;
545552

553+
export type ADTPulseAccessoryConstructorConfig = ADTPulsePlatformConfig;
554+
546555
export type ADTPulseAccessoryConstructorInstance = ADTPulse;
547556

548557
export type ADTPulseAccessoryConstructorService = typeof Service;
@@ -1575,6 +1584,8 @@ export type IsForwardSlashOSReturns = boolean;
15751584
*/
15761585
export type IsPanelAlarmActivePanelStatuses = PanelStatusStatuses;
15771586

1587+
export type IsPanelAlarmActiveIgnoreSensorProblem = boolean;
1588+
15781589
export type IsPanelAlarmActiveReturns = boolean;
15791590

15801591
/**

0 commit comments

Comments
 (0)