node-red-contrib-homekit-bridged 1.7.0-dev.8 → 1.7.0-dev.9
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 +20 -9
- package/build/lib/HAPServiceNode.js +3 -2
- package/build/lib/HAPServiceNode2.js +3 -2
- package/build/lib/types/HAPHostConfigType.d.ts +2 -0
- package/build/lib/types/HAPHostNodeType.d.ts +2 -2
- package/build/lib/types/hap-nodejs/BonjourMulticastOptions.d.ts +10 -0
- package/build/lib/types/hap-nodejs/BonjourMulticastOptions.js +2 -0
- package/build/nodes/bridge.html +83 -14
- package/build/nodes/nrchkb.html +123 -118
- package/build/nodes/standalone.html +90 -21
- package/package.json +5 -5
package/build/lib/HAPHostNode.js
CHANGED
|
@@ -22,7 +22,7 @@ const HostType_1 = __importDefault(require("./types/HostType"));
|
|
|
22
22
|
module.exports = (RED, hostType) => {
|
|
23
23
|
const MdnsUtils = require('./utils/MdnsUtils')();
|
|
24
24
|
const init = function (config) {
|
|
25
|
-
var _a, _b, _c, _d, _e;
|
|
25
|
+
var _a, _b, _c, _d, _e, _f;
|
|
26
26
|
const self = this;
|
|
27
27
|
const log = (0, logger_1.logger)('NRCHKB', 'HAPHostNode', config.bridgeName, self);
|
|
28
28
|
self.hostType = hostType;
|
|
@@ -36,7 +36,8 @@ module.exports = (RED, hostType) => {
|
|
|
36
36
|
if (preload_1.default.parse(config.firmwareRev) == null) {
|
|
37
37
|
config.firmwareRev = new semver_1.SemVer('0.0.0');
|
|
38
38
|
}
|
|
39
|
-
if (config.customMdnsConfig) {
|
|
39
|
+
if (!((_a = config.bind) === null || _a === void 0 ? void 0 : _a.length) && config.customMdnsConfig) {
|
|
40
|
+
log.error('Custom mdns config is deprecated, use bind instead!');
|
|
40
41
|
self.mdnsConfig = {};
|
|
41
42
|
if (MdnsUtils.checkMulticast(config.mdnsMulticast)) {
|
|
42
43
|
self.mdnsConfig.multicast = config.mdnsMulticast;
|
|
@@ -45,13 +46,13 @@ module.exports = (RED, hostType) => {
|
|
|
45
46
|
self.mdnsConfig.interface = config.mdnsInterface;
|
|
46
47
|
}
|
|
47
48
|
if (MdnsUtils.checkPort(config.mdnsPort)) {
|
|
48
|
-
self.mdnsConfig.port = parseInt((
|
|
49
|
+
self.mdnsConfig.port = parseInt((_b = config.mdnsPort) === null || _b === void 0 ? void 0 : _b.toString());
|
|
49
50
|
}
|
|
50
51
|
if (MdnsUtils.checkIp(config.mdnsIp)) {
|
|
51
52
|
self.mdnsConfig.ip = config.mdnsIp;
|
|
52
53
|
}
|
|
53
54
|
if (MdnsUtils.checkTtl(config.mdnsTtl)) {
|
|
54
|
-
self.mdnsConfig.ttl = parseInt((
|
|
55
|
+
self.mdnsConfig.ttl = parseInt((_c = config.mdnsTtl) === null || _c === void 0 ? void 0 : _c.toString());
|
|
55
56
|
}
|
|
56
57
|
if (MdnsUtils.checkLoopback(config.mdnsLoopback)) {
|
|
57
58
|
self.mdnsConfig.loopback = config.mdnsLoopback;
|
|
@@ -81,7 +82,7 @@ module.exports = (RED, hostType) => {
|
|
|
81
82
|
self.host = new hap_nodejs_1.Accessory(self.name, hostUUID);
|
|
82
83
|
}
|
|
83
84
|
self.publish = function () {
|
|
84
|
-
var _a, _b, _c;
|
|
85
|
+
var _a, _b, _c, _d;
|
|
85
86
|
if (self.hostType == HostType_1.default.BRIDGE) {
|
|
86
87
|
log.debug(`Publishing ${hostTypeName} with pin code ${self.config.pinCode} and ${self.host.bridgedAccessories.length} accessories`);
|
|
87
88
|
}
|
|
@@ -99,6 +100,15 @@ module.exports = (RED, hostType) => {
|
|
|
99
100
|
oldPinCode = oldPinCode.replace(/-/g, '');
|
|
100
101
|
oldPinCode = `${oldPinCode.slice(0, 3)}-${oldPinCode.slice(3, 5)}-${oldPinCode.slice(5, 8)}`;
|
|
101
102
|
}
|
|
103
|
+
let bind;
|
|
104
|
+
if (((_c = self.config.bind) === null || _c === void 0 ? void 0 : _c.length) && self.config.bindType) {
|
|
105
|
+
if (self.config.bindType == 'str') {
|
|
106
|
+
bind = self.config.bind;
|
|
107
|
+
}
|
|
108
|
+
else if (self.config.bindType == 'json') {
|
|
109
|
+
bind = JSON.parse(self.config.bind);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
102
112
|
self.host.publish({
|
|
103
113
|
username: self.bridgeUsername,
|
|
104
114
|
port: self.config.port && !isNaN(self.config.port)
|
|
@@ -107,7 +117,8 @@ module.exports = (RED, hostType) => {
|
|
|
107
117
|
pincode: oldPinCode,
|
|
108
118
|
category: self.accessoryCategory,
|
|
109
119
|
mdns: self.mdnsConfig,
|
|
110
|
-
|
|
120
|
+
bind: bind,
|
|
121
|
+
advertiser: (_d = self.config.advertiser) !== null && _d !== void 0 ? _d : "bonjour-hap",
|
|
111
122
|
}, self.config.allowInsecureRequest);
|
|
112
123
|
self.published = true;
|
|
113
124
|
return true;
|
|
@@ -141,9 +152,9 @@ module.exports = (RED, hostType) => {
|
|
|
141
152
|
.setCharacteristic(hap_nodejs_1.Characteristic.Manufacturer, self.config.manufacturer)
|
|
142
153
|
.setCharacteristic(hap_nodejs_1.Characteristic.SerialNumber, self.config.serialNo)
|
|
143
154
|
.setCharacteristic(hap_nodejs_1.Characteristic.Model, self.config.model)
|
|
144
|
-
.setCharacteristic(hap_nodejs_1.Characteristic.FirmwareRevision, (
|
|
145
|
-
.setCharacteristic(hap_nodejs_1.Characteristic.HardwareRevision, (
|
|
146
|
-
.setCharacteristic(hap_nodejs_1.Characteristic.SoftwareRevision, (
|
|
155
|
+
.setCharacteristic(hap_nodejs_1.Characteristic.FirmwareRevision, (_d = self.config.firmwareRev) === null || _d === void 0 ? void 0 : _d.toString())
|
|
156
|
+
.setCharacteristic(hap_nodejs_1.Characteristic.HardwareRevision, (_e = self.config.hardwareRev) === null || _e === void 0 ? void 0 : _e.toString())
|
|
157
|
+
.setCharacteristic(hap_nodejs_1.Characteristic.SoftwareRevision, (_f = self.config.softwareRev) === null || _f === void 0 ? void 0 : _f.toString());
|
|
147
158
|
};
|
|
148
159
|
const macify = (nodeId) => {
|
|
149
160
|
if (nodeId) {
|
|
@@ -95,8 +95,9 @@ module.exports = (RED) => {
|
|
|
95
95
|
: self.config.accessoryId;
|
|
96
96
|
self.hostNode = RED.nodes.getNode(hostId);
|
|
97
97
|
if (!self.hostNode) {
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const message = `Host node ${self.config.hostType == HostType_1.default.BRIDGE ? 'Bridge' : 'Standalone Accessory'} ${hostId} not found`;
|
|
99
|
+
log.error(message, false);
|
|
100
|
+
throw new NRCHKBError_1.default(message);
|
|
100
101
|
}
|
|
101
102
|
self.childNodes = [];
|
|
102
103
|
self.childNodes.push(self);
|
|
@@ -95,8 +95,9 @@ module.exports = (RED) => {
|
|
|
95
95
|
: self.config.accessoryId;
|
|
96
96
|
self.hostNode = RED.nodes.getNode(hostId);
|
|
97
97
|
if (!self.hostNode) {
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const message = `Host node ${self.config.hostType == HostType_1.default.BRIDGE ? 'Bridge' : 'Standalone Accessory'} ${hostId} not found`;
|
|
99
|
+
log.error(message, false);
|
|
100
|
+
throw new NRCHKBError_1.default(message);
|
|
100
101
|
}
|
|
101
102
|
self.childNodes = [];
|
|
102
103
|
self.childNodes.push(self);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { MulticastOptions } from 'bonjour-hap';
|
|
2
1
|
import { Accessory, Categories } from 'hap-nodejs';
|
|
2
|
+
import BonjourMulticastOptions from './hap-nodejs/BonjourMulticastOptions';
|
|
3
3
|
import HAPHostConfigType from './HAPHostConfigType';
|
|
4
4
|
import HostType from './HostType';
|
|
5
5
|
import NodeType from './NodeType';
|
|
6
6
|
type HAPHostNodeType = NodeType & {
|
|
7
7
|
config: HAPHostConfigType;
|
|
8
|
-
mdnsConfig:
|
|
8
|
+
mdnsConfig: BonjourMulticastOptions;
|
|
9
9
|
accessoryCategory: Categories;
|
|
10
10
|
published: boolean;
|
|
11
11
|
bridgeUsername: string;
|
package/build/nodes/bridge.html
CHANGED
|
@@ -55,9 +55,14 @@
|
|
|
55
55
|
<label for="node-config-input-allowMessagePassthrough" style="width: 70%;"> <i class="fa fa-step-forward"></i> Allow Message Passthrough</label>
|
|
56
56
|
</div>
|
|
57
57
|
<hr>
|
|
58
|
+
<div class="form-row">
|
|
59
|
+
<label for="node-config-input-bind"><i class="fa fa-filter"></i> Bind</label>
|
|
60
|
+
<input type="text" id="node-config-input-bind" placeholder="::">
|
|
61
|
+
<input type="hidden" id="node-config-input-bindType">
|
|
62
|
+
</div>
|
|
58
63
|
<div class="form-row">
|
|
59
64
|
<input type="checkbox" id="node-config-input-customMdnsConfig" style="display: inline-block; width: auto; vertical-align: top;">
|
|
60
|
-
<label for="node-config-input-customMdnsConfig" style="width: 70%;"> <i class="fa fa-filter"></i> Custom MDNS Configuration</label>
|
|
65
|
+
<label for="node-config-input-customMdnsConfig" style="width: 70%;"> <i class="fa fa-filter"></i> Custom MDNS Configuration (DEPRECATED, use Bind)</label>
|
|
61
66
|
</div>
|
|
62
67
|
<div id="mdns-configuration" style="display: none;">
|
|
63
68
|
<div class="form-row">
|
|
@@ -108,7 +113,60 @@
|
|
|
108
113
|
<li><strong>Software Revision</strong>: Should be a version number string in the form of <em>MAJOR.MINOR.REVISION</em> e.g. <em>1.2.0</em>. Other types of strings are ignored and won't be displayed.</li>
|
|
109
114
|
<li><strong>Name</strong>: If you intend to simulate a rocket, then why don't you call it <em>Rocket</em>. Name should be maximum 64 chars long and not contain <pre>.</pre></li>
|
|
110
115
|
<li><strong>Allow Message Passthrough</strong>: If you allow then message from node input will be sent to node output.</li>
|
|
111
|
-
<li><strong>
|
|
116
|
+
<li><strong>Bind</strong>: Defines the host where the HAP server will be bound to. </li>
|
|
117
|
+
<ul>
|
|
118
|
+
<li>
|
|
119
|
+
Defines the host where the HAP server will be bound to.
|
|
120
|
+
When undefined the HAP server will bind to all available interfaces
|
|
121
|
+
(see https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback).
|
|
122
|
+
|
|
123
|
+
This property accepts a mixture of IPAddresses and network interface names.
|
|
124
|
+
Depending on the mixture of supplied addresses/names hap-nodejs will bind differently.
|
|
125
|
+
|
|
126
|
+
It is advised to not just bind to a specific address, but specifying the interface name
|
|
127
|
+
in oder to bind on all address records (and ip version) available.
|
|
128
|
+
|
|
129
|
+
HAP-NodeJS (or the underlying ciao library) will not report about misspelled interface names,
|
|
130
|
+
as it could be that the interface is currently just down and will come up later.
|
|
131
|
+
|
|
132
|
+
Here are a few examples:
|
|
133
|
+
- bind: "::"
|
|
134
|
+
Pretty much identical to not specifying anything, as most systems (with ipv6 support)
|
|
135
|
+
will default to the unspecified ipv6 address (with dual stack support).
|
|
136
|
+
|
|
137
|
+
- bind: "0.0.0.0"
|
|
138
|
+
Binding TCP socket to the unspecified ipv4 address.
|
|
139
|
+
The mdns advertisement will exclude any ipv6 address records.
|
|
140
|
+
|
|
141
|
+
- bind: ["en0", "lo0"]
|
|
142
|
+
The mdns advertising will advertise all records of the en0 and loopback interface (if available) and
|
|
143
|
+
will also react to address changes on those interfaces.
|
|
144
|
+
In order for the HAP server to accept all those address records (which may contain ipv6 records)
|
|
145
|
+
it will bind on the unspecified ipv6 address "::" (assuming dual stack is supported).
|
|
146
|
+
|
|
147
|
+
- bind: ["en0", "lo0", "0.0.0.0"]
|
|
148
|
+
Same as above, only that the HAP server will bind on the unspecified ipv4 address "0.0.0.0".
|
|
149
|
+
The mdns advertisement will not advertise any ipv6 records.
|
|
150
|
+
|
|
151
|
+
- bind: "169.254.104.90"
|
|
152
|
+
This will bind the HAP server to the address 0.0.0.0.
|
|
153
|
+
The mdns advertisement will only advertise the A record 169.254.104.90.
|
|
154
|
+
If the given network interface of that address encounters an ip address change (to a different address),
|
|
155
|
+
the mdns advertisement will result in not advertising an address at all.
|
|
156
|
+
So it is advised to specify an interface name instead of a specific address.
|
|
157
|
+
This is identical with ipv6 addresses.
|
|
158
|
+
|
|
159
|
+
- bind: ["169.254.104.90", "192.168.1.4"]
|
|
160
|
+
As the HAP TCP socket can only bind to a single address, when specifying multiple ip addresses
|
|
161
|
+
the HAP server will bind to the unspecified ip address (0.0.0.0 if only ipv4 addresses are supplied,
|
|
162
|
+
:: if a mixture or only ipv6 addresses are supplied).
|
|
163
|
+
The mdns advertisement will only advertise the specified ip addresses.
|
|
164
|
+
If the given network interface of that address encounters an ip address change (to different addresses),
|
|
165
|
+
the mdns advertisement will result in not advertising an address at all.
|
|
166
|
+
So it is advised to specify an interface name instead of a specific address.
|
|
167
|
+
</li>
|
|
168
|
+
</ul>
|
|
169
|
+
<li><strong>Custom MDNS Configuration (DEPRECATED, use Bind)</strong>: Check if you would like to use custom mdns configuration.</li>
|
|
112
170
|
<ul>
|
|
113
171
|
<li><strong>Multicast</strong>: Use udp multicasting. Optional. Default true.</li>
|
|
114
172
|
<li><strong>Multicast Interface IP:</strong>: Explicitly specify a network interface. Optional. Defaults to all.</li>
|
|
@@ -185,37 +243,42 @@
|
|
|
185
243
|
required: false,
|
|
186
244
|
validate: versionValidator,
|
|
187
245
|
},
|
|
246
|
+
bind: {
|
|
247
|
+
value: undefined,
|
|
248
|
+
required: false,
|
|
249
|
+
},
|
|
250
|
+
bindType: {
|
|
251
|
+
value: undefined,
|
|
252
|
+
required: false,
|
|
253
|
+
},
|
|
188
254
|
customMdnsConfig: {
|
|
189
255
|
value: false,
|
|
190
256
|
required: false,
|
|
257
|
+
validate: (value) => !value
|
|
191
258
|
},
|
|
192
259
|
mdnsMulticast: {
|
|
193
260
|
value: true,
|
|
194
|
-
required: false
|
|
261
|
+
required: false
|
|
195
262
|
},
|
|
196
263
|
mdnsInterface: {
|
|
197
|
-
required: false
|
|
264
|
+
required: false
|
|
198
265
|
},
|
|
199
266
|
mdnsPort: {
|
|
200
|
-
required: false
|
|
201
|
-
validate: function (value) {
|
|
202
|
-
if (value) return RED.validators.port(value)
|
|
203
|
-
else return true
|
|
204
|
-
},
|
|
267
|
+
required: false
|
|
205
268
|
},
|
|
206
269
|
mdnsIp: {
|
|
207
|
-
required: false
|
|
270
|
+
required: false
|
|
208
271
|
},
|
|
209
272
|
mdnsTtl: {
|
|
210
|
-
required: false
|
|
273
|
+
required: false
|
|
211
274
|
},
|
|
212
275
|
mdnsLoopback: {
|
|
213
276
|
value: true,
|
|
214
|
-
required: false
|
|
277
|
+
required: false
|
|
215
278
|
},
|
|
216
279
|
mdnsReuseAddr: {
|
|
217
280
|
value: true,
|
|
218
|
-
required: false
|
|
281
|
+
required: false
|
|
219
282
|
},
|
|
220
283
|
allowMessagePassthrough: {
|
|
221
284
|
value: true,
|
|
@@ -231,7 +294,7 @@
|
|
|
231
294
|
oneditprepare: function () {
|
|
232
295
|
if (!validatePinCode(this.pinCode)) {
|
|
233
296
|
this.pinCode = generatePinCode()
|
|
234
|
-
$(
|
|
297
|
+
$('#node-config-input-pinCode').val(this.pinCode)
|
|
235
298
|
}
|
|
236
299
|
|
|
237
300
|
if (typeof this.allowMessagePassthrough == 'undefined') {
|
|
@@ -256,6 +319,12 @@
|
|
|
256
319
|
}
|
|
257
320
|
})
|
|
258
321
|
.change()
|
|
322
|
+
|
|
323
|
+
$('#node-config-input-bind').typedInput({
|
|
324
|
+
typeField: '#node-config-input-bindType',
|
|
325
|
+
default: 'str',
|
|
326
|
+
types: ['json', 'str']
|
|
327
|
+
})
|
|
259
328
|
},
|
|
260
329
|
})
|
|
261
330
|
</script>
|
package/build/nodes/nrchkb.html
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
border-radius: .25rem;
|
|
8
8
|
margin-right: 60px;
|
|
9
9
|
}
|
|
10
|
+
|
|
10
11
|
.alert-warning {
|
|
11
12
|
color: #856404;
|
|
12
13
|
background-color: #fff3cd;
|
|
@@ -56,55 +57,55 @@
|
|
|
56
57
|
|
|
57
58
|
$('#node-input-customCharacteristics-container').css('min-height', '150px').css('min-width', '550px').editableList({
|
|
58
59
|
addItem: function (container, i, opt) {
|
|
59
|
-
$(
|
|
60
|
+
$('.properties-accordion').accordion('option', 'active', false)
|
|
60
61
|
|
|
61
62
|
const {name, UUID, ...props} = opt
|
|
62
63
|
|
|
63
64
|
container.css({
|
|
64
65
|
overflow: 'hidden',
|
|
65
66
|
whiteSpace: 'nowrap'
|
|
66
|
-
})
|
|
67
|
+
})
|
|
67
68
|
|
|
68
|
-
const fragment = document.createDocumentFragment()
|
|
69
|
-
const row1 = $('<div/>', {style:
|
|
70
|
-
const row2 = $('<div/>', {style:
|
|
71
|
-
const row3 = $('<div/>', {style:
|
|
69
|
+
const fragment = document.createDocumentFragment()
|
|
70
|
+
const row1 = $('<div/>', {style: 'display:flex; align-items: center;'}).appendTo(fragment)
|
|
71
|
+
const row2 = $('<div/>', {style: 'display:flex; margin-top:8px; align-items: center;'}).appendTo(fragment)
|
|
72
|
+
const row3 = $('<div/>', {style: 'margin-top:8px; align-items: center;'}).appendTo(fragment)
|
|
72
73
|
|
|
73
74
|
$('<div/>', {
|
|
74
|
-
style:
|
|
75
|
-
required:
|
|
75
|
+
style: 'display:inline-block;text-align:left; width:120px; padding-left:10px; box-sizing:border-box;',
|
|
76
|
+
required: 'required'
|
|
76
77
|
})
|
|
77
78
|
.text('UUID ')
|
|
78
|
-
.appendTo(row1)
|
|
79
|
-
$('<input/>', {class:
|
|
79
|
+
.appendTo(row1)
|
|
80
|
+
$('<input/>', {class: 'property-uuid', type: 'text'})
|
|
80
81
|
.val(UUID ? UUID : uuidv4)
|
|
81
82
|
.appendTo(row1)
|
|
82
83
|
|
|
83
84
|
$('<div/>', {
|
|
84
|
-
style:
|
|
85
|
-
required:
|
|
85
|
+
style: 'display:inline-block;text-align:left; width:120px; padding-left:10px; box-sizing:border-box;',
|
|
86
|
+
required: 'required'
|
|
86
87
|
})
|
|
87
88
|
.text('Name ')
|
|
88
|
-
.appendTo(row2)
|
|
89
|
-
$('<input/>', {class:
|
|
89
|
+
.appendTo(row2)
|
|
90
|
+
$('<input/>', {class: 'property-name', type: 'text'})
|
|
90
91
|
.val(name)
|
|
91
92
|
.appendTo(row2)
|
|
92
93
|
|
|
93
|
-
const row3_properties_accordion = $('<div/>', {class:
|
|
94
|
-
.appendTo(row3)
|
|
94
|
+
const row3_properties_accordion = $('<div/>', {class: 'properties-accordion'})
|
|
95
|
+
.appendTo(row3)
|
|
95
96
|
|
|
96
|
-
$('<h3/>').text('Properties').appendTo(row3_properties_accordion)
|
|
97
|
+
$('<h3/>').text('Properties').appendTo(row3_properties_accordion)
|
|
97
98
|
|
|
98
|
-
const row3_properties = $('<div/>', {class:
|
|
99
|
+
const row3_properties = $('<div/>', {class: 'properties'}).appendTo(row3_properties_accordion)
|
|
99
100
|
|
|
100
|
-
const formatRow = $('<div/>', {class:
|
|
101
|
+
const formatRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
101
102
|
$('<label/>', {
|
|
102
|
-
class:
|
|
103
|
-
htmlFor:
|
|
104
|
-
}).text('Format *').appendTo(formatRow)
|
|
103
|
+
class: 'form-row',
|
|
104
|
+
htmlFor: 'property-format'
|
|
105
|
+
}).text('Format *').appendTo(formatRow)
|
|
105
106
|
const formatInput = $('<select/>', {
|
|
106
|
-
class:
|
|
107
|
-
required:
|
|
107
|
+
class: 'property-format',
|
|
108
|
+
required: 'required'
|
|
108
109
|
}).appendTo(formatRow)
|
|
109
110
|
$('<option/>').val(undefined).text('Choose...').appendTo(formatInput)
|
|
110
111
|
$('<option/>').val('bool').text('BOOL').appendTo(formatInput)
|
|
@@ -121,9 +122,9 @@
|
|
|
121
122
|
$('<option/>').val('dict').text('DICTIONARY').appendTo(formatInput)
|
|
122
123
|
formatInput.val(props.format)
|
|
123
124
|
|
|
124
|
-
const unitRow = $('<div/>', {class:
|
|
125
|
-
$('<label/>', {class:
|
|
126
|
-
const unitSelect = $('<select/>', {class:
|
|
125
|
+
const unitRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
126
|
+
$('<label/>', {class: 'form-row', htmlFor: 'property-unit'}).text('Unit').appendTo(unitRow)
|
|
127
|
+
const unitSelect = $('<select/>', {class: 'property-unit'}).appendTo(unitRow)
|
|
127
128
|
$('<option/>').val(undefined).text('Choose...').appendTo(unitSelect)
|
|
128
129
|
$('<option/>').val('celsius').text('CELSIUS').appendTo(unitSelect)
|
|
129
130
|
$('<option/>').val('percentage').text('PERCENTAGE').appendTo(unitSelect)
|
|
@@ -132,14 +133,14 @@
|
|
|
132
133
|
$('<option/>').val('seconds').text('SECONDS').appendTo(unitSelect)
|
|
133
134
|
unitSelect.val(props.unit)
|
|
134
135
|
|
|
135
|
-
const permsRow = $('<div/>', {class:
|
|
136
|
+
const permsRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
136
137
|
$('<label/>', {
|
|
137
|
-
class:
|
|
138
|
-
htmlFor:
|
|
138
|
+
class: 'form-row',
|
|
139
|
+
htmlFor: 'property-perms'
|
|
139
140
|
}).text('Permissions').appendTo(permsRow)
|
|
140
141
|
const permsSelect = $('<select/>', {
|
|
141
|
-
class:
|
|
142
|
-
multiple:
|
|
142
|
+
class: 'property-perms',
|
|
143
|
+
multiple: 'multiple'
|
|
143
144
|
}).appendTo(permsRow)
|
|
144
145
|
$('<option/>').val('pr').text('PAIRED_READ / READ').appendTo(permsSelect)
|
|
145
146
|
$('<option/>').val('pw').text('PAIRED_WRITE / WRITE').appendTo(permsSelect)
|
|
@@ -150,94 +151,94 @@
|
|
|
150
151
|
$('<option/>').val('wr').text('WRITE_RESPONSE').appendTo(permsSelect)
|
|
151
152
|
permsSelect.val(props.perms)
|
|
152
153
|
|
|
153
|
-
const evRow = $('<div/>', {class:
|
|
154
|
+
const evRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
154
155
|
$('<label/>', {
|
|
155
|
-
class:
|
|
156
|
-
htmlFor:
|
|
156
|
+
class: 'form-row',
|
|
157
|
+
htmlFor: 'property-ev'
|
|
157
158
|
}).text('Event Notifications').appendTo(evRow)
|
|
158
159
|
$('<input/>', {
|
|
159
|
-
class:
|
|
160
|
-
type:
|
|
160
|
+
class: 'property-ev',
|
|
161
|
+
type: 'checkbox',
|
|
161
162
|
checked: props.ev
|
|
162
163
|
}).appendTo(evRow)
|
|
163
164
|
|
|
164
|
-
const descriptionRow = $('<div/>', {class:
|
|
165
|
+
const descriptionRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
165
166
|
$('<label/>', {
|
|
166
|
-
class:
|
|
167
|
-
htmlFor:
|
|
167
|
+
class: 'form-row',
|
|
168
|
+
htmlFor: 'property-description'
|
|
168
169
|
}).text('Description').appendTo(descriptionRow)
|
|
169
170
|
$('<input/>', {
|
|
170
|
-
class:
|
|
171
|
+
class: 'property-description',
|
|
171
172
|
type: 'text'
|
|
172
173
|
}).appendTo(descriptionRow).val(props.description)
|
|
173
174
|
|
|
174
|
-
const minValueRow = $('<div/>', {class:
|
|
175
|
+
const minValueRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
175
176
|
$('<label/>', {
|
|
176
|
-
class:
|
|
177
|
-
htmlFor:
|
|
177
|
+
class: 'form-row',
|
|
178
|
+
htmlFor: 'property-minValue'
|
|
178
179
|
}).text('Minimum Value').appendTo(minValueRow)
|
|
179
180
|
$('<input/>', {
|
|
180
|
-
class:
|
|
181
|
+
class: 'property-minValue',
|
|
181
182
|
type: 'number'
|
|
182
183
|
}).appendTo(minValueRow).val(props.minValue)
|
|
183
184
|
|
|
184
|
-
const maxValueRow = $('<div/>', {class:
|
|
185
|
+
const maxValueRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
185
186
|
$('<label/>', {
|
|
186
|
-
class:
|
|
187
|
-
htmlFor:
|
|
187
|
+
class: 'form-row',
|
|
188
|
+
htmlFor: 'property-maxValue'
|
|
188
189
|
}).text('Maximum Value').appendTo(maxValueRow)
|
|
189
190
|
$('<input/>', {
|
|
190
|
-
class:
|
|
191
|
+
class: 'property-maxValue',
|
|
191
192
|
type: 'number'
|
|
192
193
|
}).appendTo(maxValueRow).val(props.maxValue)
|
|
193
194
|
|
|
194
|
-
const minStepRow = $('<div/>', {class:
|
|
195
|
+
const minStepRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
195
196
|
$('<label/>', {
|
|
196
|
-
class:
|
|
197
|
-
htmlFor:
|
|
197
|
+
class: 'form-row',
|
|
198
|
+
htmlFor: 'property-minStep'
|
|
198
199
|
}).text('Minimum Step').appendTo(minStepRow)
|
|
199
200
|
$('<input/>', {
|
|
200
|
-
class:
|
|
201
|
+
class: 'property-minStep',
|
|
201
202
|
type: 'number'
|
|
202
203
|
}).appendTo(minStepRow).val(props.minStep)
|
|
203
204
|
|
|
204
|
-
const maxLenRow = $('<div/>', {class:
|
|
205
|
+
const maxLenRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
205
206
|
$('<label/>', {
|
|
206
|
-
class:
|
|
207
|
-
htmlFor:
|
|
207
|
+
class: 'form-row',
|
|
208
|
+
htmlFor: 'property-maxLen'
|
|
208
209
|
}).text('Maximum Length').appendTo(maxLenRow)
|
|
209
210
|
$('<input/>', {
|
|
210
|
-
class:
|
|
211
|
+
class: 'property-maxLen',
|
|
211
212
|
type: 'number'
|
|
212
213
|
}).appendTo(maxLenRow).val(props.maxLen)
|
|
213
214
|
|
|
214
|
-
const maxDataLenRow = $('<div/>', {class:
|
|
215
|
+
const maxDataLenRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
215
216
|
$('<label/>', {
|
|
216
|
-
class:
|
|
217
|
-
htmlFor:
|
|
217
|
+
class: 'form-row',
|
|
218
|
+
htmlFor: 'property-maxDataLen'
|
|
218
219
|
}).text('Maximum Data Length').appendTo(maxDataLenRow)
|
|
219
220
|
$('<input/>', {
|
|
220
|
-
class:
|
|
221
|
+
class: 'property-maxDataLen',
|
|
221
222
|
type: 'number'
|
|
222
223
|
}).appendTo(maxDataLenRow).val(props.maxDataLen)
|
|
223
224
|
|
|
224
|
-
const validValuesRow = $('<div/>', {class:
|
|
225
|
+
const validValuesRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
225
226
|
$('<label/>', {
|
|
226
|
-
class:
|
|
227
|
-
htmlFor:
|
|
227
|
+
class: 'form-row',
|
|
228
|
+
htmlFor: 'property-validValues'
|
|
228
229
|
}).text('Valid Values').appendTo(validValuesRow)
|
|
229
230
|
$('<input/>', {
|
|
230
|
-
class:
|
|
231
|
+
class: 'property-validValues',
|
|
231
232
|
type: 'text'
|
|
232
233
|
}).appendTo(validValuesRow).val(props.validValues)
|
|
233
234
|
|
|
234
|
-
const validValueRangesRow = $('<div/>', {class:
|
|
235
|
+
const validValueRangesRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
235
236
|
const validValueRangesLabel = $('<label/>', {
|
|
236
|
-
class:
|
|
237
|
-
htmlFor:
|
|
237
|
+
class: 'form-row property-validValueRanges-label',
|
|
238
|
+
htmlFor: 'property-validValueRanges'
|
|
238
239
|
}).text('Valid Value Ranges: ').appendTo(validValueRangesRow)
|
|
239
240
|
const validValueRangesSlider = $('<div/>', {
|
|
240
|
-
class:
|
|
241
|
+
class: 'property-validValueRanges',
|
|
241
242
|
type: 'text'
|
|
242
243
|
}).appendTo(validValueRangesRow)
|
|
243
244
|
|
|
@@ -247,19 +248,19 @@
|
|
|
247
248
|
max: 500,
|
|
248
249
|
values: props.validValueRanges,
|
|
249
250
|
slide: function (event, ui) {
|
|
250
|
-
validValueRangesLabel.text(
|
|
251
|
+
validValueRangesLabel.text('Valid Value Ranges: [' + ui.values[0] + ', ' + ui.values[1] + ']')
|
|
251
252
|
}
|
|
252
|
-
})
|
|
253
|
-
validValueRangesLabel.text(
|
|
253
|
+
})
|
|
254
|
+
validValueRangesLabel.text('Valid Value Ranges: [' + validValueRangesSlider.slider('values', 0) + ', ' + validValueRangesSlider.slider('values', 1) + ']')
|
|
254
255
|
|
|
255
|
-
const adminOnlyAccessRow = $('<div/>', {class:
|
|
256
|
+
const adminOnlyAccessRow = $('<div/>', {class: 'form-row'}).appendTo(row3_properties)
|
|
256
257
|
$('<label/>', {
|
|
257
|
-
class:
|
|
258
|
-
htmlFor:
|
|
258
|
+
class: 'form-row',
|
|
259
|
+
htmlFor: 'property-adminOnlyAccess'
|
|
259
260
|
}).text('Admin Only Access').appendTo(adminOnlyAccessRow)
|
|
260
261
|
const adminOnlyAccessSelect = $('<select/>', {
|
|
261
|
-
class:
|
|
262
|
-
multiple:
|
|
262
|
+
class: 'property-adminOnlyAccess',
|
|
263
|
+
multiple: 'multiple'
|
|
263
264
|
}).appendTo(adminOnlyAccessRow)
|
|
264
265
|
$('<option/>').val(0).text('READ').appendTo(adminOnlyAccessSelect)
|
|
265
266
|
$('<option/>').val(1).text('WRITE').appendTo(adminOnlyAccessSelect)
|
|
@@ -269,30 +270,30 @@
|
|
|
269
270
|
row3_properties_accordion.accordion({
|
|
270
271
|
collapsible: true,
|
|
271
272
|
active: 'UUID' in opt ? false : 0,
|
|
272
|
-
heightStyle:
|
|
273
|
-
})
|
|
273
|
+
heightStyle: 'content'
|
|
274
|
+
})
|
|
274
275
|
|
|
275
|
-
container[0].appendChild(fragment)
|
|
276
|
+
container[0].appendChild(fragment)
|
|
276
277
|
},
|
|
277
278
|
removable: true,
|
|
278
279
|
sortable: true
|
|
279
|
-
})
|
|
280
|
+
})
|
|
280
281
|
|
|
281
282
|
for (let i = 0; i < config.customCharacteristics.length; i++) {
|
|
282
|
-
const customCharacteristic = config.customCharacteristics[i]
|
|
283
|
-
$(
|
|
283
|
+
const customCharacteristic = config.customCharacteristics[i]
|
|
284
|
+
$('#node-input-customCharacteristics-container').editableList('addItem', customCharacteristic)
|
|
284
285
|
}
|
|
285
286
|
},
|
|
286
287
|
oneditresize: function (size) {
|
|
287
|
-
const rows = $(
|
|
288
|
-
let height = size.height
|
|
288
|
+
const rows = $('#dialog-form>div:not(.node-input-customCharacteristics-container-row)')
|
|
289
|
+
let height = size.height
|
|
289
290
|
for (let i = 0; i < rows.length; i++) {
|
|
290
|
-
height -= $(rows[i]).outerHeight(true)
|
|
291
|
+
height -= $(rows[i]).outerHeight(true)
|
|
291
292
|
}
|
|
292
|
-
const editorRow = $(
|
|
293
|
-
height -= (parseInt(editorRow.css(
|
|
294
|
-
height += 16
|
|
295
|
-
$(
|
|
293
|
+
const editorRow = $('#dialog-form>div.node-input-customCharacteristics-container-row')
|
|
294
|
+
height -= (parseInt(editorRow.css('marginTop')) + parseInt(editorRow.css('marginBottom')))
|
|
295
|
+
height += 16
|
|
296
|
+
$('#node-input-customCharacteristics-container').editableList('height', height)
|
|
296
297
|
}
|
|
297
298
|
})
|
|
298
299
|
}
|
|
@@ -352,27 +353,27 @@
|
|
|
352
353
|
|
|
353
354
|
const saveCustomCharacteristics = function (self) {
|
|
354
355
|
const customCharacteristics = []
|
|
355
|
-
const items = $(
|
|
356
|
+
const items = $('#node-input-customCharacteristics-container').editableList('items')
|
|
356
357
|
|
|
357
358
|
items.each(function () {
|
|
358
|
-
const item = $(this)
|
|
359
|
-
const name = item.find(
|
|
360
|
-
const UUID = item.find(
|
|
361
|
-
const format = item.find(
|
|
362
|
-
const unit = item.find(
|
|
363
|
-
const perms = item.find(
|
|
364
|
-
const ev = item.find(
|
|
365
|
-
const description = item.find(
|
|
366
|
-
const minValue = item.find(
|
|
367
|
-
const maxValue = item.find(
|
|
368
|
-
const minStep = item.find(
|
|
369
|
-
const maxLen = item.find(
|
|
370
|
-
const maxDataLen = item.find(
|
|
371
|
-
const validValues = item.find(
|
|
372
|
-
const validValueRangesMin = item.find(
|
|
373
|
-
const validValueRangesMax = item.find(
|
|
359
|
+
const item = $(this)
|
|
360
|
+
const name = item.find('.property-name').val()
|
|
361
|
+
const UUID = item.find('.property-uuid').val()
|
|
362
|
+
const format = item.find('.property-format').val()
|
|
363
|
+
const unit = item.find('.property-unit').val()
|
|
364
|
+
const perms = item.find('.property-perms').val()
|
|
365
|
+
const ev = item.find('.property-ev').prop('checked')
|
|
366
|
+
const description = item.find('.property-description').val()
|
|
367
|
+
const minValue = item.find('.property-minValue').val()
|
|
368
|
+
const maxValue = item.find('.property-maxValue').val()
|
|
369
|
+
const minStep = item.find('.property-minStep').val()
|
|
370
|
+
const maxLen = item.find('.property-maxLen').val()
|
|
371
|
+
const maxDataLen = item.find('.property-maxDataLen').val()
|
|
372
|
+
const validValues = item.find('.property-validValues').val()
|
|
373
|
+
const validValueRangesMin = item.find('.property-validValueRanges').slider('values', 0)
|
|
374
|
+
const validValueRangesMax = item.find('.property-validValueRanges').slider('values', 1)
|
|
374
375
|
const validValueRanges = validValueRangesMin && validValueRangesMax ? [validValueRangesMin, validValueRangesMax] : undefined
|
|
375
|
-
const adminOnlyAccess = item.find(
|
|
376
|
+
const adminOnlyAccess = item.find('.property-adminOnlyAccess').val()
|
|
376
377
|
customCharacteristics.push({
|
|
377
378
|
name,
|
|
378
379
|
UUID,
|
|
@@ -389,8 +390,8 @@
|
|
|
389
390
|
validValues,
|
|
390
391
|
validValueRanges,
|
|
391
392
|
adminOnlyAccess
|
|
392
|
-
})
|
|
393
|
-
})
|
|
393
|
+
})
|
|
394
|
+
})
|
|
394
395
|
|
|
395
396
|
config.customCharacteristics = customCharacteristics
|
|
396
397
|
|
|
@@ -399,19 +400,19 @@
|
|
|
399
400
|
url: 'nrchkb/config',
|
|
400
401
|
dataType: 'json',
|
|
401
402
|
data: {customCharacteristics}
|
|
402
|
-
})
|
|
403
|
+
})
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
const uuidv4 = function () {
|
|
406
407
|
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
|
|
407
408
|
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
408
|
-
)
|
|
409
|
+
)
|
|
409
410
|
}
|
|
410
411
|
|
|
411
412
|
const getRandomIntInclusive = function (min, max) {
|
|
412
|
-
min = Math.ceil(min)
|
|
413
|
-
max = Math.floor(max)
|
|
414
|
-
return Math.floor(Math.random() * (max - min + 1) + min)
|
|
413
|
+
min = Math.ceil(min)
|
|
414
|
+
max = Math.floor(max)
|
|
415
|
+
return Math.floor(Math.random() * (max - min + 1) + min)
|
|
415
416
|
}
|
|
416
417
|
|
|
417
418
|
const forbiddenPinCodes = [
|
|
@@ -430,7 +431,7 @@
|
|
|
430
431
|
]
|
|
431
432
|
|
|
432
433
|
const generatePinCode = function () {
|
|
433
|
-
const [a, b, c, d, e, f, g, h] = Array.from({length: 9}, () => getRandomIntInclusive(0, 9))
|
|
434
|
+
const [a, b, c, d, e, f, g, h] = Array.from({length: 9}, () => getRandomIntInclusive(0, 9))
|
|
434
435
|
|
|
435
436
|
if (forbiddenPinCodes.includes(`${a}${b}${c}${d}${e}${f}${g}${h}`)) {
|
|
436
437
|
return generatePinCode()
|
|
@@ -440,11 +441,15 @@
|
|
|
440
441
|
}
|
|
441
442
|
|
|
442
443
|
const validatePinCode = function (value) {
|
|
443
|
-
if (!
|
|
444
|
+
if (!value) {
|
|
445
|
+
return false
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (!RED.validators.regex(/([0-9]{3}-[0-9]{2}-[0-9]{3}|[0-9]{4}-[0-9]{4})/)(value)) {
|
|
444
449
|
return false
|
|
445
450
|
}
|
|
446
451
|
|
|
447
|
-
return !forbiddenPinCodes.includes(value.replaceAll(
|
|
452
|
+
return !forbiddenPinCodes.includes(value.replaceAll('-', ''))
|
|
448
453
|
}
|
|
449
454
|
</script>
|
|
450
455
|
|
|
@@ -63,9 +63,14 @@
|
|
|
63
63
|
<label for="node-config-input-allowMessagePassthrough" style="width: 70%;"> <i class="fa fa-step-forward"></i> Allow Message Passthrough</label>
|
|
64
64
|
</div>
|
|
65
65
|
<hr>
|
|
66
|
+
<div class="form-row">
|
|
67
|
+
<label for="node-config-input-bind"><i class="fa fa-filter"></i> Bind</label>
|
|
68
|
+
<input type="text" id="node-config-input-bind" placeholder="::">
|
|
69
|
+
<input type="hidden" id="node-config-input-bindType">
|
|
70
|
+
</div>
|
|
66
71
|
<div class="form-row">
|
|
67
72
|
<input type="checkbox" id="node-config-input-customMdnsConfig" style="display: inline-block; width: auto; vertical-align: top;">
|
|
68
|
-
<label for="node-config-input-customMdnsConfig" style="width: 70%;"> <i class="fa fa-filter"></i> Custom MDNS Configuration</label>
|
|
73
|
+
<label for="node-config-input-customMdnsConfig" style="width: 70%;"> <i class="fa fa-filter"></i> Custom MDNS Configuration (DEPRECATED, use Bind)</label>
|
|
69
74
|
</div>
|
|
70
75
|
<div id="mdns-configuration" style="display: none;">
|
|
71
76
|
<div class="form-row">
|
|
@@ -115,7 +120,60 @@
|
|
|
115
120
|
<li><strong>Software Revision</strong>: Should be a version number string in the form of <em>MAJOR.MINOR.REVISION</em> e.g. <em>1.2.0</em>. Other types of strings are ignored and won't be displayed.</li>
|
|
116
121
|
<li><strong>Name</strong>: If you intend to simulate a rocket, then why don't you call it <em>Rocket</em>. Name should be maximum 64 chars long and not contain <pre>.</pre></li>
|
|
117
122
|
<li><strong>Allow Message Passthrough</strong>: If you allow then message from node input will be sent to node output.</li>
|
|
118
|
-
<li><strong>
|
|
123
|
+
<li><strong>Bind</strong>: Defines the host where the HAP server will be bound to. </li>
|
|
124
|
+
<ul>
|
|
125
|
+
<li>
|
|
126
|
+
Defines the host where the HAP server will be bound to.
|
|
127
|
+
When undefined the HAP server will bind to all available interfaces
|
|
128
|
+
(see https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback).
|
|
129
|
+
|
|
130
|
+
This property accepts a mixture of IPAddresses and network interface names.
|
|
131
|
+
Depending on the mixture of supplied addresses/names hap-nodejs will bind differently.
|
|
132
|
+
|
|
133
|
+
It is advised to not just bind to a specific address, but specifying the interface name
|
|
134
|
+
in oder to bind on all address records (and ip version) available.
|
|
135
|
+
|
|
136
|
+
HAP-NodeJS (or the underlying ciao library) will not report about misspelled interface names,
|
|
137
|
+
as it could be that the interface is currently just down and will come up later.
|
|
138
|
+
|
|
139
|
+
Here are a few examples:
|
|
140
|
+
- bind: "::"
|
|
141
|
+
Pretty much identical to not specifying anything, as most systems (with ipv6 support)
|
|
142
|
+
will default to the unspecified ipv6 address (with dual stack support).
|
|
143
|
+
|
|
144
|
+
- bind: "0.0.0.0"
|
|
145
|
+
Binding TCP socket to the unspecified ipv4 address.
|
|
146
|
+
The mdns advertisement will exclude any ipv6 address records.
|
|
147
|
+
|
|
148
|
+
- bind: ["en0", "lo0"]
|
|
149
|
+
The mdns advertising will advertise all records of the en0 and loopback interface (if available) and
|
|
150
|
+
will also react to address changes on those interfaces.
|
|
151
|
+
In order for the HAP server to accept all those address records (which may contain ipv6 records)
|
|
152
|
+
it will bind on the unspecified ipv6 address "::" (assuming dual stack is supported).
|
|
153
|
+
|
|
154
|
+
- bind: ["en0", "lo0", "0.0.0.0"]
|
|
155
|
+
Same as above, only that the HAP server will bind on the unspecified ipv4 address "0.0.0.0".
|
|
156
|
+
The mdns advertisement will not advertise any ipv6 records.
|
|
157
|
+
|
|
158
|
+
- bind: "169.254.104.90"
|
|
159
|
+
This will bind the HAP server to the address 0.0.0.0.
|
|
160
|
+
The mdns advertisement will only advertise the A record 169.254.104.90.
|
|
161
|
+
If the given network interface of that address encounters an ip address change (to a different address),
|
|
162
|
+
the mdns advertisement will result in not advertising an address at all.
|
|
163
|
+
So it is advised to specify an interface name instead of a specific address.
|
|
164
|
+
This is identical with ipv6 addresses.
|
|
165
|
+
|
|
166
|
+
- bind: ["169.254.104.90", "192.168.1.4"]
|
|
167
|
+
As the HAP TCP socket can only bind to a single address, when specifying multiple ip addresses
|
|
168
|
+
the HAP server will bind to the unspecified ip address (0.0.0.0 if only ipv4 addresses are supplied,
|
|
169
|
+
:: if a mixture or only ipv6 addresses are supplied).
|
|
170
|
+
The mdns advertisement will only advertise the specified ip addresses.
|
|
171
|
+
If the given network interface of that address encounters an ip address change (to different addresses),
|
|
172
|
+
the mdns advertisement will result in not advertising an address at all.
|
|
173
|
+
So it is advised to specify an interface name instead of a specific address.
|
|
174
|
+
</li>
|
|
175
|
+
</ul>
|
|
176
|
+
<li><strong>Custom MDNS Configuration (DEPRECATED, use Bind)</strong>: Check if you would like to use custom mdns configuration.</li>
|
|
119
177
|
<ul>
|
|
120
178
|
<li><strong>Multicast</strong>: Use udp multicasting. Optional. Default true.</li>
|
|
121
179
|
<li><strong>Multicast Interface IP:</strong>: Explicitly specify a network interface. Optional. Defaults to all.</li>
|
|
@@ -194,41 +252,46 @@
|
|
|
194
252
|
required: false,
|
|
195
253
|
validate: versionValidator,
|
|
196
254
|
},
|
|
255
|
+
bind: {
|
|
256
|
+
value: undefined,
|
|
257
|
+
required: false,
|
|
258
|
+
},
|
|
259
|
+
bindType: {
|
|
260
|
+
value: undefined,
|
|
261
|
+
required: false,
|
|
262
|
+
},
|
|
197
263
|
customMdnsConfig: {
|
|
198
264
|
value: false,
|
|
199
265
|
required: false,
|
|
266
|
+
validate: (value) => !value
|
|
200
267
|
},
|
|
201
268
|
mdnsMulticast: {
|
|
202
269
|
value: true,
|
|
203
|
-
required: false
|
|
270
|
+
required: false
|
|
204
271
|
},
|
|
205
272
|
mdnsInterface: {
|
|
206
|
-
required: false
|
|
273
|
+
required: false
|
|
207
274
|
},
|
|
208
275
|
mdnsPort: {
|
|
209
|
-
required: false
|
|
210
|
-
validate: function (value) {
|
|
211
|
-
if (value) return RED.validators.port(value)
|
|
212
|
-
else return true
|
|
213
|
-
},
|
|
276
|
+
required: false
|
|
214
277
|
},
|
|
215
278
|
mdnsIp: {
|
|
216
|
-
required: false
|
|
279
|
+
required: false
|
|
217
280
|
},
|
|
218
281
|
mdnsTtl: {
|
|
219
|
-
required: false
|
|
282
|
+
required: false
|
|
220
283
|
},
|
|
221
284
|
mdnsLoopback: {
|
|
222
285
|
value: true,
|
|
223
|
-
required: false
|
|
286
|
+
required: false
|
|
224
287
|
},
|
|
225
288
|
mdnsReuseAddr: {
|
|
226
289
|
value: true,
|
|
227
|
-
required: false
|
|
290
|
+
required: false
|
|
228
291
|
},
|
|
229
292
|
allowMessagePassthrough: {
|
|
230
293
|
value: true,
|
|
231
|
-
required: true
|
|
294
|
+
required: true
|
|
232
295
|
},
|
|
233
296
|
},
|
|
234
297
|
label: function () {
|
|
@@ -242,7 +305,7 @@
|
|
|
242
305
|
|
|
243
306
|
if (!validatePinCode(node.pinCode)) {
|
|
244
307
|
node.pinCode = generatePinCode()
|
|
245
|
-
$(
|
|
308
|
+
$('#node-config-input-pinCode').val(this.pinCode)
|
|
246
309
|
}
|
|
247
310
|
|
|
248
311
|
$('#node-config-input-allowMessagePassthrough').prop(
|
|
@@ -265,22 +328,28 @@
|
|
|
265
328
|
})
|
|
266
329
|
.change()
|
|
267
330
|
|
|
268
|
-
const selectCategoryName = $(
|
|
331
|
+
const selectCategoryName = $('#node-config-input-accessoryCategory')
|
|
269
332
|
|
|
270
333
|
Object.entries(accessoryCategories).forEach(([key, value]) => {
|
|
271
334
|
selectCategoryName.append(
|
|
272
|
-
$(
|
|
335
|
+
$('<option></option>')
|
|
273
336
|
.val(key)
|
|
274
337
|
.text(value)
|
|
275
|
-
)
|
|
338
|
+
)
|
|
276
339
|
})
|
|
277
340
|
|
|
278
341
|
selectCategoryName
|
|
279
|
-
.find(
|
|
342
|
+
.find('option')
|
|
280
343
|
.filter(function () {
|
|
281
|
-
return $(this).val() === node.accessoryCategory
|
|
344
|
+
return $(this).val() === node.accessoryCategory
|
|
282
345
|
})
|
|
283
|
-
.attr(
|
|
346
|
+
.attr('selected', 'true')
|
|
347
|
+
|
|
348
|
+
$('#node-config-input-bind').typedInput({
|
|
349
|
+
typeField: '#node-config-input-bindType',
|
|
350
|
+
default: 'str',
|
|
351
|
+
types: ['json', 'str']
|
|
352
|
+
})
|
|
284
353
|
},
|
|
285
354
|
})
|
|
286
355
|
</script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-homekit-bridged",
|
|
3
|
-
"version": "1.7.0-dev.
|
|
3
|
+
"version": "1.7.0-dev.9",
|
|
4
4
|
"description": "Node-RED nodes to simulate Apple HomeKit devices.",
|
|
5
5
|
"main": "build/nodes/nrchkb.js",
|
|
6
6
|
"scripts": {
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"homepage": "https://github.com/NRCHKB/node-red-contrib-homekit-bridged#readme",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@nrchkb/logger": "^3.0.0",
|
|
46
|
-
"hap-nodejs": "0.12.
|
|
46
|
+
"hap-nodejs": "0.12.3-beta.7",
|
|
47
47
|
"node-persist": "^4.0.1",
|
|
48
48
|
"semver": "^7.6.2",
|
|
49
49
|
"uuid": "^10.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@homebridge/ciao": "^1.2.0",
|
|
53
|
-
"@node-red/registry": "^4.0.
|
|
53
|
+
"@node-red/registry": "^4.0.1",
|
|
54
54
|
"@types/mocha": "^10.0.7",
|
|
55
55
|
"@types/node": "^18",
|
|
56
56
|
"@types/node-persist": "^3.1.8",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"eslint-plugin-prettier": "^5.1.3",
|
|
68
68
|
"eslint-plugin-simple-import-sort": "^12.1.0",
|
|
69
69
|
"husky": "^9.0.11",
|
|
70
|
-
"mocha": "^10.5.
|
|
71
|
-
"node-red": "^4.0.
|
|
70
|
+
"mocha": "^10.5.2",
|
|
71
|
+
"node-red": "^4.0.1",
|
|
72
72
|
"node-red-node-test-helper": "^0.3.4",
|
|
73
73
|
"prettier": "^3.3.2",
|
|
74
74
|
"ts-node": "^10.9.2",
|