node-red-contrib-homekit-bridged 2.0.0-dev.1 → 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 -146
- 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 -290
- 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 -112
- 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 -368
- package/build/lib/utils/ServiceUtils2.js +519 -304
- 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 -1885
- package/examples/demo/02 - Air Purifier.json +279 -279
- package/examples/demo/03 - Air Quality sensor with Battery.json +254 -254
- package/examples/demo/04 - Dimmable Bulb.json +172 -172
- package/examples/demo/05 - Color Bulb (HSV).json +195 -195
- package/examples/demo/06 - Fan (simple, 3 speeds).json +240 -240
- package/examples/demo/07 - Fan (with speed, oscillate, rotation direction).json +175 -175
- package/examples/demo/08 - CO2 detector.json +224 -224
- package/examples/demo/09 - CO (carbon monoxide) example.json +255 -255
- package/examples/demo/10 - Door window contact sensor.json +234 -234
- package/examples/demos (advanced)/01 - Television with inputs and speaker.json +541 -541
- package/examples/switch/01 - Plain Switch.json +178 -178
- package/package.json +95 -82
- 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
package/build/nodes/status.js
CHANGED
|
@@ -1,45 +1,51 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const log = (0, logger_1.logger)('NRCHKB', 'HAPStatusNode');
|
|
2
|
+
var import_hap_nodejs = require("@homebridge/hap-nodejs");
|
|
3
|
+
var import_logger = require("@nrchkb/logger");
|
|
4
|
+
var import_NodeStatusUtils = require("../lib/utils/NodeStatusUtils");
|
|
5
|
+
const log = (0, import_logger.logger)("NRCHKB", "HAPStatusNode");
|
|
7
6
|
module.exports = (RED) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
log.debug("Registering homekit-status type");
|
|
8
|
+
RED.nodes.registerType(
|
|
9
|
+
"homekit-status",
|
|
10
|
+
function(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
RED.nodes.createNode(this, config);
|
|
13
|
+
this.nodeStatusUtils = new import_NodeStatusUtils.NodeStatusUtils(this);
|
|
14
|
+
try {
|
|
15
|
+
this.serviceNode = RED.nodes.getNode(
|
|
16
|
+
this.config.serviceNodeId
|
|
17
|
+
);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
log.error(error);
|
|
20
|
+
}
|
|
21
|
+
this.on("input", (_) => {
|
|
22
|
+
if (this.serviceNode) {
|
|
23
|
+
this.nodeStatusUtils.setStatus(
|
|
24
|
+
{
|
|
25
|
+
fill: "green",
|
|
26
|
+
shape: "dot",
|
|
27
|
+
text: "Done"
|
|
28
|
+
},
|
|
29
|
+
3e3
|
|
30
|
+
);
|
|
31
|
+
const serializedService = import_hap_nodejs.Service.serialize(
|
|
32
|
+
this.serviceNode.service
|
|
33
|
+
);
|
|
34
|
+
this.send({
|
|
35
|
+
payload: serializedService
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
this.nodeStatusUtils.setStatus({
|
|
39
|
+
fill: "red",
|
|
40
|
+
shape: "dot",
|
|
41
|
+
text: "Check your config"
|
|
42
|
+
});
|
|
16
43
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
shape: 'dot',
|
|
25
|
-
text: 'Done'
|
|
26
|
-
}, 3000);
|
|
27
|
-
const serializedService = hap_nodejs_1.Service.serialize(self.serviceNode.service);
|
|
28
|
-
self.send({
|
|
29
|
-
payload: serializedService
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
self.nodeStatusUtils.setStatus({
|
|
34
|
-
fill: 'red',
|
|
35
|
-
shape: 'dot',
|
|
36
|
-
text: 'Check your config'
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
self.on('close', (_, done) => {
|
|
41
|
-
self.serviceNode = undefined;
|
|
42
|
-
done();
|
|
43
|
-
});
|
|
44
|
-
});
|
|
44
|
+
});
|
|
45
|
+
this.on("close", (_, done) => {
|
|
46
|
+
this.serviceNode = void 0;
|
|
47
|
+
done();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
);
|
|
45
51
|
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<script data-template-name="homekit-unifi-controller" type="text/x-red">
|
|
2
|
+
<div class="nrchkb-editor">
|
|
3
|
+
<details class="nrchkb-section" open>
|
|
4
|
+
<summary><i class="fa fa-server"></i> UniFi Controller</summary>
|
|
5
|
+
<div class="nrchkb-section-body">
|
|
6
|
+
<div class="form-row">
|
|
7
|
+
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
8
|
+
<input type="text" id="node-config-input-name" placeholder="UniFi Protect">
|
|
9
|
+
</div>
|
|
10
|
+
<div class="form-row">
|
|
11
|
+
<label for="node-config-input-application"><i class="fa fa-cubes"></i> Application</label>
|
|
12
|
+
<select id="node-config-input-application">
|
|
13
|
+
<option value="protect" selected>Protect</option>
|
|
14
|
+
</select>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="form-row">
|
|
17
|
+
<label for="node-config-input-address"><i class="fa fa-globe"></i> Address</label>
|
|
18
|
+
<input type="text" id="node-config-input-address" placeholder="192.168.1.1" autocomplete="url" spellcheck="false">
|
|
19
|
+
</div>
|
|
20
|
+
<div class="form-row">
|
|
21
|
+
<label for="node-config-input-username"><i class="fa fa-user"></i> Username</label>
|
|
22
|
+
<input type="text" id="node-config-input-username" autocomplete="username" spellcheck="false">
|
|
23
|
+
</div>
|
|
24
|
+
<div class="form-row">
|
|
25
|
+
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
|
|
26
|
+
<input type="password" id="node-config-input-password" autocomplete="current-password">
|
|
27
|
+
</div>
|
|
28
|
+
<div class="form-row">
|
|
29
|
+
<label for="node-config-input-overrideAddress"><i class="fa fa-random"></i> Override Address</label>
|
|
30
|
+
<input type="text" id="node-config-input-overrideAddress" placeholder="Optional livestream address" autocomplete="url" spellcheck="false">
|
|
31
|
+
</div>
|
|
32
|
+
<div class="form-row nrchkb-checkbox-row">
|
|
33
|
+
<label class="nrchkb-checkbox-label" for="node-config-input-allowSelfSigned">
|
|
34
|
+
<input type="checkbox" id="node-config-input-allowSelfSigned">
|
|
35
|
+
<span><i class="fa fa-certificate"></i> Allow self-signed certificates</span>
|
|
36
|
+
</label>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</details>
|
|
40
|
+
</div>
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<script data-help-name="homekit-unifi-controller" type="text/markdown">
|
|
44
|
+
# UniFi Controller
|
|
45
|
+
|
|
46
|
+
Stores connection details for UniFi application integrations. Protect is supported now; the generic node name leaves room for future Access or Network integrations.
|
|
47
|
+
|
|
48
|
+
> [!IMPORTANT]
|
|
49
|
+
> Use a dedicated local UniFi account with the minimum permissions needed to read Protect camera data.
|
|
50
|
+
|
|
51
|
+
> [!WARNING]
|
|
52
|
+
> Allow self-signed certificates only for controllers you administer and trust on your local network.
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<script type="text/javascript">
|
|
56
|
+
RED.nodes.registerType('homekit-unifi-controller', {
|
|
57
|
+
category: 'config',
|
|
58
|
+
defaults: {
|
|
59
|
+
name: {
|
|
60
|
+
value: '',
|
|
61
|
+
},
|
|
62
|
+
application: {
|
|
63
|
+
value: 'protect',
|
|
64
|
+
required: true,
|
|
65
|
+
},
|
|
66
|
+
address: {
|
|
67
|
+
value: '',
|
|
68
|
+
required: true,
|
|
69
|
+
},
|
|
70
|
+
allowSelfSigned: {
|
|
71
|
+
value: false,
|
|
72
|
+
},
|
|
73
|
+
overrideAddress: {
|
|
74
|
+
value: '',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
credentials: {
|
|
78
|
+
username: {
|
|
79
|
+
type: 'text',
|
|
80
|
+
},
|
|
81
|
+
password: {
|
|
82
|
+
type: 'password',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
label: function () {
|
|
86
|
+
return this.name || this.address || 'UniFi Controller'
|
|
87
|
+
},
|
|
88
|
+
onadd: function () {
|
|
89
|
+
applyDefaultNodeDocumentation(this, 'homekit-unifi-controller')
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var import_logger = require("@nrchkb/logger");
|
|
3
|
+
const log = (0, import_logger.logger)("NRCHKB", "UniFiController");
|
|
4
|
+
module.exports = (RED) => {
|
|
5
|
+
const init = function(config) {
|
|
6
|
+
RED.nodes.createNode(this, config);
|
|
7
|
+
this.name = config.name;
|
|
8
|
+
this.address = config.address;
|
|
9
|
+
this.application = config.application ?? "protect";
|
|
10
|
+
this.allowSelfSigned = config.allowSelfSigned === true;
|
|
11
|
+
this.overrideAddress = config.overrideAddress;
|
|
12
|
+
};
|
|
13
|
+
log.debug("Registering homekit-unifi-controller type");
|
|
14
|
+
RED.nodes.registerType("homekit-unifi-controller", init, {
|
|
15
|
+
credentials: {
|
|
16
|
+
username: { type: "text" },
|
|
17
|
+
password: { type: "password" }
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
};
|
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
"use strict";
|
|
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 __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var homebridge_camera_ffmpeg_exports = {};
|
|
30
|
+
__export(homebridge_camera_ffmpeg_exports, {
|
|
31
|
+
HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_ID: () => HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_ID,
|
|
32
|
+
HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_NAME: () => HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_NAME,
|
|
33
|
+
createAutomaticHomebridgeCameraFfmpegPluginEntry: () => createAutomaticHomebridgeCameraFfmpegPluginEntry,
|
|
34
|
+
homebridgeCameraFfmpegPluginFactory: () => homebridgeCameraFfmpegPluginFactory,
|
|
35
|
+
homebridgeCameraFfmpegPluginMetadata: () => homebridgeCameraFfmpegPluginMetadata,
|
|
36
|
+
mapLegacyCameraConfigToPluginConfig: () => mapLegacyCameraConfigToPluginConfig,
|
|
37
|
+
registerHomebridgeCameraFfmpegPlugin: () => registerHomebridgeCameraFfmpegPlugin
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(homebridge_camera_ffmpeg_exports);
|
|
40
|
+
var import_hap_nodejs = require("@homebridge/hap-nodejs");
|
|
41
|
+
var import_logger = require("@nrchkb/logger");
|
|
42
|
+
var import_registry = require("../../registry");
|
|
43
|
+
const HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_NAME = "homebridge-camera-ffmpeg";
|
|
44
|
+
const HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_ID = (0, import_registry.normalizePluginId)(
|
|
45
|
+
"node-red-contrib-homekit-bridged",
|
|
46
|
+
HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_NAME
|
|
47
|
+
);
|
|
48
|
+
const requirePackageJson = (packageName) => {
|
|
49
|
+
try {
|
|
50
|
+
return require(`${packageName}/package.json`);
|
|
51
|
+
} catch (_) {
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const upstreamPackage = requirePackageJson(
|
|
56
|
+
"@homebridge-plugins/homebridge-camera-ffmpeg"
|
|
57
|
+
);
|
|
58
|
+
const toName = (value) => typeof value === "string" ? value : value?.name ?? "";
|
|
59
|
+
const upstreamAuthor = toName(upstreamPackage.author);
|
|
60
|
+
const upstreamContributors = upstreamPackage.contributors?.map(toName).filter(Boolean) ?? [];
|
|
61
|
+
const toBoolean = (value) => {
|
|
62
|
+
if (typeof value === "boolean") {
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
if (typeof value === "string") {
|
|
66
|
+
return value.trim().toLowerCase() === "true";
|
|
67
|
+
}
|
|
68
|
+
return Boolean(value);
|
|
69
|
+
};
|
|
70
|
+
const importEsm = (specifier) => {
|
|
71
|
+
const importer = new Function("specifier", "return import(specifier)");
|
|
72
|
+
return importer(specifier);
|
|
73
|
+
};
|
|
74
|
+
const createHomebridgeLogger = () => {
|
|
75
|
+
const log = (0, import_logger.logger)("NRCHKB", "HomebridgeCameraFFmpeg");
|
|
76
|
+
const write = (level) => (message, ...parameters) => {
|
|
77
|
+
const suffix = parameters.length ? ` ${parameters.join(" ")}` : "";
|
|
78
|
+
const text = `${message}${suffix}`;
|
|
79
|
+
if (level === "debug") {
|
|
80
|
+
log.debug(text);
|
|
81
|
+
} else if (level === "error") {
|
|
82
|
+
log.error(text);
|
|
83
|
+
} else {
|
|
84
|
+
log.debug(text);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
debug: write("debug"),
|
|
89
|
+
info: write("info"),
|
|
90
|
+
warn: write("warn"),
|
|
91
|
+
error: write("error"),
|
|
92
|
+
success: write("info"),
|
|
93
|
+
log: write("info")
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
const createHomebridgeApiShim = () => ({
|
|
97
|
+
on: (_event, _handler) => {
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const getCameraConfig = (context) => ({
|
|
101
|
+
name: context.config.camera?.name ?? context.serviceInformation.name,
|
|
102
|
+
manufacturer: context.config.camera?.manufacturer ?? context.serviceInformation.config.manufacturer,
|
|
103
|
+
model: context.config.camera?.model ?? context.serviceInformation.config.model,
|
|
104
|
+
serialNumber: context.config.camera?.serialNumber ?? context.serviceInformation.config.serialNo,
|
|
105
|
+
firmwareRevision: context.config.camera?.firmwareRevision ?? context.serviceInformation.config.firmwareRev,
|
|
106
|
+
motion: context.config.camera?.motion,
|
|
107
|
+
doorbell: context.config.camera?.doorbell,
|
|
108
|
+
switches: context.config.camera?.switches,
|
|
109
|
+
motionTimeout: context.config.camera?.motionTimeout,
|
|
110
|
+
motionDoorbell: context.config.camera?.motionDoorbell,
|
|
111
|
+
videoConfig: {
|
|
112
|
+
...context.config.camera?.videoConfig
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const mapLegacyCameraConfigToPluginConfig = (config) => ({
|
|
116
|
+
videoProcessor: config.cameraConfigVideoProcessor || "ffmpeg",
|
|
117
|
+
camera: {
|
|
118
|
+
name: config.name,
|
|
119
|
+
manufacturer: config.manufacturer,
|
|
120
|
+
model: config.model,
|
|
121
|
+
serialNumber: config.serialNo,
|
|
122
|
+
firmwareRevision: config.firmwareRev,
|
|
123
|
+
videoConfig: {
|
|
124
|
+
source: config.cameraConfigSource,
|
|
125
|
+
stillImageSource: config.cameraConfigStillImageSource,
|
|
126
|
+
maxStreams: config.cameraConfigMaxStreams,
|
|
127
|
+
maxWidth: config.cameraConfigMaxWidth,
|
|
128
|
+
maxHeight: config.cameraConfigMaxHeight,
|
|
129
|
+
maxFPS: config.cameraConfigMaxFPS,
|
|
130
|
+
maxBitrate: config.cameraConfigMaxBitrate,
|
|
131
|
+
vcodec: config.cameraConfigVideoCodec,
|
|
132
|
+
audio: toBoolean(config.cameraConfigAudio),
|
|
133
|
+
returnAudioTarget: config.cameraConfigReturnAudioTarget,
|
|
134
|
+
packetSize: config.cameraConfigPacketSize,
|
|
135
|
+
forceMax: toBoolean(config.cameraConfigForceMax),
|
|
136
|
+
mapvideo: config.cameraConfigMapVideo,
|
|
137
|
+
mapaudio: config.cameraConfigMapAudio,
|
|
138
|
+
videoFilter: config.cameraConfigVideoFilter,
|
|
139
|
+
encoderOptions: config.cameraConfigAdditionalCommandLine,
|
|
140
|
+
debug: toBoolean(config.cameraConfigDebug),
|
|
141
|
+
debugReturn: toBoolean(config.cameraConfigDebugReturn),
|
|
142
|
+
recording: toBoolean(config.cameraConfigRecording),
|
|
143
|
+
prebuffer: toBoolean(config.cameraConfigPrebuffer)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const createAutomaticHomebridgeCameraFfmpegPluginEntry = (config) => ({
|
|
148
|
+
id: HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_ID,
|
|
149
|
+
automatic: true,
|
|
150
|
+
modified: false,
|
|
151
|
+
config: mapLegacyCameraConfigToPluginConfig(config)
|
|
152
|
+
});
|
|
153
|
+
const homebridgeCameraFfmpegPluginMetadata = {
|
|
154
|
+
id: HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_ID,
|
|
155
|
+
packageName: "node-red-contrib-homekit-bridged",
|
|
156
|
+
pluginName: HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_NAME,
|
|
157
|
+
displayName: "Homebridge Camera FFmpeg",
|
|
158
|
+
author: "NRCHKB",
|
|
159
|
+
version: "1.0.0",
|
|
160
|
+
description: "Adds FFmpeg-backed HomeKit camera snapshots, live video, audio, and experimental recording features.",
|
|
161
|
+
attachment: "inline",
|
|
162
|
+
license: "Apache-2.0",
|
|
163
|
+
capabilities: {
|
|
164
|
+
camera: true,
|
|
165
|
+
snapshots: true,
|
|
166
|
+
liveVideo: true,
|
|
167
|
+
audio: true,
|
|
168
|
+
twoWayAudio: true,
|
|
169
|
+
secureVideo: true,
|
|
170
|
+
experimental: ["twoWayAudio", "secureVideo"]
|
|
171
|
+
},
|
|
172
|
+
prerequisites: {
|
|
173
|
+
serviceNames: ["Camera"]
|
|
174
|
+
},
|
|
175
|
+
multipleInstances: false,
|
|
176
|
+
upstream: {
|
|
177
|
+
packageName: "@homebridge-plugins/homebridge-camera-ffmpeg",
|
|
178
|
+
packageVersion: upstreamPackage.version,
|
|
179
|
+
projectName: "Homebridge Camera FFmpeg",
|
|
180
|
+
repoUrl: "https://github.com/homebridge-plugins/homebridge-camera-ffmpeg",
|
|
181
|
+
license: upstreamPackage.license,
|
|
182
|
+
authors: upstreamAuthor ? [upstreamAuthor] : [],
|
|
183
|
+
contributors: upstreamContributors,
|
|
184
|
+
disclaimer: "Original authors and contributors are credited for the upstream Homebridge plugin. NRCHKB owns and supports this embedded integration."
|
|
185
|
+
},
|
|
186
|
+
editor: {
|
|
187
|
+
defaultConfig: {
|
|
188
|
+
videoProcessor: "ffmpeg",
|
|
189
|
+
camera: {
|
|
190
|
+
videoConfig: {
|
|
191
|
+
source: "",
|
|
192
|
+
stillImageSource: "",
|
|
193
|
+
maxStreams: 2,
|
|
194
|
+
maxWidth: 1280,
|
|
195
|
+
maxHeight: 720,
|
|
196
|
+
maxFPS: 10,
|
|
197
|
+
maxBitrate: 300,
|
|
198
|
+
vcodec: "libx264",
|
|
199
|
+
audio: false,
|
|
200
|
+
returnAudioTarget: "",
|
|
201
|
+
packetSize: 1316,
|
|
202
|
+
forceMax: false,
|
|
203
|
+
mapvideo: "0:0",
|
|
204
|
+
mapaudio: "0:1",
|
|
205
|
+
videoFilter: "scale=1280:720",
|
|
206
|
+
encoderOptions: "-tune zerolatency",
|
|
207
|
+
debug: false,
|
|
208
|
+
debugReturn: false,
|
|
209
|
+
recording: true,
|
|
210
|
+
prebuffer: true
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
sections: [
|
|
215
|
+
{
|
|
216
|
+
title: "FFmpeg",
|
|
217
|
+
description: "Configure the command arguments used for HomeKit camera snapshots and live video.",
|
|
218
|
+
fields: [
|
|
219
|
+
{
|
|
220
|
+
path: "videoProcessor",
|
|
221
|
+
label: "Video Processor",
|
|
222
|
+
type: "text",
|
|
223
|
+
icon: "fa-terminal",
|
|
224
|
+
placeholder: "ffmpeg",
|
|
225
|
+
default: "ffmpeg"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
path: "camera.videoConfig.source",
|
|
229
|
+
label: "Source",
|
|
230
|
+
type: "text",
|
|
231
|
+
icon: "fa-sign-in"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
path: "camera.videoConfig.stillImageSource",
|
|
235
|
+
label: "Still Image Source",
|
|
236
|
+
type: "text",
|
|
237
|
+
icon: "fa-picture-o"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
path: "camera.videoConfig.maxStreams",
|
|
241
|
+
label: "Max Streams",
|
|
242
|
+
type: "number",
|
|
243
|
+
icon: "fa-random",
|
|
244
|
+
default: 2
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
path: "camera.videoConfig.maxWidth",
|
|
248
|
+
label: "Max Width",
|
|
249
|
+
type: "number",
|
|
250
|
+
icon: "fa-arrows-h",
|
|
251
|
+
default: 1280
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
path: "camera.videoConfig.maxHeight",
|
|
255
|
+
label: "Max Height",
|
|
256
|
+
type: "number",
|
|
257
|
+
icon: "fa-arrows-v",
|
|
258
|
+
default: 720
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
path: "camera.videoConfig.maxFPS",
|
|
262
|
+
label: "Max FPS",
|
|
263
|
+
type: "number",
|
|
264
|
+
icon: "fa-clock-o",
|
|
265
|
+
default: 10
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
path: "camera.videoConfig.maxBitrate",
|
|
269
|
+
label: "Max Bitrate",
|
|
270
|
+
type: "number",
|
|
271
|
+
icon: "fa-tachometer",
|
|
272
|
+
default: 300
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
path: "camera.videoConfig.vcodec",
|
|
276
|
+
label: "Video Codec",
|
|
277
|
+
type: "text",
|
|
278
|
+
icon: "fa-film",
|
|
279
|
+
default: "libx264"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
path: "camera.videoConfig.audio",
|
|
283
|
+
label: "Audio",
|
|
284
|
+
type: "checkbox",
|
|
285
|
+
icon: "fa-headphones",
|
|
286
|
+
default: false
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
path: "camera.videoConfig.returnAudioTarget",
|
|
290
|
+
label: "Return Audio Target",
|
|
291
|
+
type: "text",
|
|
292
|
+
icon: "fa-microphone"
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
path: "camera.videoConfig.packetSize",
|
|
296
|
+
label: "Packet Size",
|
|
297
|
+
type: "number",
|
|
298
|
+
icon: "fa-archive",
|
|
299
|
+
default: 1316
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
path: "camera.videoConfig.forceMax",
|
|
303
|
+
label: "Force Max",
|
|
304
|
+
type: "checkbox",
|
|
305
|
+
icon: "fa-arrows-alt",
|
|
306
|
+
default: false
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
path: "camera.videoConfig.mapvideo",
|
|
310
|
+
label: "Map Video",
|
|
311
|
+
type: "text",
|
|
312
|
+
icon: "fa-film",
|
|
313
|
+
default: "0:0"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
path: "camera.videoConfig.mapaudio",
|
|
317
|
+
label: "Map Audio",
|
|
318
|
+
type: "text",
|
|
319
|
+
icon: "fa-volume-up",
|
|
320
|
+
default: "0:1"
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
path: "camera.videoConfig.videoFilter",
|
|
324
|
+
label: "Video Filter",
|
|
325
|
+
type: "text",
|
|
326
|
+
icon: "fa-filter",
|
|
327
|
+
default: "scale=1280:720"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
path: "camera.videoConfig.encoderOptions",
|
|
331
|
+
label: "Additional Command Line",
|
|
332
|
+
type: "text",
|
|
333
|
+
icon: "fa-terminal",
|
|
334
|
+
default: "-tune zerolatency"
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
path: "camera.videoConfig.debug",
|
|
338
|
+
label: "Debug",
|
|
339
|
+
type: "checkbox",
|
|
340
|
+
icon: "fa-bug",
|
|
341
|
+
default: false
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
path: "camera.videoConfig.debugReturn",
|
|
345
|
+
label: "Debug Return Audio",
|
|
346
|
+
type: "checkbox",
|
|
347
|
+
icon: "fa-bug",
|
|
348
|
+
default: false
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
path: "camera.videoConfig.recording",
|
|
352
|
+
label: "Recording",
|
|
353
|
+
type: "checkbox",
|
|
354
|
+
icon: "fa-video-camera",
|
|
355
|
+
default: true
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
path: "camera.videoConfig.prebuffer",
|
|
359
|
+
label: "Prebuffer",
|
|
360
|
+
type: "checkbox",
|
|
361
|
+
icon: "fa-clock-o",
|
|
362
|
+
default: true
|
|
363
|
+
}
|
|
364
|
+
]
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
title: "Camera Events",
|
|
368
|
+
description: "Expose HomeKit motion and doorbell helpers supported by Camera FFmpeg.",
|
|
369
|
+
fields: [
|
|
370
|
+
{
|
|
371
|
+
path: "camera.motion",
|
|
372
|
+
label: "Motion Sensor",
|
|
373
|
+
type: "checkbox",
|
|
374
|
+
icon: "fa-bell",
|
|
375
|
+
default: false
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
path: "camera.doorbell",
|
|
379
|
+
label: "Doorbell",
|
|
380
|
+
type: "checkbox",
|
|
381
|
+
icon: "fa-bell-o",
|
|
382
|
+
default: false
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
path: "camera.switches",
|
|
386
|
+
label: "Trigger Switches",
|
|
387
|
+
type: "checkbox",
|
|
388
|
+
icon: "fa-toggle-on",
|
|
389
|
+
default: false
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
path: "camera.motionTimeout",
|
|
393
|
+
label: "Motion Timeout",
|
|
394
|
+
type: "number",
|
|
395
|
+
icon: "fa-clock-o",
|
|
396
|
+
default: 1
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
path: "camera.motionDoorbell",
|
|
400
|
+
label: "Motion Rings Doorbell",
|
|
401
|
+
type: "checkbox",
|
|
402
|
+
icon: "fa-bell",
|
|
403
|
+
default: false
|
|
404
|
+
}
|
|
405
|
+
]
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
title: "Camera Identity",
|
|
409
|
+
description: "Optional HomeKit metadata overrides for this camera.",
|
|
410
|
+
fields: [
|
|
411
|
+
{
|
|
412
|
+
path: "camera.manufacturer",
|
|
413
|
+
label: "Manufacturer",
|
|
414
|
+
type: "text",
|
|
415
|
+
icon: "fa-industry"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
path: "camera.model",
|
|
419
|
+
label: "Model",
|
|
420
|
+
type: "text",
|
|
421
|
+
icon: "fa-cube"
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
path: "camera.serialNumber",
|
|
425
|
+
label: "Serial Number",
|
|
426
|
+
type: "text",
|
|
427
|
+
icon: "fa-barcode"
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
path: "camera.firmwareRevision",
|
|
431
|
+
label: "Firmware Revision",
|
|
432
|
+
type: "text",
|
|
433
|
+
icon: "fa-microchip"
|
|
434
|
+
}
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
const homebridgeCameraFfmpegPluginFactory = {
|
|
441
|
+
attach: async (context) => {
|
|
442
|
+
const hap = await import("@homebridge/hap-nodejs");
|
|
443
|
+
const module2 = await importEsm(
|
|
444
|
+
"@homebridge-plugins/homebridge-camera-ffmpeg/dist/streamingDelegate.js"
|
|
445
|
+
);
|
|
446
|
+
const delegate = new module2.StreamingDelegate(
|
|
447
|
+
createHomebridgeLogger(),
|
|
448
|
+
getCameraConfig(context),
|
|
449
|
+
createHomebridgeApiShim(),
|
|
450
|
+
hap,
|
|
451
|
+
context.accessory,
|
|
452
|
+
context.config.videoProcessor
|
|
453
|
+
);
|
|
454
|
+
context.accessory.configureController(delegate.controller);
|
|
455
|
+
const service = context.accessory.services.find(
|
|
456
|
+
(candidate) => candidate.UUID === import_hap_nodejs.Service.CameraRTPStreamManagement.UUID
|
|
457
|
+
);
|
|
458
|
+
if (!service) {
|
|
459
|
+
throw new Error(
|
|
460
|
+
"Homebridge Camera FFmpeg did not create a camera stream service."
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
return service;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
const registerHomebridgeCameraFfmpegPlugin = () => (0, import_registry.registerPlugin)(
|
|
467
|
+
homebridgeCameraFfmpegPluginMetadata,
|
|
468
|
+
homebridgeCameraFfmpegPluginFactory
|
|
469
|
+
);
|
|
470
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
471
|
+
0 && (module.exports = {
|
|
472
|
+
HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_ID,
|
|
473
|
+
HOMEBRIDGE_CAMERA_FFMPEG_PLUGIN_NAME,
|
|
474
|
+
createAutomaticHomebridgeCameraFfmpegPluginEntry,
|
|
475
|
+
homebridgeCameraFfmpegPluginFactory,
|
|
476
|
+
homebridgeCameraFfmpegPluginMetadata,
|
|
477
|
+
mapLegacyCameraConfigToPluginConfig,
|
|
478
|
+
registerHomebridgeCameraFfmpegPlugin
|
|
479
|
+
});
|