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.
- package/LICENSE +198 -12
- package/README.md +168 -106
- package/build/config.schema.json +18 -13
- package/build/src/lib/accessory.js +441 -122
- package/build/src/lib/accessory.js.map +1 -1
- package/build/src/lib/api.js +177 -232
- package/build/src/lib/api.js.map +1 -1
- package/build/src/lib/detect.js +188 -240
- package/build/src/lib/detect.js.map +1 -1
- package/build/src/lib/items.js +337 -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 +4 -3
- package/build/src/lib/schema.js.map +1 -1
- package/build/src/lib/utility.js +277 -38
- package/build/src/lib/utility.js.map +1 -1
- package/build/src/scripts/repl.js +14 -8
- package/build/src/scripts/repl.js.map +1 -1
- package/build/src/scripts/test-api.js +6 -6
- package/build/src/scripts/test-api.js.map +1 -1
- package/config.schema.json +18 -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,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.
|
|
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.
|
|
73
|
+
case 'shock':
|
|
74
|
+
this.#services.Primary = this.#accessory.getService(service.OccupancySensor) ?? this.#accessory.addService(service.OccupancySensor);
|
|
52
75
|
break;
|
|
53
|
-
case '
|
|
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 (
|
|
63
|
-
this.#log.error(`Failed to
|
|
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 (
|
|
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
|
-
.
|
|
134
|
+
.updateValue(this.getSensorStatus('status'));
|
|
71
135
|
break;
|
|
72
136
|
case 'doorWindow':
|
|
73
137
|
this.#services.Primary.getCharacteristic(this.#characteristic.ContactSensorState)
|
|
74
|
-
.
|
|
138
|
+
.updateValue(this.getSensorStatus('status'));
|
|
75
139
|
break;
|
|
76
140
|
case 'fire':
|
|
77
141
|
this.#services.Primary.getCharacteristic(this.#characteristic.SmokeDetected)
|
|
78
|
-
.
|
|
142
|
+
.updateValue(this.getSensorStatus('status'));
|
|
79
143
|
break;
|
|
80
144
|
case 'flood':
|
|
81
145
|
this.#services.Primary.getCharacteristic(this.#characteristic.LeakDetected)
|
|
82
|
-
.
|
|
83
|
-
break;
|
|
84
|
-
case 'gateway':
|
|
146
|
+
.updateValue(this.getSensorStatus('status'));
|
|
85
147
|
break;
|
|
86
148
|
case 'glass':
|
|
87
|
-
this.#services.Primary.getCharacteristic(this.#characteristic.
|
|
88
|
-
.
|
|
149
|
+
this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
|
|
150
|
+
.updateValue(this.getSensorStatus('status'));
|
|
89
151
|
break;
|
|
90
|
-
case '
|
|
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
|
-
.
|
|
158
|
+
.updateValue(this.getSensorStatus('status'));
|
|
95
159
|
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));
|
|
160
|
+
case 'shock':
|
|
161
|
+
this.#services.Primary.getCharacteristic(this.#characteristic.OccupancyDetected)
|
|
162
|
+
.updateValue(this.getSensorStatus('status'));
|
|
102
163
|
break;
|
|
103
|
-
case '
|
|
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
|
-
.
|
|
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(
|
|
114
|
-
const {
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
'
|
|
120
|
-
'
|
|
121
|
-
'
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
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
|
-
|
|
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 (
|
|
252
|
+
if (statuses.includes('ALARM') || statuses.includes('Open')) {
|
|
139
253
|
return this.#characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
|
|
140
254
|
}
|
|
141
|
-
if (
|
|
255
|
+
if (statuses.includes('Closed')) {
|
|
142
256
|
return this.#characteristic.ContactSensorState.CONTACT_DETECTED;
|
|
143
257
|
}
|
|
144
258
|
break;
|
|
145
259
|
case 'fire':
|
|
146
|
-
|
|
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 (
|
|
268
|
+
if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
|
|
149
269
|
return this.#characteristic.LeakDetected.LEAK_DETECTED;
|
|
150
270
|
}
|
|
151
|
-
if (
|
|
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 (
|
|
157
|
-
return
|
|
276
|
+
if (statuses.includes('ALARM') || statuses.includes('Tripped')) {
|
|
277
|
+
return this.#characteristic.OccupancyDetected.OCCUPANCY_DETECTED;
|
|
158
278
|
}
|
|
159
|
-
if (
|
|
160
|
-
return
|
|
279
|
+
if (statuses.includes('Okay')) {
|
|
280
|
+
return this.#characteristic.OccupancyDetected.OCCUPANCY_NOT_DETECTED;
|
|
161
281
|
}
|
|
162
282
|
break;
|
|
163
|
-
case '
|
|
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 (
|
|
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 '
|
|
301
|
+
case 'supervisory':
|
|
174
302
|
break;
|
|
175
303
|
case 'temperature':
|
|
176
|
-
|
|
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
|
-
|
|
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
|
|
183
|
-
|
|
184
|
-
|
|
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.
|
|
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;
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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 (
|
|
234
|
-
|
|
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
|