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