homebridge-adt-pulse 3.0.0-beta.23 → 3.0.0-beta.24

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.
package/README.md CHANGED
@@ -1,11 +1,6 @@
1
1
  ADT Pulse for Homebridge
2
2
  =========================
3
3
 
4
- ### ⚠️ Please Install the Beta Version ⚠️
5
- This plugin is completely re-written from the ground up (supports v27.0.0-140), and I would love everyone on board! Please install the beta version, so I can quickly get a faster and more stable version to you!
6
-
7
- Please bear with me, as the beta version is being actively developed and tested. If you see any unusual or annoying bugs, please comment on this [GitHub issue](https://github.com/mrjackyliang/homebridge-adt-pulse/issues/124).
8
-
9
4
  [![NPM Package](https://img.shields.io/npm/v/homebridge-adt-pulse?style=flat-square&logo=npm&logoColor=%23ffffff&color=%23b25da6)](https://www.npmjs.com/package/homebridge-adt-pulse)
10
5
  [![NPM Downloads](https://img.shields.io/npm/dt/homebridge-adt-pulse?style=flat-square&logo=npm&logoColor=%23ffffff&color=%236688c3)](https://www.npmjs.com/package/homebridge-adt-pulse)
11
6
  [![GitHub License](https://img.shields.io/github/license/mrjackyliang/homebridge-adt-pulse?style=flat-square&logo=googledocs&logoColor=%23ffffff&color=%2348a56a)](https://github.com/mrjackyliang/homebridge-adt-pulse/blob/main/LICENSE)
@@ -71,7 +66,8 @@ This plugin can expose these devices (in read-only mode) based on your configura
71
66
  6. `heat` - Heat (Rate-of-Rise) Detector
72
67
  7. `motion` - Motion Sensor __::__ Motion Sensor (Notable Events Only)
73
68
  8. `shock` - Shock Sensor
74
- 9. `temperature` - Temperature Sensor
69
+ 9. `supervisory` - System/Supervisory
70
+ 10. `temperature` - Temperature Sensor
75
71
 
76
72
  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.
77
73
 
@@ -162,6 +158,14 @@ Consumers would enable debug mode, but forget to also enable Homebridge debug mo
162
158
 
163
159
  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.
164
160
 
161
+ ## Temperature Sensors in HAP Protocol
162
+ The Temperature Sensor (`temperature`) functions differently compared to standard contact sensors when it comes to processing sensor statuses.
163
+
164
+ In contrast to typical contact sensors that convey open or closed status, the temperature sensor exposed in the Home app (utilizing the HAP protocol) operates with temperature values. To accommodate this difference, the accessory converts these binary states into corresponding temperature degrees:
165
+ - Cold temperatures are represented as __0°C__.
166
+ - Normal temperatures are indicated as __20°C__.
167
+ - Hot temperatures are reflected as __40°C__.
168
+
165
169
  ## Support for HOOBS
166
170
  Please note that HOOBS may use an outdated configuration UI. This issue that was reported by me, remains unresolved by the HOOBS team. For additional details, refer to this [GitHub issue](https://github.com/hoobs-org/HOOBS/issues/1873).
167
171
 
@@ -205,6 +205,12 @@
205
205
  "shock"
206
206
  ]
207
207
  },
208
+ {
209
+ "title": "System/Supervisory",
210
+ "enum": [
211
+ "supervisory"
212
+ ]
213
+ },
208
214
  {
209
215
  "title": "Temperature Sensor",
210
216
  "enum": [
@@ -1,6 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { condensedSensorTypeItems } from './items.js';
3
- import { condensePanelStates, stackTracer } from './utility.js';
3
+ import { condensePanelStates, isPanelAlarmActive, stackTracer } from './utility.js';
4
4
  export class ADTPulseAccessory {
5
5
  #accessory;
6
6
  #api;
@@ -9,6 +9,7 @@ export class ADTPulseAccessory {
9
9
  #log;
10
10
  #services;
11
11
  #state;
12
+ #status;
12
13
  constructor(accessory, state, instance, service, characteristic, api, log) {
13
14
  this.#accessory = accessory;
14
15
  this.#api = api;
@@ -17,8 +18,12 @@ export class ADTPulseAccessory {
17
18
  this.#log = log;
18
19
  this.#services = {};
19
20
  this.#state = state;
21
+ this.#status = {
22
+ isBusy: false,
23
+ setValue: null,
24
+ };
20
25
  const { context } = this.#accessory;
21
- const { firmware, hardware, id, manufacturer, model, name, serial, software, type, uuid, } = context;
26
+ const { firmware, hardware, manufacturer, model, name, serial, software, type, } = context;
22
27
  this.#services.Information = this.#accessory.getService(service.AccessoryInformation) ?? this.#accessory.addService(service.AccessoryInformation);
23
28
  this.#services.Information
24
29
  .setCharacteristic(this.#characteristic.Identify, false)
@@ -63,122 +68,11 @@ export class ADTPulseAccessory {
63
68
  case 'shock':
64
69
  this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
65
70
  break;
66
- case 'temperature':
67
- this.#services.Primary = this.#accessory.getService(service.TemperatureSensor) ?? this.#accessory.addService(service.TemperatureSensor);
68
- break;
69
- default:
70
- break;
71
- }
72
- if (this.#services.Primary === undefined) {
73
- if (type !== 'gateway') {
74
- this.#log.error(`Failed to initialize ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory because the primary service does not exist ...`);
75
- }
76
- return;
77
- }
78
- switch (type) {
79
- case 'gateway':
80
- break;
81
- case 'panel':
82
- this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemCurrentState)
83
- .onGet(() => this.getPanelStatus('constructor', 'current'))
84
- .updateValue(this.getPanelStatus('updater', 'current'));
85
- this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
86
- .onGet(() => this.getPanelStatus('constructor', 'target'))
87
- .updateValue(this.getPanelStatus('updater', 'target'));
88
- this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
89
- .onSet(async (value) => this.setPanelStatus(value));
90
- break;
91
- default:
92
- break;
93
- }
94
- switch (type) {
95
- case 'gateway':
96
- break;
97
- case 'panel':
98
- this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemAlarmType)
99
- .onGet(() => this.getPanelStatus('constructor', 'alarmType'))
100
- .updateValue(this.getPanelStatus('updater', 'alarmType'));
101
- this.#services.Primary.getCharacteristic(this.#characteristic.StatusFault)
102
- .onGet(() => this.getPanelStatus('constructor', 'fault'))
103
- .updateValue(this.getPanelStatus('updater', 'fault'));
104
- this.#services.Primary.getCharacteristic(this.#characteristic.StatusTampered)
105
- .onGet(() => this.getPanelStatus('constructor', 'tamper'))
106
- .updateValue(this.getPanelStatus('updater', 'tamper'));
107
- break;
108
- default:
109
- break;
110
- }
111
- switch (type) {
112
- case 'co':
113
- this.#services.Primary.getCharacteristic(this.#characteristic.CarbonMonoxideDetected)
114
- .onGet(() => this.getSensorStatus('constructor', 'status'))
115
- .updateValue(this.getSensorStatus('updater', 'status'));
116
- break;
117
- case 'doorWindow':
118
- this.#services.Primary.getCharacteristic(this.#characteristic.ContactSensorState)
119
- .onGet(() => this.getSensorStatus('constructor', 'status'))
120
- .updateValue(this.getSensorStatus('updater', 'status'));
121
- break;
122
- case 'fire':
123
- this.#services.Primary.getCharacteristic(this.#characteristic.SmokeDetected)
124
- .onGet(() => this.getSensorStatus('constructor', 'status'))
125
- .updateValue(this.getSensorStatus('updater', 'status'));
126
- break;
127
- case 'flood':
128
- this.#services.Primary.getCharacteristic(this.#characteristic.LeakDetected)
129
- .onGet(() => this.getSensorStatus('constructor', 'status'))
130
- .updateValue(this.getSensorStatus('updater', 'status'));
131
- break;
132
- case 'glass':
133
- this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
134
- .onGet(() => this.getSensorStatus('constructor', 'status'))
135
- .updateValue(this.getSensorStatus('updater', 'status'));
136
- break;
137
- case 'heat':
138
- this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
139
- .onGet(() => this.getSensorStatus('constructor', 'status'))
140
- .updateValue(this.getSensorStatus('updater', 'status'));
141
- break;
142
- case 'motion':
143
- this.#services.Primary.getCharacteristic(this.#characteristic.MotionDetected)
144
- .onGet(() => this.getSensorStatus('constructor', 'status'))
145
- .updateValue(this.getSensorStatus('updater', 'status'));
146
- break;
147
- case 'shock':
148
- this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
149
- .onGet(() => this.getSensorStatus('constructor', 'status'))
150
- .updateValue(this.getSensorStatus('updater', 'status'));
71
+ case 'supervisory':
72
+ this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
151
73
  break;
152
74
  case 'temperature':
153
- this.#services.Primary.getCharacteristic(this.#characteristic.CurrentTemperature)
154
- .onGet(() => this.getSensorStatus('constructor', 'status'))
155
- .updateValue(this.getSensorStatus('updater', 'status'));
156
- break;
157
- default:
158
- break;
159
- }
160
- switch (type) {
161
- case 'co':
162
- case 'doorWindow':
163
- case 'fire':
164
- case 'flood':
165
- case 'glass':
166
- case 'heat':
167
- case 'motion':
168
- case 'shock':
169
- case 'temperature':
170
- this.#services.Primary.getCharacteristic(this.#characteristic.StatusActive)
171
- .onGet(() => this.getSensorStatus('constructor', 'active'))
172
- .updateValue(this.getSensorStatus('updater', 'active'));
173
- this.#services.Primary.getCharacteristic(this.#characteristic.StatusFault)
174
- .onGet(() => this.getSensorStatus('constructor', 'fault'))
175
- .updateValue(this.getSensorStatus('updater', 'fault'));
176
- this.#services.Primary.getCharacteristic(this.#characteristic.StatusLowBattery)
177
- .onGet(() => this.getSensorStatus('constructor', 'lowBattery'))
178
- .updateValue(this.getSensorStatus('updater', 'lowBattery'));
179
- this.#services.Primary.getCharacteristic(this.#characteristic.StatusTampered)
180
- .onGet(() => this.getSensorStatus('constructor', 'tamper'))
181
- .updateValue(this.getSensorStatus('updater', 'tamper'));
75
+ this.#services.Primary = this.#accessory.getService(service.TemperatureSensor) ?? this.#accessory.addService(service.TemperatureSensor);
182
76
  break;
183
77
  default:
184
78
  break;
@@ -198,11 +92,11 @@ export class ADTPulseAccessory {
198
92
  break;
199
93
  case 'panel':
200
94
  this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemCurrentState)
201
- .updateValue(this.getPanelStatus('updater', 'current'));
95
+ .updateValue(this.getPanelStatus('current'));
202
96
  this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
203
- .updateValue(this.getPanelStatus('updater', 'target'));
204
- this.#services.Primary.updateCharacteristic(this.#characteristic.SecuritySystemCurrentState, this.getPanelStatus('constructor', 'current'));
205
- this.#services.Primary.updateCharacteristic(this.#characteristic.SecuritySystemTargetState, this.getPanelStatus('constructor', 'target'));
97
+ .updateValue(this.getPanelStatus('target'));
98
+ this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
99
+ .onSet(async (value) => this.setPanelStatus(value));
206
100
  break;
207
101
  default:
208
102
  break;
@@ -212,14 +106,11 @@ export class ADTPulseAccessory {
212
106
  break;
213
107
  case 'panel':
214
108
  this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemAlarmType)
215
- .updateValue(this.getPanelStatus('updater', 'alarmType'));
109
+ .updateValue(this.getPanelStatus('alarmType'));
216
110
  this.#services.Primary.getCharacteristic(this.#characteristic.StatusFault)
217
- .updateValue(this.getPanelStatus('updater', 'fault'));
111
+ .updateValue(this.getPanelStatus('fault'));
218
112
  this.#services.Primary.getCharacteristic(this.#characteristic.StatusTampered)
219
- .updateValue(this.getPanelStatus('updater', 'tamper'));
220
- this.#services.Primary.updateCharacteristic(this.#characteristic.SecuritySystemAlarmType, this.getPanelStatus('constructor', 'alarmType'));
221
- this.#services.Primary.updateCharacteristic(this.#characteristic.StatusFault, this.getPanelStatus('constructor', 'fault'));
222
- this.#services.Primary.updateCharacteristic(this.#characteristic.StatusTampered, this.getPanelStatus('constructor', 'tamper'));
113
+ .updateValue(this.getPanelStatus('tamper'));
223
114
  break;
224
115
  default:
225
116
  break;
@@ -227,48 +118,43 @@ export class ADTPulseAccessory {
227
118
  switch (type) {
228
119
  case 'co':
229
120
  this.#services.Primary.getCharacteristic(this.#characteristic.CarbonMonoxideDetected)
230
- .updateValue(this.getSensorStatus('updater', 'status'));
231
- this.#services.Primary.updateCharacteristic(this.#characteristic.CarbonMonoxideDetected, this.getSensorStatus('constructor', 'status'));
121
+ .updateValue(this.getSensorStatus('status'));
232
122
  break;
233
123
  case 'doorWindow':
234
124
  this.#services.Primary.getCharacteristic(this.#characteristic.ContactSensorState)
235
- .updateValue(this.getSensorStatus('updater', 'status'));
236
- this.#services.Primary.updateCharacteristic(this.#characteristic.ContactSensorState, this.getSensorStatus('constructor', 'status'));
125
+ .updateValue(this.getSensorStatus('status'));
237
126
  break;
238
127
  case 'fire':
239
128
  this.#services.Primary.getCharacteristic(this.#characteristic.SmokeDetected)
240
- .updateValue(this.getSensorStatus('updater', 'status'));
241
- this.#services.Primary.updateCharacteristic(this.#characteristic.SmokeDetected, this.getSensorStatus('constructor', 'status'));
129
+ .updateValue(this.getSensorStatus('status'));
242
130
  break;
243
131
  case 'flood':
244
132
  this.#services.Primary.getCharacteristic(this.#characteristic.LeakDetected)
245
- .updateValue(this.getSensorStatus('updater', 'status'));
246
- this.#services.Primary.updateCharacteristic(this.#characteristic.LeakDetected, this.getSensorStatus('constructor', 'status'));
133
+ .updateValue(this.getSensorStatus('status'));
247
134
  break;
248
135
  case 'glass':
249
136
  this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
250
- .updateValue(this.getSensorStatus('updater', 'status'));
251
- this.#services.Primary.updateCharacteristic(this.#characteristic.OccupancyDetected, this.getSensorStatus('constructor', 'status'));
137
+ .updateValue(this.getSensorStatus('status'));
252
138
  break;
253
139
  case 'heat':
254
140
  this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
255
- .updateValue(this.getSensorStatus('updater', 'status'));
256
- this.#services.Primary.updateCharacteristic(this.#characteristic.OccupancyDetected, this.getSensorStatus('constructor', 'status'));
141
+ .updateValue(this.getSensorStatus('status'));
257
142
  break;
258
143
  case 'motion':
259
144
  this.#services.Primary.getCharacteristic(this.#characteristic.MotionDetected)
260
- .updateValue(this.getSensorStatus('updater', 'status'));
261
- this.#services.Primary.updateCharacteristic(this.#characteristic.MotionDetected, this.getSensorStatus('constructor', 'status'));
145
+ .updateValue(this.getSensorStatus('status'));
262
146
  break;
263
147
  case 'shock':
264
148
  this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
265
- .updateValue(this.getSensorStatus('updater', 'status'));
266
- this.#services.Primary.updateCharacteristic(this.#characteristic.OccupancyDetected, this.getSensorStatus('constructor', 'status'));
149
+ .updateValue(this.getSensorStatus('status'));
150
+ break;
151
+ case 'supervisory':
152
+ this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
153
+ .updateValue(this.getSensorStatus('status'));
267
154
  break;
268
155
  case 'temperature':
269
156
  this.#services.Primary.getCharacteristic(this.#characteristic.CurrentTemperature)
270
- .updateValue(this.getSensorStatus('updater', 'status'));
271
- this.#services.Primary.updateCharacteristic(this.#characteristic.CurrentTemperature, this.getSensorStatus('constructor', 'status'));
157
+ .updateValue(this.getSensorStatus('status'));
272
158
  break;
273
159
  default:
274
160
  break;
@@ -282,52 +168,46 @@ export class ADTPulseAccessory {
282
168
  case 'heat':
283
169
  case 'motion':
284
170
  case 'shock':
171
+ case 'supervisory':
285
172
  case 'temperature':
286
173
  this.#services.Primary.getCharacteristic(this.#characteristic.StatusActive)
287
- .updateValue(this.getSensorStatus('updater', 'active'));
174
+ .updateValue(this.getSensorStatus('active'));
288
175
  this.#services.Primary.getCharacteristic(this.#characteristic.StatusFault)
289
- .updateValue(this.getSensorStatus('updater', 'fault'));
176
+ .updateValue(this.getSensorStatus('fault'));
290
177
  this.#services.Primary.getCharacteristic(this.#characteristic.StatusLowBattery)
291
- .updateValue(this.getSensorStatus('updater', 'lowBattery'));
178
+ .updateValue(this.getSensorStatus('lowBattery'));
292
179
  this.#services.Primary.getCharacteristic(this.#characteristic.StatusTampered)
293
- .updateValue(this.getSensorStatus('updater', 'tamper'));
294
- this.#services.Primary.updateCharacteristic(this.#characteristic.StatusActive, this.getSensorStatus('constructor', 'active'));
295
- this.#services.Primary.updateCharacteristic(this.#characteristic.StatusFault, this.getSensorStatus('constructor', 'fault'));
296
- this.#services.Primary.updateCharacteristic(this.#characteristic.StatusLowBattery, this.getSensorStatus('constructor', 'lowBattery'));
297
- this.#services.Primary.updateCharacteristic(this.#characteristic.StatusTampered, this.getSensorStatus('constructor', 'tamper'));
180
+ .updateValue(this.getSensorStatus('tamper'));
298
181
  break;
299
182
  default:
300
183
  break;
301
184
  }
302
185
  }
303
- getSensorStatus(caller, mode) {
186
+ getSensorStatus(mode) {
304
187
  const { context } = this.#accessory;
305
188
  const { id, name, originalName, type, uuid, zone, } = context;
306
189
  const matchedSensorStatus = this.#state.data.sensorsStatus.find((sensorStatus) => originalName === sensorStatus.name && zone !== null && sensorStatus.zone === zone);
307
- let hapStatus = new this.#api.hap.HapStatusError(0);
190
+ let hapStatus;
308
191
  if (matchedSensorStatus === undefined
309
192
  || type === 'gateway'
310
193
  || type === 'panel'
311
194
  || !condensedSensorTypeItems.includes(type)) {
312
195
  hapStatus = new this.#api.hap.HapStatusError(-70409);
313
196
  this.#log.error(`Attempted to get sensor status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but sensor is not found or sensor type is not supported.`);
314
- switch (caller) {
315
- case 'updater':
316
- return hapStatus;
317
- default:
318
- throw hapStatus;
319
- }
197
+ return hapStatus;
320
198
  }
321
199
  const { icon, statuses } = matchedSensorStatus;
322
200
  if (mode === 'active') {
323
- return !statuses.includes('Offline')
201
+ return (!statuses.includes('Offline')
324
202
  && !statuses.includes('Unknown')
325
203
  && icon !== 'devStatOffline'
326
- && icon !== 'devStatUnknown';
204
+ && icon !== 'devStatUnknown');
327
205
  }
328
206
  if (mode === 'fault') {
329
- if (statuses.includes('Bypassed')
330
- || statuses.includes('Trouble')) {
207
+ if (statuses.includes('ALARM')
208
+ || statuses.includes('Bypassed')
209
+ || statuses.includes('Trouble')
210
+ || icon === 'devStatAlarm') {
331
211
  return this.#characteristic.StatusFault.GENERAL_FAULT;
332
212
  }
333
213
  return this.#characteristic.StatusFault.NO_FAULT;
@@ -355,7 +235,7 @@ export class ADTPulseAccessory {
355
235
  }
356
236
  break;
357
237
  case 'doorWindow':
358
- if (statuses.includes('Open')) {
238
+ if (statuses.includes('ALARM') || statuses.includes('Open')) {
359
239
  return this.#characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
360
240
  }
361
241
  if (statuses.includes('Closed')) {
@@ -363,6 +243,9 @@ export class ADTPulseAccessory {
363
243
  }
364
244
  break;
365
245
  case 'fire':
246
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
247
+ return this.#characteristic.SmokeDetected.SMOKE_DETECTED;
248
+ }
366
249
  if (statuses.includes('Okay')) {
367
250
  return this.#characteristic.SmokeDetected.SMOKE_NOT_DETECTED;
368
251
  }
@@ -373,7 +256,7 @@ export class ADTPulseAccessory {
373
256
  }
374
257
  break;
375
258
  case 'glass':
376
- if (statuses.includes('Tripped')) {
259
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
377
260
  return this.#characteristic.OccupancyDetected.OCCUPANCY_DETECTED;
378
261
  }
379
262
  if (statuses.includes('Okay')) {
@@ -386,16 +269,21 @@ export class ADTPulseAccessory {
386
269
  }
387
270
  break;
388
271
  case 'motion':
272
+ if (statuses.includes('ALARM') || statuses.includes('Motion')) {
273
+ return true;
274
+ }
389
275
  if (statuses.includes('No Motion') || statuses.includes('Okay')) {
390
276
  return false;
391
277
  }
392
- if (statuses.includes('Motion')) {
393
- return true;
394
- }
395
278
  break;
396
279
  case 'shock':
397
280
  break;
281
+ case 'supervisory':
282
+ break;
398
283
  case 'temperature':
284
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
285
+ return 0;
286
+ }
399
287
  if (statuses.includes('Okay')) {
400
288
  return 20;
401
289
  }
@@ -406,55 +294,31 @@ export class ADTPulseAccessory {
406
294
  if (statuses.includes('Offline') || statuses.includes('Unknown')) {
407
295
  hapStatus = new this.#api.hap.HapStatusError(-70412);
408
296
  this.#log.warn(`Attempted to get sensor status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but sensor is currently "Offline" or "Unknown".`);
409
- switch (caller) {
410
- case 'updater':
411
- return hapStatus;
412
- default:
413
- throw hapStatus;
414
- }
297
+ return hapStatus;
415
298
  }
416
299
  hapStatus = new this.#api.hap.HapStatusError(-70410);
417
300
  this.#log.warn(`Attempted to get sensor status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but actions have not been implemented yet.`);
418
- switch (caller) {
419
- case 'updater':
420
- return hapStatus;
421
- default:
422
- throw hapStatus;
423
- }
301
+ return hapStatus;
424
302
  }
425
- getPanelStatus(caller, mode) {
303
+ getPanelStatus(mode) {
426
304
  const { context } = this.#accessory;
427
305
  const { id, name, type, uuid, } = context;
428
- let hapStatus = new this.#api.hap.HapStatusError(0);
306
+ let hapStatus;
429
307
  if (type !== 'panel') {
430
308
  hapStatus = new this.#api.hap.HapStatusError(-70410);
431
309
  this.#log.error(`Attempted to get panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but device is not a security panel.`);
432
- switch (caller) {
433
- case 'updater':
434
- return hapStatus;
435
- default:
436
- throw hapStatus;
437
- }
310
+ return hapStatus;
438
311
  }
439
312
  if (this.#state.data.panelStatus === null
440
313
  || this.#state.data.panelStatus.panelStates.length === 0
441
314
  || this.#state.data.panelStatus.panelStatuses.length === 0) {
442
315
  hapStatus = new this.#api.hap.HapStatusError(-70403);
443
316
  this.#log.debug(`Attempted to get panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel status has not been retrieved yet.`);
444
- switch (caller) {
445
- case 'updater':
446
- return hapStatus;
447
- default:
448
- throw hapStatus;
449
- }
317
+ return hapStatus;
450
318
  }
451
319
  const { panelStates, panelStatuses } = this.#state.data.panelStatus;
452
320
  if (mode === 'alarmType') {
453
- if (panelStatuses.includes('BURGLARY ALARM')
454
- || panelStatuses.includes('Carbon Monoxide Alarm')
455
- || panelStatuses.includes('FIRE ALARM')
456
- || panelStatuses.includes('Uncleared Alarm')
457
- || panelStatuses.includes('WATER ALARM')) {
321
+ if (isPanelAlarmActive(panelStatuses)) {
458
322
  return 1;
459
323
  }
460
324
  return 0;
@@ -466,19 +330,20 @@ export class ADTPulseAccessory {
466
330
  return this.#characteristic.StatusFault.NO_FAULT;
467
331
  }
468
332
  if (mode === 'tamper') {
333
+ if (panelStatuses.includes('Sensor Problem') || panelStatuses.includes('Sensor Problems')) {
334
+ return this.#characteristic.StatusTampered.TAMPERED;
335
+ }
469
336
  return this.#characteristic.StatusTampered.NOT_TAMPERED;
470
337
  }
471
338
  switch (true) {
472
- case mode === 'current' && panelStatuses.includes('BURGLARY ALARM'):
473
- case mode === 'current' && panelStatuses.includes('Carbon Monoxide Alarm'):
474
- case mode === 'current' && panelStatuses.includes('FIRE ALARM'):
475
- case mode === 'current' && panelStatuses.includes('Uncleared Alarm'):
476
- case mode === 'current' && panelStatuses.includes('WATER ALARM'):
339
+ case mode === 'current' && isPanelAlarmActive(panelStatuses):
477
340
  return this.#characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED;
478
- case mode === 'current' && panelStates.includes('Armed Away'):
479
- return this.#characteristic.SecuritySystemCurrentState.AWAY_ARM;
341
+ case mode === 'current' && this.#status.isBusy && this.#status.setValue !== null:
342
+ return this.#status.setValue;
480
343
  case mode === 'current' && panelStates.includes('Armed Stay'):
481
344
  return this.#characteristic.SecuritySystemCurrentState.STAY_ARM;
345
+ case mode === 'current' && panelStates.includes('Armed Away'):
346
+ return this.#characteristic.SecuritySystemCurrentState.AWAY_ARM;
482
347
  case mode === 'current' && panelStates.includes('Armed Night'):
483
348
  return this.#characteristic.SecuritySystemCurrentState.NIGHT_ARM;
484
349
  case mode === 'current' && panelStates.includes('Disarmed'):
@@ -487,10 +352,14 @@ export class ADTPulseAccessory {
487
352
  break;
488
353
  }
489
354
  switch (true) {
490
- case mode === 'target' && panelStates.includes('Armed Away'):
491
- return this.#characteristic.SecuritySystemTargetState.AWAY_ARM;
355
+ case mode === 'target' && panelStates.includes('Disarmed') && isPanelAlarmActive(panelStatuses):
356
+ return this.#characteristic.SecuritySystemTargetState.STAY_ARM;
357
+ case mode === 'target' && this.#status.isBusy && this.#status.setValue !== null:
358
+ return this.#status.setValue;
492
359
  case mode === 'target' && panelStates.includes('Armed Stay'):
493
360
  return this.#characteristic.SecuritySystemTargetState.STAY_ARM;
361
+ case mode === 'target' && panelStates.includes('Armed Away'):
362
+ return this.#characteristic.SecuritySystemTargetState.AWAY_ARM;
494
363
  case mode === 'target' && panelStates.includes('Armed Night'):
495
364
  return this.#characteristic.SecuritySystemTargetState.NIGHT_ARM;
496
365
  case mode === 'target' && panelStates.includes('Disarmed'):
@@ -501,68 +370,78 @@ export class ADTPulseAccessory {
501
370
  if (panelStates.includes('Status Unavailable')) {
502
371
  hapStatus = new this.#api.hap.HapStatusError(-70403);
503
372
  this.#log.warn(`Attempted to get panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel state is "Status Unavailable".`);
504
- switch (caller) {
505
- case 'updater':
506
- return hapStatus;
507
- default:
508
- throw hapStatus;
509
- }
373
+ return hapStatus;
510
374
  }
511
375
  hapStatus = new this.#api.hap.HapStatusError(-70402);
512
376
  this.#log.warn(`Attempted to get panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but actions have not been implemented yet.`);
513
- switch (caller) {
514
- case 'updater':
515
- return hapStatus;
516
- default:
517
- throw hapStatus;
518
- }
377
+ return hapStatus;
519
378
  }
520
379
  async setPanelStatus(arm) {
521
380
  const { context } = this.#accessory;
522
381
  const { id, name, type, uuid, } = context;
382
+ let hapStatus;
523
383
  let result = {
524
384
  success: false,
525
385
  };
526
386
  let unknownArmValue = false;
527
387
  if (type !== 'panel') {
388
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
528
389
  this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but device is not a security panel.`);
529
- throw new this.#api.hap.HapStatusError(-70410);
390
+ throw hapStatus;
530
391
  }
531
392
  if (this.#state.data.panelStatus === null || this.#state.data.panelStatus.panelStates.length === 0) {
393
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
532
394
  this.#log.warn(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel status has not been retrieved yet.`);
533
- throw new this.#api.hap.HapStatusError(-70403);
395
+ throw hapStatus;
534
396
  }
535
397
  const { panelStates } = this.#state.data.panelStatus;
536
- const armFrom = condensePanelStates(panelStates);
398
+ const armFrom = condensePanelStates(this.#characteristic, panelStates);
399
+ const isAlarmActive = isPanelAlarmActive(this.#state.data.panelStatus.panelStatuses);
537
400
  if (armFrom === undefined) {
401
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
538
402
  this.#log.warn(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel status cannot be found or most likely "Status Unavailable".`);
539
- throw new this.#api.hap.HapStatusError(-70403);
540
- }
541
- switch (arm) {
542
- case this.#characteristic.SecuritySystemTargetState.STAY_ARM:
543
- result = await this.#instance.setPanelStatus(armFrom, 'stay');
544
- break;
545
- case this.#characteristic.SecuritySystemTargetState.AWAY_ARM:
546
- result = await this.#instance.setPanelStatus(armFrom, 'away');
547
- break;
548
- case this.#characteristic.SecuritySystemTargetState.NIGHT_ARM:
549
- result = await this.#instance.setPanelStatus(armFrom, 'night');
550
- break;
551
- case this.#characteristic.SecuritySystemTargetState.DISARM:
552
- result = await this.#instance.setPanelStatus(armFrom, 'off');
553
- break;
554
- default:
555
- unknownArmValue = true;
556
- break;
557
- }
558
- if (unknownArmValue) {
559
- this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request has unknown arm value.`);
560
- throw new this.#api.hap.HapStatusError(-70410);
561
- }
562
- if (!result.success) {
563
- this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request was not successful.`);
564
- stackTracer('api-response', result);
565
- throw new this.#api.hap.HapStatusError(-70408);
403
+ throw hapStatus;
404
+ }
405
+ if (armFrom.characteristicValue !== arm
406
+ || (armFrom.armValue === 'off'
407
+ && arm === this.#characteristic.SecuritySystemTargetState.DISARM
408
+ && isAlarmActive)) {
409
+ this.#status = {
410
+ isBusy: true,
411
+ setValue: arm,
412
+ };
413
+ switch (arm) {
414
+ case this.#characteristic.SecuritySystemTargetState.STAY_ARM:
415
+ result = await this.#instance.setPanelStatus(armFrom.armValue, 'stay', isAlarmActive);
416
+ break;
417
+ case this.#characteristic.SecuritySystemTargetState.AWAY_ARM:
418
+ result = await this.#instance.setPanelStatus(armFrom.armValue, 'away', isAlarmActive);
419
+ break;
420
+ case this.#characteristic.SecuritySystemTargetState.NIGHT_ARM:
421
+ result = await this.#instance.setPanelStatus(armFrom.armValue, 'night', isAlarmActive);
422
+ break;
423
+ case this.#characteristic.SecuritySystemTargetState.DISARM:
424
+ result = await this.#instance.setPanelStatus(armFrom.armValue, 'off', isAlarmActive);
425
+ break;
426
+ default:
427
+ unknownArmValue = true;
428
+ break;
429
+ }
430
+ this.#status = {
431
+ isBusy: false,
432
+ setValue: null,
433
+ };
434
+ if (unknownArmValue) {
435
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
436
+ this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request has unknown arm value.`);
437
+ throw hapStatus;
438
+ }
439
+ if (!result.success) {
440
+ hapStatus = new this.#api.hap.HapStatusError(-70408);
441
+ this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request was not successful.`);
442
+ stackTracer('api-response', result);
443
+ throw hapStatus;
444
+ }
566
445
  }
567
446
  }
568
447
  }