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