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

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,5 +1,9 @@
1
+ import chalk from 'chalk';
2
+ import { condensedSensorTypeItems } from './items.js';
3
+ import { condensePanelStates, convertPanelCharacteristicValue, isPanelAlarmActive, stackTracer, } from './utility.js';
1
4
  export class ADTPulseAccessory {
2
5
  #accessory;
6
+ #activity;
3
7
  #api;
4
8
  #characteristic;
5
9
  #instance;
@@ -8,23 +12,43 @@ export class ADTPulseAccessory {
8
12
  #state;
9
13
  constructor(accessory, state, instance, service, characteristic, api, log) {
10
14
  this.#accessory = accessory;
15
+ this.#activity = {
16
+ isBusy: false,
17
+ setCurrentValue: null,
18
+ setTargetValue: null,
19
+ setValue: null,
20
+ };
11
21
  this.#api = api;
12
22
  this.#characteristic = characteristic;
13
23
  this.#instance = instance;
14
24
  this.#log = log;
15
25
  this.#services = {};
16
26
  this.#state = state;
27
+ const { context } = this.#accessory;
28
+ const { firmware, hardware, manufacturer, model, name, serial, software, type, } = context;
17
29
  this.#services.Information = this.#accessory.getService(service.AccessoryInformation) ?? this.#accessory.addService(service.AccessoryInformation);
18
30
  this.#services.Information
19
31
  .setCharacteristic(this.#characteristic.Identify, false)
20
- .setCharacteristic(this.#characteristic.Manufacturer, accessory.context.manufacturer ?? 'ADT')
21
- .setCharacteristic(this.#characteristic.Model, accessory.context.model ?? 'N/A')
22
- .setCharacteristic(this.#characteristic.Name, accessory.context.name)
23
- .setCharacteristic(this.#characteristic.SerialNumber, accessory.context.serial ?? 'N/A')
24
- .setCharacteristic(this.#characteristic.FirmwareRevision, accessory.context.firmware ?? 'N/A')
25
- .setCharacteristic(this.#characteristic.HardwareRevision, accessory.context.hardware ?? 'N/A')
26
- .setCharacteristic(this.#characteristic.SoftwareRevision, accessory.context.software ?? 'N/A');
27
- switch (accessory.context.type) {
32
+ .setCharacteristic(this.#characteristic.Manufacturer, manufacturer ?? 'ADT')
33
+ .setCharacteristic(this.#characteristic.Model, model ?? 'N/A')
34
+ .setCharacteristic(this.#characteristic.Name, name)
35
+ .setCharacteristic(this.#characteristic.SerialNumber, serial ?? 'N/A')
36
+ .setCharacteristic(this.#characteristic.FirmwareRevision, firmware ?? 'N/A')
37
+ .setCharacteristic(this.#characteristic.HardwareRevision, hardware ?? 'N/A')
38
+ .setCharacteristic(this.#characteristic.SoftwareRevision, software ?? 'N/A');
39
+ switch (type) {
40
+ case 'gateway':
41
+ break;
42
+ case 'panel':
43
+ this.#services.Primary = this.#accessory.getService(service.SecuritySystem) ?? this.#accessory.addService(service.SecuritySystem);
44
+ break;
45
+ case 'panelSwitch':
46
+ this.#services.Primary = this.#accessory.getService(service.Switch) ?? this.#accessory.addService(service.Switch);
47
+ break;
48
+ default:
49
+ break;
50
+ }
51
+ switch (type) {
28
52
  case 'co':
29
53
  this.#services.Primary = this.#accessory.getService(service.CarbonMonoxideSensor) ?? this.#accessory.addService(service.CarbonMonoxideSensor);
30
54
  break;
@@ -37,20 +61,17 @@ export class ADTPulseAccessory {
37
61
  case 'flood':
38
62
  this.#services.Primary = this.#accessory.getService(service.LeakSensor) ?? this.#accessory.addService(service.LeakSensor);
39
63
  break;
40
- case 'gateway':
41
- break;
42
64
  case 'glass':
43
- this.#services.Primary = this.#accessory.getService(service.MotionSensor) ?? this.#accessory.addService(service.MotionSensor);
65
+ this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
44
66
  break;
45
- case 'keypad':
67
+ case 'heat':
68
+ this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
46
69
  break;
47
70
  case 'motion':
48
71
  this.#services.Primary = this.#accessory.getService(service.MotionSensor) ?? this.#accessory.addService(service.MotionSensor);
49
72
  break;
50
- case 'panel':
51
- this.#services.Primary = this.#accessory.getService(service.SecuritySystem) ?? this.#accessory.addService(service.SecuritySystem);
52
- break;
53
- case 'panic':
73
+ case 'shock':
74
+ this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
54
75
  break;
55
76
  case 'temperature':
56
77
  this.#services.Primary = this.#accessory.getService(service.TemperatureSensor) ?? this.#accessory.addService(service.TemperatureSensor);
@@ -58,182 +79,471 @@ export class ADTPulseAccessory {
58
79
  default:
59
80
  break;
60
81
  }
82
+ }
83
+ updater() {
84
+ const { context } = this.#accessory;
85
+ const { id, name, type, uuid, } = context;
61
86
  if (this.#services.Primary === undefined) {
62
- if (accessory.context.type !== 'gateway') {
63
- this.#log.error(`Failed to initialize ${accessory.context.name} (id: ${accessory.context.id}, uuid: ${accessory.context.uuid}) accessory services ...`);
87
+ if (type !== 'gateway') {
88
+ this.#log.error(`Failed to update ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory because the primary service does not exist ...`);
64
89
  }
65
90
  return;
66
91
  }
67
- switch (accessory.context.type) {
92
+ switch (type) {
93
+ case 'gateway':
94
+ break;
95
+ case 'panel':
96
+ this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemCurrentState)
97
+ .updateValue(this.getPanelStatus('current'));
98
+ this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
99
+ .updateValue(this.getPanelStatus('target'));
100
+ this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
101
+ .onSet(async (value) => this.setPanelStatus(value));
102
+ break;
103
+ case 'panelSwitch':
104
+ this.#services.Primary.getCharacteristic(this.#characteristic.On)
105
+ .updateValue(this.getPanelSwitchStatus());
106
+ this.#services.Primary.getCharacteristic(this.#characteristic.On)
107
+ .onSet(async (value) => this.setPanelSwitchStatus(value));
108
+ break;
109
+ default:
110
+ break;
111
+ }
112
+ switch (type) {
113
+ case 'gateway':
114
+ break;
115
+ case 'panel':
116
+ this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemAlarmType)
117
+ .updateValue(this.getPanelStatus('alarmType'));
118
+ this.#services.Primary.getCharacteristic(this.#characteristic.StatusFault)
119
+ .updateValue(this.getPanelStatus('fault'));
120
+ this.#services.Primary.getCharacteristic(this.#characteristic.StatusTampered)
121
+ .updateValue(this.getPanelStatus('tamper'));
122
+ break;
123
+ case 'panelSwitch':
124
+ break;
125
+ default:
126
+ break;
127
+ }
128
+ switch (type) {
68
129
  case 'co':
69
130
  this.#services.Primary.getCharacteristic(this.#characteristic.CarbonMonoxideDetected)
70
- .onGet(() => this.getSensorStatus(accessory.context));
131
+ .updateValue(this.getSensorStatus('status'));
71
132
  break;
72
133
  case 'doorWindow':
73
134
  this.#services.Primary.getCharacteristic(this.#characteristic.ContactSensorState)
74
- .onGet(() => this.getSensorStatus(accessory.context));
135
+ .updateValue(this.getSensorStatus('status'));
75
136
  break;
76
137
  case 'fire':
77
138
  this.#services.Primary.getCharacteristic(this.#characteristic.SmokeDetected)
78
- .onGet(() => this.getSensorStatus(accessory.context));
139
+ .updateValue(this.getSensorStatus('status'));
79
140
  break;
80
141
  case 'flood':
81
142
  this.#services.Primary.getCharacteristic(this.#characteristic.LeakDetected)
82
- .onGet(() => this.getSensorStatus(accessory.context));
83
- break;
84
- case 'gateway':
143
+ .updateValue(this.getSensorStatus('status'));
85
144
  break;
86
145
  case 'glass':
87
- this.#services.Primary.getCharacteristic(this.#characteristic.MotionDetected)
88
- .onGet(() => this.getSensorStatus(accessory.context));
146
+ this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
147
+ .updateValue(this.getSensorStatus('status'));
89
148
  break;
90
- case 'keypad':
149
+ case 'heat':
150
+ this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
151
+ .updateValue(this.getSensorStatus('status'));
91
152
  break;
92
153
  case 'motion':
93
154
  this.#services.Primary.getCharacteristic(this.#characteristic.MotionDetected)
94
- .onGet(() => this.getSensorStatus(accessory.context));
155
+ .updateValue(this.getSensorStatus('status'));
95
156
  break;
96
- case 'panel':
97
- this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemCurrentState)
98
- .onGet(() => this.getPanelStatus('current', accessory.context));
99
- this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
100
- .onGet(() => this.getPanelStatus('target', accessory.context))
101
- .onSet((value) => this.setPanelStatus(value, accessory.context));
102
- break;
103
- case 'panic':
157
+ case 'shock':
158
+ this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
159
+ .updateValue(this.getSensorStatus('status'));
104
160
  break;
105
161
  case 'temperature':
106
162
  this.#services.Primary.getCharacteristic(this.#characteristic.CurrentTemperature)
107
- .onGet(() => this.getSensorStatus(accessory.context));
163
+ .updateValue(this.getSensorStatus('status'));
164
+ break;
165
+ default:
166
+ break;
167
+ }
168
+ switch (type) {
169
+ case 'co':
170
+ case 'doorWindow':
171
+ case 'fire':
172
+ case 'flood':
173
+ case 'glass':
174
+ case 'heat':
175
+ case 'motion':
176
+ case 'shock':
177
+ case 'temperature':
178
+ this.#services.Primary.getCharacteristic(this.#characteristic.StatusActive)
179
+ .updateValue(this.getSensorStatus('active'));
180
+ this.#services.Primary.getCharacteristic(this.#characteristic.StatusFault)
181
+ .updateValue(this.getSensorStatus('fault'));
182
+ this.#services.Primary.getCharacteristic(this.#characteristic.StatusLowBattery)
183
+ .updateValue(this.getSensorStatus('lowBattery'));
184
+ this.#services.Primary.getCharacteristic(this.#characteristic.StatusTampered)
185
+ .updateValue(this.getSensorStatus('tamper'));
108
186
  break;
109
187
  default:
110
188
  break;
111
189
  }
112
190
  }
113
- getSensorStatus(context) {
114
- const { name, type, zone } = context;
115
- const sensor = this.#state.data.sensorsStatus.find((sensorStatus) => zone !== null && sensorStatus.name === name && sensorStatus.zone === zone);
116
- const knownSensorTypes = [
117
- 'co',
118
- 'doorWindow',
119
- 'fire',
120
- 'flood',
121
- 'glass',
122
- 'keypad',
123
- 'motion',
124
- 'panic',
125
- 'temperature',
126
- ];
127
- if (sensor === undefined || !knownSensorTypes.includes(type)) {
128
- throw new this.#api.hap.HapStatusError(-70409);
129
- }
130
- const { status } = sensor;
131
- if (status === 'Unknown') {
132
- throw new this.#api.hap.HapStatusError(-70402);
133
- }
134
- switch (context.type) {
191
+ getSensorStatus(mode) {
192
+ const { context } = this.#accessory;
193
+ const { id, name, originalName, type, uuid, zone, } = context;
194
+ const matchedSensorStatus = this.#state.data.sensorsStatus.find((sensorStatus) => originalName === sensorStatus.name && zone !== null && sensorStatus.zone === zone);
195
+ let hapStatus;
196
+ if (matchedSensorStatus === undefined
197
+ || type === 'gateway'
198
+ || type === 'panel'
199
+ || type === 'panelSwitch'
200
+ || !condensedSensorTypeItems.includes(type)) {
201
+ hapStatus = new this.#api.hap.HapStatusError(-70409);
202
+ 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.`);
203
+ return hapStatus;
204
+ }
205
+ const { icon, statuses } = matchedSensorStatus;
206
+ if (mode === 'active') {
207
+ return (!statuses.includes('Offline')
208
+ && !statuses.includes('Unknown')
209
+ && icon !== 'devStatOffline'
210
+ && icon !== 'devStatUnknown');
211
+ }
212
+ if (mode === 'fault') {
213
+ if (statuses.includes('ALARM')
214
+ || statuses.includes('Bypassed')
215
+ || statuses.includes('Trouble')
216
+ || icon === 'devStatAlarm') {
217
+ return this.#characteristic.StatusFault.GENERAL_FAULT;
218
+ }
219
+ return this.#characteristic.StatusFault.NO_FAULT;
220
+ }
221
+ if (mode === 'lowBattery') {
222
+ if (statuses.includes('Low Battery')
223
+ || icon === 'devStatLowBatt') {
224
+ return this.#characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
225
+ }
226
+ return this.#characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
227
+ }
228
+ if (mode === 'tamper') {
229
+ if (statuses.includes('Tampered')
230
+ || icon === 'devStatTamper') {
231
+ return this.#characteristic.StatusTampered.TAMPERED;
232
+ }
233
+ return this.#characteristic.StatusTampered.NOT_TAMPERED;
234
+ }
235
+ switch (type) {
135
236
  case 'co':
136
- return this.#characteristic.CarbonMonoxideDetected.CO_LEVELS_NORMAL;
237
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
238
+ return this.#characteristic.CarbonMonoxideDetected.CO_LEVELS_ABNORMAL;
239
+ }
240
+ if (statuses.includes('Okay')) {
241
+ return this.#characteristic.CarbonMonoxideDetected.CO_LEVELS_NORMAL;
242
+ }
243
+ break;
137
244
  case 'doorWindow':
138
- if (status.includes('Open')) {
245
+ if (statuses.includes('ALARM') || statuses.includes('Open')) {
139
246
  return this.#characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
140
247
  }
141
- if (status.includes('Closed')) {
248
+ if (statuses.includes('Closed')) {
142
249
  return this.#characteristic.ContactSensorState.CONTACT_DETECTED;
143
250
  }
144
251
  break;
145
252
  case 'fire':
146
- return this.#characteristic.SmokeDetected.SMOKE_NOT_DETECTED;
253
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
254
+ return this.#characteristic.SmokeDetected.SMOKE_DETECTED;
255
+ }
256
+ if (statuses.includes('Okay')) {
257
+ return this.#characteristic.SmokeDetected.SMOKE_NOT_DETECTED;
258
+ }
259
+ break;
147
260
  case 'flood':
148
- if (status.includes('ALARM')) {
261
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
149
262
  return this.#characteristic.LeakDetected.LEAK_DETECTED;
150
263
  }
151
- if (status.includes('Okay')) {
264
+ if (statuses.includes('Okay')) {
152
265
  return this.#characteristic.LeakDetected.LEAK_NOT_DETECTED;
153
266
  }
154
267
  break;
155
268
  case 'glass':
156
- if (status.includes('Okay')) {
157
- return false;
269
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
270
+ return this.#characteristic.OccupancyDetected.OCCUPANCY_DETECTED;
158
271
  }
159
- if (status.includes('Tripped')) {
160
- return true;
272
+ if (statuses.includes('Okay')) {
273
+ return this.#characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED;
161
274
  }
162
275
  break;
163
- case 'keypad':
276
+ case 'heat':
277
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
278
+ return this.#characteristic.OccupancyDetected.OCCUPANCY_DETECTED;
279
+ }
280
+ if (statuses.includes('Okay')) {
281
+ return this.#characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED;
282
+ }
164
283
  break;
165
284
  case 'motion':
166
- if (status.includes('No Motion')) {
167
- return false;
168
- }
169
- if (status.includes('Motion')) {
285
+ if (statuses.includes('ALARM') || statuses.includes('Motion')) {
170
286
  return true;
171
287
  }
288
+ if (statuses.includes('No Motion') || statuses.includes('Okay')) {
289
+ return false;
290
+ }
172
291
  break;
173
- case 'panic':
292
+ case 'shock':
174
293
  break;
175
294
  case 'temperature':
176
- return 75;
295
+ if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
296
+ return 100;
297
+ }
298
+ if (statuses.includes('Okay')) {
299
+ return 0;
300
+ }
301
+ break;
177
302
  default:
178
303
  break;
179
304
  }
180
- throw new this.#api.hap.HapStatusError(-70409);
305
+ if (statuses.includes('Offline') || statuses.includes('Unknown')) {
306
+ hapStatus = new this.#api.hap.HapStatusError(-70412);
307
+ this.#log.warn(`Attempted to get sensor status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but sensor is currently "Offline" or "Unknown".`);
308
+ return hapStatus;
309
+ }
310
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
311
+ this.#log.warn(`Attempted to get sensor status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but actions have not been implemented yet.`);
312
+ return hapStatus;
181
313
  }
182
- getPanelStatus(mode, context) {
183
- if (context.type !== 'panel') {
184
- throw new this.#api.hap.HapStatusError(-70409);
314
+ getPanelStatus(mode) {
315
+ const { context } = this.#accessory;
316
+ const { id, name, type, uuid, } = context;
317
+ let hapStatus;
318
+ if (type !== 'panel') {
319
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
320
+ this.#log.error(`Attempted to get panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but device is not a security panel.`);
321
+ return hapStatus;
185
322
  }
186
323
  if (this.#state.data.panelStatus === null
187
- || this.#state.data.panelStatus.state === null
188
- || this.#state.data.panelStatus.status === null) {
189
- throw new this.#api.hap.HapStatusError(-70402);
190
- }
191
- const { state, status } = this.#state.data.panelStatus;
192
- if (state === 'Status Unavailable') {
193
- throw new this.#api.hap.HapStatusError(-70402);
194
- }
195
- if (mode === 'current' && status === 'BURGLARY ALARM') {
196
- return this.#characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED;
197
- }
198
- switch (state) {
199
- case 'Armed Away':
200
- return (mode === 'current') ? this.#characteristic.SecuritySystemCurrentState.AWAY_ARM : this.#characteristic.SecuritySystemTargetState.AWAY_ARM;
201
- case 'Armed Stay':
202
- return (mode === 'current') ? this.#characteristic.SecuritySystemCurrentState.STAY_ARM : this.#characteristic.SecuritySystemTargetState.STAY_ARM;
203
- case 'Armed Night':
204
- return (mode === 'current') ? this.#characteristic.SecuritySystemCurrentState.NIGHT_ARM : this.#characteristic.SecuritySystemTargetState.NIGHT_ARM;
205
- case 'Disarmed':
206
- return (mode === 'current') ? this.#characteristic.SecuritySystemCurrentState.DISARMED : this.#characteristic.SecuritySystemTargetState.DISARM;
207
- default:
208
- break;
324
+ || this.#state.data.panelStatus.panelStates.length === 0
325
+ || this.#state.data.panelStatus.panelStatuses.length === 0) {
326
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
327
+ 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.`);
328
+ return hapStatus;
209
329
  }
210
- throw new this.#api.hap.HapStatusError(-70402);
211
- }
212
- async setPanelStatus(arm, context) {
213
- let result;
214
- if (context.type !== 'panel') {
215
- throw new this.#api.hap.HapStatusError(-70409);
330
+ const { panelStates, panelStatuses } = this.#state.data.panelStatus;
331
+ if (mode === 'alarmType') {
332
+ if (isPanelAlarmActive(panelStatuses)) {
333
+ return 1;
334
+ }
335
+ return 0;
216
336
  }
217
- switch (arm) {
218
- case this.#characteristic.SecuritySystemTargetState.STAY_ARM:
219
- result = await this.#instance.setPanelStatus('stay');
220
- break;
221
- case this.#characteristic.SecuritySystemTargetState.AWAY_ARM:
222
- result = await this.#instance.setPanelStatus('away');
223
- break;
224
- case this.#characteristic.SecuritySystemTargetState.NIGHT_ARM:
225
- result = await this.#instance.setPanelStatus('night');
226
- break;
227
- case this.#characteristic.SecuritySystemTargetState.DISARM:
228
- result = await this.#instance.setPanelStatus('off');
337
+ if (mode === 'fault') {
338
+ if (!panelStatuses.includes('All Quiet')) {
339
+ return this.#characteristic.StatusFault.GENERAL_FAULT;
340
+ }
341
+ return this.#characteristic.StatusFault.NO_FAULT;
342
+ }
343
+ if (mode === 'tamper') {
344
+ if (panelStatuses.includes('Sensor Problem') || panelStatuses.includes('Sensor Problems')) {
345
+ return this.#characteristic.StatusTampered.TAMPERED;
346
+ }
347
+ return this.#characteristic.StatusTampered.NOT_TAMPERED;
348
+ }
349
+ switch (true) {
350
+ case mode === 'current' && this.#activity.isBusy && this.#activity.setCurrentValue !== null:
351
+ return this.#activity.setCurrentValue;
352
+ case mode === 'current' && isPanelAlarmActive(panelStatuses):
353
+ return this.#characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED;
354
+ case mode === 'current' && panelStates.includes('Armed Stay'):
355
+ return this.#characteristic.SecuritySystemCurrentState.STAY_ARM;
356
+ case mode === 'current' && panelStates.includes('Armed Away'):
357
+ return this.#characteristic.SecuritySystemCurrentState.AWAY_ARM;
358
+ case mode === 'current' && panelStates.includes('Armed Night'):
359
+ return this.#characteristic.SecuritySystemCurrentState.NIGHT_ARM;
360
+ case mode === 'current' && panelStates.includes('Disarmed'):
361
+ return this.#characteristic.SecuritySystemCurrentState.DISARMED;
362
+ default:
229
363
  break;
364
+ }
365
+ switch (true) {
366
+ case mode === 'target' && this.#activity.isBusy && this.#activity.setTargetValue !== null:
367
+ return this.#activity.setTargetValue;
368
+ case mode === 'target' && panelStates.includes('Armed Stay'):
369
+ return this.#characteristic.SecuritySystemTargetState.STAY_ARM;
370
+ case mode === 'target' && panelStates.includes('Armed Away'):
371
+ return this.#characteristic.SecuritySystemTargetState.AWAY_ARM;
372
+ case mode === 'target' && panelStates.includes('Armed Night'):
373
+ return this.#characteristic.SecuritySystemTargetState.NIGHT_ARM;
374
+ case mode === 'target' && panelStates.includes('Disarmed'):
375
+ return this.#characteristic.SecuritySystemTargetState.DISARM;
230
376
  default:
231
377
  break;
232
378
  }
233
- if (result && result.success) {
234
- return;
379
+ if (panelStates.includes('Status Unavailable')) {
380
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
381
+ this.#log.warn(`Attempted to get panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel state is "Status Unavailable".`);
382
+ return hapStatus;
383
+ }
384
+ hapStatus = new this.#api.hap.HapStatusError(-70402);
385
+ this.#log.warn(`Attempted to get panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but actions have not been implemented yet.`);
386
+ return hapStatus;
387
+ }
388
+ getPanelSwitchStatus() {
389
+ const { context } = this.#accessory;
390
+ const { id, name, uuid } = context;
391
+ let hapStatus;
392
+ if (this.#state.data.panelStatus === null
393
+ || this.#state.data.panelStatus.panelStates.length === 0
394
+ || this.#state.data.panelStatus.panelStatuses.length === 0) {
395
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
396
+ this.#log.debug(`Attempted to get panel switch status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel switch status has not been retrieved yet.`);
397
+ return hapStatus;
398
+ }
399
+ const { panelStates, panelStatuses } = this.#state.data.panelStatus;
400
+ if (this.#activity.isBusy && this.#activity.setValue !== null) {
401
+ return this.#activity.setValue;
402
+ }
403
+ return panelStates.includes('Disarmed') && isPanelAlarmActive(panelStatuses);
404
+ }
405
+ async setPanelStatus(arm) {
406
+ const { context } = this.#accessory;
407
+ const { id, name, type, uuid, } = context;
408
+ let hapStatus;
409
+ let result = {
410
+ success: false,
411
+ };
412
+ let unknownArmValue = false;
413
+ if (type !== 'panel') {
414
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
415
+ this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but device is not a security panel.`);
416
+ throw hapStatus;
417
+ }
418
+ if (this.#state.data.panelStatus === null || this.#state.data.panelStatus.panelStates.length === 0) {
419
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
420
+ 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.`);
421
+ throw hapStatus;
422
+ }
423
+ const { panelStates } = this.#state.data.panelStatus;
424
+ const condensedPanelStates = condensePanelStates(this.#characteristic, panelStates);
425
+ const isAlarmActive = isPanelAlarmActive(this.#state.data.panelStatus.panelStatuses);
426
+ if (condensedPanelStates === undefined) {
427
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
428
+ 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".`);
429
+ throw hapStatus;
430
+ }
431
+ if (!this.#activity.isBusy
432
+ && condensedPanelStates.characteristicValue.target !== arm) {
433
+ const setCurrentValue = convertPanelCharacteristicValue('target-to-current', this.#characteristic, arm);
434
+ if (setCurrentValue === undefined) {
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 current characteristic value does not exist.`);
437
+ throw hapStatus;
438
+ }
439
+ this.#activity = {
440
+ isBusy: true,
441
+ setCurrentValue,
442
+ setTargetValue: arm,
443
+ setValue: null,
444
+ };
445
+ switch (arm) {
446
+ case this.#characteristic.SecuritySystemTargetState.STAY_ARM:
447
+ result = await this.#instance.setPanelStatus(condensedPanelStates.armValue, 'stay', isAlarmActive);
448
+ break;
449
+ case this.#characteristic.SecuritySystemTargetState.AWAY_ARM:
450
+ result = await this.#instance.setPanelStatus(condensedPanelStates.armValue, 'away', isAlarmActive);
451
+ break;
452
+ case this.#characteristic.SecuritySystemTargetState.NIGHT_ARM:
453
+ result = await this.#instance.setPanelStatus(condensedPanelStates.armValue, 'night', isAlarmActive);
454
+ break;
455
+ case this.#characteristic.SecuritySystemTargetState.DISARM:
456
+ result = await this.#instance.setPanelStatus(condensedPanelStates.armValue, 'off', isAlarmActive);
457
+ break;
458
+ default:
459
+ unknownArmValue = true;
460
+ break;
461
+ }
462
+ this.#activity = {
463
+ isBusy: false,
464
+ setCurrentValue: null,
465
+ setTargetValue: null,
466
+ setValue: null,
467
+ };
468
+ if (unknownArmValue) {
469
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
470
+ this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request has unknown arm value.`);
471
+ throw hapStatus;
472
+ }
473
+ if (!result.success) {
474
+ hapStatus = new this.#api.hap.HapStatusError(-70408);
475
+ this.#log.error(`Attempted to set panel status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request was not successful.`);
476
+ stackTracer('api-response', result);
477
+ throw hapStatus;
478
+ }
479
+ }
480
+ }
481
+ async setPanelSwitchStatus(on) {
482
+ const { context } = this.#accessory;
483
+ const { id, name, type, uuid, } = context;
484
+ let hapStatus;
485
+ let result = {
486
+ success: false,
487
+ };
488
+ let unknownArmValue = false;
489
+ if (type !== 'panelSwitch') {
490
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
491
+ this.#log.error(`Attempted to set panel switch status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but device is not a panel switch.`);
492
+ throw hapStatus;
493
+ }
494
+ if (this.#state.data.panelStatus === null || this.#state.data.panelStatus.panelStates.length === 0) {
495
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
496
+ this.#log.warn(`Attempted to set panel switch status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel status has not been retrieved yet.`);
497
+ throw hapStatus;
498
+ }
499
+ if (on === true) {
500
+ hapStatus = new this.#api.hap.HapStatusError(0);
501
+ this.#log.error(`Attempted to set panel switch status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but switch is only used for turning off ringing alarm while system is "Disarmed".`);
502
+ throw hapStatus;
503
+ }
504
+ const { panelStates } = this.#state.data.panelStatus;
505
+ const condensedPanelStates = condensePanelStates(this.#characteristic, panelStates);
506
+ const isAlarmActive = isPanelAlarmActive(this.#state.data.panelStatus.panelStatuses);
507
+ if (condensedPanelStates === undefined) {
508
+ hapStatus = new this.#api.hap.HapStatusError(-70403);
509
+ this.#log.warn(`Attempted to set panel switch status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but panel status cannot be found or most likely "Status Unavailable".`);
510
+ throw hapStatus;
511
+ }
512
+ if (!this.#activity.isBusy
513
+ && condensedPanelStates.armValue === 'off'
514
+ && isAlarmActive) {
515
+ this.#activity = {
516
+ isBusy: true,
517
+ setCurrentValue: null,
518
+ setTargetValue: null,
519
+ setValue: false,
520
+ };
521
+ switch (on) {
522
+ case false:
523
+ result = await this.#instance.setPanelStatus(condensedPanelStates.armValue, 'off', isAlarmActive);
524
+ break;
525
+ default:
526
+ unknownArmValue = true;
527
+ break;
528
+ }
529
+ this.#activity = {
530
+ isBusy: false,
531
+ setCurrentValue: null,
532
+ setTargetValue: null,
533
+ setValue: null,
534
+ };
535
+ if (unknownArmValue) {
536
+ hapStatus = new this.#api.hap.HapStatusError(-70410);
537
+ this.#log.error(`Attempted to set panel switch status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request has unknown arm value.`);
538
+ throw hapStatus;
539
+ }
540
+ if (!result.success) {
541
+ hapStatus = new this.#api.hap.HapStatusError(-70408);
542
+ this.#log.error(`Attempted to set panel switch status on ${chalk.underline(name)} (id: ${id}, uuid: ${uuid}) accessory but request was not successful.`);
543
+ stackTracer('api-response', result);
544
+ throw hapStatus;
545
+ }
235
546
  }
236
- throw new this.#api.hap.HapStatusError(-70410);
237
547
  }
238
548
  }
239
549
  //# sourceMappingURL=accessory.js.map