node-red-contrib-homekit-bridged 2.0.0-dev.0 → 2.0.0-dev.10
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/build/lib/HAPHostNode.js +185 -148
- package/build/lib/HAPServiceNode.js +200 -177
- package/build/lib/HAPServiceNode2.js +208 -177
- package/build/lib/NRCHKBError.js +23 -2
- package/build/lib/PairingQRCode.js +62 -0
- package/build/lib/Storage.js +152 -90
- package/build/lib/api.js +654 -291
- package/build/lib/camera/CameraControl.js +125 -0
- package/build/lib/camera/CameraDelegate.js +507 -0
- package/build/lib/camera/MP4StreamingServer.js +159 -0
- package/build/lib/hap/HAPCharacteristic.js +25 -4
- package/build/lib/hap/HAPService.js +25 -4
- package/build/lib/hap/eve-app/EveCharacteristics.js +124 -81
- package/build/lib/hap/eve-app/EveServices.js +50 -17
- package/build/lib/hap/hap-nodejs.js +32 -0
- package/build/lib/migration/HomeKitService2Migration.js +34 -0
- package/build/lib/migration/NodeMigration.js +75 -0
- package/build/lib/types/AccessoryInformationType.js +15 -1
- package/build/lib/types/CameraConfigType.js +15 -1
- package/build/lib/types/CustomCharacteristicType.js +15 -1
- package/build/lib/types/HAPHostConfigType.js +15 -1
- package/build/lib/types/HAPHostNodeType.js +15 -1
- package/build/lib/types/HAPService2ConfigType.js +15 -1
- package/build/lib/types/HAPService2NodeType.js +15 -1
- package/build/lib/types/HAPServiceConfigType.js +15 -1
- package/build/lib/types/HAPServiceNodeType.js +15 -1
- package/build/lib/types/HAPStatusConfigType.js +15 -1
- package/build/lib/types/HAPStatusNodeType.js +15 -1
- package/build/lib/types/HostType.js +28 -7
- package/build/lib/types/NodeType.js +15 -1
- package/build/lib/types/PublishTimersType.js +15 -1
- package/build/lib/types/UniFiControllerConfigType.js +16 -0
- package/build/lib/types/hap-nodejs/HapAdaptiveLightingControllerMode.js +28 -7
- package/build/lib/types/hap-nodejs/HapCategories.js +64 -43
- package/build/lib/types/storage/SerializedHostType.js +15 -1
- package/build/lib/types/storage/StorageType.js +34 -10
- package/build/lib/unifi/ProtectDiscovery.js +80 -0
- package/build/lib/utils/AccessoryUtils.js +152 -110
- package/build/lib/utils/BridgeUtils.js +95 -39
- package/build/lib/utils/CharacteristicUtils.js +5 -49
- package/build/lib/utils/CharacteristicUtils2.js +5 -49
- package/build/lib/utils/CharacteristicUtilsBase.js +81 -0
- package/build/lib/utils/NodeStatusUtils.js +89 -40
- package/build/lib/utils/ServiceUtils.js +433 -371
- package/build/lib/utils/ServiceUtils2.js +519 -305
- package/build/lib/utils/index.js +11 -12
- package/build/nodes/bridge.html +206 -168
- package/build/nodes/bridge.js +27 -9
- package/build/nodes/locales/en-US/node-red-contrib-homekit-bridged.json +22 -0
- package/build/nodes/nrchkb.html +1753 -117
- package/build/nodes/nrchkb.js +66 -88
- package/build/nodes/plugin-instance.html +509 -0
- package/build/nodes/plugin-instance.js +46 -0
- package/build/nodes/service.html +557 -306
- package/build/nodes/service.js +5 -6
- package/build/nodes/service2.html +1735 -455
- package/build/nodes/service2.js +5 -8
- package/build/nodes/standalone.html +208 -176
- package/build/nodes/standalone.js +27 -9
- package/build/nodes/status.html +51 -18
- package/build/nodes/status.js +47 -41
- package/build/nodes/unifi-controller.html +92 -0
- package/build/nodes/unifi-controller.js +20 -0
- package/build/plugins/embedded/homebridge-camera-ffmpeg/index.js +479 -0
- package/build/plugins/embedded/homebridge-unifi-protect/index.js +521 -0
- package/build/plugins/embedded/index.js +58 -0
- package/build/plugins/nrchkb-homekit-plugins.js +17 -0
- package/build/plugins/registry/index.js +203 -0
- package/build/plugins/registry/types.js +16 -0
- package/build/scripts/migrate-homekit-service-flows.js +47 -0
- package/examples/demo/01 - ALL Demos single import.json +1885 -2139
- package/examples/demo/02 - Air Purifier.json +12 -61
- package/examples/demo/03 - Air Quality sensor with Battery.json +8 -36
- package/examples/demo/04 - Dimmable Bulb.json +4 -21
- package/examples/demo/05 - Color Bulb (HSV).json +5 -26
- package/examples/demo/06 - Fan (simple, 3 speeds).json +6 -31
- package/examples/demo/07 - Fan (with speed, oscillate, rotation direction).json +4 -21
- package/examples/demo/08 - CO2 detector.json +8 -39
- package/examples/demo/09 - CO (carbon monoxide) example.json +9 -44
- package/examples/demo/10 - Door window contact sensor.json +8 -39
- package/examples/demos (advanced)/01 - Television with inputs and speaker.json +19 -85
- package/examples/switch/01 - Plain Switch.json +179 -199
- package/package.json +48 -34
- package/build/lib/HAPHostNode.d.ts +0 -1
- package/build/lib/HAPServiceNode.d.ts +0 -1
- package/build/lib/HAPServiceNode2.d.ts +0 -1
- package/build/lib/NRCHKBError.d.ts +0 -3
- package/build/lib/Storage.d.ts +0 -30
- package/build/lib/api.d.ts +0 -1
- package/build/lib/hap/HAPCharacteristic.d.ts +0 -9
- package/build/lib/hap/HAPService.d.ts +0 -6
- package/build/lib/hap/eve-app/EveCharacteristics.d.ts +0 -20
- package/build/lib/hap/eve-app/EveServices.d.ts +0 -5
- package/build/lib/types/AccessoryInformationType.d.ts +0 -11
- package/build/lib/types/CameraConfigType.d.ts +0 -24
- package/build/lib/types/CustomCharacteristicType.d.ts +0 -6
- package/build/lib/types/HAPHostConfigType.d.ts +0 -22
- package/build/lib/types/HAPHostNodeType.d.ts +0 -14
- package/build/lib/types/HAPService2ConfigType.d.ts +0 -6
- package/build/lib/types/HAPService2NodeType.d.ts +0 -7
- package/build/lib/types/HAPServiceConfigType.d.ts +0 -26
- package/build/lib/types/HAPServiceNodeType.d.ts +0 -38
- package/build/lib/types/HAPStatusConfigType.d.ts +0 -5
- package/build/lib/types/HAPStatusNodeType.d.ts +0 -12
- package/build/lib/types/HostType.d.ts +0 -5
- package/build/lib/types/NodeType.d.ts +0 -3
- package/build/lib/types/PublishTimersType.d.ts +0 -4
- package/build/lib/types/hap-nodejs/HapAdaptiveLightingControllerMode.d.ts +0 -5
- package/build/lib/types/hap-nodejs/HapCategories.d.ts +0 -41
- package/build/lib/types/storage/SerializedHostType.d.ts +0 -5
- package/build/lib/types/storage/StorageType.d.ts +0 -8
- package/build/lib/utils/AccessoryUtils.d.ts +0 -1
- package/build/lib/utils/BridgeUtils.d.ts +0 -1
- package/build/lib/utils/CharacteristicUtils.d.ts +0 -1
- package/build/lib/utils/CharacteristicUtils2.d.ts +0 -1
- package/build/lib/utils/NodeStatusUtils.d.ts +0 -17
- package/build/lib/utils/ServiceUtils.d.ts +0 -1
- package/build/lib/utils/ServiceUtils2.d.ts +0 -1
- package/build/lib/utils/index.d.ts +0 -1
- package/build/nodes/bridge.d.ts +0 -1
- package/build/nodes/nrchkb.d.ts +0 -1
- package/build/nodes/service.d.ts +0 -1
- package/build/nodes/service2.d.ts +0 -1
- package/build/nodes/standalone.d.ts +0 -1
- package/build/nodes/status.d.ts +0 -1
|
@@ -1,384 +1,446 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var import_hap_nodejs = require("@homebridge/hap-nodejs");
|
|
25
|
+
var import_logger = require("@nrchkb/logger");
|
|
26
|
+
var import_CameraControl = require("../camera/CameraControl");
|
|
27
|
+
var import_NRCHKBError = __toESM(require("../NRCHKBError"));
|
|
28
|
+
const buildAdaptiveLightingOptions = (config) => ({
|
|
29
|
+
controllerMode: config.adaptiveLightingOptionsMode !== void 0 ? +config.adaptiveLightingOptionsMode : import_hap_nodejs.AdaptiveLightingControllerMode.AUTOMATIC,
|
|
30
|
+
customTemperatureAdjustment: config.adaptiveLightingOptionsCustomTemperatureAdjustment !== void 0 ? +config.adaptiveLightingOptionsCustomTemperatureAdjustment : void 0
|
|
17
31
|
});
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
32
|
+
const describeContext = (context) => {
|
|
33
|
+
if (context === null) {
|
|
34
|
+
return "null";
|
|
35
|
+
}
|
|
36
|
+
if (context === void 0) {
|
|
37
|
+
return "undefined";
|
|
38
|
+
}
|
|
39
|
+
const type = typeof context;
|
|
40
|
+
if (type !== "object") {
|
|
41
|
+
return String(context);
|
|
42
|
+
}
|
|
43
|
+
if (Array.isArray(context)) {
|
|
44
|
+
return `Array(${context.length})`;
|
|
45
|
+
}
|
|
46
|
+
const keys = Object.keys(context);
|
|
47
|
+
return keys.length > 0 ? `Object(${keys.slice(0, 5).join(",")}${keys.length > 5 ? ",..." : ""})` : "Object";
|
|
37
48
|
};
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
49
|
+
const describeSupported = (supported) => Array.from(supported).join("', '");
|
|
50
|
+
const buildServiceUtils = (node) => {
|
|
51
|
+
const log = (0, import_logger.logger)("NRCHKB", "ServiceUtils", node.config.name, node);
|
|
52
|
+
const { Service, Characteristic } = require("@homebridge/hap-nodejs");
|
|
53
|
+
const NO_RESPONSE_MSG = "NO_RESPONSE";
|
|
54
|
+
const prepareHapData = (context, connection) => {
|
|
55
|
+
const hap = {};
|
|
56
|
+
if (connection) {
|
|
57
|
+
hap.session = {
|
|
58
|
+
sessionID: connection.sessionID,
|
|
59
|
+
username: connection.username,
|
|
60
|
+
remoteAddress: connection.remoteAddress,
|
|
61
|
+
localAddress: connection.localAddress,
|
|
62
|
+
httpPort: connection.remotePort
|
|
63
|
+
};
|
|
64
|
+
hap.context = {};
|
|
65
|
+
}
|
|
66
|
+
if (context) {
|
|
67
|
+
hap.context = context;
|
|
68
|
+
}
|
|
69
|
+
return hap;
|
|
70
|
+
};
|
|
71
|
+
const onCharacteristicGet = function(callback, context, connection) {
|
|
72
|
+
const reachability = (node.parentNode ?? node).reachable;
|
|
73
|
+
log.debug(
|
|
74
|
+
`onCharacteristicGet with status: ${this.statusCode}, value: ${this.value}, reachability is ${reachability} with context ${describeContext(context)} on connection ${connection?.sessionID}`
|
|
75
|
+
);
|
|
76
|
+
if (callback) {
|
|
77
|
+
try {
|
|
78
|
+
callback(
|
|
79
|
+
(node.parentNode ?? node).reachable ? null : new import_hap_nodejs.HapStatusError(
|
|
80
|
+
import_hap_nodejs.HAPStatus.SERVICE_COMMUNICATION_FAILURE
|
|
81
|
+
),
|
|
82
|
+
this.value
|
|
83
|
+
);
|
|
84
|
+
} catch (_) {
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const onValueChange = function(allCharacteristics, outputNumber, { oldValue, newValue, context }, connection) {
|
|
89
|
+
const topic = node.config.topic ? node.config.topic : node.topic_in;
|
|
90
|
+
const msg = { payload: {}, hap: {}, name: node.name, topic };
|
|
91
|
+
const key = this.constructor.name;
|
|
92
|
+
msg.payload[key] = newValue;
|
|
93
|
+
msg.hap = prepareHapData(context, connection);
|
|
94
|
+
const allChars = {};
|
|
95
|
+
for (const singleChar of allCharacteristics) {
|
|
96
|
+
const cKey = singleChar.constructor.name;
|
|
97
|
+
allChars[cKey] = singleChar.value;
|
|
98
|
+
}
|
|
99
|
+
msg.hap.allChars = allChars;
|
|
100
|
+
if (oldValue !== void 0) {
|
|
101
|
+
msg.hap.oldValue = oldValue;
|
|
102
|
+
}
|
|
103
|
+
msg.hap.reachable = node.reachable ?? node.parentNode?.reachable;
|
|
104
|
+
if (msg.hap.reachable === false) {
|
|
105
|
+
;
|
|
106
|
+
[node, ...node.childNodes ?? []].forEach((n) => {
|
|
107
|
+
n.nodeStatusUtils.setStatus({
|
|
108
|
+
fill: "red",
|
|
109
|
+
shape: "ring",
|
|
110
|
+
text: "Not reachable",
|
|
111
|
+
type: "NO_RESPONSE"
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
} else {
|
|
115
|
+
msg.hap.newValue = newValue;
|
|
116
|
+
node.nodeStatusUtils.setStatus(
|
|
117
|
+
{
|
|
118
|
+
fill: "yellow",
|
|
119
|
+
shape: "dot",
|
|
120
|
+
text: `${key}: ${newValue}`
|
|
121
|
+
},
|
|
122
|
+
3e3
|
|
123
|
+
);
|
|
124
|
+
node.childNodes?.forEach((n) => {
|
|
125
|
+
n.nodeStatusUtils.clearStatusByType("NO_RESPONSE");
|
|
126
|
+
});
|
|
127
|
+
node.parentNode?.nodeStatusUtils.clearStatusByType("NO_RESPONSE");
|
|
128
|
+
}
|
|
129
|
+
log.debug(`${node.name} received ${key} : ${newValue}`);
|
|
130
|
+
if (connection || context || node.hostNode.config.allowMessagePassthrough) {
|
|
131
|
+
if (outputNumber === 0) {
|
|
132
|
+
node.send(msg);
|
|
133
|
+
} else if (outputNumber === 1) {
|
|
134
|
+
node.send([null, msg]);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const onCharacteristicSet = (allCharacteristics) => function(newValue, callback, context, connection) {
|
|
139
|
+
const reachability = (node.parentNode ?? node).reachable;
|
|
140
|
+
log.debug(
|
|
141
|
+
`onCharacteristicSet with status: ${this.statusCode}, value: ${this.value}, reachability is ${reachability} with context ${describeContext(context)} on connection ${connection?.sessionID}`
|
|
142
|
+
);
|
|
143
|
+
try {
|
|
144
|
+
if (callback) {
|
|
145
|
+
callback(
|
|
146
|
+
(node.parentNode ?? node).reachable ? null : new import_hap_nodejs.HapStatusError(
|
|
147
|
+
import_hap_nodejs.HAPStatus.SERVICE_COMMUNICATION_FAILURE
|
|
148
|
+
)
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
} catch (_) {
|
|
152
|
+
}
|
|
153
|
+
onValueChange.call(
|
|
154
|
+
this,
|
|
155
|
+
allCharacteristics,
|
|
156
|
+
1,
|
|
157
|
+
{
|
|
158
|
+
newValue,
|
|
159
|
+
context
|
|
160
|
+
},
|
|
161
|
+
connection
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
|
+
const onCharacteristicChange = (allCharacteristics) => function(change) {
|
|
165
|
+
const { oldValue, newValue, context, originator, reason } = change;
|
|
166
|
+
log.debug(
|
|
167
|
+
`onCharacteristicChange with reason: ${reason}, oldValue: ${oldValue}, newValue: ${newValue}, reachability is ${(node.parentNode ?? node).reachable} with context ${describeContext(context)} on connection ${originator?.sessionID}`
|
|
168
|
+
);
|
|
169
|
+
if (oldValue !== newValue) {
|
|
170
|
+
onValueChange.call(
|
|
171
|
+
this,
|
|
172
|
+
allCharacteristics,
|
|
173
|
+
0,
|
|
174
|
+
{
|
|
175
|
+
oldValue,
|
|
176
|
+
newValue,
|
|
177
|
+
context
|
|
178
|
+
},
|
|
179
|
+
originator
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const onInput = (msg) => {
|
|
184
|
+
if (msg.payload) {
|
|
185
|
+
const type = typeof msg.payload;
|
|
186
|
+
if (type !== "object") {
|
|
187
|
+
log.error(`Invalid payload type: ${type}`);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
log.error("Invalid message (payload missing)");
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const topic = node.config.topic ?? node.name;
|
|
195
|
+
if (node.config.filter && msg.topic !== topic) {
|
|
196
|
+
log.debug(
|
|
197
|
+
"msg.topic doesn't match configured value and filter is enabled. Dropping message."
|
|
198
|
+
);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
let context = null;
|
|
202
|
+
if (msg.payload.Context) {
|
|
203
|
+
context = msg.payload.Context;
|
|
204
|
+
delete msg.payload.Context;
|
|
205
|
+
}
|
|
206
|
+
node.topic_in = msg.topic ?? "";
|
|
207
|
+
for (const key in msg.payload) {
|
|
208
|
+
if (!Object.hasOwn(msg.payload, key)) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (!node.supported.has(key)) {
|
|
212
|
+
if (key === "AdaptiveLightingController" && node.adaptiveLightingController) {
|
|
213
|
+
const value = msg.payload?.[key];
|
|
214
|
+
const event = value?.event;
|
|
215
|
+
if (event === "disable") {
|
|
216
|
+
node.adaptiveLightingController?.disableAdaptiveLighting();
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
log.error(
|
|
220
|
+
`Instead of '${key}' try one of these characteristics: '${describeSupported(node.supported)}'`
|
|
221
|
+
);
|
|
167
222
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
223
|
+
} else {
|
|
224
|
+
const value = msg.payload?.[key];
|
|
225
|
+
const normalizedValue = value === NO_RESPONSE_MSG ? false : value;
|
|
226
|
+
const parentNode = node.parentNode ?? node;
|
|
227
|
+
parentNode.reachable = value !== NO_RESPONSE_MSG;
|
|
228
|
+
const characteristic = node.service.getCharacteristic(
|
|
229
|
+
Characteristic[key]
|
|
230
|
+
);
|
|
231
|
+
if (context !== null) {
|
|
232
|
+
characteristic.setValue(normalizedValue, context);
|
|
233
|
+
} else {
|
|
234
|
+
characteristic.setValue(normalizedValue);
|
|
172
235
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const onClose = (removed, done) => {
|
|
240
|
+
if (node.waitForParentTimer) {
|
|
241
|
+
clearTimeout(node.waitForParentTimer);
|
|
242
|
+
node.waitForParentTimer = void 0;
|
|
243
|
+
}
|
|
244
|
+
Object.values(node.publishTimers).forEach((timer) => {
|
|
245
|
+
clearTimeout(timer);
|
|
246
|
+
});
|
|
247
|
+
node.publishTimers = {};
|
|
248
|
+
const characteristics = node.service ? node.service.characteristics.concat(
|
|
249
|
+
node.service.optionalCharacteristics
|
|
250
|
+
) : [];
|
|
251
|
+
characteristics.forEach((characteristic) => {
|
|
252
|
+
characteristic.removeListener("get", node.onCharacteristicGet);
|
|
253
|
+
characteristic.removeListener("set", node.onCharacteristicSet);
|
|
254
|
+
characteristic.removeListener("change", node.onCharacteristicChange);
|
|
255
|
+
});
|
|
256
|
+
if (node.config.isParent && node.accessory && node.onIdentify) {
|
|
257
|
+
node.accessory.removeListener("identify", node.onIdentify);
|
|
258
|
+
}
|
|
259
|
+
if (removed && node.accessory) {
|
|
260
|
+
if (node.config.isParent) {
|
|
261
|
+
node.hostNode.host.removeBridgedAccessories([node.accessory]);
|
|
262
|
+
node.accessory.destroy();
|
|
263
|
+
} else if (node.service && node.parentService) {
|
|
264
|
+
node.accessory.removeService(node.service);
|
|
265
|
+
node.parentService.removeLinkedService(node.service);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
node.nodeStatusUtils.cleanup();
|
|
269
|
+
done();
|
|
270
|
+
};
|
|
271
|
+
const getOrCreate = (accessory, serviceInformation, parentService) => {
|
|
272
|
+
if (serviceInformation.serviceName === "CameraControl") {
|
|
273
|
+
let service2 = accessory.services.find(
|
|
274
|
+
(service3) => {
|
|
275
|
+
return service3.UUID === Service.CameraRTPStreamManagement.UUID;
|
|
177
276
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
node.adaptiveLightingController) {
|
|
184
|
-
const value = (_a = msg.payload) === null || _a === void 0 ? void 0 : _a[key];
|
|
185
|
-
const event = value === null || value === void 0 ? void 0 : value.event;
|
|
186
|
-
if (event === 'disable') {
|
|
187
|
-
(_b = node.adaptiveLightingController) === null || _b === void 0 ? void 0 : _b.disableAdaptiveLighting();
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
log.error(`Instead of '${key}' try one of these characteristics: '${node.supported.join("', '")}'`);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
const value = (_c = msg.payload) === null || _c === void 0 ? void 0 : _c[key];
|
|
196
|
-
const parentNode = (_d = node.parentNode) !== null && _d !== void 0 ? _d : node;
|
|
197
|
-
parentNode.reachable = value !== NO_RESPONSE_MSG;
|
|
198
|
-
const characteristic = node.service.getCharacteristic(Characteristic[key]);
|
|
199
|
-
if (context !== null) {
|
|
200
|
-
characteristic.setValue(value, context);
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
characteristic.setValue(value);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
};
|
|
208
|
-
const onClose = function (removed, done) {
|
|
209
|
-
const characteristics = node.service.characteristics.concat(node.service.optionalCharacteristics);
|
|
210
|
-
characteristics.forEach(function (characteristic) {
|
|
211
|
-
characteristic.removeListener('get', node.onCharacteristicGet);
|
|
212
|
-
characteristic.removeListener('set', node.onCharacteristicSet);
|
|
213
|
-
characteristic.removeListener('change', node.onCharacteristicChange);
|
|
277
|
+
);
|
|
278
|
+
if (!service2) {
|
|
279
|
+
configureCameraSource(accessory, serviceInformation.config);
|
|
280
|
+
service2 = accessory.services.find((service3) => {
|
|
281
|
+
return service3.UUID === Service.CameraRTPStreamManagement.UUID;
|
|
214
282
|
});
|
|
215
|
-
|
|
216
|
-
|
|
283
|
+
}
|
|
284
|
+
if (!service2) {
|
|
285
|
+
throw new import_NRCHKBError.default(
|
|
286
|
+
"Failed to configure CameraControl service."
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
return service2;
|
|
290
|
+
}
|
|
291
|
+
const ServiceConstructor = Service[serviceInformation.serviceName];
|
|
292
|
+
if (typeof ServiceConstructor !== "function") {
|
|
293
|
+
throw new import_NRCHKBError.default(
|
|
294
|
+
`Unknown HomeKit service "${serviceInformation.serviceName}".`
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
const newService = new ServiceConstructor(
|
|
298
|
+
serviceInformation.name,
|
|
299
|
+
serviceInformation.UUID
|
|
300
|
+
);
|
|
301
|
+
log.debug(
|
|
302
|
+
`Looking for service with UUID ${serviceInformation.UUID} ...`
|
|
303
|
+
);
|
|
304
|
+
let service = accessory.services.find(
|
|
305
|
+
(service2) => {
|
|
306
|
+
return newService.subtype === service2.subtype;
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
if (service && newService.UUID !== service.UUID) {
|
|
310
|
+
log.debug("... service type changed! Removing the old service.");
|
|
311
|
+
accessory.removeService(service);
|
|
312
|
+
service = void 0;
|
|
313
|
+
}
|
|
314
|
+
if (!service) {
|
|
315
|
+
log.debug(
|
|
316
|
+
`... didn't find it. Adding new ${serviceInformation.serviceName} service.`
|
|
317
|
+
);
|
|
318
|
+
service = accessory.addService(newService);
|
|
319
|
+
} else {
|
|
320
|
+
log.debug("... found it! Updating it.");
|
|
321
|
+
service.getCharacteristic(Characteristic.Name).setValue(serviceInformation.name);
|
|
322
|
+
}
|
|
323
|
+
if (parentService) {
|
|
324
|
+
if (service) {
|
|
325
|
+
log.debug("... and linking service to parent.");
|
|
326
|
+
parentService.addLinkedService(service);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return service ?? newService;
|
|
330
|
+
};
|
|
331
|
+
const configureCameraSource = (accessory, config) => {
|
|
332
|
+
if (config.cameraConfigSource) {
|
|
333
|
+
log.debug("Configuring Camera Source");
|
|
334
|
+
if (!config.cameraConfigVideoProcessor) {
|
|
335
|
+
log.error(
|
|
336
|
+
"Missing configuration for CameraControl: videoProcessor cannot be empty!"
|
|
337
|
+
);
|
|
338
|
+
} else {
|
|
339
|
+
(0, import_CameraControl.configureCamera)(accessory, config);
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
log.error("Missing configuration for CameraControl.");
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const waitForParent = () => {
|
|
346
|
+
log.debug("Waiting for Parent Service");
|
|
347
|
+
return new Promise((resolve) => {
|
|
348
|
+
node.nodeStatusUtils.setStatus({
|
|
349
|
+
fill: "blue",
|
|
350
|
+
shape: "dot",
|
|
351
|
+
text: "Waiting for Parent Service"
|
|
352
|
+
});
|
|
353
|
+
const checkAndWait = () => {
|
|
354
|
+
const parentNode = node.RED.nodes.getNode(
|
|
355
|
+
node.config.parentService
|
|
356
|
+
);
|
|
357
|
+
if (parentNode?.configured) {
|
|
358
|
+
node.waitForParentTimer = void 0;
|
|
359
|
+
resolve(parentNode);
|
|
360
|
+
} else {
|
|
361
|
+
node.waitForParentTimer = setTimeout(checkAndWait, 1e3);
|
|
217
362
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
363
|
+
};
|
|
364
|
+
checkAndWait();
|
|
365
|
+
}).catch((error) => {
|
|
366
|
+
log.error(`Waiting for Parent Service failed due to: ${error}`);
|
|
367
|
+
throw new import_NRCHKBError.default(error);
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
const handleWaitForSetup = (config, msg, resolve) => {
|
|
371
|
+
if (node.setupDone) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (msg && Object.hasOwn(msg, "payload") && msg.payload && typeof msg.payload === "object" && Object.hasOwn(msg.payload, "nrchkb") && msg.payload.nrchkb && typeof msg.payload.nrchkb === "object" && Object.hasOwn(msg.payload.nrchkb, "setup")) {
|
|
375
|
+
node.setupDone = true;
|
|
376
|
+
const newConfig = {
|
|
377
|
+
...config,
|
|
378
|
+
...msg.payload.nrchkb.setup
|
|
379
|
+
};
|
|
380
|
+
node.removeListener("input", node.handleWaitForSetup);
|
|
381
|
+
resolve(newConfig);
|
|
382
|
+
} else {
|
|
383
|
+
log.error(
|
|
384
|
+
'Invalid message (required {"payload":{"nrchkb":{"setup":{}}}})'
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
const configureAdaptiveLightning = () => {
|
|
389
|
+
if (node.service.UUID === Service.Lightbulb.UUID && node.config.adaptiveLightingOptionsEnable) {
|
|
390
|
+
try {
|
|
391
|
+
node.service.getCharacteristic(Characteristic.Brightness);
|
|
392
|
+
node.service.getCharacteristic(Characteristic.ColorTemperature);
|
|
393
|
+
const options = buildAdaptiveLightingOptions(node.config);
|
|
394
|
+
log.trace(`Configuring Adaptive Lighting with options:`);
|
|
395
|
+
log.trace(JSON.stringify(options));
|
|
396
|
+
const adaptiveLightingController = new import_hap_nodejs.AdaptiveLightingController(node.service, options);
|
|
397
|
+
adaptiveLightingController.on("update", () => {
|
|
398
|
+
const activeAdaptiveLightingTransition = {
|
|
399
|
+
transitionStartMillis: adaptiveLightingController.getAdaptiveLightingStartTimeOfTransition(),
|
|
400
|
+
timeMillisOffset: adaptiveLightingController.getAdaptiveLightingTimeOffset(),
|
|
401
|
+
transitionCurve: adaptiveLightingController.getAdaptiveLightingTransitionCurve(),
|
|
402
|
+
brightnessAdjustmentRange: adaptiveLightingController.getAdaptiveLightingBrightnessMultiplierRange(),
|
|
403
|
+
updateInterval: adaptiveLightingController.getAdaptiveLightingUpdateInterval(),
|
|
404
|
+
notifyIntervalThreshold: adaptiveLightingController.getAdaptiveLightingNotifyIntervalThreshold()
|
|
405
|
+
};
|
|
406
|
+
node.send({
|
|
407
|
+
payload: {
|
|
408
|
+
AdaptiveLightingController: {
|
|
409
|
+
event: "update",
|
|
410
|
+
data: activeAdaptiveLightingTransition
|
|
411
|
+
}
|
|
226
412
|
}
|
|
227
|
-
|
|
228
|
-
done();
|
|
229
|
-
};
|
|
230
|
-
const getOrCreate = function (accessory, serviceInformation, parentService) {
|
|
231
|
-
const newService = new Service[serviceInformation.serviceName](serviceInformation.name, serviceInformation.UUID);
|
|
232
|
-
log.debug(`Looking for service with UUID ${serviceInformation.UUID} ...`);
|
|
233
|
-
let service = accessory.services.find((service) => {
|
|
234
|
-
return newService.subtype === service.subtype;
|
|
413
|
+
});
|
|
235
414
|
});
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
log.debug(`... didn't find it. Adding new ${serviceInformation.serviceName} service.`);
|
|
243
|
-
if (serviceInformation.serviceName === 'CameraControl') {
|
|
244
|
-
configureCameraSource(accessory, newService, serviceInformation.config);
|
|
245
|
-
service = newService;
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
service = accessory.addService(newService);
|
|
415
|
+
adaptiveLightingController.on("disable", () => {
|
|
416
|
+
node.send({
|
|
417
|
+
payload: {
|
|
418
|
+
AdaptiveLightingController: {
|
|
419
|
+
event: "disable"
|
|
420
|
+
}
|
|
249
421
|
}
|
|
250
|
-
|
|
251
|
-
else {
|
|
252
|
-
log.debug('... found it! Updating it.');
|
|
253
|
-
service
|
|
254
|
-
.getCharacteristic(Characteristic.Name)
|
|
255
|
-
.setValue(serviceInformation.name);
|
|
256
|
-
}
|
|
257
|
-
if (parentService) {
|
|
258
|
-
if (serviceInformation.serviceName === 'CameraControl') {
|
|
259
|
-
log.debug('... and adding service to accessory.');
|
|
260
|
-
}
|
|
261
|
-
else if (service) {
|
|
262
|
-
log.debug('... and linking service to parent.');
|
|
263
|
-
parentService.addLinkedService(service);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return service;
|
|
267
|
-
};
|
|
268
|
-
const configureCameraSource = function (_accessory, _service, config) {
|
|
269
|
-
if (config.cameraConfigSource) {
|
|
270
|
-
log.debug('Configuring Camera Source');
|
|
271
|
-
if (!config.cameraConfigVideoProcessor) {
|
|
272
|
-
log.error('Missing configuration for CameraControl: videoProcessor cannot be empty!');
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
log.error('Missing configuration for CameraControl.');
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
const waitForParent = () => {
|
|
282
|
-
log.debug('Waiting for Parent Service');
|
|
283
|
-
return new Promise((resolve) => {
|
|
284
|
-
node.nodeStatusUtils.setStatus({
|
|
285
|
-
fill: 'blue',
|
|
286
|
-
shape: 'dot',
|
|
287
|
-
text: 'Waiting for Parent Service',
|
|
288
|
-
});
|
|
289
|
-
const checkAndWait = () => {
|
|
290
|
-
const parentNode = node.RED.nodes.getNode(node.config.parentService);
|
|
291
|
-
if (parentNode && parentNode.configured) {
|
|
292
|
-
resolve(parentNode);
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
setTimeout(checkAndWait, 1000);
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
checkAndWait();
|
|
299
|
-
}).catch((error) => {
|
|
300
|
-
log.error(`Waiting for Parent Service failed due to: ${error}`);
|
|
301
|
-
throw new NRCHKBError_1.default(error);
|
|
422
|
+
});
|
|
302
423
|
});
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
try {
|
|
324
|
-
node.service.getCharacteristic(Characteristic.Brightness);
|
|
325
|
-
node.service.getCharacteristic(Characteristic.ColorTemperature);
|
|
326
|
-
const options = {
|
|
327
|
-
controllerMode: node.config.adaptiveLightingOptionsMode
|
|
328
|
-
? +node.config.adaptiveLightingOptionsMode
|
|
329
|
-
: 1,
|
|
330
|
-
customTemperatureAdjustment: node.config
|
|
331
|
-
.adaptiveLightingOptionsCustomTemperatureAdjustment
|
|
332
|
-
? +node.config
|
|
333
|
-
.adaptiveLightingOptionsCustomTemperatureAdjustment
|
|
334
|
-
: undefined,
|
|
335
|
-
};
|
|
336
|
-
log.trace(`Configuring Adaptive Lighting with options: ${options}`);
|
|
337
|
-
const adaptiveLightingController = new hap_nodejs_1.AdaptiveLightingController(node.service, options);
|
|
338
|
-
adaptiveLightingController.on('update', () => {
|
|
339
|
-
const activeAdaptiveLightingTransition = {
|
|
340
|
-
transitionStartMillis: adaptiveLightingController.getAdaptiveLightingStartTimeOfTransition(),
|
|
341
|
-
timeMillisOffset: adaptiveLightingController.getAdaptiveLightingTimeOffset(),
|
|
342
|
-
transitionCurve: adaptiveLightingController.getAdaptiveLightingTransitionCurve(),
|
|
343
|
-
brightnessAdjustmentRange: adaptiveLightingController.getAdaptiveLightingBrightnessMultiplierRange(),
|
|
344
|
-
updateInterval: adaptiveLightingController.getAdaptiveLightingUpdateInterval(),
|
|
345
|
-
notifyIntervalThreshold: adaptiveLightingController.getAdaptiveLightingNotifyIntervalThreshold(),
|
|
346
|
-
};
|
|
347
|
-
node.send({
|
|
348
|
-
payload: {
|
|
349
|
-
AdaptiveLightingController: {
|
|
350
|
-
event: 'update',
|
|
351
|
-
data: activeAdaptiveLightingTransition,
|
|
352
|
-
},
|
|
353
|
-
},
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
adaptiveLightingController.on('disable', () => {
|
|
357
|
-
node.send({
|
|
358
|
-
payload: {
|
|
359
|
-
AdaptiveLightingController: {
|
|
360
|
-
event: 'disable',
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
node.accessory.configureController(adaptiveLightingController);
|
|
366
|
-
node.adaptiveLightingController = adaptiveLightingController;
|
|
367
|
-
}
|
|
368
|
-
catch (error) {
|
|
369
|
-
log.error(`Failed to configure Adaptive Lightning due to ${error}`);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
return {
|
|
374
|
-
getOrCreate,
|
|
375
|
-
onCharacteristicGet,
|
|
376
|
-
onCharacteristicSet,
|
|
377
|
-
onCharacteristicChange,
|
|
378
|
-
onInput,
|
|
379
|
-
onClose,
|
|
380
|
-
waitForParent,
|
|
381
|
-
handleWaitForSetup,
|
|
382
|
-
configureAdaptiveLightning,
|
|
383
|
-
};
|
|
424
|
+
node.accessory.configureController(adaptiveLightingController);
|
|
425
|
+
node.adaptiveLightingController = adaptiveLightingController;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
log.error(
|
|
428
|
+
`Failed to configure Adaptive Lightning due to ${error}`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
return {
|
|
434
|
+
getOrCreate,
|
|
435
|
+
onCharacteristicGet,
|
|
436
|
+
onCharacteristicSet,
|
|
437
|
+
onCharacteristicChange,
|
|
438
|
+
onInput,
|
|
439
|
+
onClose,
|
|
440
|
+
waitForParent,
|
|
441
|
+
handleWaitForSetup,
|
|
442
|
+
configureAdaptiveLightning
|
|
443
|
+
};
|
|
384
444
|
};
|
|
445
|
+
buildServiceUtils.buildAdaptiveLightingOptions = buildAdaptiveLightingOptions;
|
|
446
|
+
module.exports = buildServiceUtils;
|