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.
- package/LICENSE +198 -12
- package/README.md +167 -106
- package/build/config.schema.json +12 -13
- package/build/src/lib/accessory.js +434 -124
- package/build/src/lib/accessory.js.map +1 -1
- package/build/src/lib/api.js +276 -240
- package/build/src/lib/api.js.map +1 -1
- package/build/src/lib/detect.js +308 -280
- package/build/src/lib/detect.js.map +1 -1
- package/build/src/lib/items.js +345 -0
- package/build/src/lib/items.js.map +1 -0
- package/build/src/lib/platform.js +198 -38
- package/build/src/lib/platform.js.map +1 -1
- package/build/src/lib/regex.js +2 -2
- package/build/src/lib/regex.js.map +1 -1
- package/build/src/lib/schema.js +3 -3
- package/build/src/lib/schema.js.map +1 -1
- package/build/src/lib/utility.js +284 -38
- package/build/src/lib/utility.js.map +1 -1
- package/build/src/scripts/repl.js +23 -17
- package/build/src/scripts/repl.js.map +1 -1
- package/build/src/scripts/test-api.js +12 -12
- package/build/src/scripts/test-api.js.map +1 -1
- package/config.schema.json +12 -13
- package/package.json +25 -15
|
@@ -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,
|
|
21
|
-
.setCharacteristic(this.#characteristic.Model,
|
|
22
|
-
.setCharacteristic(this.#characteristic.Name,
|
|
23
|
-
.setCharacteristic(this.#characteristic.SerialNumber,
|
|
24
|
-
.setCharacteristic(this.#characteristic.FirmwareRevision,
|
|
25
|
-
.setCharacteristic(this.#characteristic.HardwareRevision,
|
|
26
|
-
.setCharacteristic(this.#characteristic.SoftwareRevision,
|
|
27
|
-
switch (
|
|
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.
|
|
65
|
+
this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
|
|
44
66
|
break;
|
|
45
|
-
case '
|
|
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 '
|
|
51
|
-
this.#services.Primary = this.#accessory.getService(service.
|
|
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 (
|
|
63
|
-
this.#log.error(`Failed to
|
|
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 (
|
|
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
|
-
.
|
|
131
|
+
.updateValue(this.getSensorStatus('status'));
|
|
71
132
|
break;
|
|
72
133
|
case 'doorWindow':
|
|
73
134
|
this.#services.Primary.getCharacteristic(this.#characteristic.ContactSensorState)
|
|
74
|
-
.
|
|
135
|
+
.updateValue(this.getSensorStatus('status'));
|
|
75
136
|
break;
|
|
76
137
|
case 'fire':
|
|
77
138
|
this.#services.Primary.getCharacteristic(this.#characteristic.SmokeDetected)
|
|
78
|
-
.
|
|
139
|
+
.updateValue(this.getSensorStatus('status'));
|
|
79
140
|
break;
|
|
80
141
|
case 'flood':
|
|
81
142
|
this.#services.Primary.getCharacteristic(this.#characteristic.LeakDetected)
|
|
82
|
-
.
|
|
83
|
-
break;
|
|
84
|
-
case 'gateway':
|
|
143
|
+
.updateValue(this.getSensorStatus('status'));
|
|
85
144
|
break;
|
|
86
145
|
case 'glass':
|
|
87
|
-
this.#services.Primary.getCharacteristic(this.#characteristic.
|
|
88
|
-
.
|
|
146
|
+
this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
|
|
147
|
+
.updateValue(this.getSensorStatus('status'));
|
|
89
148
|
break;
|
|
90
|
-
case '
|
|
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
|
-
.
|
|
155
|
+
.updateValue(this.getSensorStatus('status'));
|
|
95
156
|
break;
|
|
96
|
-
case '
|
|
97
|
-
this.#services.Primary.getCharacteristic(this.#characteristic.
|
|
98
|
-
.
|
|
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
|
-
.
|
|
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(
|
|
114
|
-
const {
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
'
|
|
120
|
-
'
|
|
121
|
-
'
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
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
|
-
|
|
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 (
|
|
245
|
+
if (statuses.includes('ALARM') || statuses.includes('Open')) {
|
|
139
246
|
return this.#characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
|
|
140
247
|
}
|
|
141
|
-
if (
|
|
248
|
+
if (statuses.includes('Closed')) {
|
|
142
249
|
return this.#characteristic.ContactSensorState.CONTACT_DETECTED;
|
|
143
250
|
}
|
|
144
251
|
break;
|
|
145
252
|
case 'fire':
|
|
146
|
-
|
|
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 (
|
|
261
|
+
if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
|
|
149
262
|
return this.#characteristic.LeakDetected.LEAK_DETECTED;
|
|
150
263
|
}
|
|
151
|
-
if (
|
|
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 (
|
|
157
|
-
return
|
|
269
|
+
if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
|
|
270
|
+
return this.#characteristic.OccupancyDetected.OCCUPANCY_DETECTED;
|
|
158
271
|
}
|
|
159
|
-
if (
|
|
160
|
-
return
|
|
272
|
+
if (statuses.includes('Okay')) {
|
|
273
|
+
return this.#characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED;
|
|
161
274
|
}
|
|
162
275
|
break;
|
|
163
|
-
case '
|
|
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 (
|
|
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 '
|
|
292
|
+
case 'shock':
|
|
174
293
|
break;
|
|
175
294
|
case 'temperature':
|
|
176
|
-
|
|
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
|
-
|
|
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
|
|
183
|
-
|
|
184
|
-
|
|
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.
|
|
188
|
-
|| this.#state.data.panelStatus.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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 (
|
|
234
|
-
|
|
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
|