node-red-contrib-knx-ultimate
Version:
Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control, ETS group address importer, and KNX routing between interfaces. Easy to use and highly configurable.
248 lines (210 loc) • 11.9 kB
HTML
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
<script type="text/javascript">
RED.nodes.registerType('knxUltimateAlerter', {
category: "KNX Ultimate",
color: '#C7E9C0',
defaults: {
//buttonState: {value: true},
server: { type: "knxUltimate-config", required: false },
name: { value: "" },
property: { value: "payload", required: true, validate: RED.validators.typedInput("propertyType") },
propertyType: { value: "msg" },
rules: { value: [{ t: "eq", v: "", vt: "str" }] },
whentostart: { value: "ifnewalert" },
timerinterval: { value: "2" },
initialreadGAInRules: { value: "1" },
},
inputs: 1,
outputs: 3,
outputLabels: function (index) {
if (index === 0) return "Emits a message for each alerted device, at selectable intervals.";
if (index === 1) return "Emits a unique message containing all alerted devices.";
if (index === 2) return "Emits a message containing only the last alerted device.";
},
icon: "node-alerter-icon.svg",
label: function () {
return (this.outputRBE == true ? "|rbe| " : "") + (this.name || this.topic || "KNX Alerter") + (this.inputRBE == true ? " |rbe|" : "")
},
paletteLabel: "KNX Alerter",
// button: {
// enabled: function() {
// // return whether or not the button is enabled, based on the current
// // configuration of the node
// return !this.changed
// },
// visible: function() {
// // return whether or not the button is visible, based on the current
// // configuration of the node
// return this.hasButton
// },
// //toggle: "buttonState",
// onclick: function() {}
// },
oneditprepare: function () {
// Go to the help panel
try {
RED.sidebar.show("help");
} catch (error) { }
var node = this;
var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
// 19/02/2020 Used to get the server sooner als deploy.
$("#node-input-server").change(function () {
try {
oNodeServer = RED.nodes.node($(this).val());
} catch (error) { }
});
// Scene configuration
var previousValueType = { value: "prev", label: this._("switch.previous"), hasValue: false };
function resizeRule(rule) {
}
$("#node-input-rule-container").css('min-height', '350px').css('min-width', '450px').editableList({
addItem: function (container, i, opt) { // row, index, data
// opt.r is: { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
var rule = opt.r;
if (!opt.hasOwnProperty('i')) {
opt._i = Math.floor((0x99999 - 0x10000) * Math.random()).toString();
}
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
var row = $('<div class="form-row"/>').appendTo(container);
var oTopicField = $("<input/>", { class: "rowRuleTopic", type: "text", placeholder: "GA or devicename", style: "width:20%; margin-left: 5px; text-align: left;" }).appendTo(row);
var finalspan = $('<span/>', { style: "" }).appendTo(row);
finalspan.append(' <span class="node-input-rule-index"></span> ');
var orowRuleDeviceName = $('<input/>', { maxlength: "14", class: "rowRuleDeviceName", type: "text", style: "width:30%; margin-left: 0px; text-align: left;font-style: italic;", placeholder: "Name (max 14 chars)" }).appendTo(row);
var orowRuleLongDeviceName = $('<input/>', { class: "rowRuleLongDeviceName", type: "text", style: "width:45%; margin-left: 0px; text-align: left;", placeholder: "Long name" }).appendTo(row);
oTopicField.on("change", function () {
resizeRule(container);
});
// Autocomplete suggestion with ETS csv File
oTopicField.autocomplete({
minLength: 0,
source: function (request, response) {
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
response($.map(data, function (value, key) {
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
if (htmlUtilsfullCSVSearch(sSearch, request.term + " 1.")) {
return {
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
value: value.ga // Value
}
} else {
return null;
}
}));
});
}, select: function (event, ui) {
// Sets Datapoint and device name automatically
var sDevName = ui.item.label.split("#")[1].trim();
try {
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
orowRuleDeviceName.val(sDevName.substr(0, 14));
orowRuleLongDeviceName.val(sDevName);
} catch (error) {
}
}
});
oTopicField.on('focus.knxUltimateAlerter click.knxUltimateAlerter', function () {
try {
$(this).autocomplete('search', '');
} catch (error) { /* empty */ }
});
try { if (oNodeServer && oNodeServer.id) KNX_enableSecureFormatting(oTopicField, oNodeServer.id); } catch (e) {}
oTopicField.val(rule.topic);
orowRuleDeviceName.val(rule.devicename);
orowRuleLongDeviceName.val(rule.longdevicename);
oTopicField.change();
},
removeItem: function (opt) {
},
resizeItem: resizeRule,
sortItems: function (rules) {
},
sortable: true,
removable: true
});
// Put some spaces after the container
$('<br/><br/><br/><br/><br/><br/><br/><br/>').insertAfter($("#node-input-rule-container"));
// 10/03/2020 For each rule, create a row
for (var i = 0; i < this.rules.length; i++) {
var rule = this.rules[i];
$("#node-input-rule-container").editableList('addItem', { r: rule, i: i });
}
},
oneditsave: function () {
// Return to the info tab
try {
RED.sidebar.show("info");
} catch (error) { }
var node = this;
var rules = $("#node-input-rule-container").editableList('items');
node.rules = [];
rules.each(function (i) {
var rule = $(this);
var rowRuleTopic = rule.find(".rowRuleTopic").val();
var rowRuleDeviceName = rule.find(".rowRuleDeviceName").val();
var rowRuleLongDeviceName = rule.find(".rowRuleLongDeviceName").val();
node.rules.push({ topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName });
});
this.propertyType = $("#node-input-property").typedInput('type');
},
oneditresize: function (size) {
var node = this;
var rows = $("#dialog-form>div:not(.node-input-rule-container-row)");
var height = size.height;
for (var i = 0; i < rows.length; i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-rule-container-row");
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
height += 16;
$("#node-input-rule-container").editableList('height', height);
}
})
</script>
<script type="text/html" data-template-name="knxUltimateAlerter">
<div class="form-row">
<b><span data-i18n="knxUltimateAlerter.title"></span></b>
<br/><br/>
<label for="node-input-server"> <img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKnRFWHRDcmVhdGlvbiBUaW1lAEZyIDYgQXVnIDIwMTAgMjE6NTI6MTkgKzAxMDD84aS8AAAAB3RJTUUH3gYYCicNV+4WIQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAACUSURBVHjaY2CgFZg5c+Z/ZEyWAZ8+f/6/ZsWs/xoamqMGkGrA6Wla/1+fVARjEBuGsSoGmY4eZSCNL59d/g8DIDbIAHR14OgFGQByKjIGKX5+6/T///8gGMQGiV1+/B0Fg70GIkD+RMYgxf/O5/7//2MSmAZhkBi6OrgB6Bg5DGB4ajr3f2xqsYYLSDE2THJUDg0AAAqyDVd4tp4YAAAAAElFTkSuQmCC"></img>
<span data-i18n="knxUltimateAlerter.properties.node-input-server"></span> </label>
<input type="text" id="node-input-server">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="knxUltimateAlerter.properties.node-input-name"></span> </label>
<input type="text" id="node-input-name" data-i18n="[placeholder]knxUltimateAlerter.properties.node-input-name" style="flex:1 1 240px; min-width:240px; max-width:240px;">
</div>
<div class="form-row">
<label for="node-input-whentostart"><i class="fa fa-repeat"></i> <span data-i18n="knxUltimateAlerter.properties.node-input-whentostart"></span> </label>
<select id="node-input-whentostart">
<option value="manualstart" data-i18n="knxUltimateAlerter.selectlists.manualstart"></option>
<option value="ifnewalert" data-i18n="knxUltimateAlerter.selectlists.ifnewalert"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-timerinterval" style="width:70%"><i class="fa fa-clock-o"></i> <span data-i18n="knxUltimateAlerter.properties.node-input-timerinterval"></span> </label>
<input type="text" id="node-input-timerinterval" style="width:10%">
</div>
<br/>
<br/>
<dt><i class="fa fa-code-fork"></i> <span data-i18n="knxUltimateAlerter.other.sceneConfig"></dt>
<br/>
<div class="form-row" id="divNode-input-initialreadGAInRules">
<label style="width:60%" for="node-input-initialreadGAInRules">
<i class="fa fa-question-circle-o"></i>
<span data-i18n="knxUltimateAlerter.properties.node-input-initialreadGAInRules"></span>
</label>
<select style="width:30%" id="node-input-initialreadGAInRules">
<option value="0" data-i18n="knxUltimateAlerter.properties.node-input-initialread0"></option>
<option value="1" data-i18n="knxUltimateAlerter.properties.node-input-initialread1"></option>
</select>
</div>
<div class="form-row node-input-rule-container-row">
<ol id="node-input-rule-container"></ol>
</div>
<div class="form-row">
<p><span data-i18n="knxUltimateAlerter.other.add"></p>
</div>
</script>