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

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