node-red-contrib-homekit-bridged
Version:
Node-RED nodes to simulate Apple HomeKit devices.
356 lines (338 loc) • 17 kB
HTML
<script data-template-name="homekit-standalone" type="text/x-red">
<div class="form-row">
<label for="node-config-input-accessoryCategory">
<i class="fa fa-cog"></i>
Accessory Category</label>
<select id="node-config-input-accessoryCategory">
<option value="">Choose...</option>
</select>
</div>
<div class="form-row">
<label for="node-config-input-pinCode"><i class="fa fa-lock"></i> Pin Code</label>
<input type="text" id="node-config-input-pinCode" placeholder="xxxx-xxxx">
</div>
<div class="form-row">
<label for="node-config-input-port"><i class="fa fa-plug"></i> Port</label>
<input type="text" id="node-config-input-port" placeholder="Leave blank to auto assign">
</div>
<div class="form-row">
<label for="node-config-input-advertiser"><i class="fa fa-globe"></i> Advertiser</label>
<select id="node-config-input-advertiser">
<option value="bonjour-hap" selected="selected">BONJOUR</option>
<option value="ciao">CIAO</option>
<option value="avahi">AVAHI</option>
<option value="resolved">RESOLVED</option>
</select>
</div>
<div class="form-row">
<label> </label>
<input type="checkbox" id="node-config-input-allowInsecureRequest" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-allowInsecureRequest" style="width: 70%;"> <i class="fa fa-shield"></i> Allow Insecure Request</label>
</div>
<div class="form-row">
<label for="node-config-input-manufacturer"><i class="fa fa-wrench"></i> Manufacturer</label>
<input type="text" id="node-config-input-manufacturer" placeholder="Manufacturer">
</div>
<div class="form-row">
<label for="node-config-input-serialNo"><i class="fa fa-wrench"></i> Serial Number</label>
<input type="text" id="node-config-input-serialNo" placeholder="Serial Number">
</div>
<div class="form-row">
<label for="node-config-input-model"><i class="fa fa-wrench"></i> Model</label>
<input type="text" id="node-config-input-model" placeholder="Model">
</div>
<div class="form-row">
<label for="node-config-input-firmwareRev"><i class="fa fa-wrench"></i> Firmware Revision</label>
<input type="text" id="node-config-input-firmwareRev" placeholder="Firmware Revision">
</div>
<div class="form-row">
<label for="node-config-input-hardwareRev"><i class="fa fa-wrench"></i> Hardware Revision</label>
<input type="text" id="node-config-input-hardwareRev" placeholder="Hardware Revision">
</div>
<div class="form-row">
<label for="node-config-input-softwareRev"><i class="fa fa-wrench"></i> Software Revision</label>
<input type="text" id="node-config-input-softwareRev" placeholder="Software Revision">
</div>
<div class="form-row">
<label for="node-config-input-bridgeName"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-config-input-bridgeName" placeholder="Name">
</div>
<hr>
<div class="form-row">
<input type="checkbox" id="node-config-input-allowMessagePassthrough" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-allowMessagePassthrough" style="width: 70%;"> <i class="fa fa-step-forward"></i> Allow Message Passthrough</label>
</div>
<hr>
<div class="form-row">
<label for="node-config-input-bind"><i class="fa fa-filter"></i> Bind</label>
<input type="text" id="node-config-input-bind" placeholder="::">
<input type="hidden" id="node-config-input-bindType">
</div>
<div class="form-row">
<input type="checkbox" id="node-config-input-customMdnsConfig" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-customMdnsConfig" style="width: 70%;"> <i class="fa fa-filter"></i> Custom MDNS Configuration (DEPRECATED, use Bind)</label>
</div>
<div id="mdns-configuration" style="display: none;">
<div class="form-row">
<label for="node-config-input-mdnsMulticast"><i class="fa fa-ellipsis-v"></i> Multicast</label>
<input type="checkbox" id="node-config-input-mdnsMulticast" checked>
</div>
<div class="form-row">
<label for="node-config-input-mdnsInterface"><i class="fa fa-location-arrow"></i> Multicast Interface IP</label>
<input type="text" id="node-config-input-mdnsInterface" placeholder="">
</div>
<div class="form-row">
<label for="node-config-input-mdnsPort"><i class="fa fa-location-arrow"></i> Port</label>
<input type="text" id="node-config-input-mdnsPort" placeholder="">
</div>
<div class="form-row">
<label for="node-config-input-mdnsIp"><i class="fa fa-location-arrow"></i> Multicast Address IP</label>
<input type="text" id="node-config-input-mdnsIp" placeholder="">
</div>
<div class="form-row">
<label for="node-config-input-mdnsTtl"><i class="fa fa-repeat"></i> TTL</label>
<input type="text" id="node-config-input-mdnsTtl" placeholder="255">
</div>
<div class="form-row">
<label for="node-config-input-mdnsLoopback"><i class="fa fa-undo"></i> Loopback</label>
<input type="checkbox" id="node-config-input-mdnsLoopback" checked>
</div>
<div class="form-row">
<label for="node-config-input-mdnsReuseAddr"><i class="fa fa-location-arrow"></i> Reuse Address</label>
<input type="checkbox" id="node-config-input-mdnsReuseAddr" checked>
</div>
</div>
<hr>
</script>
<script data-help-name="homekit-standalone" type="text/x-red">
<h3 id="toc_4">Bridge</h3>
<p>The Bridge node is a configuration node, specifying the <em>bridge</em> that iOS sees, i.e. the device that is manually being added by the user. All accessories behind a bridge node are then automatically added by iOS.
</p>
<ul>
<li><strong>Accessory Category</strong>: What kind of category is this Accessory, default <em>OTHER</em></li>
<li><strong>Pin Code</strong>: Specify the Pin for the pairing process.</li>
<li><strong>Port</strong>: If you are behind a Firewall, you may want to specify a port. Cannot be 1880 as it is reserved for node-red. Otherwise, leave empty.</li>
<li><strong>Advertiser</strong>: Which MDNS advertiser to use <em>ciao</em> (new, improved but not yet proved) or (good old) <em>bonjour</em> or experimental <em>avahi</em> and <em>resolved</em>. Default <em>bonjour</em>.</li>
<li><strong>Allow Insecure Request</strong>: Should we allow insecure request? Default false.</li>
<li><strong>Manufacturer, Model, Serial Number</strong>: Can be anything you want.</li>
<li><strong>Firmware 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>
<li><strong>Hardware 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>
<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>
<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>
<li><strong>Allow Message Passthrough</strong>: If you allow then message from node input will be sent to node output.</li>
<li><strong>Bind</strong>: Defines the host where the HAP server will be bound to. </li>
<ul>
<li>
Defines the host where the HAP server will be bound to.
When undefined the HAP server will bind to all available interfaces
(see https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback).
This property accepts a mixture of IPAddresses and network interface names.
Depending on the mixture of supplied addresses/names hap-nodejs will bind differently.
It is advised to not just bind to a specific address, but specifying the interface name
in oder to bind on all address records (and ip version) available.
HAP-NodeJS (or the underlying ciao library) will not report about misspelled interface names,
as it could be that the interface is currently just down and will come up later.
Here are a few examples:
- bind: "::"
Pretty much identical to not specifying anything, as most systems (with ipv6 support)
will default to the unspecified ipv6 address (with dual stack support).
- bind: "0.0.0.0"
Binding TCP socket to the unspecified ipv4 address.
The mdns advertisement will exclude any ipv6 address records.
- bind: ["en0", "lo0"]
The mdns advertising will advertise all records of the en0 and loopback interface (if available) and
will also react to address changes on those interfaces.
In order for the HAP server to accept all those address records (which may contain ipv6 records)
it will bind on the unspecified ipv6 address "::" (assuming dual stack is supported).
- bind: ["en0", "lo0", "0.0.0.0"]
Same as above, only that the HAP server will bind on the unspecified ipv4 address "0.0.0.0".
The mdns advertisement will not advertise any ipv6 records.
- bind: "169.254.104.90"
This will bind the HAP server to the address 0.0.0.0.
The mdns advertisement will only advertise the A record 169.254.104.90.
If the given network interface of that address encounters an ip address change (to a different address),
the mdns advertisement will result in not advertising an address at all.
So it is advised to specify an interface name instead of a specific address.
This is identical with ipv6 addresses.
- bind: ["169.254.104.90", "192.168.1.4"]
As the HAP TCP socket can only bind to a single address, when specifying multiple ip addresses
the HAP server will bind to the unspecified ip address (0.0.0.0 if only ipv4 addresses are supplied,
:: if a mixture or only ipv6 addresses are supplied).
The mdns advertisement will only advertise the specified ip addresses.
If the given network interface of that address encounters an ip address change (to different addresses),
the mdns advertisement will result in not advertising an address at all.
So it is advised to specify an interface name instead of a specific address.
</li>
</ul>
<li><strong>Custom MDNS Configuration (DEPRECATED, use Bind)</strong>: Check if you would like to use custom mdns configuration.</li>
<ul>
<li><strong>Multicast</strong>: Use udp multicasting. Optional. Default true.</li>
<li><strong>Multicast Interface IP:</strong>: Explicitly specify a network interface. Optional. Defaults to all.</li>
<li><strong>Port</strong>: Set the udp port. Cannot be 1880 as it is reserved for node-red. Optional. Default 5353.</li>
<li><strong>Multicast Address IP</strong>: Set the udp ip. Optional. </li>
<li><strong>TTL</strong>: Set the multicast ttl. Optional. </li>
<li><strong>Loopback</strong>: Receive your own packets. Optional. Default true.</li>
<li><strong>Reuse Address</strong>: Set the reuseAddr option when creating the socket. Optional. Default true.</li>
</ul>
</ul>
</script>
<script type="text/javascript">
RED.nodes.registerType('homekit-standalone', {
category: 'config',
defaults: {
accessoryCategory: {
value: 'OTHER',
required: true
},
bridgeName: {
value: '',
required: true,
validate: hostNameValidator,
},
hostType: {
value: 1,
required: true,
},
pinCode: {
required: true,
validate: validatePinCode,
},
port: {
required: false,
validate: function (value) {
if (value) return RED.validators.port(value)
else return true
},
},
advertiser: {
value: 'bonjour-hap',
required: false,
validate: function (value) {
if (value) return value === 'bonjour-hap' || value === 'ciao' || value === 'avahi' || value === 'resolved'
else return true
},
},
allowInsecureRequest: {
value: false,
required: true,
},
manufacturer: {
value: 'NRCHKB',
required: true,
},
model: {
value: nrchkbVersion,
required: true,
},
serialNo: {
value: 'Default Serial Number',
required: true,
},
firmwareRev: {
value: nrchkbVersion,
required: false,
validate: versionValidator,
},
hardwareRev: {
value: nrchkbVersion,
required: false,
validate: versionValidator,
},
softwareRev: {
value: nrchkbVersion,
required: false,
validate: versionValidator,
},
bind: {
value: undefined,
required: false,
},
bindType: {
value: undefined,
required: false,
},
customMdnsConfig: {
value: false,
required: false,
validate: (value) => !value
},
mdnsMulticast: {
value: true,
required: false
},
mdnsInterface: {
required: false
},
mdnsPort: {
required: false
},
mdnsIp: {
required: false
},
mdnsTtl: {
required: false
},
mdnsLoopback: {
value: true,
required: false
},
mdnsReuseAddr: {
value: true,
required: false
},
allowMessagePassthrough: {
value: true,
required: true
},
},
label: function () {
return this.bridgeName || 'Bridge'
},
labelStyle: function () {
return this.bridgeName ? 'node_label_italic' : ''
},
oneditprepare: function () {
const node = this
if (!validatePinCode(node.pinCode)) {
node.pinCode = generatePinCode()
$('#node-config-input-pinCode').val(this.pinCode)
}
$('#node-config-input-allowMessagePassthrough').prop(
'checked',
node.allowMessagePassthrough,
)
let customMdnsConfigCheckbox = $(
'#node-config-input-customMdnsConfig',
)
let mdnsConfiguration = $('#mdns-configuration')
customMdnsConfigCheckbox
.change(function () {
if (this.checked) {
mdnsConfiguration.fadeIn('fast')
} else {
mdnsConfiguration.fadeOut('fast')
}
})
.change()
const selectCategoryName = $('#node-config-input-accessoryCategory')
Object.entries(accessoryCategories).forEach(([key, value]) => {
selectCategoryName.append(
$('<option></option>')
.val(key)
.text(value)
)
})
selectCategoryName
.find('option')
.filter(function () {
return $(this).val() === node.accessoryCategory
})
.attr('selected', 'true')
$('#node-config-input-bind').typedInput({
typeField: '#node-config-input-bindType',
default: 'str',
types: ['json', 'str']
})
},
})
</script>