redmatic-homekit
Version:
HAP-Nodejs based Node-RED nodes to create HomeKit Accessories
416 lines (375 loc) • 16.5 kB
HTML
<script type="text/javascript">
RED.nodes.registerType('redmatic-homekit-homematic-garage', {
category: 'redmatic homekit',
defaults: {
bridgeConfig: {value: 'CC:22:3D:E3:CE:C7:51826', type: 'redmatic-homekit-bridge', required: true},
name: {value: ''},
ccuConfig: {value: 'localhost', type: 'ccu-connection', required: true},
ifaceActuator: {value: '', required: true},
channelActuator: {value: ''},
channelActuatorOpen: {value: ''},
channelActuatorClose: {value: ''},
channelActuatorType: {value: '1'},
ifaceSensor: {value: '', required: true},
channelSensorOpened: {value: ''},
channelSensorClosed: {value: ''},
channelSensorType: {value: 'c'},
onTime: {value: 0.4, required: true},
directionOpened: {value: 'true'},
directionClosed: {value: 'true'},
duration: {value: 15, required: true},
durationClose: {value: 15, required: true},
revertTime: {value: 0.5, required: true}
},
inputs: 1,
outputs: 1,
icon: 'homekit2.png',
color: '#E2D96E',
paletteLabel: 'garage',
align: 'left',
label() {
return this.name || 'garage';
},
labelStyle() {
return this.name ? 'node_label_italic' : '';
},
oneditprepare() {
const $nodeInputCcuConfig = $('#node-input-ccuConfig');
const $nodeInputIfaceActuator = $('#node-input-ifaceActuator');
const $nodeInputIfaceSensor = $('#node-input-ifaceSensor');
const $nodeInputChannelActuatorType = $('#node-input-channelActuatorType');
const $nodeInputChannelSensorType = $('#node-input-channelSensorType');
const $nodeInputChannelActuator = $('#node-input-channelActuator');
const $nodeInputChannelActuatorOpen = $('#node-input-channelActuatorOpen');
const $nodeInputChannelActuatorClose = $('#node-input-channelActuatorClose');
const $nodeInputChannelSensorOpened = $('#node-input-channelSensorOpened');
const $nodeInputChannelSensorClosed = $('#node-input-channelSensorClosed');
$nodeInputChannelActuator.autocomplete({
source: [],
close: () => {},
delay: 0,
minLength: 0
});
$nodeInputChannelActuator.on('focus', () => {
$nodeInputChannelActuator.autocomplete('search');
});
$nodeInputChannelActuatorOpen.autocomplete({
source: [],
close: () => {},
delay: 0,
minLength: 0
});
$nodeInputChannelActuatorOpen.on('focus', () => {
$nodeInputChannelActuatorOpen.autocomplete('search');
});
$nodeInputChannelActuatorClose.autocomplete({
source: [],
close: () => {},
delay: 0,
minLength: 0
});
$nodeInputChannelActuatorClose.on('focus', () => {
$nodeInputChannelActuatorClose.autocomplete('search');
});
$nodeInputChannelSensorClosed.autocomplete({
source: [],
close: () => {},
delay: 0,
minLength: 0
});
$nodeInputChannelSensorClosed.on('focus', () => {
$nodeInputChannelSensorClosed.autocomplete('search');
});
$nodeInputChannelSensorOpened.autocomplete({
source: [],
close: () => {},
delay: 0,
minLength: 0
});
$nodeInputChannelSensorOpened.on('focus', () => {
$nodeInputChannelSensorOpened.autocomplete('search');
});
$nodeInputChannelActuatorType.change(() => {
if ($nodeInputChannelActuatorType.val() === '1') {
$('.garage-actuator-2').hide();
$('.garage-actuator-1').show();
} else {
$('.garage-actuator-1').hide();
$('.garage-actuator-2').show();
}
});
$nodeInputChannelSensorType.change(() => {
if ($nodeInputChannelSensorType.val().includes('c')) {
$('.garage-sensor-c').show();
} else {
$('.garage-sensor-c').hide();
}
if ($nodeInputChannelSensorType.val().includes('o')) {
$('.garage-sensor-o').show();
} else {
$('.garage-sensor-o').hide();
}
});
let data;
this.loadIfaces = cb => {
console.log('loadIfaces()');
const nodeId = $nodeInputCcuConfig.val();
if (nodeId !== '_ADD_') {
const url = 'ccu?config=' + nodeId + '&type=ifaces';
$.getJSON(url, d => {
console.log(d);
$nodeInputIfaceActuator.html('');
$nodeInputIfaceSensor.html('');
Object.keys(d).forEach(i => {
if (i !== 'ReGaHSS' && i !== 'VirtualDevices') {
$nodeInputIfaceActuator.append('<option' + (d[i].enabled ? '' : ' disabled') + (i === this.ifaceActuator ? ' selected' : '') + '>' + i + '</option>');
$nodeInputIfaceSensor.append('<option' + (d[i].enabled ? '' : ' disabled') + (i === this.ifaceSensor ? ' selected' : '') + '>' + i + '</option>');
}
});
cb();
});
}
};
function paramsetName(iface, device, paramset) {
let cType = '';
let d;
if (device) {
if (device.PARENT) {
// channel
cType = device.TYPE;
d = data.metadata.devices[iface][device.PARENT];
} else {
// device
d = device;
}
return [iface, d.TYPE, d.FIRMWARE, d.VERSION, cType, paramset].join('/');
}
}
function autoCompleteActuator() {
const iface = $nodeInputIfaceActuator.val();
const arr = [];
Object.keys(data.metadata.devices[iface]).forEach(addr => {
if (addr.includes(':')) {
const psName = paramsetName(iface, data.metadata.devices[iface][addr]) + 'VALUES';
const ps = data.paramsetDescriptions[psName];
if (ps && ps.STATE && (ps.STATE.OPERATIONS & 2)) {
console.log(addr, data.channelNames[addr], ps.STATE);
let name = addr;
if (data.channelNames[addr]) {
name = name + ' ' + data.channelNames[addr];
}
arr.push(name);
}
}
});
$nodeInputChannelActuator.autocomplete('option', 'source', arr);
$nodeInputChannelActuatorOpen.autocomplete('option', 'source', arr);
$nodeInputChannelActuatorClose.autocomplete('option', 'source', arr);
}
function autoCompleteSensor() {
const iface = $nodeInputIfaceSensor.val();
const arr = [];
Object.keys(data.metadata.devices[iface]).forEach(addr => {
if (addr.includes(':')) {
const psName = paramsetName(iface, data.metadata.devices[iface][addr]) + 'VALUES';
const ps = data.paramsetDescriptions[psName];
if (
(ps && ps.STATE && !(ps.STATE.OPERATIONS & 2))
|| (ps && ps.MOTION)
|| (ps && ps.SENSOR)
) {
let name = addr;
if (data.channelNames[addr]) {
name = name + ' ' + data.channelNames[addr];
}
arr.push(name);
}
}
});
$nodeInputChannelSensorOpened.autocomplete('option', 'source', arr);
$nodeInputChannelSensorClosed.autocomplete('option', 'source', arr);
}
function loadConfig() {
const nodeId = $nodeInputCcuConfig.val();
const url = 'ccu?config=' + nodeId;
$.getJSON(url, d => {
data = d;
console.log(data);
autoCompleteActuator();
autoCompleteSensor();
});
}
$nodeInputCcuConfig.change(() => {
this.loadIfaces(() => {
$nodeInputIfaceActuator.removeAttr('disabled');
$nodeInputIfaceSensor.removeAttr('disabled');
loadConfig();
});
});
$nodeInputIfaceActuator.change(() => {
//$nodeInputChannelActuator.val('');
//$nodeInputChannelActuatorOpen.val('');
//$nodeInputChannelActuatorClose.val('');
if (data) {
autoCompleteActuator();
}
});
$nodeInputIfaceSensor.change(() => {
//$nodeInputChannelSensorClosed.val('');
//$nodeInputChannelSensorOpened.val('');
if (data) {
autoCompleteSensor();
}
});
},
oneditsave() {
}
});
</script>
<script type="text/x-red" data-template-name="redmatic-homekit-homematic-garage">
<div class="form-row">
<label for="node-input-bridgeConfig"><i class="icon-globe"></i> Bridge</label>
<input type="text" id="node-input-bridgeConfig">
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-globe"></i> Name</label>
<input type="text" id="node-input-name">
</div>
<div class="form-row">
<label for="node-input-ccuConfig"><i class="icon-globe"></i> CCU</label>
<input type="text" id="node-input-ccuConfig">
</div>
<div class="form-row">
<label for="node-input-ifaceActuator"><i class="fa fa-empire"></i> Interface Aktor</label>
<select id="node-input-ifaceActuator" disabled></select>
</div>
<div class="form-row">
<label for="node-input-channelActuatorType"><i class="icon-tags"></i> Aktor</label>
<select id="node-input-channelActuatorType">
<option value="1">Öffnen/Schließen mit einem Kanal</option>
<option value="2">Öffnen/Schließen getrennt mit zwei Kanälen</option>
</select>
</div>
<div class="form-row garage-actuator-1">
<label for="node-input-channelActuator"><i class="icon-tags"></i> Kanal Aktor</label>
<input type="text" id="node-input-channelActuator">
</div>
<div class="form-row garage-actuator-2">
<label for="node-input-channelActuatorOpen"><i class="icon-tags"></i> Kanal Aktor öffnen</label>
<input type="text" id="node-input-channelActuatorOpen">
</div>
<div class="form-row garage-actuator-2">
<label for="node-input-channelActuatoCloser"><i class="icon-tags"></i> Kanal Aktor schließen</label>
<input type="text" id="node-input-channelActuatorClose">
</div>
<div class="form-row">
<label for="node-input-onTime"><i class="icon-tags"></i> Schaltdauer Aktor</label>
<input type="number" id="node-input-onTime">
</div>
<div class="form-row">
<label for="node-input-ifaceSensor"><i class="fa fa-empire"></i> Interface Sensor</label>
<select id="node-input-ifaceSensor" disabled></select>
</div>
<div class="form-row">
<label for="node-input-channelSensorType"><i class="icon-tags"></i> Sensor</label>
<select id="node-input-channelSensorType">
<option value="c">Ein Sensor detektiert geschlossen</option>
<option value="o">Ein Sensor detektiert offen</option>
<option value="co">Zwei Sensoren detektieren offen und geschlossen</option>
</select>
</div>
<div class="form-row garage-sensor-c">
<label for="node-input-channelSensorClosed"><i class="icon-tags"></i> Kanal Sensor geschlossen</label>
<input type="text" id="node-input-channelSensorClosed">
</div>
<div class="form-row garage-sensor-c">
<label for="node-input-directionClosed"><i class="icon-tags"></i> Richtung Sensor geschlossen</label>
<select id="node-input-directionClosed">
<option value="true">true = geschlossen</option>
<option value="">true = nicht geschlossen</option>
</select>
</div>
<div class="form-row garage-sensor-o">
<label for="node-input-channelSensorOpened"><i class="icon-tags"></i> Kanal Sensor offen</label>
<input type="text" id="node-input-channelSensorOpened">
</div>
<div class="form-row garage-sensor-o">
<label for="node-input-directionOpened"><i class="icon-tags"></i> Richtung Sensor offen</label>
<select id="node-input-directionOpened">
<option value="true">true = offen</option>
<option value="">true = nicht offen</option>
</select>
</div>
<div class="form-row">
<label for="node-input-durationClose"><i class="icon-tags"></i> Fahrzeit schließen</label>
<input type="number" id="node-input-durationClose">
</div>
<div class="form-row">
<label for="node-input-duration"><i class="icon-tags"></i> Fahrzeit öffnen</label>
<input type="number" id="node-input-duration">
</div>
<div class="form-row">
<label for="node-input-revertTime"><i class="icon-tags"></i> Wartezeit Richtungsumkehr</label>
<input type="number" id="node-input-revertTime">
</div>
<style>
.form-row select {
width: 70%;
}
</style>
</script>
<script type="text/x-red" data-help-name="redmatic-homekit-homematic-garage">
<h3>Inputs</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">string</span>
</dt>
<dd><code>open</code> oder <code>close</code> </dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">boolean</span>
</dt>
<dd><code>true</code> wenn das Tor geschlossen ist, anderenfalls <code>false</code> </dd>
<dt>text
<span class="property-type">string</span>
</dt>
<dd>
<ul>
<li><code>open</code></li>
<li><code>closed</code></li>
<li><code>opening</code></li>
<li><code>closed</code></li>
<li><code>stopped</code></li>
<li><code>obstruction</code></li>
</ul>
</dd>
<dt>CurrentDoorState
<span class="property-type">number</span>
</dt>
<dd>
<ul>
<li><code>0</code> (open)</li>
<li><code>1</code> (closed)</li>
<li><code>2</code> (opening)</li>
<li><code>3</code> (closed)</li>
<li><code>4</code> (stopped)</li>
</ul>
</dd>
<dt>TargetDoorState
<span class="property-type">number</span>
</dt>
<dd>
<ul>
<li><code>0</code> (open)</li>
<li><code>1</code> (closed)</li>
</ul>
</dd>
<dt>ObstructionDetected
<span class="property-type">boolean</span>
</dt>
<dd>
</dd>
</dl>
</script>