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 and ETS group address importer. Easy to use and highly configurable.
594 lines (533 loc) • 30.2 kB
HTML
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
<script type="text/javascript">
RED.nodes.registerType('knxUltimateHueScene', {
category: "KNX Ultimate",
color: '#C0C7E9',
defaults: {
//buttonState: {value: true},
server: { type: "knxUltimate-config", required: false },
serverHue: { type: "hue-config", required: true },
name: { value: "" },
// Single scene
namescene: { value: "" },
GAscene: { value: "" },
dptscene: { value: "" },
valscene: { value: 0 }, // the scene number or true/false
namesceneStatus: { value: "" },
GAsceneStatus: { value: "" },
dptsceneStatus: { value: "" },
enableNodePINS: { value: "no" },
outputs: { value: 0 },
inputs: { value: 0 },
hueDevice: { value: "" },
hueSceneRecallType: { value: "active" },
// Multi scene
GAsceneMulti: { value: "" },
namesceneMulti: { value: "" },
dptsceneMulti: { value: "" },
rules: { value: [{ t: "eq", v: "", vt: "str" }] },
selectedModeTabNumber: { value: 0 }
},
inputs: 0,
outputs: 0,
icon: "node-hue-icon.svg",
label: function () {
if (this.selectedModeTabNumber === undefined) return this.name;
if (Number(this.selectedModeTabNumber) === 0) return this.name;
if (Number(this.selectedModeTabNumber) === 1) return this.namesceneMulti;
},
paletteLabel: "Hue Scene",
// 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
var oNodeServerHue = RED.nodes.node($("#node-input-serverHue").val()); // Store the config-node
for (let index = 1; index <= 64; index++) {
$("#node-input-valscene").append($("<option></option>")
.attr("value", index)
.text("Scene n. " + index)
)
}
$("#node-input-valscene").val(node.valscene)
// 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) { }
});
// 19/02/2020 Used to get the server sooner als deploy.
$("#node-input-serverHue").change(function () {
try {
oNodeServerHue = RED.nodes.node($(this).val());
} catch (error) { }
});
// DPT
// ########################
$.getJSON('knxUltimateDpts?serverId=' + $("#node-input-server").val(), (data) => {
data.forEach(dpt => {
if (dpt.value.startsWith("1.") || dpt.value.startsWith("18.")) {
$("#node-input-dptscene").append($("<option></option>")
.attr("value", dpt.value)
.text(dpt.text))
}
if (dpt.value.startsWith("18.")) {
$("#node-input-dptsceneMulti").append($("<option></option>")
.attr("value", dpt.value)
.text(dpt.text))
}
if (dpt.value.startsWith("1.")) {
$("#node-input-dptsceneStatus").append($("<option></option>")
.attr("value", dpt.value)
.text(dpt.text))
}
});
$("#node-input-dptscene").val(this.dptscene)
$("#node-input-dptsceneStatus").val(this.dptsceneStatus)
$("#node-input-dptsceneMulti").val(this.dptsceneMulti)
ShowHideValScene();
})
// Autocomplete suggestion with ETS csv File
$("#node-input-GAscene").autocomplete({
minLength: 0,
source: function (request, response) {
//$.getJSON("csv", request, function( data, status, xhr ) {
$.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)) {
if (value.dpt.startsWith("1.") || value.dpt.startsWith("18.")) {
return {
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
value: value.ga // Value
}
} else { return null; }
} 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();
} catch (error) {
}
$('#node-input-namescene').val(sDevName);
var optVal = $("#node-input-dptscene option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
// Select the option value
$("#node-input-dptscene").val(optVal);
ShowHideValScene();
}
}).focus(function () {
$(this).autocomplete('search', $(this).val() + 'exactmatch');
});
try { if (oNodeServer && oNodeServer.id) KNX_enableSecureFormatting($("#node-input-GAscene"), oNodeServer.id); } catch (e) {}
$("#node-input-GAsceneStatus").autocomplete({
minLength: 0,
source: function (request, response) {
//$.getJSON("csv", request, function( data, status, xhr ) {
$.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)) {
if (value.dpt.startsWith("1.")) {
return {
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
value: value.ga // Value
}
} else { return null; }
} 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();
} catch (error) {
}
$('#node-input-namesceneStatus').val(sDevName);
var optVal = $("#node-input-dptsceneStatus option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
// Select the option value
$("#node-input-dptsceneStatus").val(optVal);
ShowHideValScene();
}
}).focus(function () {
$(this).autocomplete('search', $(this).val() + 'exactmatch');
});
try { if (oNodeServer && oNodeServer.id) KNX_enableSecureFormatting($("#node-input-GAsceneStatus"), oNodeServer.id); } catch (e) {}
$("#node-input-GAsceneMulti").autocomplete({
minLength: 0,
source: function (request, response) {
//$.getJSON("csv", request, function( data, status, xhr ) {
$.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)) {
if (value.dpt.startsWith("18.")) {
return {
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
value: value.ga // Value
}
} else { return null; }
} 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();
} catch (error) {
}
$('#node-input-namesceneMulti').val(sDevName);
var optVal = $("#node-input-dptsceneMulti option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
// Select the option value
$("#node-input-dptsceneMulti").val(optVal);
ShowHideValScene();
}
}).focus(function () {
$(this).autocomplete('search', $(this).val() + 'exactmatch');
});
try { if (oNodeServer && oNodeServer.id) KNX_enableSecureFormatting($("#node-input-GAsceneMulti"), oNodeServer.id); } catch (e) {}
// ########################
function ShowHideValScene() {
if ($("#node-input-dptscene").val() !== null) {
// Adapt the scene value/true
if ($("#node-input-dptscene").val().startsWith("1.")) {
$("#divValScene").hide();
//$("#node-input-valscene").attr("disabled", "disabled");
} else {
$("#divValScene").show()
//$("#node-input-valscene").removeAttr("disabled");
}
}
}
$("#node-input-dptscene").on("change", function () {
ShowHideValScene()
});
ShowHideValScene();
// Autocomplete suggestion with HUE
$("#node-input-name").autocomplete({
minLength: 0,
source: function (request, response) {
$.getJSON("KNXUltimateGetResourcesHUE?rtype=scene&serverId=" + oNodeServerHue.id, (data) => {
response($.map(data.devices, function (value, key) {
//alert(JSON.stringify(value) + " "+ key)
var sSearch = (value.name);
if (htmlUtilsfullCSVSearch(sSearch, request.term)) {
return {
hueDevice: value.id, // Label for Display
value: value.name // Value
}
} else {
return null;
}
}));
});
}, select: function (event, ui) {
// Sets the fields
$('#node-input-hueDevice').val(ui.item.hueDevice);
}
}).focus(function () {
$(this).autocomplete('search', $(this).val() + 'exactmatch');
});
// ########################
// -----------------------------------------------------------------------
// MULTI SCENE
// ########################
function resizeRule(rule) { }
function setTableTitle(_selectedIndex) {
// Save only the tab 0 or 1
if (_selectedIndex === undefined) _selectedIndex = 0;
if (Number(_selectedIndex) <= 1) {
$("#node-input-selectedModeTabNumber").val(Number(_selectedIndex));
if (Number(_selectedIndex) === 0) {
$('#tabs ul:first li:eq(0) a').html('<i class="fa fa-check" aria-hidden="true"></i> Single mode');
$('#tabs ul:first li:eq(1) a').text('Multi mode');
} else if (Number(_selectedIndex) === 1) {
$('#tabs ul:first li:eq(0) a').text('Sigle mode');
$('#tabs ul:first li:eq(1) a').html('<i class="fa fa-check" aria-hidden="true"></i> Multi mode');
}
}
}
$("#node-input-rule-container").css('min-height', '200px').css('min-width', '450px').editableList({
scrollOnAdd: true,
//header: $("<div>").append($.parseHTML("<div style='width:5%; display: inline-grid'>Sort</div><div style='width:15%; display: inline-grid'>KNX Scene number</div><div style='width:60%; display: inline-grid'>HUE Scene name</div><div style='width:15%; display: inline-grid'>Recall scene as</div><div style='width:5%; display: inline-grid'>Delete</div>")),
addItem: function (container, i, opt) { // row, index, data
// opt.r is: { rowRuleKNXSceneNumber: rowRuleKNXSceneNumber, rowRuleHUESceneName: rowRuleHUESceneName, rowRuleHUESceneID:rowRuleHUESceneID, rowRuleRecallAs:rowRuleRecallAs}
if (!opt.hasOwnProperty('r')) {
opt.r = {};
}
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 rowRuleKNXSceneNumber = $('<select/>', { class: "rowRuleKNXSceneNumber", type: "text", style: "width:25%; margin-left: 5px; text-align: left;" }).appendTo(row);
var rowRuleHUESceneName = $("<input/>", { class: "rowRuleHUESceneName", type: "text", placeholder: "HUE device name", style: "width:45%; margin-left: 5px; text-align: left;" }).appendTo(row);
var rowRuleHUESceneID = $("<input/>", { class: "rowRuleHUESceneID", type: "hidden", placeholder: "HUE device name", style: "width:0px; margin-left: 5px; text-align: left;" }).appendTo(row);
var rowRuleRecallAs = $('<select/>', { class: "rowRuleRecallAs", type: "text", style: "width:25%; margin-left: 5px; text-align: left;" }).appendTo(row);
var finalspan = $('<span/>', { style: "" }).appendTo(row);
finalspan.append('<span class="node-input-rule-index"></span> ');
for (let index = 1; index <= 64; index++) {
rowRuleKNXSceneNumber.append(
$("<option>")
.val(index)
.text(node._("knxUltimateHueScene.knx_scene_n") + index.toString())
);
rowRuleKNXSceneNumber.val(rule.rowRuleKNXSceneNumber);
}
rowRuleRecallAs.append(
$("<option>")
.val("active")
.text(node._("knxUltimateHueScene.recall_active"))
);
rowRuleRecallAs.append(
$("<option>")
.val("dynamic_palette")
.text(node._("knxUltimateHueScene.recall_dynamic"))
);
rowRuleRecallAs.append(
$("<option>")
.val("static")
.text(node._("knxUltimateHueScene.recall_static"))
);
rowRuleRecallAs.val(rule.rowRuleRecallAs);
rowRuleHUESceneName.autocomplete({
minLength: 1,
source: function (request, response) {
$.getJSON("KNXUltimateGetResourcesHUE?rtype=scene&serverId=" + oNodeServerHue.id, (data) => {
response($.map(data.devices, function (value, key) {
//alert(JSON.stringify(value) + " "+ key)
var sSearch = (value.name);
if (htmlUtilsfullCSVSearch(sSearch, request.term)) {
return {
hueDevice: value.id, // Label for Display
value: value.name // Value
}
} else {
return null;
}
}));
});
}, select: function (event, ui) {
// Sets Datapoint and device name automatically
rowRuleHUESceneID.val(ui.item.hueDevice);
}
}).focus(function () {
$(this).autocomplete('search', $(this).val() + 'exactmatch');
});
rowRuleRecallAs.val(rule.rowRuleRecallAs)
rowRuleHUESceneName.val(rule.rowRuleHUESceneName);
rowRuleHUESceneID.val(rule.rowRuleHUESceneID);
},
removeItem: function (opt) {
},
resizeItem: resizeRule,
sortItems: function (rules) {
},
sortable: true,
removable: true
});
// Put some spaces after the container
$('<br/><br/><br/>').insertAfter($("#node-input-rule-container"));
// For each rule, create a row
if (this.rules !== undefined) {
for (var i = 0; i < this.rules.length; i++) {
var rule = this.rules[i];
$("#node-input-rule-container").editableList('addItem', { r: rule, i: i });
}
}
// ########################
// MULTI SCENE
// -----------------------------------------------------------------------
this.selectedModeTabNumber === undefined ? 0 : this.selectedModeTabNumber;
$("#tabs").tabs({
activate: function (event, ui) {
setTableTitle(ui.newTab.index());
}
});
$("#tabs").tabs("option", "active", this.selectedModeTabNumber);
setTableTitle(this.selectedModeTabNumber);
},
oneditsave: function () {
// Return to the info tab
try {
RED.sidebar.show("info");
} catch (error) { }
if ($("#node-input-enableNodePINS").val() === "yes") {
this.outputs = 1;
this.inputs = 1;
} else {
this.outputs = 0;
this.inputs = 0;
}
var node = this;
// opt.r is: { rowRuleKNXSceneNumber: rowRuleKNXSceneNumber, rowRuleHUESceneName: rowRuleHUESceneName, rowRuleHUESceneID:rowRuleHUESceneID, rowRuleRecallAs:rowRuleRecallAs}
var rules = $("#node-input-rule-container").editableList('items');
node.rules = [];
rules.each(function (i) {
var rule = $(this);
var rowRuleKNXSceneNumber = rule.find(".rowRuleKNXSceneNumber").val();
var rowRuleHUESceneName = rule.find(".rowRuleHUESceneName").val();
var rowRuleHUESceneID = rule.find(".rowRuleHUESceneID").val();
var rowRuleRecallAs = rule.find(".rowRuleRecallAs").val();
node.rules.push({ rowRuleKNXSceneNumber: rowRuleKNXSceneNumber, rowRuleHUESceneName: rowRuleHUESceneName, rowRuleHUESceneID: rowRuleHUESceneID, rowRuleRecallAs: rowRuleRecallAs });
});
},
oneditcancel: function () {
// Return to the info tab
try {
RED.sidebar.show("info");
} catch (error) { }
},
oneditresize: function (size) {
}
})
</script>
<script type="text/html" data-template-name="knxUltimateHueScene">
<div class="form-row">
<input type="hidden" id="node-input-selectedModeTabNumber">
<b><span data-i18n="knxUltimateHueScene.title"></span></b>  <span style="color:red"
 <i class="fa fa-youtube"></i></span> <a target="_blank" href="https://youtu.be/jjEUI1J8bkA"><u><span data-i18n="common.youtube_sample"></span></u></a>
<br />
<br />
<p align="center">
<i class="fa fa-tv fa-fade fa-4x"></i>
</p>
<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="common.knx_gw"></span>
</label>
<input type="text" id="node-input-server" />
</div>
<div class="form-row">
<label for="node-input-serverHue">
<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAAA0VXHyAAABFUlEQVQ4EZWSsWoCQRCG1yiENEFEi6QSkjqWWoqFoBYJ+Br6JHkMn8Iibd4ihQpaJIhWNkry/ZtdGZY78Qa+m39nZ+dm9s4550awglNBluS/gVtAX6KgDclf68w2OThgfR9iT/jnoEv4TtByDThWTCDKW4SSZTf/zj9/eZbN+izTDuKGimu0vPF8B/YN8aC8LmcOj/AAn9CFTEs70Js/oGqy79C69bqJ5XbQI2kGO5N8QL9D08S8zBtBF5ZaVsznpCMoqJnVdjTpb1Db0fwIWmQV6BLXzFOYgA6/gDVfQN9bBWp2J2hdWDPoBV5FrKnAJutHikk/CHHR8i7x4iG7qQ720IYvu3GFbpHjx3pFrOFYkA354z/5bkK826phyAAAAABJRU5ErkJggg=="/>
<span data-i18n="common.hue_bridge"></span>
</label>
<input type="text" id="node-input-serverHue" />
</div>
<br/>
<div id="tabs">
<ul>
<li><a href="#tabs-1"> Single scene</a></li>
<li><a href="#tabs-2"> Multi scene</a></li>
<li><a href="#tabs-3"> Behaviour</a></li>
</ul>
<div id="tabs-1">
<br/>
<p>
<b><span data-i18n="common.philips_hue"></span></b>
</p>
<div class="form-row">
<label for="node-input-hueDevice" >
<i class="fa fa-play-circle"></i> <span data-i18n="knxUltimateHueScene.hue_scene"></span></label>
<input type="text" id="node-input-name" placeholder="Enter your hue device name" />
<input type="hidden" id="node-input-hueDevice" />
</div>
<div class="form-row">
<label for="node-input-hueSceneRecallType">
<i class="fa fa-minus-circle"></i> <span data-i18n="knxUltimateHueScene.recall_as"></span>
</label>
<select id="node-input-hueSceneRecallType">
<option value="active" data-i18n="knxUltimateHueScene.recall_active"></option>
<option value="dynamic_palette" data-i18n="knxUltimateHueScene.recall_dynamic"></option>
<option value="static" data-i18n="knxUltimateHueScene.recall_static"></option>
</select>
</div>
<br/>
<p>
<b>KNX</b>
</p>
<div class="form-row">
<label for="node-input-namescene" style="width:100px;"><i class="fa fa-play-circle-o"></i> <span data-i18n="knxUltimateHueScene.recall"></span></label>
<label for="node-input-GAscene" style="width:20px;"><span data-i18n="common.ga"></span></label>
<input type="text" id="node-input-GAscene" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
<label for="node-input-dptscene" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
<select id="node-input-dptscene" style="width:140px;"></select>
<label for="node-input-namescene" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
<input type="text" id="node-input-namescene" style="width:200px;margin-left: 5px; text-align: left;">
</div>
<div class="form-row" id="divValScene" hidden>
<label for="node-input-valscene" style="width:100px;"></label>
<label for="node-input-valscene" style="width:20px;">#</label>
<select id="node-input-valscene" style="width:180px;margin-left: 5px; text-align: left;"></select>
</div>
<div class="form-row">
<label for="node-input-namesceneStatus" style="width:100px;"><i class="fa fa-question-circle"></i> <span data-i18n="knxUltimateHueScene.status"></span></label>
<label for="node-input-GAsceneStatus" style="width:20px;"><span data-i18n="common.ga"></span></label>
<input type="text" id="node-input-GAsceneStatus" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
<label for="node-input-dptsceneStatus" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
<select id="node-input-dptsceneStatus" style="width:140px;"></select>
<label for="node-input-namesceneStatus" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
<input type="text" id="node-input-namesceneStatus" style="width:200px;margin-left: 5px; text-align: left;">
</div>
<br/>
<br/>
</div> <!-- // End Tab 1 -->
<div id="tabs-2">
<br/>
<div class="form-row">
<label for="node-input-namesceneMulti" style="width:100px;"><i class="fa fa-play-circle-o"></i> <span data-i18n="knxUltimateHueScene.recall"></span></label>
<label for="node-input-GAsceneMulti" style="width:20px;"><span data-i18n="common.ga"></span></label>
<input type="text" id="node-input-GAsceneMulti" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
<label for="node-input-dptsceneMulti" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
<select id="node-input-dptsceneMulti" style="width:140px;"></select>
<label for="node-input-namesceneMulti" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
<input type="text" id="node-input-namesceneMulti" style="width:200px;margin-left: 5px; text-align: left;">
</div>
<div>
<dt><i class="fa fa-code-fork"></i> <span data-i18n="knxUltimateHueScene.scene_selector"></span></dt>
<div class="form-row node-input-rule-container-row">
<ol id="node-input-rule-container"></ol>
</div>
<div class="form-row">
<p></p>
</div>
</div>
<br/>
</div> <!-- // End Tab 2 -->
<div id="tabs-3">
<br/>
<div class="form-row">
<label for="node-input-enableNodePINS" style="width:240px;">
<i class="fa fa-circle"></i> <span data-i18n="knxUltimateHueScene.node_pins"></span>
</label>
<select id="node-input-enableNodePINS">
<option value="no" data-i18n="knxUltimateHueScene.node_pins_hide"></option>
<option value="yes" data-i18n="knxUltimateHueScene.node_pins_show"></option>
</select>
</div>
</div> <!-- // End Tab 3 -->
</div> <!-- // End TABS -->
</script>