hap-nodejs 0.12.3-beta.10 → 0.12.3-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/BridgedCore.js +14 -14
- package/dist/BridgedCore.js.map +1 -1
- package/dist/Core.js +14 -14
- package/dist/Core.js.map +1 -1
- package/dist/accessories/AirConditioner_accessory.js +24 -24
- package/dist/accessories/AirConditioner_accessory.js.map +1 -1
- package/dist/accessories/AppleTVRemote_accessory.js +23 -23
- package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
- package/dist/accessories/Camera_accessory.js +292 -373
- package/dist/accessories/Camera_accessory.js.map +1 -1
- package/dist/accessories/Fan_accessory.js +15 -21
- package/dist/accessories/Fan_accessory.js.map +1 -1
- package/dist/accessories/GarageDoorOpener_accessory.js +12 -12
- package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
- package/dist/accessories/Light-AdaptiveLighting_accessory.js +26 -26
- package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
- package/dist/accessories/Light_accessory.js +45 -48
- package/dist/accessories/Light_accessory.js.map +1 -1
- package/dist/accessories/Lock_accessory.js +11 -11
- package/dist/accessories/Lock_accessory.js.map +1 -1
- package/dist/accessories/MotionSensor_accessory.js +8 -8
- package/dist/accessories/MotionSensor_accessory.js.map +1 -1
- package/dist/accessories/Outlet_accessory.js +10 -10
- package/dist/accessories/Outlet_accessory.js.map +1 -1
- package/dist/accessories/SmartSpeaker_accessory.js +11 -11
- package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
- package/dist/accessories/Sprinkler_accessory.js +19 -19
- package/dist/accessories/Sprinkler_accessory.js.map +1 -1
- package/dist/accessories/TV_accessory.js +17 -17
- package/dist/accessories/TV_accessory.js.map +1 -1
- package/dist/accessories/TemperatureSensor_accessory.js +6 -6
- package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.js +3 -3
- package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.js +4 -4
- package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.js +36 -47
- package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
- package/dist/accessories/types.js +2 -2
- package/dist/accessories/types.js.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/Accessory.d.ts.map +1 -1
- package/dist/lib/Accessory.js +780 -1093
- package/dist/lib/Accessory.js.map +1 -1
- package/dist/lib/AccessoryLoader.js +40 -40
- package/dist/lib/AccessoryLoader.js.map +1 -1
- package/dist/lib/Advertiser.js +392 -524
- package/dist/lib/Advertiser.js.map +1 -1
- package/dist/lib/Bridge.js +6 -10
- package/dist/lib/Bridge.js.map +1 -1
- package/dist/lib/Characteristic.js +1465 -501
- package/dist/lib/Characteristic.js.map +1 -1
- package/dist/lib/HAPServer.js +215 -265
- package/dist/lib/HAPServer.js.map +1 -1
- package/dist/lib/Service.js +519 -322
- package/dist/lib/Service.js.map +1 -1
- package/dist/lib/camera/Camera.js +14 -14
- package/dist/lib/camera/Camera.js.map +1 -1
- package/dist/lib/camera/RTPProxy.js +112 -104
- package/dist/lib/camera/RTPProxy.js.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.js +284 -257
- package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
- package/dist/lib/camera/RecordingManagement.js +318 -381
- package/dist/lib/camera/RecordingManagement.js.map +1 -1
- package/dist/lib/camera/index.js +1 -1
- package/dist/lib/controller/AdaptiveLightingController.js +198 -209
- package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
- package/dist/lib/controller/CameraController.js +190 -249
- package/dist/lib/controller/CameraController.js.map +1 -1
- package/dist/lib/controller/DoorbellController.js +38 -39
- package/dist/lib/controller/DoorbellController.js.map +1 -1
- package/dist/lib/controller/RemoteController.js +343 -401
- package/dist/lib/controller/RemoteController.js.map +1 -1
- package/dist/lib/controller/index.js +1 -1
- package/dist/lib/datastream/DataStreamManagement.js +56 -57
- package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
- package/dist/lib/datastream/DataStreamParser.js +259 -304
- package/dist/lib/datastream/DataStreamParser.js.map +1 -1
- package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamServer.js +252 -269
- package/dist/lib/datastream/DataStreamServer.js.map +1 -1
- package/dist/lib/datastream/index.js +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.js +2089 -2858
- package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.js +864 -1096
- package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
- package/dist/lib/definitions/generate-definitions.js +383 -679
- package/dist/lib/definitions/generate-definitions.js.map +1 -1
- package/dist/lib/definitions/generator-configuration.js +29 -29
- package/dist/lib/definitions/generator-configuration.js.map +1 -1
- package/dist/lib/definitions/index.js +1 -1
- package/dist/lib/model/AccessoryInfo.js +101 -136
- package/dist/lib/model/AccessoryInfo.js.map +1 -1
- package/dist/lib/model/ControllerStorage.js +86 -89
- package/dist/lib/model/ControllerStorage.js.map +1 -1
- package/dist/lib/model/HAPStorage.js +15 -16
- package/dist/lib/model/HAPStorage.js.map +1 -1
- package/dist/lib/model/IdentifierCache.js +49 -49
- package/dist/lib/model/IdentifierCache.js.map +1 -1
- package/dist/lib/tv/AccessControlManagement.js +40 -44
- package/dist/lib/tv/AccessControlManagement.js.map +1 -1
- package/dist/lib/util/checkName.d.ts +2 -1
- package/dist/lib/util/checkName.d.ts.map +1 -1
- package/dist/lib/util/checkName.js +7 -11
- package/dist/lib/util/checkName.js.map +1 -1
- package/dist/lib/util/clone.js +5 -27
- package/dist/lib/util/clone.js.map +1 -1
- package/dist/lib/util/color-utils.js +8 -12
- package/dist/lib/util/color-utils.js.map +1 -1
- package/dist/lib/util/eventedhttp.js +288 -384
- package/dist/lib/util/eventedhttp.js.map +1 -1
- package/dist/lib/util/hapCrypto.js +31 -32
- package/dist/lib/util/hapCrypto.js.map +1 -1
- package/dist/lib/util/hapStatusError.js +9 -12
- package/dist/lib/util/hapStatusError.js.map +1 -1
- package/dist/lib/util/net-utils.js +32 -53
- package/dist/lib/util/net-utils.js.map +1 -1
- package/dist/lib/util/once.js +3 -8
- package/dist/lib/util/once.js.map +1 -1
- package/dist/lib/util/promise-utils.js +8 -13
- package/dist/lib/util/promise-utils.js.map +1 -1
- package/dist/lib/util/request-util.js +2 -3
- package/dist/lib/util/request-util.js.map +1 -1
- package/dist/lib/util/time.js +5 -5
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/tlv.js +57 -76
- package/dist/lib/util/tlv.js.map +1 -1
- package/dist/lib/util/uuid.js +15 -19
- package/dist/lib/util/uuid.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/Accessory.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Accessory = exports.AccessoryEventTypes = exports.MDNSAdvertiser = exports.CharacteristicWarningType = exports.Categories = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
|
+
const crypto_1 = tslib_1.__importDefault(require("crypto"));
|
|
7
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
8
|
+
const events_1 = require("events");
|
|
9
|
+
const net_1 = tslib_1.__importDefault(require("net"));
|
|
10
|
+
const Advertiser_1 = require("./Advertiser");
|
|
11
11
|
// noinspection JSDeprecatedSymbols
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
12
|
+
const camera_1 = require("./camera");
|
|
13
|
+
const Characteristic_1 = require("./Characteristic");
|
|
14
|
+
const controller_1 = require("./controller");
|
|
15
|
+
const HAPServer_1 = require("./HAPServer");
|
|
16
|
+
const AccessoryInfo_1 = require("./model/AccessoryInfo");
|
|
17
|
+
const ControllerStorage_1 = require("./model/ControllerStorage");
|
|
18
|
+
const IdentifierCache_1 = require("./model/IdentifierCache");
|
|
19
|
+
const Service_1 = require("./Service");
|
|
20
|
+
const clone_1 = require("./util/clone");
|
|
21
|
+
const request_util_1 = require("./util/request-util");
|
|
22
|
+
const uuid = tslib_1.__importStar(require("./util/uuid"));
|
|
23
|
+
const uuid_1 = require("./util/uuid");
|
|
24
|
+
const checkName_1 = require("./util/checkName");
|
|
25
|
+
const debug = (0, debug_1.default)("HAP-NodeJS:Accessory");
|
|
26
|
+
const MAX_ACCESSORIES = 149; // Maximum number of bridged accessories per bridge.
|
|
27
|
+
const MAX_SERVICES = 100;
|
|
28
28
|
/**
|
|
29
29
|
* Known category values. Category is a hint to iOS clients about what "type" of Accessory this represents, for UI only.
|
|
30
30
|
*
|
|
@@ -164,71 +164,97 @@ var AccessoryEventTypes;
|
|
|
164
164
|
* @group Accessory
|
|
165
165
|
*/
|
|
166
166
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
167
|
+
class Accessory extends events_1.EventEmitter {
|
|
168
|
+
displayName;
|
|
169
|
+
UUID;
|
|
170
|
+
/**
|
|
171
|
+
* @deprecated Please use the Categories const enum above.
|
|
172
|
+
*/
|
|
173
|
+
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
174
|
+
static Categories = Categories;
|
|
175
|
+
/// Timeout in milliseconds until a characteristic warning is issue
|
|
176
|
+
static TIMEOUT_WARNING = 3000;
|
|
177
|
+
/// Timeout in milliseconds after `TIMEOUT_WARNING` until the operation on the characteristic is considered timed out.
|
|
178
|
+
static TIMEOUT_AFTER_WARNING = 6000;
|
|
179
|
+
// NOTICE: when adding/changing properties, remember to possibly adjust the serialize/deserialize functions
|
|
180
|
+
aid = null; // assigned by us in assignIDs() or by a Bridge
|
|
181
|
+
_isBridge = false; // true if we are a Bridge (creating a new instance of the Bridge subclass sets this to true)
|
|
182
|
+
bridged = false; // true if we are hosted "behind" a Bridge Accessory
|
|
183
|
+
bridge; // if accessory is bridged, this property points to the bridge which bridges this accessory
|
|
184
|
+
bridgedAccessories = []; // If we are a Bridge, these are the Accessories we are bridging
|
|
185
|
+
reachable = true;
|
|
186
|
+
lastKnownUsername;
|
|
187
|
+
category = 1 /* Categories.OTHER */;
|
|
188
|
+
services = [];
|
|
189
|
+
primaryService;
|
|
190
|
+
shouldPurgeUnusedIDs = true; // Purge unused ids by default
|
|
191
|
+
/**
|
|
192
|
+
* Captures if initialization steps inside {@link publish} have been called.
|
|
193
|
+
* This is important when calling {@link publish} multiple times (e.g. after calling {@link unpublish}).
|
|
194
|
+
* @private Private API
|
|
195
|
+
*/
|
|
196
|
+
initialized = false;
|
|
197
|
+
controllers = {};
|
|
198
|
+
serializedControllers; // store uninitialized controller data after a Accessory.deserialize call
|
|
199
|
+
activeCameraController;
|
|
200
|
+
/**
|
|
201
|
+
* @private Private API.
|
|
202
|
+
*/
|
|
203
|
+
_accessoryInfo;
|
|
204
|
+
/**
|
|
205
|
+
* @private Private API.
|
|
206
|
+
*/
|
|
207
|
+
_setupID = null;
|
|
208
|
+
/**
|
|
209
|
+
* @private Private API.
|
|
210
|
+
*/
|
|
211
|
+
_identifierCache;
|
|
212
|
+
/**
|
|
213
|
+
* @private Private API.
|
|
214
|
+
*/
|
|
215
|
+
controllerStorage = new ControllerStorage_1.ControllerStorage(this);
|
|
216
|
+
/**
|
|
217
|
+
* @private Private API.
|
|
218
|
+
*/
|
|
219
|
+
_advertiser;
|
|
220
|
+
/**
|
|
221
|
+
* @private Private API.
|
|
222
|
+
*/
|
|
223
|
+
_server;
|
|
224
|
+
/**
|
|
225
|
+
* @private Private API.
|
|
226
|
+
*/
|
|
227
|
+
_setupURI;
|
|
228
|
+
configurationChangeDebounceTimeout;
|
|
229
|
+
/**
|
|
230
|
+
* This property captures the time when we last served a /accessories request.
|
|
231
|
+
* For multiple bursts of /accessories request we don't want to always contact GET handlers
|
|
232
|
+
*/
|
|
233
|
+
lastAccessoriesRequest = 0;
|
|
234
|
+
constructor(displayName, UUID) {
|
|
235
|
+
super();
|
|
236
|
+
this.displayName = displayName;
|
|
237
|
+
this.UUID = UUID;
|
|
211
238
|
(0, assert_1.default)(displayName, "Accessories must be created with a non-empty displayName.");
|
|
212
239
|
(0, assert_1.default)(UUID, "Accessories must be created with a valid UUID.");
|
|
213
240
|
(0, assert_1.default)(uuid.isValid(UUID), "UUID '" + UUID + "' is not a valid UUID. Try using the provided 'generateUUID' function to create a " +
|
|
214
241
|
"valid UUID from any arbitrary string, like a serial number.");
|
|
215
242
|
// create our initial "Accessory Information" Service that all Accessories are expected to have
|
|
216
|
-
(0, checkName_1.checkName)(
|
|
217
|
-
|
|
243
|
+
(0, checkName_1.checkName)(this.displayName, "Name", displayName);
|
|
244
|
+
this.addService(Service_1.Service.AccessoryInformation)
|
|
218
245
|
.setCharacteristic(Characteristic_1.Characteristic.Name, displayName);
|
|
219
246
|
// sign up for when iOS attempts to "set" the `Identify` characteristic - this means a paired device wishes
|
|
220
247
|
// for us to identify ourselves (as opposed to an unpaired device - that case is handled by HAPServer 'identify' event)
|
|
221
|
-
|
|
248
|
+
this.getService(Service_1.Service.AccessoryInformation)
|
|
222
249
|
.getCharacteristic(Characteristic_1.Characteristic.Identify)
|
|
223
|
-
.on("set" /* CharacteristicEventTypes.SET */,
|
|
250
|
+
.on("set" /* CharacteristicEventTypes.SET */, (value, callback) => {
|
|
224
251
|
if (value) {
|
|
225
|
-
|
|
226
|
-
|
|
252
|
+
const paired = true;
|
|
253
|
+
this.identificationRequest(paired, callback);
|
|
227
254
|
}
|
|
228
255
|
});
|
|
229
|
-
return _this;
|
|
230
256
|
}
|
|
231
|
-
|
|
257
|
+
identificationRequest(paired, callback) {
|
|
232
258
|
debug("[%s] Identification request", this.displayName);
|
|
233
259
|
if (this.listeners("identify" /* AccessoryEventTypes.IDENTIFY */).length > 0) {
|
|
234
260
|
// allow implementors to identify this Accessory in whatever way is appropriate, and pass along
|
|
@@ -239,43 +265,28 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
239
265
|
debug("[%s] Identification request ignored; no listeners to 'identify' event", this.displayName);
|
|
240
266
|
callback();
|
|
241
267
|
}
|
|
242
|
-
}
|
|
268
|
+
}
|
|
243
269
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
|
-
|
|
245
|
-
var e_1, _a;
|
|
246
|
-
var constructorArgs = [];
|
|
247
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
248
|
-
constructorArgs[_i - 1] = arguments[_i];
|
|
249
|
-
}
|
|
270
|
+
addService(serviceParam, ...constructorArgs) {
|
|
250
271
|
// service might be a constructor like `Service.AccessoryInformation` instead of an instance
|
|
251
272
|
// of Service. Coerce if necessary.
|
|
252
|
-
|
|
273
|
+
const service = typeof serviceParam === "function"
|
|
253
274
|
? new serviceParam(constructorArgs[0], constructorArgs[1], constructorArgs[2])
|
|
254
275
|
: serviceParam;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
throw new Error("Cannot add a Service with the same UUID '" + existing.UUID +
|
|
267
|
-
"' and subtype '" + existing.subtype + "' as another Service in this Accessory.");
|
|
268
|
-
}
|
|
276
|
+
// check for UUID+subtype conflict
|
|
277
|
+
for (const existing of this.services) {
|
|
278
|
+
if (existing.UUID === service.UUID) {
|
|
279
|
+
// OK we have two Services with the same UUID. Check that each defines a `subtype` property and that each is unique.
|
|
280
|
+
if (!service.subtype) {
|
|
281
|
+
throw new Error("Cannot add a Service with the same UUID '" + existing.UUID +
|
|
282
|
+
"' as another Service in this Accessory without also defining a unique 'subtype' property.");
|
|
283
|
+
}
|
|
284
|
+
if (service.subtype === existing.subtype) {
|
|
285
|
+
throw new Error("Cannot add a Service with the same UUID '" + existing.UUID +
|
|
286
|
+
"' and subtype '" + existing.subtype + "' as another Service in this Accessory.");
|
|
269
287
|
}
|
|
270
288
|
}
|
|
271
289
|
}
|
|
272
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
273
|
-
finally {
|
|
274
|
-
try {
|
|
275
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
276
|
-
}
|
|
277
|
-
finally { if (e_1) throw e_1.error; }
|
|
278
|
-
}
|
|
279
290
|
if (this.services.length >= MAX_SERVICES) {
|
|
280
291
|
throw new Error("Cannot add more than " + MAX_SERVICES + " services to a single accessory!");
|
|
281
292
|
}
|
|
@@ -294,15 +305,15 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
294
305
|
}
|
|
295
306
|
this.setupServiceEventHandlers(service);
|
|
296
307
|
return service;
|
|
297
|
-
}
|
|
308
|
+
}
|
|
298
309
|
/**
|
|
299
310
|
* @deprecated use {@link Service.setPrimaryService} directly
|
|
300
311
|
*/
|
|
301
|
-
|
|
312
|
+
setPrimaryService(service) {
|
|
302
313
|
service.setPrimaryService();
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
|
|
314
|
+
}
|
|
315
|
+
removeService(service) {
|
|
316
|
+
const index = this.services.indexOf(service);
|
|
306
317
|
if (index >= 0) {
|
|
307
318
|
this.services.splice(index, 1);
|
|
308
319
|
if (this.primaryService === service) { // check if we are removing out primary service
|
|
@@ -317,86 +328,60 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
317
328
|
}
|
|
318
329
|
service.removeAllListeners();
|
|
319
330
|
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
for (var _b = tslib_1.__values(this.services), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
325
|
-
var service = _c.value;
|
|
326
|
-
service.removeLinkedService(removed);
|
|
327
|
-
}
|
|
331
|
+
}
|
|
332
|
+
removeLinkedService(removed) {
|
|
333
|
+
for (const service of this.services) {
|
|
334
|
+
service.removeLinkedService(removed);
|
|
328
335
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
336
|
+
}
|
|
337
|
+
getService(name) {
|
|
338
|
+
for (const service of this.services) {
|
|
339
|
+
if (typeof name === "string" && (service.displayName === name || service.name === name || service.subtype === name)) {
|
|
340
|
+
return service;
|
|
333
341
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
Accessory.prototype.getService = function (name) {
|
|
338
|
-
var e_3, _a;
|
|
339
|
-
try {
|
|
340
|
-
for (var _b = tslib_1.__values(this.services), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
341
|
-
var service = _c.value;
|
|
342
|
-
if (typeof name === "string" && (service.displayName === name || service.name === name || service.subtype === name)) {
|
|
342
|
+
else {
|
|
343
|
+
// @ts-expect-error ('UUID' does not exist on type 'never')
|
|
344
|
+
if (typeof name === "function" && ((service instanceof name) || (name.UUID === service.UUID))) {
|
|
343
345
|
return service;
|
|
344
346
|
}
|
|
345
|
-
else {
|
|
346
|
-
// @ts-expect-error ('UUID' does not exist on type 'never')
|
|
347
|
-
if (typeof name === "function" && ((service instanceof name) || (name.UUID === service.UUID))) {
|
|
348
|
-
return service;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
347
|
}
|
|
352
348
|
}
|
|
353
|
-
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
354
|
-
finally {
|
|
355
|
-
try {
|
|
356
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
357
|
-
}
|
|
358
|
-
finally { if (e_3) throw e_3.error; }
|
|
359
|
-
}
|
|
360
349
|
return undefined;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
350
|
+
}
|
|
351
|
+
getServiceById(uuid, subType) {
|
|
352
|
+
for (const service of this.services) {
|
|
353
|
+
if (typeof uuid === "string" && (service.displayName === uuid || service.name === uuid) && service.subtype === subType) {
|
|
354
|
+
return service;
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
// @ts-expect-error ('UUID' does not exist on type 'never')
|
|
358
|
+
if (typeof uuid === "function" && ((service instanceof uuid) || (uuid.UUID === service.UUID)) && service.subtype === subType) {
|
|
368
359
|
return service;
|
|
369
360
|
}
|
|
370
|
-
else {
|
|
371
|
-
// @ts-expect-error ('UUID' does not exist on type 'never')
|
|
372
|
-
if (typeof uuid === "function" && ((service instanceof uuid) || (uuid.UUID === service.UUID)) && service.subtype === subType) {
|
|
373
|
-
return service;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
379
|
-
finally {
|
|
380
|
-
try {
|
|
381
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
382
361
|
}
|
|
383
|
-
finally { if (e_4) throw e_4.error; }
|
|
384
362
|
}
|
|
385
363
|
return undefined;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Returns the bridging accessory if this accessory is bridged.
|
|
367
|
+
* Otherwise, returns itself.
|
|
368
|
+
*
|
|
369
|
+
* @returns the primary accessory
|
|
370
|
+
*/
|
|
371
|
+
getPrimaryAccessory = () => {
|
|
372
|
+
return this.bridged ? this.bridge : this;
|
|
386
373
|
};
|
|
387
374
|
/**
|
|
388
375
|
* @deprecated Not supported anymore
|
|
389
376
|
*/
|
|
390
|
-
|
|
377
|
+
updateReachability(reachable) {
|
|
391
378
|
if (!this.bridged) {
|
|
392
379
|
throw new Error("Cannot update reachability on non-bridged accessory!");
|
|
393
380
|
}
|
|
394
381
|
this.reachable = reachable;
|
|
395
382
|
debug("Reachability update is no longer being supported.");
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
var _this = this;
|
|
399
|
-
if (deferUpdate === void 0) { deferUpdate = false; }
|
|
383
|
+
}
|
|
384
|
+
addBridgedAccessory(accessory, deferUpdate = false) {
|
|
400
385
|
if (accessory._isBridge || accessory === this) {
|
|
401
386
|
throw new Error("Illegal state: either trying to bridge a bridge or trying to bridge itself!");
|
|
402
387
|
}
|
|
@@ -411,7 +396,7 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
411
396
|
throw new Error("Cannot Bridge more than " + MAX_ACCESSORIES + " Accessories");
|
|
412
397
|
}
|
|
413
398
|
// listen for changes in ANY characteristics of ANY services on this Accessory
|
|
414
|
-
accessory.on("service-characteristic-change" /* AccessoryEventTypes.SERVICE_CHARACTERISTIC_CHANGE */,
|
|
399
|
+
accessory.on("service-characteristic-change" /* AccessoryEventTypes.SERVICE_CHARACTERISTIC_CHANGE */, change => this.handleCharacteristicChangeEvent(accessory, change.service, change));
|
|
415
400
|
accessory.on("service-configurationChange" /* AccessoryEventTypes.SERVICE_CONFIGURATION_CHANGE */, this.enqueueConfigurationUpdate.bind(this));
|
|
416
401
|
accessory.on("characteristic-warning" /* AccessoryEventTypes.CHARACTERISTIC_WARNING */, this.handleCharacteristicWarning.bind(this));
|
|
417
402
|
accessory.bridged = true;
|
|
@@ -422,28 +407,16 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
422
407
|
this.enqueueConfigurationUpdate();
|
|
423
408
|
}
|
|
424
409
|
return accessory;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
for (var accessories_1 = tslib_1.__values(accessories), accessories_1_1 = accessories_1.next(); !accessories_1_1.done; accessories_1_1 = accessories_1.next()) {
|
|
430
|
-
var accessory = accessories_1_1.value;
|
|
431
|
-
this.addBridgedAccessory(accessory, true);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
435
|
-
finally {
|
|
436
|
-
try {
|
|
437
|
-
if (accessories_1_1 && !accessories_1_1.done && (_a = accessories_1.return)) _a.call(accessories_1);
|
|
438
|
-
}
|
|
439
|
-
finally { if (e_5) throw e_5.error; }
|
|
410
|
+
}
|
|
411
|
+
addBridgedAccessories(accessories) {
|
|
412
|
+
for (const accessory of accessories) {
|
|
413
|
+
this.addBridgedAccessory(accessory, true);
|
|
440
414
|
}
|
|
441
415
|
this.enqueueConfigurationUpdate();
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (deferUpdate === void 0) { deferUpdate = false; }
|
|
416
|
+
}
|
|
417
|
+
removeBridgedAccessory(accessory, deferUpdate = false) {
|
|
445
418
|
// check for UUID conflict
|
|
446
|
-
|
|
419
|
+
const accessoryIndex = this.bridgedAccessories.indexOf(accessory);
|
|
447
420
|
if (accessoryIndex === -1) {
|
|
448
421
|
throw new Error("Cannot find the bridged Accessory to remove.");
|
|
449
422
|
}
|
|
@@ -454,59 +427,37 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
454
427
|
if (!deferUpdate) {
|
|
455
428
|
this.enqueueConfigurationUpdate();
|
|
456
429
|
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
for (var accessories_2 = tslib_1.__values(accessories), accessories_2_1 = accessories_2.next(); !accessories_2_1.done; accessories_2_1 = accessories_2.next()) {
|
|
462
|
-
var accessory = accessories_2_1.value;
|
|
463
|
-
this.removeBridgedAccessory(accessory, true);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
467
|
-
finally {
|
|
468
|
-
try {
|
|
469
|
-
if (accessories_2_1 && !accessories_2_1.done && (_a = accessories_2.return)) _a.call(accessories_2);
|
|
470
|
-
}
|
|
471
|
-
finally { if (e_6) throw e_6.error; }
|
|
430
|
+
}
|
|
431
|
+
removeBridgedAccessories(accessories) {
|
|
432
|
+
for (const accessory of accessories) {
|
|
433
|
+
this.removeBridgedAccessory(accessory, true);
|
|
472
434
|
}
|
|
473
435
|
this.enqueueConfigurationUpdate();
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
for (
|
|
436
|
+
}
|
|
437
|
+
removeAllBridgedAccessories() {
|
|
438
|
+
for (let i = this.bridgedAccessories.length - 1; i >= 0; i--) {
|
|
477
439
|
this.removeBridgedAccessory(this.bridgedAccessories[i], true);
|
|
478
440
|
}
|
|
479
441
|
this.enqueueConfigurationUpdate();
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
var characteristic = service.getCharacteristicByIID(iid);
|
|
487
|
-
if (characteristic) {
|
|
488
|
-
return characteristic;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
|
493
|
-
finally {
|
|
494
|
-
try {
|
|
495
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
442
|
+
}
|
|
443
|
+
getCharacteristicByIID(iid) {
|
|
444
|
+
for (const service of this.services) {
|
|
445
|
+
const characteristic = service.getCharacteristicByIID(iid);
|
|
446
|
+
if (characteristic) {
|
|
447
|
+
return characteristic;
|
|
496
448
|
}
|
|
497
|
-
finally { if (e_7) throw e_7.error; }
|
|
498
449
|
}
|
|
499
|
-
}
|
|
500
|
-
|
|
450
|
+
}
|
|
451
|
+
getAccessoryByAID(aid) {
|
|
501
452
|
if (this.aid === aid) {
|
|
502
453
|
return this;
|
|
503
454
|
}
|
|
504
|
-
return this.bridgedAccessories.find(
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
|
|
455
|
+
return this.bridgedAccessories.find(value => value.aid === aid);
|
|
456
|
+
}
|
|
457
|
+
findCharacteristic(aid, iid) {
|
|
458
|
+
const accessory = this.getAccessoryByAID(aid);
|
|
508
459
|
return accessory && accessory.getCharacteristicByIID(iid);
|
|
509
|
-
}
|
|
460
|
+
}
|
|
510
461
|
// noinspection JSDeprecatedSymbols
|
|
511
462
|
/**
|
|
512
463
|
* Method is used to configure an old style CameraSource.
|
|
@@ -530,34 +481,33 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
530
481
|
* @param cameraSource - The instance of the legacy camera source
|
|
531
482
|
* @deprecated please refer to the new {@link CameraController} API and {@link configureController}
|
|
532
483
|
*/
|
|
533
|
-
|
|
534
|
-
var _this = this;
|
|
484
|
+
configureCameraSource(cameraSource) {
|
|
535
485
|
if (cameraSource.streamControllers.length === 0) {
|
|
536
486
|
throw new Error("Malformed legacy CameraSource. Did not expose any StreamControllers!");
|
|
537
487
|
}
|
|
538
|
-
|
|
539
|
-
|
|
488
|
+
const options = cameraSource.streamControllers[0].options; // grab options from one of the StreamControllers
|
|
489
|
+
const cameraControllerOptions = {
|
|
540
490
|
cameraStreamCount: cameraSource.streamControllers.length,
|
|
541
491
|
streamingOptions: options,
|
|
542
492
|
delegate: new camera_1.LegacyCameraSourceAdapter(cameraSource),
|
|
543
493
|
};
|
|
544
|
-
|
|
494
|
+
const cameraController = new controller_1.CameraController(cameraControllerOptions, true); // create CameraController in legacy mode
|
|
545
495
|
this.configureController(cameraController);
|
|
546
496
|
// we try here to be as good as possibly of keeping current behaviour
|
|
547
|
-
cameraSource.services.forEach(
|
|
497
|
+
cameraSource.services.forEach(service => {
|
|
548
498
|
if (service.UUID === Service_1.Service.CameraRTPStreamManagement.UUID || service.UUID === Service_1.Service.CameraOperatingMode.UUID
|
|
549
499
|
|| service.UUID === Service_1.Service.CameraRecordingManagement.UUID) {
|
|
550
500
|
return; // ignore those services, as they get replaced by the RTPStreamManagement
|
|
551
501
|
}
|
|
552
502
|
// all other services get added. We can't really control possibly linking to any of those ignored services
|
|
553
503
|
// so this is really only half-baked stuff.
|
|
554
|
-
|
|
504
|
+
this.addService(service);
|
|
555
505
|
});
|
|
556
506
|
// replace stream controllers; basically only to still support the "forceStop" call
|
|
557
507
|
// noinspection JSDeprecatedSymbols
|
|
558
508
|
cameraSource.streamControllers = cameraController.streamManagements;
|
|
559
509
|
return cameraController; // return the reference for the controller (maybe this could be useful?)
|
|
560
|
-
}
|
|
510
|
+
}
|
|
561
511
|
/**
|
|
562
512
|
* This method is used to set up a new Controller for this accessory. See {@link Controller} for a more detailed
|
|
563
513
|
* explanation what a Controller is and what it is capable of.
|
|
@@ -572,20 +522,19 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
572
522
|
*
|
|
573
523
|
* @param controllerConstructor - The Controller instance or constructor to the Controller with no required arguments.
|
|
574
524
|
*/
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
var controller = typeof controllerConstructor === "function"
|
|
525
|
+
configureController(controllerConstructor) {
|
|
526
|
+
const controller = typeof controllerConstructor === "function"
|
|
578
527
|
? new controllerConstructor() // any custom constructor arguments should be passed before using .bind(...)
|
|
579
528
|
: controllerConstructor;
|
|
580
|
-
|
|
529
|
+
const id = controller.controllerId();
|
|
581
530
|
if (this.controllers[id]) {
|
|
582
|
-
throw new Error(
|
|
531
|
+
throw new Error(`A Controller with the type/id '${id}' was already added to the accessory ${this.displayName}`);
|
|
583
532
|
}
|
|
584
|
-
|
|
585
|
-
|
|
533
|
+
const savedServiceMap = this.serializedControllers && this.serializedControllers[id];
|
|
534
|
+
let serviceMap;
|
|
586
535
|
if (savedServiceMap) { // we found data to restore from
|
|
587
|
-
|
|
588
|
-
|
|
536
|
+
const clonedServiceMap = (0, clone_1.clone)(savedServiceMap);
|
|
537
|
+
const updatedServiceMap = controller.initWithServices(savedServiceMap); // init controller with existing services
|
|
589
538
|
serviceMap = updatedServiceMap || savedServiceMap; // initWithServices could return an updated serviceMap, otherwise just use the existing one
|
|
590
539
|
if (updatedServiceMap) { // controller returned a ServiceMap and thus signaled an updated set of services
|
|
591
540
|
// clonedServiceMap is altered by this method, should not be touched again after this call (for the future people)
|
|
@@ -601,14 +550,14 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
601
550
|
else {
|
|
602
551
|
serviceMap = controller.constructServices(); // let the controller create his services
|
|
603
552
|
controller.configureServices(); // let the controller setup all its handlers
|
|
604
|
-
Object.values(serviceMap).forEach(
|
|
605
|
-
if (service && !
|
|
606
|
-
|
|
553
|
+
Object.values(serviceMap).forEach(service => {
|
|
554
|
+
if (service && !this.services.includes(service)) {
|
|
555
|
+
this.addService(service);
|
|
607
556
|
}
|
|
608
557
|
});
|
|
609
558
|
}
|
|
610
559
|
// --- init handlers and setup context ---
|
|
611
|
-
|
|
560
|
+
const context = {
|
|
612
561
|
controller: controller,
|
|
613
562
|
serviceMap: serviceMap,
|
|
614
563
|
};
|
|
@@ -619,7 +568,7 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
619
568
|
if (controller instanceof controller_1.CameraController) { // save CameraController for Snapshot handling
|
|
620
569
|
this.activeCameraController = controller;
|
|
621
570
|
}
|
|
622
|
-
}
|
|
571
|
+
}
|
|
623
572
|
/**
|
|
624
573
|
* This method will remove a given Controller from this accessory.
|
|
625
574
|
* The controller object will be restored to its initial state.
|
|
@@ -627,10 +576,9 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
627
576
|
*
|
|
628
577
|
* @param controller - The controller which should be removed from the accessory.
|
|
629
578
|
*/
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
var storedController = this.controllers[id];
|
|
579
|
+
removeController(controller) {
|
|
580
|
+
const id = controller.controllerId();
|
|
581
|
+
const storedController = this.controllers[id];
|
|
634
582
|
if (storedController) {
|
|
635
583
|
if (storedController.controller !== controller) {
|
|
636
584
|
throw new Error("[" + this.displayName + "] tried removing a controller with the id/type '" + id +
|
|
@@ -648,136 +596,117 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
648
596
|
if (this.activeCameraController === controller) {
|
|
649
597
|
this.activeCameraController = undefined;
|
|
650
598
|
}
|
|
651
|
-
Object.values(storedController.serviceMap).forEach(
|
|
599
|
+
Object.values(storedController.serviceMap).forEach(service => {
|
|
652
600
|
if (service) {
|
|
653
|
-
|
|
601
|
+
this.removeService(service);
|
|
654
602
|
}
|
|
655
603
|
});
|
|
656
604
|
}
|
|
657
605
|
if (this.serializedControllers) {
|
|
658
606
|
delete this.serializedControllers[id];
|
|
659
607
|
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
var controller = context.controller;
|
|
667
|
-
if (controller.handleFactoryReset) { // if the controller implements handleFactoryReset, setup event handlers for this controller
|
|
668
|
-
controller.handleFactoryReset();
|
|
669
|
-
}
|
|
670
|
-
if ((0, controller_1.isSerializableController)(controller)) {
|
|
671
|
-
this.controllerStorage.purgeControllerData(controller);
|
|
672
|
-
}
|
|
608
|
+
}
|
|
609
|
+
handleAccessoryUnpairedForControllers() {
|
|
610
|
+
for (const context of Object.values(this.controllers)) {
|
|
611
|
+
const controller = context.controller;
|
|
612
|
+
if (controller.handleFactoryReset) { // if the controller implements handleFactoryReset, setup event handlers for this controller
|
|
613
|
+
controller.handleFactoryReset();
|
|
673
614
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
finally {
|
|
677
|
-
try {
|
|
678
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
615
|
+
if ((0, controller_1.isSerializableController)(controller)) {
|
|
616
|
+
this.controllerStorage.purgeControllerData(controller);
|
|
679
617
|
}
|
|
680
|
-
finally { if (e_8) throw e_8.error; }
|
|
681
618
|
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
var _this = this;
|
|
619
|
+
}
|
|
620
|
+
handleUpdatedControllerServiceMap(originalServiceMap, updatedServiceMap) {
|
|
685
621
|
updatedServiceMap = (0, clone_1.clone)(updatedServiceMap); // clone it so we can alter it
|
|
686
|
-
Object.keys(originalServiceMap).forEach(
|
|
687
|
-
|
|
688
|
-
|
|
622
|
+
Object.keys(originalServiceMap).forEach(name => {
|
|
623
|
+
const service = originalServiceMap[name];
|
|
624
|
+
const updatedService = updatedServiceMap[name];
|
|
689
625
|
if (service && updatedService) { // we check all names contained in both ServiceMaps for changes
|
|
690
626
|
delete originalServiceMap[name]; // delete from original ServiceMap, so it will only contain deleted services at the end
|
|
691
627
|
delete updatedServiceMap[name]; // delete from updated ServiceMap, so it will only contain added services at the end
|
|
692
628
|
if (service !== updatedService) {
|
|
693
|
-
|
|
694
|
-
|
|
629
|
+
this.removeService(service);
|
|
630
|
+
this.addService(updatedService);
|
|
695
631
|
}
|
|
696
632
|
}
|
|
697
633
|
});
|
|
698
634
|
// now originalServiceMap contains only deleted services and updateServiceMap only added services
|
|
699
|
-
Object.values(originalServiceMap).forEach(
|
|
635
|
+
Object.values(originalServiceMap).forEach(service => {
|
|
700
636
|
if (service) {
|
|
701
|
-
|
|
637
|
+
this.removeService(service);
|
|
702
638
|
}
|
|
703
639
|
});
|
|
704
|
-
Object.values(updatedServiceMap).forEach(
|
|
640
|
+
Object.values(updatedServiceMap).forEach(service => {
|
|
705
641
|
if (service) {
|
|
706
|
-
|
|
642
|
+
this.addService(service);
|
|
707
643
|
}
|
|
708
644
|
});
|
|
709
|
-
}
|
|
710
|
-
|
|
645
|
+
}
|
|
646
|
+
setupURI() {
|
|
711
647
|
if (this._setupURI) {
|
|
712
648
|
return this._setupURI;
|
|
713
649
|
}
|
|
714
650
|
(0, assert_1.default)(!!this._accessoryInfo, "Cannot generate setupURI on an accessory that isn't published yet!");
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
651
|
+
const buffer = Buffer.alloc(8);
|
|
652
|
+
let value_low = parseInt(this._accessoryInfo.pincode.replace(/-/g, ""), 10);
|
|
653
|
+
const value_high = this._accessoryInfo.category >> 1;
|
|
718
654
|
value_low |= 1 << 28; // Supports IP;
|
|
719
655
|
buffer.writeUInt32BE(value_low, 4);
|
|
720
656
|
if (this._accessoryInfo.category & 1) {
|
|
721
657
|
buffer[4] = buffer[4] | 1 << 7;
|
|
722
658
|
}
|
|
723
659
|
buffer.writeUInt32BE(value_high, 0);
|
|
724
|
-
|
|
660
|
+
let encodedPayload = (buffer.readUInt32BE(4) + (buffer.readUInt32BE(0) * 0x100000000)).toString(36).toUpperCase();
|
|
725
661
|
if (encodedPayload.length !== 9) {
|
|
726
|
-
for (
|
|
662
|
+
for (let i = 0; i <= 9 - encodedPayload.length; i++) {
|
|
727
663
|
encodedPayload = "0" + encodedPayload;
|
|
728
664
|
}
|
|
729
665
|
}
|
|
730
666
|
this._setupURI = "X-HM://" + encodedPayload + this._setupID;
|
|
731
667
|
return this._setupURI;
|
|
732
|
-
}
|
|
668
|
+
}
|
|
733
669
|
/**
|
|
734
670
|
* This method is called right before the accessory is published. It should be used to check for common
|
|
735
671
|
* mistakes in Accessory structured, which may lead to HomeKit rejecting the accessory when pairing.
|
|
736
672
|
* If it is called on a bridge it will call this method for all bridged accessories.
|
|
737
673
|
*/
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
var service = this.getService(Service_1.Service.AccessoryInformation);
|
|
674
|
+
validateAccessory(mainAccessory) {
|
|
675
|
+
const service = this.getService(Service_1.Service.AccessoryInformation);
|
|
741
676
|
if (!service) {
|
|
742
677
|
console.log("HAP-NodeJS WARNING: The accessory '" + this.displayName + "' is getting published without a AccessoryInformation service. " +
|
|
743
678
|
"This might prevent the accessory from being added to the Home app or leading to the accessory being unresponsive!");
|
|
744
679
|
}
|
|
745
680
|
else {
|
|
746
681
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
747
|
-
|
|
682
|
+
const checkValue = (name, value) => {
|
|
748
683
|
if (!value) {
|
|
749
|
-
console.log("HAP-NodeJS WARNING: The accessory '" +
|
|
684
|
+
console.log("HAP-NodeJS WARNING: The accessory '" + this.displayName + "' is getting published with the characteristic '" + name + "'" +
|
|
750
685
|
" (of the AccessoryInformation service) not having a value set. " +
|
|
751
686
|
"This might prevent the accessory from being added to the Home App or leading to the accessory being unresponsive!");
|
|
752
687
|
}
|
|
753
688
|
};
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
checkValue("
|
|
760
|
-
checkValue("SerialNumber", serialNumber);
|
|
761
|
-
checkValue("FirmwareRevision", firmwareRevision);
|
|
762
|
-
checkValue("Name", name);
|
|
763
|
-
(0, checkName_1.checkName)(this.displayName, "Name", name);
|
|
764
|
-
(0, checkName_1.checkName)(this.displayName, "Manufacturer", manufacturer);
|
|
689
|
+
(0, checkName_1.checkName)(this.displayName, "Name", service.getCharacteristic(Characteristic_1.Characteristic.Name).value);
|
|
690
|
+
checkValue("FirmwareRevision", service.getCharacteristic(Characteristic_1.Characteristic.FirmwareRevision).value);
|
|
691
|
+
checkValue("Manufacturer", service.getCharacteristic(Characteristic_1.Characteristic.Manufacturer).value);
|
|
692
|
+
checkValue("Model", service.getCharacteristic(Characteristic_1.Characteristic.Model).value);
|
|
693
|
+
checkValue("Name", service.getCharacteristic(Characteristic_1.Characteristic.Name).value);
|
|
694
|
+
checkValue("SerialNumber", service.getCharacteristic(Characteristic_1.Characteristic.SerialNumber).value);
|
|
765
695
|
}
|
|
766
696
|
if (mainAccessory) {
|
|
767
697
|
// the main accessory which is advertised via bonjour must have a name with length <= 63 (limitation of DNS FQDN names)
|
|
768
698
|
(0, assert_1.default)(Buffer.from(this.displayName, "utf8").length <= 63, "Accessory displayName cannot be longer than 63 bytes!");
|
|
769
699
|
}
|
|
770
700
|
if (this.bridged) {
|
|
771
|
-
this.bridgedAccessories.forEach(
|
|
701
|
+
this.bridgedAccessories.forEach(accessory => accessory.validateAccessory());
|
|
772
702
|
}
|
|
773
|
-
}
|
|
703
|
+
}
|
|
774
704
|
/**
|
|
775
705
|
* Assigns aid/iid to ourselves, any Accessories we are bridging, and all associated Services+Characteristics. Uses
|
|
776
706
|
* the provided identifierCache to keep IDs stable.
|
|
777
707
|
* @private Private API
|
|
778
708
|
*/
|
|
779
|
-
|
|
780
|
-
var e_9, _a, e_10, _b;
|
|
709
|
+
_assignIDs(identifierCache) {
|
|
781
710
|
// if we are responsible for our own identifierCache, start the expiration process
|
|
782
711
|
// also check weather we want to have an expiration process
|
|
783
712
|
if (this._identifierCache && this.shouldPurgeUnusedIDs) {
|
|
@@ -793,37 +722,17 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
793
722
|
// we must have aid = 1
|
|
794
723
|
this.aid = 1;
|
|
795
724
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
if (this._isBridge) {
|
|
800
|
-
service._assignIDs(identifierCache, this.UUID, 2000000000);
|
|
801
|
-
}
|
|
802
|
-
else {
|
|
803
|
-
service._assignIDs(identifierCache, this.UUID);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
|
808
|
-
finally {
|
|
809
|
-
try {
|
|
810
|
-
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
725
|
+
for (const service of this.services) {
|
|
726
|
+
if (this._isBridge) {
|
|
727
|
+
service._assignIDs(identifierCache, this.UUID, 2000000000);
|
|
811
728
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
try {
|
|
815
|
-
// now assign IDs for any Accessories we are bridging
|
|
816
|
-
for (var _e = tslib_1.__values(this.bridgedAccessories), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
817
|
-
var accessory = _f.value;
|
|
818
|
-
accessory._assignIDs(identifierCache);
|
|
729
|
+
else {
|
|
730
|
+
service._assignIDs(identifierCache, this.UUID);
|
|
819
731
|
}
|
|
820
732
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
|
|
825
|
-
}
|
|
826
|
-
finally { if (e_10) throw e_10.error; }
|
|
733
|
+
// now assign IDs for any Accessories we are bridging
|
|
734
|
+
for (const accessory of this.bridgedAccessories) {
|
|
735
|
+
accessory._assignIDs(identifierCache);
|
|
827
736
|
}
|
|
828
737
|
// expire any now-unused cache keys (for Accessories, Services, or Characteristics
|
|
829
738
|
// that have been removed since the last call to assignIDs())
|
|
@@ -835,94 +744,64 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
835
744
|
//Save in case we have new ones
|
|
836
745
|
this._identifierCache.save();
|
|
837
746
|
}
|
|
838
|
-
}
|
|
839
|
-
|
|
747
|
+
}
|
|
748
|
+
disableUnusedIDPurge() {
|
|
840
749
|
this.shouldPurgeUnusedIDs = false;
|
|
841
|
-
}
|
|
842
|
-
|
|
750
|
+
}
|
|
751
|
+
enableUnusedIDPurge() {
|
|
843
752
|
this.shouldPurgeUnusedIDs = true;
|
|
844
|
-
}
|
|
753
|
+
}
|
|
845
754
|
/**
|
|
846
755
|
* Manually purge the unused ids if you like, comes handy
|
|
847
756
|
* when you have disabled auto purge, so you can do it manually
|
|
848
757
|
*/
|
|
849
|
-
|
|
758
|
+
purgeUnusedIDs() {
|
|
850
759
|
//Cache the state of the purge mechanism and set it to true
|
|
851
|
-
|
|
760
|
+
const oldValue = this.shouldPurgeUnusedIDs;
|
|
852
761
|
this.shouldPurgeUnusedIDs = true;
|
|
853
762
|
//Reassign all ids
|
|
854
763
|
this._assignIDs(this._identifierCache);
|
|
855
764
|
// Revert the purge mechanism state
|
|
856
765
|
this.shouldPurgeUnusedIDs = oldValue;
|
|
857
|
-
}
|
|
766
|
+
}
|
|
858
767
|
/**
|
|
859
768
|
* Returns a JSON representation of this accessory suitable for delivering to HAP clients.
|
|
860
769
|
*/
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
case 1:
|
|
876
|
-
accessory = (_e.services = _f.sent(),
|
|
877
|
-
_e);
|
|
878
|
-
accessories = [accessory];
|
|
879
|
-
if (!!this.bridged) return [3 /*break*/, 3];
|
|
880
|
-
_b = (_a = accessories.push).apply;
|
|
881
|
-
_c = [accessories];
|
|
882
|
-
_d = [[]];
|
|
883
|
-
return [4 /*yield*/, Promise.all(this.bridgedAccessories
|
|
884
|
-
.map(function (accessory) { return accessory.toHAP(connection, contactGetHandlers).then(function (value) { return value[0]; }); }))];
|
|
885
|
-
case 2:
|
|
886
|
-
_b.apply(_a, _c.concat([tslib_1.__spreadArray.apply(void 0, _d.concat([tslib_1.__read.apply(void 0, [_f.sent()]), false]))]));
|
|
887
|
-
_f.label = 3;
|
|
888
|
-
case 3: return [2 /*return*/, accessories];
|
|
889
|
-
}
|
|
890
|
-
});
|
|
891
|
-
});
|
|
892
|
-
};
|
|
770
|
+
async toHAP(connection, contactGetHandlers = true) {
|
|
771
|
+
(0, assert_1.default)(this.aid, "aid cannot be undefined for accessory '" + this.displayName + "'");
|
|
772
|
+
(0, assert_1.default)(this.services.length, "accessory '" + this.displayName + "' does not have any services!");
|
|
773
|
+
const accessory = {
|
|
774
|
+
aid: this.aid,
|
|
775
|
+
services: await Promise.all(this.services.map(service => service.toHAP(connection, contactGetHandlers))),
|
|
776
|
+
};
|
|
777
|
+
const accessories = [accessory];
|
|
778
|
+
if (!this.bridged) {
|
|
779
|
+
accessories.push(...await Promise.all(this.bridgedAccessories
|
|
780
|
+
.map(accessory => accessory.toHAP(connection, contactGetHandlers).then(value => value[0]))));
|
|
781
|
+
}
|
|
782
|
+
return accessories;
|
|
783
|
+
}
|
|
893
784
|
/**
|
|
894
785
|
* Returns a JSON representation of this accessory without characteristic values.
|
|
895
786
|
*/
|
|
896
|
-
|
|
897
|
-
var e_11, _a;
|
|
898
|
-
if (assignIds === void 0) { assignIds = true; }
|
|
787
|
+
internalHAPRepresentation(assignIds = true) {
|
|
899
788
|
if (assignIds) {
|
|
900
789
|
this._assignIDs(this._identifierCache); // make sure our aid/iid's are all assigned
|
|
901
790
|
}
|
|
902
791
|
(0, assert_1.default)(this.aid, "aid cannot be undefined for accessory '" + this.displayName + "'");
|
|
903
792
|
(0, assert_1.default)(this.services.length, "accessory '" + this.displayName + "' does not have any services!");
|
|
904
|
-
|
|
793
|
+
const accessory = {
|
|
905
794
|
aid: this.aid,
|
|
906
|
-
services: this.services.map(
|
|
795
|
+
services: this.services.map(service => service.internalHAPRepresentation()),
|
|
907
796
|
};
|
|
908
|
-
|
|
797
|
+
const accessories = [accessory];
|
|
909
798
|
if (!this.bridged) {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
var accessory_1 = _c.value;
|
|
913
|
-
accessories.push(accessory_1.internalHAPRepresentation(false)[0]);
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
catch (e_11_1) { e_11 = { error: e_11_1 }; }
|
|
917
|
-
finally {
|
|
918
|
-
try {
|
|
919
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
920
|
-
}
|
|
921
|
-
finally { if (e_11) throw e_11.error; }
|
|
799
|
+
for (const accessory of this.bridgedAccessories) {
|
|
800
|
+
accessories.push(accessory.internalHAPRepresentation(false)[0]);
|
|
922
801
|
}
|
|
923
802
|
}
|
|
924
803
|
return accessories;
|
|
925
|
-
}
|
|
804
|
+
}
|
|
926
805
|
/**
|
|
927
806
|
* Publishes this accessory on the local network for iOS clients to communicate with.
|
|
928
807
|
* - `info.username` - formatted as a MAC address, like `CC:22:3D:E3:CE:F6`, of this accessory.
|
|
@@ -940,182 +819,157 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
940
819
|
* }} info - Required info for publishing.
|
|
941
820
|
* @param {boolean} allowInsecureRequest - Will allow unencrypted and unauthenticated access to the http server
|
|
942
821
|
*/
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
disabledIpv6: parsed.serviceDisableIpv6,
|
|
1070
|
-
});
|
|
1071
|
-
break;
|
|
1072
|
-
case "avahi" /* MDNSAdvertiser.AVAHI */:
|
|
1073
|
-
this._advertiser = new Advertiser_1.AvahiAdvertiser(this._accessoryInfo);
|
|
1074
|
-
break;
|
|
1075
|
-
case "resolved" /* MDNSAdvertiser.RESOLVED */:
|
|
1076
|
-
this._advertiser = new Advertiser_1.ResolvedAdvertiser(this._accessoryInfo);
|
|
1077
|
-
break;
|
|
1078
|
-
default:
|
|
1079
|
-
throw new Error("Unsupported advertiser setting: '" + info.advertiser + "'");
|
|
1080
|
-
}
|
|
1081
|
-
this._advertiser.on("updated-name" /* AdvertiserEvent.UPDATED_NAME */, function (name) {
|
|
1082
|
-
_this.displayName = name;
|
|
1083
|
-
if (_this._accessoryInfo) {
|
|
1084
|
-
_this._accessoryInfo.displayName = name;
|
|
1085
|
-
_this._accessoryInfo.save();
|
|
1086
|
-
}
|
|
1087
|
-
// bonjour service name MUST match the name in the accessory information service
|
|
1088
|
-
_this.getService(Service_1.Service.AccessoryInformation)
|
|
1089
|
-
.updateCharacteristic(Characteristic_1.Characteristic.Name, name);
|
|
1090
|
-
});
|
|
1091
|
-
// create our HAP server which handles all communication between iOS devices and us
|
|
1092
|
-
this._server = new HAPServer_1.HAPServer(this._accessoryInfo);
|
|
1093
|
-
this._server.allowInsecureRequest = !!allowInsecureRequest;
|
|
1094
|
-
this._server.on("listening" /* HAPServerEventTypes.LISTENING */, this.onListening.bind(this));
|
|
1095
|
-
this._server.on("identify" /* HAPServerEventTypes.IDENTIFY */, this.identificationRequest.bind(this, false));
|
|
1096
|
-
this._server.on("pair" /* HAPServerEventTypes.PAIR */, this.handleInitialPairSetupFinished.bind(this));
|
|
1097
|
-
this._server.on("add-pairing" /* HAPServerEventTypes.ADD_PAIRING */, this.handleAddPairing.bind(this));
|
|
1098
|
-
this._server.on("remove-pairing" /* HAPServerEventTypes.REMOVE_PAIRING */, this.handleRemovePairing.bind(this));
|
|
1099
|
-
this._server.on("list-pairings" /* HAPServerEventTypes.LIST_PAIRINGS */, this.handleListPairings.bind(this));
|
|
1100
|
-
this._server.on("accessories" /* HAPServerEventTypes.ACCESSORIES */, this.handleAccessories.bind(this));
|
|
1101
|
-
this._server.on("get-characteristics" /* HAPServerEventTypes.GET_CHARACTERISTICS */, this.handleGetCharacteristics.bind(this));
|
|
1102
|
-
this._server.on("set-characteristics" /* HAPServerEventTypes.SET_CHARACTERISTICS */, this.handleSetCharacteristics.bind(this));
|
|
1103
|
-
this._server.on("connection-closed" /* HAPServerEventTypes.CONNECTION_CLOSED */, this.handleHAPConnectionClosed.bind(this));
|
|
1104
|
-
this._server.on("request-resource" /* HAPServerEventTypes.REQUEST_RESOURCE */, this.handleResource.bind(this));
|
|
1105
|
-
this._server.listen(info.port, parsed.serverAddress);
|
|
1106
|
-
this.initialized = true;
|
|
1107
|
-
return [2 /*return*/];
|
|
1108
|
-
}
|
|
1109
|
-
});
|
|
822
|
+
async publish(info, allowInsecureRequest) {
|
|
823
|
+
if (this.bridged) {
|
|
824
|
+
throw new Error("Can't publish in accessory which is bridged by another accessory. Bridged by " + this.bridge?.displayName);
|
|
825
|
+
}
|
|
826
|
+
// noinspection JSDeprecatedSymbols
|
|
827
|
+
if (!info.advertiser && info.useLegacyAdvertiser != null) {
|
|
828
|
+
// noinspection JSDeprecatedSymbols
|
|
829
|
+
info.advertiser = info.useLegacyAdvertiser ? "bonjour-hap" /* MDNSAdvertiser.BONJOUR */ : "ciao" /* MDNSAdvertiser.CIAO */;
|
|
830
|
+
console.warn("DEPRECATED The PublishInfo.useLegacyAdvertiser option has been removed. " +
|
|
831
|
+
"Please use the PublishInfo.advertiser property to enable \"ciao\" (useLegacyAdvertiser=false) " +
|
|
832
|
+
"or \"bonjour-hap\" (useLegacyAdvertiser=true) mdns advertiser libraries!");
|
|
833
|
+
}
|
|
834
|
+
// noinspection JSDeprecatedSymbols
|
|
835
|
+
if (info.mdns && info.advertiser !== "bonjour-hap" /* MDNSAdvertiser.BONJOUR */) {
|
|
836
|
+
console.log("DEPRECATED user supplied a custom 'mdns' option. This option is deprecated and ignored. " +
|
|
837
|
+
"Please move to the new 'bind' option.");
|
|
838
|
+
}
|
|
839
|
+
let service = this.getService(Service_1.Service.ProtocolInformation);
|
|
840
|
+
if (!service) {
|
|
841
|
+
service = this.addService(Service_1.Service.ProtocolInformation); // add the protocol information service to the primary accessory
|
|
842
|
+
}
|
|
843
|
+
service.setCharacteristic(Characteristic_1.Characteristic.Version, Advertiser_1.CiaoAdvertiser.protocolVersionService);
|
|
844
|
+
if (this.lastKnownUsername && this.lastKnownUsername !== info.username) { // username changed since last publish
|
|
845
|
+
Accessory.cleanupAccessoryData(this.lastKnownUsername); // delete old Accessory data
|
|
846
|
+
}
|
|
847
|
+
if (!this.initialized && (info.addIdentifyingMaterial ?? true)) {
|
|
848
|
+
// adding some identifying material to our displayName if it's our first publish() call
|
|
849
|
+
this.displayName = this.displayName + " " + crypto_1.default.createHash("sha512")
|
|
850
|
+
.update(info.username, "utf8")
|
|
851
|
+
.digest("hex").slice(0, 4).toUpperCase();
|
|
852
|
+
this.getService(Service_1.Service.AccessoryInformation).updateCharacteristic(Characteristic_1.Characteristic.Name, this.displayName);
|
|
853
|
+
}
|
|
854
|
+
// attempt to load existing AccessoryInfo from disk
|
|
855
|
+
this._accessoryInfo = AccessoryInfo_1.AccessoryInfo.load(info.username);
|
|
856
|
+
// if we don't have one, create a new one.
|
|
857
|
+
if (!this._accessoryInfo) {
|
|
858
|
+
debug("[%s] Creating new AccessoryInfo for our HAP server", this.displayName);
|
|
859
|
+
this._accessoryInfo = AccessoryInfo_1.AccessoryInfo.create(info.username);
|
|
860
|
+
}
|
|
861
|
+
if (info.setupID) {
|
|
862
|
+
this._setupID = info.setupID;
|
|
863
|
+
}
|
|
864
|
+
else if (this._accessoryInfo.setupID === undefined || this._accessoryInfo.setupID === "") {
|
|
865
|
+
this._setupID = Accessory._generateSetupID();
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
this._setupID = this._accessoryInfo.setupID;
|
|
869
|
+
}
|
|
870
|
+
this._accessoryInfo.setupID = this._setupID;
|
|
871
|
+
// make sure we have up-to-date values in AccessoryInfo, then save it in case they changed (or if we just created it)
|
|
872
|
+
this._accessoryInfo.displayName = this.displayName;
|
|
873
|
+
this._accessoryInfo.model = this.getService(Service_1.Service.AccessoryInformation).getCharacteristic(Characteristic_1.Characteristic.Model).value;
|
|
874
|
+
this._accessoryInfo.category = info.category || 1 /* Categories.OTHER */;
|
|
875
|
+
this._accessoryInfo.pincode = info.pincode;
|
|
876
|
+
this._accessoryInfo.save();
|
|
877
|
+
// create our IdentifierCache, so we can provide clients with stable aid/iid's
|
|
878
|
+
this._identifierCache = IdentifierCache_1.IdentifierCache.load(info.username);
|
|
879
|
+
// if we don't have one, create a new one.
|
|
880
|
+
if (!this._identifierCache) {
|
|
881
|
+
debug("[%s] Creating new IdentifierCache", this.displayName);
|
|
882
|
+
this._identifierCache = new IdentifierCache_1.IdentifierCache(info.username);
|
|
883
|
+
}
|
|
884
|
+
// If it's bridge and there are no accessories already assigned to the bridge
|
|
885
|
+
// probably purge is not needed since it's going to delete all the ids
|
|
886
|
+
// of accessories that might be added later. Useful when dynamically adding
|
|
887
|
+
// accessories.
|
|
888
|
+
if (this._isBridge && this.bridgedAccessories.length === 0) {
|
|
889
|
+
this.disableUnusedIDPurge();
|
|
890
|
+
this.controllerStorage.purgeUnidentifiedAccessoryData = false;
|
|
891
|
+
}
|
|
892
|
+
if (!this.initialized) { // controller storage is only loaded from disk the first time we publish!
|
|
893
|
+
this.controllerStorage.load(info.username); // initializing controller data
|
|
894
|
+
}
|
|
895
|
+
// assign aid/iid
|
|
896
|
+
this._assignIDs(this._identifierCache);
|
|
897
|
+
// get our accessory information in HAP format and determine if our configuration (that is, our
|
|
898
|
+
// Accessories/Services/Characteristics) has changed since the last time we were published. make
|
|
899
|
+
// sure to omit actual values since these are not part of the "configuration".
|
|
900
|
+
const config = this.internalHAPRepresentation(false); // TODO ensure this stuff is ordered
|
|
901
|
+
// TODO queue this check until about 5 seconds after startup, allowing some last changes after the publish call
|
|
902
|
+
// without constantly incrementing the current config number
|
|
903
|
+
this._accessoryInfo.checkForCurrentConfigurationNumberIncrement(config, true);
|
|
904
|
+
this.validateAccessory(true);
|
|
905
|
+
// create our Advertiser which broadcasts our presence over mdns
|
|
906
|
+
const parsed = Accessory.parseBindOption(info);
|
|
907
|
+
let selectedAdvertiser = info.advertiser ?? "bonjour-hap" /* MDNSAdvertiser.BONJOUR */;
|
|
908
|
+
if ((info.advertiser === "avahi" /* MDNSAdvertiser.AVAHI */ && !await Advertiser_1.AvahiAdvertiser.isAvailable()) ||
|
|
909
|
+
(info.advertiser === "resolved" /* MDNSAdvertiser.RESOLVED */ && !await Advertiser_1.ResolvedAdvertiser.isAvailable())) {
|
|
910
|
+
console.error(`[${this.displayName}] The selected advertiser, "${info.advertiser}", isn't available on this platform. ` +
|
|
911
|
+
`Reverting to "${"bonjour-hap" /* MDNSAdvertiser.BONJOUR */}"`);
|
|
912
|
+
selectedAdvertiser = "bonjour-hap" /* MDNSAdvertiser.BONJOUR */;
|
|
913
|
+
}
|
|
914
|
+
switch (selectedAdvertiser) {
|
|
915
|
+
case "ciao" /* MDNSAdvertiser.CIAO */:
|
|
916
|
+
this._advertiser = new Advertiser_1.CiaoAdvertiser(this._accessoryInfo, {
|
|
917
|
+
interface: parsed.advertiserAddress,
|
|
918
|
+
}, {
|
|
919
|
+
restrictedAddresses: parsed.serviceRestrictedAddress,
|
|
920
|
+
disabledIpv6: parsed.serviceDisableIpv6,
|
|
921
|
+
});
|
|
922
|
+
break;
|
|
923
|
+
case "bonjour-hap" /* MDNSAdvertiser.BONJOUR */:
|
|
924
|
+
// noinspection JSDeprecatedSymbols
|
|
925
|
+
this._advertiser = new Advertiser_1.BonjourHAPAdvertiser(this._accessoryInfo, info.mdns, {
|
|
926
|
+
restrictedAddresses: parsed.serviceRestrictedAddress,
|
|
927
|
+
disabledIpv6: parsed.serviceDisableIpv6,
|
|
928
|
+
});
|
|
929
|
+
break;
|
|
930
|
+
case "avahi" /* MDNSAdvertiser.AVAHI */:
|
|
931
|
+
this._advertiser = new Advertiser_1.AvahiAdvertiser(this._accessoryInfo);
|
|
932
|
+
break;
|
|
933
|
+
case "resolved" /* MDNSAdvertiser.RESOLVED */:
|
|
934
|
+
this._advertiser = new Advertiser_1.ResolvedAdvertiser(this._accessoryInfo);
|
|
935
|
+
break;
|
|
936
|
+
default:
|
|
937
|
+
throw new Error("Unsupported advertiser setting: '" + info.advertiser + "'");
|
|
938
|
+
}
|
|
939
|
+
this._advertiser.on("updated-name" /* AdvertiserEvent.UPDATED_NAME */, name => {
|
|
940
|
+
this.displayName = name;
|
|
941
|
+
if (this._accessoryInfo) {
|
|
942
|
+
this._accessoryInfo.displayName = name;
|
|
943
|
+
this._accessoryInfo.save();
|
|
944
|
+
}
|
|
945
|
+
// bonjour service name MUST match the name in the accessory information service
|
|
946
|
+
this.getService(Service_1.Service.AccessoryInformation)
|
|
947
|
+
.updateCharacteristic(Characteristic_1.Characteristic.Name, name);
|
|
1110
948
|
});
|
|
1111
|
-
|
|
949
|
+
// create our HAP server which handles all communication between iOS devices and us
|
|
950
|
+
this._server = new HAPServer_1.HAPServer(this._accessoryInfo);
|
|
951
|
+
this._server.allowInsecureRequest = !!allowInsecureRequest;
|
|
952
|
+
this._server.on("listening" /* HAPServerEventTypes.LISTENING */, this.onListening.bind(this));
|
|
953
|
+
this._server.on("identify" /* HAPServerEventTypes.IDENTIFY */, this.identificationRequest.bind(this, false));
|
|
954
|
+
this._server.on("pair" /* HAPServerEventTypes.PAIR */, this.handleInitialPairSetupFinished.bind(this));
|
|
955
|
+
this._server.on("add-pairing" /* HAPServerEventTypes.ADD_PAIRING */, this.handleAddPairing.bind(this));
|
|
956
|
+
this._server.on("remove-pairing" /* HAPServerEventTypes.REMOVE_PAIRING */, this.handleRemovePairing.bind(this));
|
|
957
|
+
this._server.on("list-pairings" /* HAPServerEventTypes.LIST_PAIRINGS */, this.handleListPairings.bind(this));
|
|
958
|
+
this._server.on("accessories" /* HAPServerEventTypes.ACCESSORIES */, this.handleAccessories.bind(this));
|
|
959
|
+
this._server.on("get-characteristics" /* HAPServerEventTypes.GET_CHARACTERISTICS */, this.handleGetCharacteristics.bind(this));
|
|
960
|
+
this._server.on("set-characteristics" /* HAPServerEventTypes.SET_CHARACTERISTICS */, this.handleSetCharacteristics.bind(this));
|
|
961
|
+
this._server.on("connection-closed" /* HAPServerEventTypes.CONNECTION_CLOSED */, this.handleHAPConnectionClosed.bind(this));
|
|
962
|
+
this._server.on("request-resource" /* HAPServerEventTypes.REQUEST_RESOURCE */, this.handleResource.bind(this));
|
|
963
|
+
this._server.listen(info.port, parsed.serverAddress);
|
|
964
|
+
this.initialized = true;
|
|
965
|
+
}
|
|
1112
966
|
/**
|
|
1113
967
|
* Removes this Accessory from the local network
|
|
1114
968
|
* Accessory object will no longer valid after invoking this method
|
|
1115
969
|
* Trying to invoke publish() on the object will result undefined behavior
|
|
1116
970
|
*/
|
|
1117
|
-
|
|
1118
|
-
|
|
971
|
+
destroy() {
|
|
972
|
+
const promise = this.unpublish();
|
|
1119
973
|
if (this._accessoryInfo) {
|
|
1120
974
|
Accessory.cleanupAccessoryData(this._accessoryInfo.username);
|
|
1121
975
|
this._accessoryInfo = undefined;
|
|
@@ -1124,44 +978,31 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1124
978
|
}
|
|
1125
979
|
this.removeAllListeners();
|
|
1126
980
|
return promise;
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
case 1:
|
|
1141
|
-
// noinspection JSIgnoredPromiseFromCall
|
|
1142
|
-
_a.sent();
|
|
1143
|
-
this._advertiser = undefined;
|
|
1144
|
-
_a.label = 2;
|
|
1145
|
-
case 2: return [2 /*return*/];
|
|
1146
|
-
}
|
|
1147
|
-
});
|
|
1148
|
-
});
|
|
1149
|
-
};
|
|
1150
|
-
Accessory.prototype.enqueueConfigurationUpdate = function () {
|
|
1151
|
-
var _this = this;
|
|
981
|
+
}
|
|
982
|
+
async unpublish() {
|
|
983
|
+
if (this._server) {
|
|
984
|
+
this._server.destroy();
|
|
985
|
+
this._server = undefined;
|
|
986
|
+
}
|
|
987
|
+
if (this._advertiser) {
|
|
988
|
+
// noinspection JSIgnoredPromiseFromCall
|
|
989
|
+
await this._advertiser.destroy();
|
|
990
|
+
this._advertiser = undefined;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
enqueueConfigurationUpdate() {
|
|
1152
994
|
if (this.configurationChangeDebounceTimeout) {
|
|
1153
995
|
return; // already enqueued
|
|
1154
996
|
}
|
|
1155
|
-
this.configurationChangeDebounceTimeout = setTimeout(
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
if (_this._advertiser && _this._advertiser) {
|
|
997
|
+
this.configurationChangeDebounceTimeout = setTimeout(() => {
|
|
998
|
+
this.configurationChangeDebounceTimeout = undefined;
|
|
999
|
+
if (this._advertiser && this._advertiser) {
|
|
1159
1000
|
// get our accessory information in HAP format and determine if our configuration (that is, our
|
|
1160
1001
|
// Accessories/Services/Characteristics) has changed since the last time we were published. make
|
|
1161
1002
|
// sure to omit actual values since these are not part of the "configuration".
|
|
1162
|
-
|
|
1163
|
-
if (
|
|
1164
|
-
|
|
1003
|
+
const config = this.internalHAPRepresentation(); // TODO ensure this stuff is ordered
|
|
1004
|
+
if (this._accessoryInfo?.checkForCurrentConfigurationNumberIncrement(config)) {
|
|
1005
|
+
this._advertiser.updateAdvertisement();
|
|
1165
1006
|
}
|
|
1166
1007
|
}
|
|
1167
1008
|
}, 1000);
|
|
@@ -1169,23 +1010,22 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1169
1010
|
// 1s is fine, HomeKit is built that with configuration updates no iid or aid conflicts occur.
|
|
1170
1011
|
// Thus, the only thing happening when the txt update arrives late is already removed accessories/services
|
|
1171
1012
|
// not responding or new accessories/services not yet shown
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
var _this = this;
|
|
1013
|
+
}
|
|
1014
|
+
onListening(port, hostname) {
|
|
1175
1015
|
(0, assert_1.default)(this._advertiser, "Advertiser wasn't created at onListening!");
|
|
1176
1016
|
// the HAP server is listening, so we can now start advertising our presence.
|
|
1177
1017
|
this._advertiser.initPort(port);
|
|
1178
1018
|
this._advertiser.startAdvertising()
|
|
1179
|
-
.then(
|
|
1180
|
-
.catch(
|
|
1019
|
+
.then(() => this.emit("advertised" /* AccessoryEventTypes.ADVERTISED */))
|
|
1020
|
+
.catch(reason => {
|
|
1181
1021
|
console.error("Could not create mDNS advertisement. The HAP-Server won't be discoverable: " + reason);
|
|
1182
1022
|
if (reason.stack) {
|
|
1183
1023
|
debug("Detailed error: " + reason.stack);
|
|
1184
1024
|
}
|
|
1185
1025
|
});
|
|
1186
1026
|
this.emit("listening" /* AccessoryEventTypes.LISTENING */, port, hostname);
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1027
|
+
}
|
|
1028
|
+
handleInitialPairSetupFinished(username, publicKey, callback) {
|
|
1189
1029
|
debug("[%s] Paired with client %s", this.displayName, username);
|
|
1190
1030
|
this._accessoryInfo && this._accessoryInfo.addPairedClient(username, publicKey, 1 /* PermissionTypes.ADMIN */);
|
|
1191
1031
|
this._accessoryInfo && this._accessoryInfo.save();
|
|
@@ -1193,8 +1033,8 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1193
1033
|
this._advertiser && this._advertiser.updateAdvertisement();
|
|
1194
1034
|
callback();
|
|
1195
1035
|
this.emit("paired" /* AccessoryEventTypes.PAIRED */);
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1036
|
+
}
|
|
1037
|
+
handleAddPairing(connection, username, publicKey, permission, callback) {
|
|
1198
1038
|
if (!this._accessoryInfo) {
|
|
1199
1039
|
callback(6 /* TLVErrorCode.UNAVAILABLE */);
|
|
1200
1040
|
return;
|
|
@@ -1203,7 +1043,7 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1203
1043
|
callback(2 /* TLVErrorCode.AUTHENTICATION */);
|
|
1204
1044
|
return;
|
|
1205
1045
|
}
|
|
1206
|
-
|
|
1046
|
+
const existingKey = this._accessoryInfo.getClientPublicKey(username);
|
|
1207
1047
|
if (existingKey) {
|
|
1208
1048
|
if (existingKey.toString() !== publicKey.toString()) {
|
|
1209
1049
|
callback(1 /* TLVErrorCode.UNKNOWN */);
|
|
@@ -1217,9 +1057,8 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1217
1057
|
this._accessoryInfo.save();
|
|
1218
1058
|
// there should be no need to update advertisement
|
|
1219
1059
|
callback(0);
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
var e_12, _a;
|
|
1060
|
+
}
|
|
1061
|
+
handleRemovePairing(connection, username, callback) {
|
|
1223
1062
|
if (!this._accessoryInfo) {
|
|
1224
1063
|
callback(6 /* TLVErrorCode.UNAVAILABLE */);
|
|
1225
1064
|
return;
|
|
@@ -1235,22 +1074,12 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1235
1074
|
this._advertiser && this._advertiser.updateAdvertisement();
|
|
1236
1075
|
this.emit("unpaired" /* AccessoryEventTypes.UNPAIRED */);
|
|
1237
1076
|
this.handleAccessoryUnpairedForControllers();
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
var accessory = _c.value;
|
|
1241
|
-
accessory.handleAccessoryUnpairedForControllers();
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
catch (e_12_1) { e_12 = { error: e_12_1 }; }
|
|
1245
|
-
finally {
|
|
1246
|
-
try {
|
|
1247
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
1248
|
-
}
|
|
1249
|
-
finally { if (e_12) throw e_12.error; }
|
|
1077
|
+
for (const accessory of this.bridgedAccessories) {
|
|
1078
|
+
accessory.handleAccessoryUnpairedForControllers();
|
|
1250
1079
|
}
|
|
1251
1080
|
}
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1081
|
+
}
|
|
1082
|
+
handleListPairings(connection, callback) {
|
|
1254
1083
|
if (!this._accessoryInfo) {
|
|
1255
1084
|
callback(6 /* TLVErrorCode.UNAVAILABLE */);
|
|
1256
1085
|
return;
|
|
@@ -1260,82 +1089,57 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1260
1089
|
return;
|
|
1261
1090
|
}
|
|
1262
1091
|
callback(0, this._accessoryInfo.listPairings());
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
var _this = this;
|
|
1092
|
+
}
|
|
1093
|
+
handleAccessories(connection, callback) {
|
|
1266
1094
|
this._assignIDs(this._identifierCache); // make sure our aid/iid's are all assigned
|
|
1267
|
-
|
|
1268
|
-
|
|
1095
|
+
const now = Date.now();
|
|
1096
|
+
const contactGetHandlers = now - this.lastAccessoriesRequest > 5_000; // we query the latest value if last /accessories was more than 5s ago
|
|
1269
1097
|
this.lastAccessoriesRequest = now;
|
|
1270
|
-
this.toHAP(connection, contactGetHandlers).then(
|
|
1098
|
+
this.toHAP(connection, contactGetHandlers).then(value => {
|
|
1271
1099
|
callback(undefined, {
|
|
1272
1100
|
accessories: value,
|
|
1273
1101
|
});
|
|
1274
|
-
},
|
|
1275
|
-
console.error("[" +
|
|
1102
|
+
}, reason => {
|
|
1103
|
+
console.error("[" + this.displayName + "] /accessories request error with: " + reason.stack);
|
|
1276
1104
|
callback({ httpCode: 500 /* HAPHTTPCode.INTERNAL_SERVER_ERROR */, status: -70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */ });
|
|
1277
1105
|
});
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
var response = { characteristics: characteristics };
|
|
1284
|
-
var missingCharacteristics = new Set(request.ids.map(function (id) { return id.aid + "." + id.iid; }));
|
|
1106
|
+
}
|
|
1107
|
+
handleGetCharacteristics(connection, request, callback) {
|
|
1108
|
+
const characteristics = [];
|
|
1109
|
+
const response = { characteristics: characteristics };
|
|
1110
|
+
const missingCharacteristics = new Set(request.ids.map(id => id.aid + "." + id.iid));
|
|
1285
1111
|
if (missingCharacteristics.size !== request.ids.length) {
|
|
1286
1112
|
// if those sizes differ, we have duplicates and can't properly handle that
|
|
1287
1113
|
callback({ httpCode: 422 /* HAPHTTPCode.UNPROCESSABLE_ENTITY */, status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ });
|
|
1288
1114
|
return;
|
|
1289
1115
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
var characteristic = accessory.getCharacteristicByIID(iid);
|
|
1300
|
-
_this.sendCharacteristicWarning(characteristic, "slow-read" /* CharacteristicWarningType.SLOW_READ */, "The read handler for the characteristic '" +
|
|
1301
|
-
characteristic.displayName + "' on the accessory '" + accessory.displayName + "' was slow to respond!");
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
catch (e_14_1) { e_14 = { error: e_14_1 }; }
|
|
1305
|
-
finally {
|
|
1306
|
-
try {
|
|
1307
|
-
if (missingCharacteristics_1_1 && !missingCharacteristics_1_1.done && (_a = missingCharacteristics_1.return)) _a.call(missingCharacteristics_1);
|
|
1308
|
-
}
|
|
1309
|
-
finally { if (e_14) throw e_14.error; }
|
|
1116
|
+
let timeout = setTimeout(() => {
|
|
1117
|
+
for (const id of missingCharacteristics) {
|
|
1118
|
+
const split = id.split(".");
|
|
1119
|
+
const aid = parseInt(split[0], 10);
|
|
1120
|
+
const iid = parseInt(split[1], 10);
|
|
1121
|
+
const accessory = this.getAccessoryByAID(aid);
|
|
1122
|
+
const characteristic = accessory.getCharacteristicByIID(iid);
|
|
1123
|
+
this.sendCharacteristicWarning(characteristic, "slow-read" /* CharacteristicWarningType.SLOW_READ */, "The read handler for the characteristic '" +
|
|
1124
|
+
characteristic.displayName + "' on the accessory '" + accessory.displayName + "' was slow to respond!");
|
|
1310
1125
|
}
|
|
1311
1126
|
// after a total of 10s we do no longer wait for a request to appear and just return status code timeout
|
|
1312
|
-
timeout = setTimeout(
|
|
1313
|
-
var e_15, _a;
|
|
1127
|
+
timeout = setTimeout(() => {
|
|
1314
1128
|
timeout = undefined;
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
status: -70408 /* HAPStatus.OPERATION_TIMED_OUT */,
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
catch (e_15_1) { e_15 = { error: e_15_1 }; }
|
|
1334
|
-
finally {
|
|
1335
|
-
try {
|
|
1336
|
-
if (missingCharacteristics_2_1 && !missingCharacteristics_2_1.done && (_a = missingCharacteristics_2.return)) _a.call(missingCharacteristics_2);
|
|
1337
|
-
}
|
|
1338
|
-
finally { if (e_15) throw e_15.error; }
|
|
1129
|
+
for (const id of missingCharacteristics) {
|
|
1130
|
+
const split = id.split(".");
|
|
1131
|
+
const aid = parseInt(split[0], 10);
|
|
1132
|
+
const iid = parseInt(split[1], 10);
|
|
1133
|
+
const accessory = this.getAccessoryByAID(aid);
|
|
1134
|
+
const characteristic = accessory.getCharacteristicByIID(iid);
|
|
1135
|
+
this.sendCharacteristicWarning(characteristic, "timeout-read" /* CharacteristicWarningType.TIMEOUT_READ */, "The read handler for the characteristic '" +
|
|
1136
|
+
characteristic.displayName + "' on the accessory '" + accessory.displayName + "' didn't respond at all!. " +
|
|
1137
|
+
"Please check that you properly call the callback!");
|
|
1138
|
+
characteristics.push({
|
|
1139
|
+
aid: aid,
|
|
1140
|
+
iid: iid,
|
|
1141
|
+
status: -70408 /* HAPStatus.OPERATION_TIMED_OUT */,
|
|
1142
|
+
});
|
|
1339
1143
|
}
|
|
1340
1144
|
missingCharacteristics.clear();
|
|
1341
1145
|
callback(undefined, response);
|
|
@@ -1343,18 +1147,22 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1343
1147
|
timeout.unref();
|
|
1344
1148
|
}, Accessory.TIMEOUT_WARNING);
|
|
1345
1149
|
timeout.unref();
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
return
|
|
1350
|
-
|
|
1351
|
-
|
|
1150
|
+
for (const id of request.ids) {
|
|
1151
|
+
const name = id.aid + "." + id.iid;
|
|
1152
|
+
this.handleCharacteristicRead(connection, id, request).then(value => {
|
|
1153
|
+
return {
|
|
1154
|
+
aid: id.aid,
|
|
1155
|
+
iid: id.iid,
|
|
1156
|
+
...value,
|
|
1157
|
+
};
|
|
1158
|
+
}, reason => {
|
|
1159
|
+
console.error(`[${this.displayName}] Read request for characteristic ${name} encountered an error: ${reason.stack}`);
|
|
1352
1160
|
return {
|
|
1353
1161
|
aid: id.aid,
|
|
1354
1162
|
iid: id.iid,
|
|
1355
1163
|
status: -70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */,
|
|
1356
1164
|
};
|
|
1357
|
-
}).then(
|
|
1165
|
+
}).then(value => {
|
|
1358
1166
|
if (!timeout) {
|
|
1359
1167
|
return; // if timeout is undefined, response was already sent out
|
|
1360
1168
|
}
|
|
@@ -1368,82 +1176,60 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1368
1176
|
callback(undefined, response);
|
|
1369
1177
|
}
|
|
1370
1178
|
});
|
|
1371
|
-
};
|
|
1372
|
-
var this_1 = this;
|
|
1373
|
-
try {
|
|
1374
|
-
for (var _b = tslib_1.__values(request.ids), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
1375
|
-
var id = _c.value;
|
|
1376
|
-
_loop_1(id);
|
|
1377
|
-
}
|
|
1378
1179
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
if (request.includeType) {
|
|
1428
|
-
data.type = (0, uuid_1.toShortForm)(characteristic.UUID);
|
|
1429
|
-
}
|
|
1430
|
-
if (request.includeEvent) {
|
|
1431
|
-
data.ev = connection.hasEventNotifications(id.aid, id.iid);
|
|
1432
|
-
}
|
|
1433
|
-
return data;
|
|
1434
|
-
}, function (reason) {
|
|
1435
|
-
// @ts-expect-error: preserveConstEnums compiler option
|
|
1436
|
-
debug("[%s] Error getting value for characteristic \"%s\": %s", _this.displayName, characteristic.displayName, HAPServer_1.HAPStatus[reason]);
|
|
1437
|
-
return { status: reason };
|
|
1438
|
-
})];
|
|
1439
|
-
});
|
|
1180
|
+
}
|
|
1181
|
+
async handleCharacteristicRead(connection, id, request) {
|
|
1182
|
+
const characteristic = this.findCharacteristic(id.aid, id.iid);
|
|
1183
|
+
if (!characteristic) {
|
|
1184
|
+
debug("[%s] Could not find a Characteristic with aid of %s and iid of %s", this.displayName, id.aid, id.iid);
|
|
1185
|
+
return { status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ };
|
|
1186
|
+
}
|
|
1187
|
+
if (!characteristic.props.perms.includes("pr" /* Perms.PAIRED_READ */)) { // check if read is allowed for this characteristic
|
|
1188
|
+
debug("[%s] Tried reading from characteristic which does not allow reading (aid of %s and iid of %s)", this.displayName, id.aid, id.iid);
|
|
1189
|
+
return { status: -70405 /* HAPStatus.WRITE_ONLY_CHARACTERISTIC */ };
|
|
1190
|
+
}
|
|
1191
|
+
if (characteristic.props.adminOnlyAccess && characteristic.props.adminOnlyAccess.includes(0 /* Access.READ */)) {
|
|
1192
|
+
const verifiable = this._accessoryInfo && connection.username;
|
|
1193
|
+
if (!verifiable) {
|
|
1194
|
+
debug("[%s] Could not verify admin permissions for Characteristic which requires admin permissions for reading (aid of %s and iid of %s)", this.displayName, id.aid, id.iid);
|
|
1195
|
+
}
|
|
1196
|
+
if (!verifiable || !this._accessoryInfo.hasAdminPermissions(connection.username)) {
|
|
1197
|
+
return { status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ };
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return characteristic.handleGetRequest(connection).then(value => {
|
|
1201
|
+
value = (0, request_util_1.formatOutgoingCharacteristicValue)(value, characteristic.props);
|
|
1202
|
+
debug("[%s] Got Characteristic \"%s\" value: \"%s\"", this.displayName, characteristic.displayName, value);
|
|
1203
|
+
const data = {
|
|
1204
|
+
value: value == null ? null : value,
|
|
1205
|
+
};
|
|
1206
|
+
if (request.includeMeta) {
|
|
1207
|
+
data.format = characteristic.props.format;
|
|
1208
|
+
data.unit = characteristic.props.unit;
|
|
1209
|
+
data.minValue = characteristic.props.minValue;
|
|
1210
|
+
data.maxValue = characteristic.props.maxValue;
|
|
1211
|
+
data.minStep = characteristic.props.minStep;
|
|
1212
|
+
data.maxLen = characteristic.props.maxLen || characteristic.props.maxDataLen;
|
|
1213
|
+
}
|
|
1214
|
+
if (request.includePerms) {
|
|
1215
|
+
data.perms = characteristic.props.perms;
|
|
1216
|
+
}
|
|
1217
|
+
if (request.includeType) {
|
|
1218
|
+
data.type = (0, uuid_1.toShortForm)(characteristic.UUID);
|
|
1219
|
+
}
|
|
1220
|
+
if (request.includeEvent) {
|
|
1221
|
+
data.ev = connection.hasEventNotifications(id.aid, id.iid);
|
|
1222
|
+
}
|
|
1223
|
+
return data;
|
|
1224
|
+
}, (reason) => {
|
|
1225
|
+
// @ts-expect-error: preserveConstEnums compiler option
|
|
1226
|
+
debug("[%s] Error getting value for characteristic \"%s\": %s", this.displayName, characteristic.displayName, HAPServer_1.HAPStatus[reason]);
|
|
1227
|
+
return { status: reason };
|
|
1440
1228
|
});
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
var e_16, _a;
|
|
1444
|
-
var _this = this;
|
|
1229
|
+
}
|
|
1230
|
+
handleSetCharacteristics(connection, writeRequest, callback) {
|
|
1445
1231
|
debug("[%s] Processing characteristic set: %s", this.displayName, JSON.stringify(writeRequest));
|
|
1446
|
-
|
|
1232
|
+
let writeState = 0 /* WriteRequestState.REGULAR_REQUEST */;
|
|
1447
1233
|
if (writeRequest.pid !== undefined) { // check for timed writes
|
|
1448
1234
|
if (connection.timedWritePid === writeRequest.pid) {
|
|
1449
1235
|
writeState = 1 /* WriteRequestState.TIMED_WRITE_AUTHENTICATED */;
|
|
@@ -1457,64 +1243,42 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1457
1243
|
debug("[%s] TTL for timed write request has probably expired for pid %d", this.displayName, writeRequest.pid);
|
|
1458
1244
|
}
|
|
1459
1245
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
.map(
|
|
1246
|
+
const characteristics = [];
|
|
1247
|
+
const response = { characteristics: characteristics };
|
|
1248
|
+
const missingCharacteristics = new Set(writeRequest.characteristics
|
|
1249
|
+
.map(characteristic => characteristic.aid + "." + characteristic.iid));
|
|
1464
1250
|
if (missingCharacteristics.size !== writeRequest.characteristics.length) {
|
|
1465
1251
|
// if those sizes differ, we have duplicates and can't properly handle that
|
|
1466
1252
|
callback({ httpCode: 422 /* HAPHTTPCode.UNPROCESSABLE_ENTITY */, status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ });
|
|
1467
1253
|
return;
|
|
1468
1254
|
}
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
var characteristic = accessory.getCharacteristicByIID(iid);
|
|
1479
|
-
_this.sendCharacteristicWarning(characteristic, "slow-write" /* CharacteristicWarningType.SLOW_WRITE */, "The write handler for the characteristic '" +
|
|
1480
|
-
characteristic.displayName + "' on the accessory '" + accessory.displayName + "' was slow to respond!");
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
catch (e_17_1) { e_17 = { error: e_17_1 }; }
|
|
1484
|
-
finally {
|
|
1485
|
-
try {
|
|
1486
|
-
if (missingCharacteristics_3_1 && !missingCharacteristics_3_1.done && (_a = missingCharacteristics_3.return)) _a.call(missingCharacteristics_3);
|
|
1487
|
-
}
|
|
1488
|
-
finally { if (e_17) throw e_17.error; }
|
|
1255
|
+
let timeout = setTimeout(() => {
|
|
1256
|
+
for (const id of missingCharacteristics) {
|
|
1257
|
+
const split = id.split(".");
|
|
1258
|
+
const aid = parseInt(split[0], 10);
|
|
1259
|
+
const iid = parseInt(split[1], 10);
|
|
1260
|
+
const accessory = this.getAccessoryByAID(aid);
|
|
1261
|
+
const characteristic = accessory.getCharacteristicByIID(iid);
|
|
1262
|
+
this.sendCharacteristicWarning(characteristic, "slow-write" /* CharacteristicWarningType.SLOW_WRITE */, "The write handler for the characteristic '" +
|
|
1263
|
+
characteristic.displayName + "' on the accessory '" + accessory.displayName + "' was slow to respond!");
|
|
1489
1264
|
}
|
|
1490
1265
|
// after a total of 10s we do no longer wait for a request to appear and just return status code timeout
|
|
1491
|
-
timeout = setTimeout(
|
|
1492
|
-
var e_18, _a;
|
|
1266
|
+
timeout = setTimeout(() => {
|
|
1493
1267
|
timeout = undefined;
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
status: -70408 /* HAPStatus.OPERATION_TIMED_OUT */,
|
|
1509
|
-
});
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
catch (e_18_1) { e_18 = { error: e_18_1 }; }
|
|
1513
|
-
finally {
|
|
1514
|
-
try {
|
|
1515
|
-
if (missingCharacteristics_4_1 && !missingCharacteristics_4_1.done && (_a = missingCharacteristics_4.return)) _a.call(missingCharacteristics_4);
|
|
1516
|
-
}
|
|
1517
|
-
finally { if (e_18) throw e_18.error; }
|
|
1268
|
+
for (const id of missingCharacteristics) {
|
|
1269
|
+
const split = id.split(".");
|
|
1270
|
+
const aid = parseInt(split[0], 10);
|
|
1271
|
+
const iid = parseInt(split[1], 10);
|
|
1272
|
+
const accessory = this.getAccessoryByAID(aid);
|
|
1273
|
+
const characteristic = accessory.getCharacteristicByIID(iid);
|
|
1274
|
+
this.sendCharacteristicWarning(characteristic, "timeout-write" /* CharacteristicWarningType.TIMEOUT_WRITE */, "The write handler for the characteristic '" +
|
|
1275
|
+
characteristic.displayName + "' on the accessory '" + accessory.displayName + "' didn't respond at all!. " +
|
|
1276
|
+
"Please check that you properly call the callback!");
|
|
1277
|
+
characteristics.push({
|
|
1278
|
+
aid: aid,
|
|
1279
|
+
iid: iid,
|
|
1280
|
+
status: -70408 /* HAPStatus.OPERATION_TIMED_OUT */,
|
|
1281
|
+
});
|
|
1518
1282
|
}
|
|
1519
1283
|
missingCharacteristics.clear();
|
|
1520
1284
|
callback(undefined, response);
|
|
@@ -1522,18 +1286,22 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1522
1286
|
timeout.unref();
|
|
1523
1287
|
}, Accessory.TIMEOUT_WARNING);
|
|
1524
1288
|
timeout.unref();
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
return
|
|
1529
|
-
|
|
1530
|
-
|
|
1289
|
+
for (const data of writeRequest.characteristics) {
|
|
1290
|
+
const name = data.aid + "." + data.iid;
|
|
1291
|
+
this.handleCharacteristicWrite(connection, data, writeState).then(value => {
|
|
1292
|
+
return {
|
|
1293
|
+
aid: data.aid,
|
|
1294
|
+
iid: data.iid,
|
|
1295
|
+
...value,
|
|
1296
|
+
};
|
|
1297
|
+
}, reason => {
|
|
1298
|
+
console.error(`[${this.displayName}] Write request for characteristic ${name} encountered an error: ${reason.stack}`);
|
|
1531
1299
|
return {
|
|
1532
1300
|
aid: data.aid,
|
|
1533
1301
|
iid: data.iid,
|
|
1534
1302
|
status: -70402 /* HAPStatus.SERVICE_COMMUNICATION_FAILURE */,
|
|
1535
1303
|
};
|
|
1536
|
-
}).then(
|
|
1304
|
+
}).then(value => {
|
|
1537
1305
|
if (!timeout) {
|
|
1538
1306
|
return; // if timeout is undefined, response was already sent out
|
|
1539
1307
|
}
|
|
@@ -1547,119 +1315,100 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1547
1315
|
callback(undefined, response);
|
|
1548
1316
|
}
|
|
1549
1317
|
});
|
|
1550
|
-
};
|
|
1551
|
-
var this_2 = this;
|
|
1552
|
-
try {
|
|
1553
|
-
for (var _b = tslib_1.__values(writeRequest.characteristics), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
1554
|
-
var data = _c.value;
|
|
1555
|
-
_loop_2(data);
|
|
1556
|
-
}
|
|
1557
1318
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1319
|
+
}
|
|
1320
|
+
async handleCharacteristicWrite(connection, data, writeState) {
|
|
1321
|
+
const characteristic = this.findCharacteristic(data.aid, data.iid);
|
|
1322
|
+
if (!characteristic) {
|
|
1323
|
+
debug("[%s] Could not find a Characteristic with aid of %s and iid of %s", this.displayName, data.aid, data.iid);
|
|
1324
|
+
return { status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ };
|
|
1325
|
+
}
|
|
1326
|
+
if (writeState === 2 /* WriteRequestState.TIMED_WRITE_REJECTED */) {
|
|
1327
|
+
return { status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ };
|
|
1328
|
+
}
|
|
1329
|
+
if (data.ev == null && data.value == null) {
|
|
1330
|
+
return { status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ };
|
|
1331
|
+
}
|
|
1332
|
+
if (data.ev != null) { // register/unregister event notifications
|
|
1333
|
+
if (!characteristic.props.perms.includes("ev" /* Perms.NOTIFY */)) { // check if notify is allowed for this characteristic
|
|
1334
|
+
debug("[%s] Tried %s notifications for Characteristic which does not allow notify (aid of %s and iid of %s)", this.displayName, data.ev ? "enabling" : "disabling", data.aid, data.iid);
|
|
1335
|
+
return { status: -70406 /* HAPStatus.NOTIFICATION_NOT_SUPPORTED */ };
|
|
1336
|
+
}
|
|
1337
|
+
if (characteristic.props.adminOnlyAccess && characteristic.props.adminOnlyAccess.includes(2 /* Access.NOTIFY */)) {
|
|
1338
|
+
const verifiable = connection.username && this._accessoryInfo;
|
|
1339
|
+
if (!verifiable) {
|
|
1340
|
+
debug("[%s] Could not verify admin permissions for Characteristic which requires admin permissions for notify (aid of %s and iid of %s)", this.displayName, data.aid, data.iid);
|
|
1341
|
+
}
|
|
1342
|
+
if (!verifiable || !this._accessoryInfo.hasAdminPermissions(connection.username)) {
|
|
1343
|
+
return { status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ };
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
const notificationsEnabled = connection.hasEventNotifications(data.aid, data.iid);
|
|
1347
|
+
if (data.ev && !notificationsEnabled) {
|
|
1348
|
+
connection.enableEventNotifications(data.aid, data.iid);
|
|
1349
|
+
characteristic.subscribe();
|
|
1350
|
+
debug("[%s] Registered Characteristic \"%s\" on \"%s\" for events", connection.remoteAddress, characteristic.displayName, this.displayName);
|
|
1562
1351
|
}
|
|
1563
|
-
|
|
1352
|
+
else if (!data.ev && notificationsEnabled) {
|
|
1353
|
+
characteristic.unsubscribe();
|
|
1354
|
+
connection.disableEventNotifications(data.aid, data.iid);
|
|
1355
|
+
debug("[%s] Unregistered Characteristic \"%s\" on \"%s\" for events", connection.remoteAddress, characteristic.displayName, this.displayName);
|
|
1356
|
+
}
|
|
1357
|
+
// response is returned below in the else block
|
|
1564
1358
|
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
if (!
|
|
1573
|
-
debug("[%s] Could not
|
|
1574
|
-
return [2 /*return*/, { status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }];
|
|
1359
|
+
if (data.value != null) {
|
|
1360
|
+
if (!characteristic.props.perms.includes("pw" /* Perms.PAIRED_WRITE */)) { // check if write is allowed for this characteristic
|
|
1361
|
+
debug("[%s] Tried writing to Characteristic which does not allow writing (aid of %s and iid of %s)", this.displayName, data.aid, data.iid);
|
|
1362
|
+
return { status: -70404 /* HAPStatus.READ_ONLY_CHARACTERISTIC */ };
|
|
1363
|
+
}
|
|
1364
|
+
if (characteristic.props.adminOnlyAccess && characteristic.props.adminOnlyAccess.includes(1 /* Access.WRITE */)) {
|
|
1365
|
+
const verifiable = connection.username && this._accessoryInfo;
|
|
1366
|
+
if (!verifiable) {
|
|
1367
|
+
debug("[%s] Could not verify admin permissions for Characteristic which requires admin permissions for write (aid of %s and iid of %s)", this.displayName, data.aid, data.iid);
|
|
1575
1368
|
}
|
|
1576
|
-
if (
|
|
1577
|
-
return
|
|
1369
|
+
if (!verifiable || !this._accessoryInfo.hasAdminPermissions(connection.username)) {
|
|
1370
|
+
return { status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ };
|
|
1578
1371
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1372
|
+
}
|
|
1373
|
+
if (characteristic.props.perms.includes("aa" /* Perms.ADDITIONAL_AUTHORIZATION */) && characteristic.additionalAuthorizationHandler) {
|
|
1374
|
+
// if the characteristic "supports additional authorization" but doesn't define a handler for the check
|
|
1375
|
+
// we conclude that the characteristic doesn't want to check the authData (currently) and just allows access for everybody
|
|
1376
|
+
let allowWrite;
|
|
1377
|
+
try {
|
|
1378
|
+
allowWrite = characteristic.additionalAuthorizationHandler(data.authData);
|
|
1581
1379
|
}
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
return [2 /*return*/, { status: -70406 /* HAPStatus.NOTIFICATION_NOT_SUPPORTED */ }];
|
|
1586
|
-
}
|
|
1587
|
-
if (characteristic.props.adminOnlyAccess && characteristic.props.adminOnlyAccess.includes(2 /* Access.NOTIFY */)) {
|
|
1588
|
-
verifiable = connection.username && this._accessoryInfo;
|
|
1589
|
-
if (!verifiable) {
|
|
1590
|
-
debug("[%s] Could not verify admin permissions for Characteristic which requires admin permissions for notify (aid of %s and iid of %s)", this.displayName, data.aid, data.iid);
|
|
1591
|
-
}
|
|
1592
|
-
if (!verifiable || !this._accessoryInfo.hasAdminPermissions(connection.username)) {
|
|
1593
|
-
return [2 /*return*/, { status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }];
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
notificationsEnabled = connection.hasEventNotifications(data.aid, data.iid);
|
|
1597
|
-
if (data.ev && !notificationsEnabled) {
|
|
1598
|
-
connection.enableEventNotifications(data.aid, data.iid);
|
|
1599
|
-
characteristic.subscribe();
|
|
1600
|
-
debug("[%s] Registered Characteristic \"%s\" on \"%s\" for events", connection.remoteAddress, characteristic.displayName, this.displayName);
|
|
1601
|
-
}
|
|
1602
|
-
else if (!data.ev && notificationsEnabled) {
|
|
1603
|
-
characteristic.unsubscribe();
|
|
1604
|
-
connection.disableEventNotifications(data.aid, data.iid);
|
|
1605
|
-
debug("[%s] Unregistered Characteristic \"%s\" on \"%s\" for events", connection.remoteAddress, characteristic.displayName, this.displayName);
|
|
1606
|
-
}
|
|
1607
|
-
// response is returned below in the else block
|
|
1380
|
+
catch (error) {
|
|
1381
|
+
console.warn("[" + this.displayName + "] Additional authorization handler has thrown an error when checking authData: " + error.stack);
|
|
1382
|
+
allowWrite = false;
|
|
1608
1383
|
}
|
|
1609
|
-
if (
|
|
1610
|
-
|
|
1611
|
-
debug("[%s] Tried writing to Characteristic which does not allow writing (aid of %s and iid of %s)", this.displayName, data.aid, data.iid);
|
|
1612
|
-
return [2 /*return*/, { status: -70404 /* HAPStatus.READ_ONLY_CHARACTERISTIC */ }];
|
|
1613
|
-
}
|
|
1614
|
-
if (characteristic.props.adminOnlyAccess && characteristic.props.adminOnlyAccess.includes(1 /* Access.WRITE */)) {
|
|
1615
|
-
verifiable = connection.username && this._accessoryInfo;
|
|
1616
|
-
if (!verifiable) {
|
|
1617
|
-
debug("[%s] Could not verify admin permissions for Characteristic which requires admin permissions for write (aid of %s and iid of %s)", this.displayName, data.aid, data.iid);
|
|
1618
|
-
}
|
|
1619
|
-
if (!verifiable || !this._accessoryInfo.hasAdminPermissions(connection.username)) {
|
|
1620
|
-
return [2 /*return*/, { status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }];
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
if (characteristic.props.perms.includes("aa" /* Perms.ADDITIONAL_AUTHORIZATION */) && characteristic.additionalAuthorizationHandler) {
|
|
1624
|
-
allowWrite = void 0;
|
|
1625
|
-
try {
|
|
1626
|
-
allowWrite = characteristic.additionalAuthorizationHandler(data.authData);
|
|
1627
|
-
}
|
|
1628
|
-
catch (error) {
|
|
1629
|
-
console.warn("[" + this.displayName + "] Additional authorization handler has thrown an error when checking authData: " + error.stack);
|
|
1630
|
-
allowWrite = false;
|
|
1631
|
-
}
|
|
1632
|
-
if (!allowWrite) {
|
|
1633
|
-
return [2 /*return*/, { status: -70411 /* HAPStatus.INSUFFICIENT_AUTHORIZATION */ }];
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
if (characteristic.props.perms.includes("tw" /* Perms.TIMED_WRITE */) && writeState !== 1 /* WriteRequestState.TIMED_WRITE_AUTHENTICATED */) {
|
|
1637
|
-
debug("[%s] Tried writing to a timed write only Characteristic without properly preparing (iid of %s and aid of %s)", this.displayName, data.aid, data.iid);
|
|
1638
|
-
return [2 /*return*/, { status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }];
|
|
1639
|
-
}
|
|
1640
|
-
return [2 /*return*/, characteristic.handleSetRequest(data.value, connection).then(function (value) {
|
|
1641
|
-
debug("[%s] Setting Characteristic \"%s\" to value %s", _this.displayName, characteristic.displayName, data.value);
|
|
1642
|
-
return {
|
|
1643
|
-
// if write response is requests and value is provided, return that
|
|
1644
|
-
value: data.r && value ? (0, request_util_1.formatOutgoingCharacteristicValue)(value, characteristic.props) : undefined,
|
|
1645
|
-
status: 0 /* HAPStatus.SUCCESS */,
|
|
1646
|
-
};
|
|
1647
|
-
}, function (status) {
|
|
1648
|
-
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
1649
|
-
debug("[%s] Error setting Characteristic \"%s\" to value %s: ", _this.displayName, characteristic.displayName, data.value, HAPServer_1.HAPStatus[status]);
|
|
1650
|
-
return { status: status };
|
|
1651
|
-
})];
|
|
1384
|
+
if (!allowWrite) {
|
|
1385
|
+
return { status: -70411 /* HAPStatus.INSUFFICIENT_AUTHORIZATION */ };
|
|
1652
1386
|
}
|
|
1653
|
-
|
|
1387
|
+
}
|
|
1388
|
+
if (characteristic.props.perms.includes("tw" /* Perms.TIMED_WRITE */) && writeState !== 1 /* WriteRequestState.TIMED_WRITE_AUTHENTICATED */) {
|
|
1389
|
+
debug("[%s] Tried writing to a timed write only Characteristic without properly preparing (iid of %s and aid of %s)", this.displayName, data.aid, data.iid);
|
|
1390
|
+
return { status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ };
|
|
1391
|
+
}
|
|
1392
|
+
return characteristic.handleSetRequest(data.value, connection).then(value => {
|
|
1393
|
+
debug("[%s] Setting Characteristic \"%s\" to value %s", this.displayName, characteristic.displayName, data.value);
|
|
1394
|
+
return {
|
|
1395
|
+
// if write response is requests and value is provided, return that
|
|
1396
|
+
value: data.r && value ? (0, request_util_1.formatOutgoingCharacteristicValue)(value, characteristic.props) : undefined,
|
|
1397
|
+
status: 0 /* HAPStatus.SUCCESS */,
|
|
1398
|
+
};
|
|
1399
|
+
}, (status) => {
|
|
1400
|
+
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
1401
|
+
debug("[%s] Error setting Characteristic \"%s\" to value %s: ", this.displayName, characteristic.displayName, data.value, HAPServer_1.HAPStatus[status]);
|
|
1402
|
+
return { status: status };
|
|
1654
1403
|
});
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1404
|
+
}
|
|
1405
|
+
return { status: 0 /* HAPStatus.SUCCESS */ };
|
|
1406
|
+
}
|
|
1407
|
+
handleResource(data, callback) {
|
|
1659
1408
|
if (data["resource-type"] === "image" /* ResourceRequestType.IMAGE */) {
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1409
|
+
const aid = data.aid; // aid is optionally supplied by HomeKit (for example when camera is bridged, multiple cams, etc)
|
|
1410
|
+
let accessory = undefined;
|
|
1411
|
+
let controller = undefined;
|
|
1663
1412
|
if (aid) {
|
|
1664
1413
|
accessory = this.getAccessoryByAID(aid);
|
|
1665
1414
|
if (accessory && accessory.activeCameraController) {
|
|
@@ -1676,44 +1425,33 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1676
1425
|
callback({ httpCode: 404 /* HAPHTTPCode.NOT_FOUND */, status: -70409 /* HAPStatus.RESOURCE_DOES_NOT_EXIST */ });
|
|
1677
1426
|
return;
|
|
1678
1427
|
}
|
|
1679
|
-
controller.handleSnapshotRequest(data["image-height"], data["image-width"], accessory
|
|
1680
|
-
.then(
|
|
1428
|
+
controller.handleSnapshotRequest(data["image-height"], data["image-width"], accessory?.displayName, data.reason)
|
|
1429
|
+
.then(buffer => {
|
|
1681
1430
|
callback(undefined, buffer);
|
|
1682
|
-
},
|
|
1431
|
+
}, (status) => {
|
|
1683
1432
|
callback({ httpCode: 207 /* HAPHTTPCode.MULTI_STATUS */, status: status });
|
|
1684
1433
|
});
|
|
1685
1434
|
return;
|
|
1686
1435
|
}
|
|
1687
|
-
debug("[%s] received request for unsupported image type: " + data["resource-type"],
|
|
1436
|
+
debug("[%s] received request for unsupported image type: " + data["resource-type"], this._accessoryInfo?.username);
|
|
1688
1437
|
callback({ httpCode: 404 /* HAPHTTPCode.NOT_FOUND */, status: -70409 /* HAPStatus.RESOURCE_DOES_NOT_EXIST */ });
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
var e_19, _a;
|
|
1438
|
+
}
|
|
1439
|
+
handleHAPConnectionClosed(connection) {
|
|
1692
1440
|
if (this.activeCameraController) {
|
|
1693
1441
|
this.activeCameraController.handleCloseConnection(connection.sessionID);
|
|
1694
1442
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
if (characteristic) {
|
|
1703
|
-
characteristic.unsubscribe();
|
|
1704
|
-
}
|
|
1443
|
+
for (const event of connection.getRegisteredEvents()) {
|
|
1444
|
+
const ids = event.split(".");
|
|
1445
|
+
const aid = parseInt(ids[0], 10);
|
|
1446
|
+
const iid = parseInt(ids[1], 10);
|
|
1447
|
+
const characteristic = this.findCharacteristic(aid, iid);
|
|
1448
|
+
if (characteristic) {
|
|
1449
|
+
characteristic.unsubscribe();
|
|
1705
1450
|
}
|
|
1706
1451
|
}
|
|
1707
|
-
catch (e_19_1) { e_19 = { error: e_19_1 }; }
|
|
1708
|
-
finally {
|
|
1709
|
-
try {
|
|
1710
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
1711
|
-
}
|
|
1712
|
-
finally { if (e_19) throw e_19.error; }
|
|
1713
|
-
}
|
|
1714
1452
|
connection.clearRegisteredEvents();
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1453
|
+
}
|
|
1454
|
+
handleServiceConfigurationChangeEvent(service) {
|
|
1717
1455
|
if (!service.isPrimaryService && service === this.primaryService) {
|
|
1718
1456
|
// service changed form primary to non-primary service
|
|
1719
1457
|
this.primaryService = undefined;
|
|
@@ -1731,10 +1469,10 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1731
1469
|
else {
|
|
1732
1470
|
this.enqueueConfigurationUpdate();
|
|
1733
1471
|
}
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1472
|
+
}
|
|
1473
|
+
handleCharacteristicChangeEvent(accessory, service, change) {
|
|
1736
1474
|
if (this.bridged) { // forward this to our main accessory
|
|
1737
|
-
this.emit("service-characteristic-change" /* AccessoryEventTypes.SERVICE_CHARACTERISTIC_CHANGE */,
|
|
1475
|
+
this.emit("service-characteristic-change" /* AccessoryEventTypes.SERVICE_CHARACTERISTIC_CHANGE */, { ...change, service: service });
|
|
1738
1476
|
}
|
|
1739
1477
|
else {
|
|
1740
1478
|
if (!this._server) {
|
|
@@ -1757,14 +1495,14 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1757
1495
|
// otherwise we ignore this change event (with the return below)
|
|
1758
1496
|
return;
|
|
1759
1497
|
}
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
||
|
|
1763
|
-
|
|
1498
|
+
const uuid = change.characteristic.UUID;
|
|
1499
|
+
const immediateDelivery = uuid === Characteristic_1.Characteristic.ButtonEvent.UUID || uuid === Characteristic_1.Characteristic.ProgrammableSwitchEvent.UUID
|
|
1500
|
+
|| uuid === Characteristic_1.Characteristic.MotionDetected.UUID || uuid === Characteristic_1.Characteristic.ContactSensorState.UUID;
|
|
1501
|
+
const value = (0, request_util_1.formatOutgoingCharacteristicValue)(change.newValue, change.characteristic.props);
|
|
1764
1502
|
this._server.sendEventNotifications(accessory.aid, change.characteristic.iid, value, change.originator, immediateDelivery);
|
|
1765
1503
|
}
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1504
|
+
}
|
|
1505
|
+
sendCharacteristicWarning(characteristic, type, message) {
|
|
1768
1506
|
this.handleCharacteristicWarning({
|
|
1769
1507
|
characteristic: characteristic,
|
|
1770
1508
|
type: type,
|
|
@@ -1772,13 +1510,12 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1772
1510
|
originatorChain: [characteristic.displayName], // we are missing the service displayName, but that's okay
|
|
1773
1511
|
stack: new Error().stack,
|
|
1774
1512
|
});
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
var emitted = this.emit("characteristic-warning" /* AccessoryEventTypes.CHARACTERISTIC_WARNING */, warning);
|
|
1513
|
+
}
|
|
1514
|
+
handleCharacteristicWarning(warning) {
|
|
1515
|
+
warning.originatorChain = [this.displayName, ...warning.originatorChain];
|
|
1516
|
+
const emitted = this.emit("characteristic-warning" /* AccessoryEventTypes.CHARACTERISTIC_WARNING */, warning);
|
|
1780
1517
|
if (!emitted) {
|
|
1781
|
-
|
|
1518
|
+
const message = `[${warning.originatorChain.join("@")}] ${warning.message}`;
|
|
1782
1519
|
if (warning.type === "error-message" /* CharacteristicWarningType.ERROR_MESSAGE */
|
|
1783
1520
|
|| warning.type === "timeout-read" /* CharacteristicWarningType.TIMEOUT_READ */ || warning.type === "timeout-write" /* CharacteristicWarningType.TIMEOUT_WRITE */) {
|
|
1784
1521
|
console.error(message);
|
|
@@ -1786,67 +1523,55 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1786
1523
|
else {
|
|
1787
1524
|
console.warn(message);
|
|
1788
1525
|
}
|
|
1789
|
-
debug("[%s] Above characteristic warning was thrown at: %s", this.displayName,
|
|
1526
|
+
debug("[%s] Above characteristic warning was thrown at: %s", this.displayName, warning.stack ?? "unknown");
|
|
1790
1527
|
}
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1528
|
+
}
|
|
1529
|
+
setupServiceEventHandlers(service) {
|
|
1793
1530
|
service.on("service-configurationChange" /* ServiceEventTypes.SERVICE_CONFIGURATION_CHANGE */, this.handleServiceConfigurationChangeEvent.bind(this, service));
|
|
1794
1531
|
service.on("characteristic-change" /* ServiceEventTypes.CHARACTERISTIC_CHANGE */, this.handleCharacteristicChangeEvent.bind(this, this, service));
|
|
1795
1532
|
service.on("characteristic-warning" /* ServiceEventTypes.CHARACTERISTIC_WARNING */, this.handleCharacteristicWarning.bind(this));
|
|
1796
|
-
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
try {
|
|
1801
|
-
for (var targetServices_1 = tslib_1.__values(targetServices), targetServices_1_1 = targetServices_1.next(); !targetServices_1_1.done; targetServices_1_1 = targetServices_1.next()) {
|
|
1802
|
-
var service = targetServices_1_1.value;
|
|
1803
|
-
this.setupServiceEventHandlers(service);
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
catch (e_20_1) { e_20 = { error: e_20_1 }; }
|
|
1807
|
-
finally {
|
|
1808
|
-
try {
|
|
1809
|
-
if (targetServices_1_1 && !targetServices_1_1.done && (_a = targetServices_1.return)) _a.call(targetServices_1);
|
|
1810
|
-
}
|
|
1811
|
-
finally { if (e_20) throw e_20.error; }
|
|
1533
|
+
}
|
|
1534
|
+
_sideloadServices(targetServices) {
|
|
1535
|
+
for (const service of targetServices) {
|
|
1536
|
+
this.setupServiceEventHandlers(service);
|
|
1812
1537
|
}
|
|
1813
1538
|
this.services = targetServices.slice();
|
|
1814
1539
|
// Fix Identify
|
|
1815
1540
|
this
|
|
1816
1541
|
.getService(Service_1.Service.AccessoryInformation)
|
|
1817
1542
|
.getCharacteristic(Characteristic_1.Characteristic.Identify)
|
|
1818
|
-
.on("set" /* CharacteristicEventTypes.SET */,
|
|
1543
|
+
.on("set" /* CharacteristicEventTypes.SET */, (value, callback) => {
|
|
1819
1544
|
if (value) {
|
|
1820
|
-
|
|
1821
|
-
|
|
1545
|
+
const paired = true;
|
|
1546
|
+
this.identificationRequest(paired, callback);
|
|
1822
1547
|
}
|
|
1823
1548
|
});
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
for (
|
|
1830
|
-
|
|
1549
|
+
}
|
|
1550
|
+
static _generateSetupID() {
|
|
1551
|
+
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
1552
|
+
const max = chars.length;
|
|
1553
|
+
let setupID = "";
|
|
1554
|
+
for (let i = 0; i < 4; i++) {
|
|
1555
|
+
const index = Math.floor(Math.random() * max);
|
|
1831
1556
|
setupID += chars.charAt(index);
|
|
1832
1557
|
}
|
|
1833
1558
|
return setupID;
|
|
1834
|
-
}
|
|
1559
|
+
}
|
|
1835
1560
|
// serialization and deserialization functions, mainly designed for homebridge to create a json copy to store on disk
|
|
1836
|
-
|
|
1837
|
-
|
|
1561
|
+
static serialize(accessory) {
|
|
1562
|
+
const json = {
|
|
1838
1563
|
displayName: accessory.displayName,
|
|
1839
1564
|
UUID: accessory.UUID,
|
|
1840
1565
|
lastKnownUsername: accessory._accessoryInfo ? accessory._accessoryInfo.username : undefined,
|
|
1841
1566
|
category: accessory.category,
|
|
1842
1567
|
services: [],
|
|
1843
1568
|
};
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
accessory.services.forEach(
|
|
1569
|
+
const linkedServices = {};
|
|
1570
|
+
let hasLinkedServices = false;
|
|
1571
|
+
accessory.services.forEach(service => {
|
|
1847
1572
|
json.services.push(Service_1.Service.serialize(service));
|
|
1848
|
-
|
|
1849
|
-
service.linkedServices.forEach(
|
|
1573
|
+
const linkedServicesPresentation = [];
|
|
1574
|
+
service.linkedServices.forEach(linkedService => {
|
|
1850
1575
|
linkedServicesPresentation.push(linkedService.getServiceId());
|
|
1851
1576
|
});
|
|
1852
1577
|
if (linkedServicesPresentation.length > 0) {
|
|
@@ -1857,17 +1582,16 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1857
1582
|
if (hasLinkedServices) {
|
|
1858
1583
|
json.linkedServices = linkedServices;
|
|
1859
1584
|
}
|
|
1860
|
-
|
|
1585
|
+
const controllers = [];
|
|
1861
1586
|
// save controllers
|
|
1862
|
-
Object.values(accessory.controllers).forEach(
|
|
1587
|
+
Object.values(accessory.controllers).forEach((context) => {
|
|
1863
1588
|
controllers.push({
|
|
1864
1589
|
type: context.controller.controllerId(),
|
|
1865
1590
|
services: Accessory.serializeServiceMap(context.serviceMap),
|
|
1866
1591
|
});
|
|
1867
1592
|
});
|
|
1868
1593
|
// also save controller which didn't get initialized (could lead to service duplication if we throw that data away)
|
|
1869
|
-
accessory.serializedControllers && Object.entries(accessory.serializedControllers).forEach(
|
|
1870
|
-
var _b = tslib_1.__read(_a, 2), id = _b[0], serviceMap = _b[1];
|
|
1594
|
+
accessory.serializedControllers && Object.entries(accessory.serializedControllers).forEach(([id, serviceMap]) => {
|
|
1871
1595
|
controllers.push({
|
|
1872
1596
|
type: id,
|
|
1873
1597
|
services: Accessory.serializeServiceMap(serviceMap),
|
|
@@ -1877,89 +1601,72 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1877
1601
|
json.controllers = controllers;
|
|
1878
1602
|
}
|
|
1879
1603
|
return json;
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
var accessory = new Accessory(json.displayName, json.UUID);
|
|
1604
|
+
}
|
|
1605
|
+
static deserialize(json) {
|
|
1606
|
+
const accessory = new Accessory(json.displayName, json.UUID);
|
|
1884
1607
|
accessory.lastKnownUsername = json.lastKnownUsername;
|
|
1885
1608
|
accessory.category = json.category;
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
json.services.forEach(
|
|
1889
|
-
|
|
1609
|
+
const services = [];
|
|
1610
|
+
const servicesMap = {};
|
|
1611
|
+
json.services.forEach(serialized => {
|
|
1612
|
+
const service = Service_1.Service.deserialize(serialized);
|
|
1890
1613
|
services.push(service);
|
|
1891
1614
|
servicesMap[service.getServiceId()] = service;
|
|
1892
1615
|
});
|
|
1893
1616
|
if (json.linkedServices) {
|
|
1894
|
-
|
|
1895
|
-
|
|
1617
|
+
for (const [serviceId, linkedServicesKeys] of Object.entries(json.linkedServices)) {
|
|
1618
|
+
const primaryService = servicesMap[serviceId];
|
|
1896
1619
|
if (!primaryService) {
|
|
1897
|
-
|
|
1620
|
+
continue;
|
|
1898
1621
|
}
|
|
1899
|
-
linkedServicesKeys.forEach(
|
|
1900
|
-
|
|
1622
|
+
linkedServicesKeys.forEach(linkedServiceKey => {
|
|
1623
|
+
const linkedService = servicesMap[linkedServiceKey];
|
|
1901
1624
|
if (linkedService) {
|
|
1902
1625
|
primaryService.addLinkedService(linkedService);
|
|
1903
1626
|
}
|
|
1904
1627
|
});
|
|
1905
|
-
};
|
|
1906
|
-
try {
|
|
1907
|
-
for (var _b = tslib_1.__values(Object.entries(json.linkedServices)), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
1908
|
-
var _d = tslib_1.__read(_c.value, 2), serviceId = _d[0], linkedServicesKeys = _d[1];
|
|
1909
|
-
_loop_3(serviceId, linkedServicesKeys);
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
catch (e_21_1) { e_21 = { error: e_21_1 }; }
|
|
1913
|
-
finally {
|
|
1914
|
-
try {
|
|
1915
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
1916
|
-
}
|
|
1917
|
-
finally { if (e_21) throw e_21.error; }
|
|
1918
1628
|
}
|
|
1919
1629
|
}
|
|
1920
1630
|
if (json.controllers) { // just save it for later if it exists {@see configureController}
|
|
1921
1631
|
accessory.serializedControllers = {};
|
|
1922
|
-
json.controllers.forEach(
|
|
1632
|
+
json.controllers.forEach(serializedController => {
|
|
1923
1633
|
accessory.serializedControllers[serializedController.type] = Accessory.deserializeServiceMap(serializedController.services, servicesMap);
|
|
1924
1634
|
});
|
|
1925
1635
|
}
|
|
1926
1636
|
accessory._sideloadServices(services);
|
|
1927
1637
|
return accessory;
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1638
|
+
}
|
|
1639
|
+
static cleanupAccessoryData(username) {
|
|
1930
1640
|
IdentifierCache_1.IdentifierCache.remove(username);
|
|
1931
1641
|
AccessoryInfo_1.AccessoryInfo.remove(username);
|
|
1932
1642
|
ControllerStorage_1.ControllerStorage.remove(username);
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
Object.entries(serviceMap).forEach(
|
|
1937
|
-
var _b = tslib_1.__read(_a, 2), name = _b[0], service = _b[1];
|
|
1643
|
+
}
|
|
1644
|
+
static serializeServiceMap(serviceMap) {
|
|
1645
|
+
const serialized = {};
|
|
1646
|
+
Object.entries(serviceMap).forEach(([name, service]) => {
|
|
1938
1647
|
if (!service) {
|
|
1939
1648
|
return;
|
|
1940
1649
|
}
|
|
1941
1650
|
serialized[name] = service.getServiceId();
|
|
1942
1651
|
});
|
|
1943
1652
|
return serialized;
|
|
1944
|
-
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
Object.entries(serializedServiceMap).forEach(
|
|
1948
|
-
|
|
1949
|
-
var service = servicesMap[serviceId];
|
|
1653
|
+
}
|
|
1654
|
+
static deserializeServiceMap(serializedServiceMap, servicesMap) {
|
|
1655
|
+
const controllerServiceMap = {};
|
|
1656
|
+
Object.entries(serializedServiceMap).forEach(([name, serviceId]) => {
|
|
1657
|
+
const service = servicesMap[serviceId];
|
|
1950
1658
|
if (service) {
|
|
1951
1659
|
controllerServiceMap[name] = service;
|
|
1952
1660
|
}
|
|
1953
1661
|
});
|
|
1954
1662
|
return controllerServiceMap;
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
var serverAddress = undefined;
|
|
1663
|
+
}
|
|
1664
|
+
static parseBindOption(info) {
|
|
1665
|
+
let advertiserAddress = undefined;
|
|
1666
|
+
let disableIpv6 = undefined;
|
|
1667
|
+
let serverAddress = undefined;
|
|
1961
1668
|
if (info.bind) {
|
|
1962
|
-
|
|
1669
|
+
const entries = new Set(Array.isArray(info.bind) ? info.bind : [info.bind]);
|
|
1963
1670
|
if (entries.has("::")) {
|
|
1964
1671
|
serverAddress = "::";
|
|
1965
1672
|
entries.delete("::");
|
|
@@ -1977,8 +1684,8 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1977
1684
|
}
|
|
1978
1685
|
else if (entries.size === 1) {
|
|
1979
1686
|
advertiserAddress = Array.from(entries);
|
|
1980
|
-
|
|
1981
|
-
|
|
1687
|
+
const entry = entries.values().next().value; // grab the first one
|
|
1688
|
+
const version = net_1.default.isIP(entry); // check if ip address was specified or an interface name
|
|
1982
1689
|
if (version) {
|
|
1983
1690
|
serverAddress = version === 4 ? "0.0.0.0" : "::"; // we currently bind to unspecified addresses so config-ui always has a connection via loopback
|
|
1984
1691
|
}
|
|
@@ -1988,24 +1695,14 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
1988
1695
|
}
|
|
1989
1696
|
else if (entries.size > 1) {
|
|
1990
1697
|
advertiserAddress = Array.from(entries);
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
bindUnspecifiedIpv6 = true;
|
|
1998
|
-
break;
|
|
1999
|
-
}
|
|
1698
|
+
let bindUnspecifiedIpv6 = false; // we bind on "::" if there are interface names, or we detect ipv6 addresses
|
|
1699
|
+
for (const entry of entries) {
|
|
1700
|
+
const version = net_1.default.isIP(entry);
|
|
1701
|
+
if (version === 0 || version === 6) {
|
|
1702
|
+
bindUnspecifiedIpv6 = true;
|
|
1703
|
+
break;
|
|
2000
1704
|
}
|
|
2001
1705
|
}
|
|
2002
|
-
catch (e_22_1) { e_22 = { error: e_22_1 }; }
|
|
2003
|
-
finally {
|
|
2004
|
-
try {
|
|
2005
|
-
if (entries_1_1 && !entries_1_1.done && (_a = entries_1.return)) _a.call(entries_1);
|
|
2006
|
-
}
|
|
2007
|
-
finally { if (e_22) throw e_22.error; }
|
|
2008
|
-
}
|
|
2009
1706
|
if (bindUnspecifiedIpv6) {
|
|
2010
1707
|
serverAddress = "::";
|
|
2011
1708
|
}
|
|
@@ -2020,17 +1717,7 @@ var Accessory = /** @class */ (function (_super) {
|
|
|
2020
1717
|
serviceDisableIpv6: disableIpv6,
|
|
2021
1718
|
serverAddress: serverAddress,
|
|
2022
1719
|
};
|
|
2023
|
-
}
|
|
2024
|
-
|
|
2025
|
-
* @deprecated Please use the Categories const enum above.
|
|
2026
|
-
*/
|
|
2027
|
-
// @ts-expect-error: forceConsistentCasingInFileNames compiler option
|
|
2028
|
-
Accessory.Categories = Categories;
|
|
2029
|
-
/// Timeout in milliseconds until a characteristic warning is issue
|
|
2030
|
-
Accessory.TIMEOUT_WARNING = 3000;
|
|
2031
|
-
/// Timeout in milliseconds after `TIMEOUT_WARNING` until the operation on the characteristic is considered timed out.
|
|
2032
|
-
Accessory.TIMEOUT_AFTER_WARNING = 6000;
|
|
2033
|
-
return Accessory;
|
|
2034
|
-
}(events_1.EventEmitter));
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
2035
1722
|
exports.Accessory = Accessory;
|
|
2036
1723
|
//# sourceMappingURL=Accessory.js.map
|