node-red-contrib-mobius-flow-dali
Version:
Node-RED nodes to work with MOBiUSFlow and DALI devices
288 lines (270 loc) • 13.4 kB
HTML
<!--
Copyright (C) 2020, IAConnects Technology Limited
All Rights Reserved
ALL INFORMATION CONTAINED HEREIN IS, AND REMAINS
THE PROPERTY OF IACONNECTS TECHNOLOGY LIMITED AND ITS SUPPLIERS,
IF ANY. THE INTELLECTUAL AND TECHNICAL CONCEPTS CONTAINED
HEREIN ARE PROPRIETARY TO IACONNECTS TECHNOLOGY LIMITED
AND ITS SUPPLIERS AND ARE PROTECTED BY TRADE SECRET OR COPYRIGHT LAW.
DISSEMINATION OF THIS INFORMATION OR REPRODUCTION OF THIS MATERIAL
IS STRICTLY FORBIDDEN UNLESS PRIOR WRITTEN PERMISSION IS OBTAINED
FROM IACONNECTS TECHNOLOGY LIMITED.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-->
<script type="text/html" data-template-name="dali collection">
<div class="form-row">
<label for="node-input-selectionMethod" style="width: 160px;"><i class="fa fa-hand-pointer-o"></i> Selection Method</label>
<select type="text" id="node-input-selectionMethod" style="display: inline-block; width: 247px; vertical-align: middle;">
<option value='ins'>By Object Instance</option>
<option value='addr'>By DALI Address</option>
</select>
</div>
<div class="form-row node-input-groups-container-row">
<label for="node-input-groups-container"><i class="fa fa-bars"></i> Groups</label>
<ol id="node-input-groups-container"></ol>
</div>
<hr>
<div id="time-row" class="form-row">
<label style="width: 200px" for="node-input-errtime"><i class="fa fa-clock-o"></i> Error Check Interval</label>
<input type="text" id="node-input-errtime" placeholder="Time" style="text-align:left; width:50px !important">
<select id="node-input-errtimeUnits" style="width:120px !important">
<option value="seconds"> Seconds</option>
<option value="minutes"> Minutes</option>
<option value="hours"> Hours</option>
</select>
</div>
<div class="form-row">
<label style="width:auto; margin-right: 10px;" for="node-input-autoGrouping"><i class="fa fa-magic"></i> Auto-Group </label>
<input type="checkbox" id="node-input-autoGrouping" style="display:inline-block; width:auto; vertical-align:top;">
</div>
<div id="intervals">
<div id="time-row" class="form-row">
<label style="width: 200px" for="node-input-time"><i class="fa fa-clock-o"></i> Grouping Interval</label>
<input type="text" id="node-input-time" placeholder="Time" style="text-align:left; width:50px !important">
<select id="node-input-timeUnits" style="width:120px !important">
<option value="seconds"> Seconds</option>
<option value="minutes"> Minutes</option>
<option value="hours"> Hours</option>
</select>
</div>
</div>
<hr>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" style="width: 180px;">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('dali collection', {
category: 'dali',
color: '#ffd11a',
defaults: {
name: {value: ''},
autoGrouping: {value: true, required: true},
errtime: {value: '5'},
errtimeUnits: {value: 'minutes'},
time: {value: '5'},
timeUnits: {value: 'minutes'},
groups: {value:[{short: '', groupNum: '0', con: ''}]},
selectionMethod: {value: 'ins', required: true}
},
inputs: 1,
outputs: 1,
outputLabels: ['Command Out'],
icon: 'dali-icon.png',
align: 'left',
paletteLabel: 'dali collection',
label: function() {
return this.name||`DALI Collection`;
},
labelStyle: function() {
return this.name ? 'node_label_italic':'';
},
oneditprepare: function () {
var node = this;
$("#node-input-time").spinner({min:1});
$("#node-input-errtime").spinner({min:1});
const formSettings = {
regex: '',
label: '',
style: ''
}
function updateContainerSettings() {
if ($("#node-input-selectionMethod").val() === 'ins') {
formSettings.regex = "^(([0][0]([0]([0-9]|[A-F])|[1-3]([0-9]|[A-F])))([-]([0][0]([0]([0-9]|[A-F])|[1-3]([0-9]|[A-F])))|))((|[,](|[ ])((([0][0]([0]([0-9]|[A-F])|[1-3]([0-9]|[A-F])))([-]([0][0]([0]([0-9]|[A-F])|[1-3]([0-9]|[A-F])))|))))+)$";
formSettings.label = '<div>Instances:</div>';
formSettings.style = 'width: 200px; margin-left: 22px; text-align: left;';
} else {
formSettings.regex = "^(([0-9]|[1-5][0-9]|[6][0-3])([-]([0-9]|[1-5][0-9]|[6][0-3])|))((|[,](|[ ])((([0-9]|[1-5][0-9]|[6][0-3])([-]([0-9]|[1-5][0-9]|[6][0-3])|))))+)$";
formSettings.label = '<div>Addresses:</div>';
formSettings.style = 'width: 200px; margin-left: 16px; text-align: left;';
}
}
updateContainerSettings();
/** Create the groups container and populate it */
$('#node-input-groups-container').css('min-height', '300px').css('min-width', '450px').editableList ({
addButton: "add",
removable: true,
sortable: true,
addItem: function (container, i, group) {
container.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
// Add a default group if it does not exist
if (!group.hasOwnProperty("short")) {
group = {short: '', groupNum: '0', con: null};
}
let pattern = $("#node-input-selectionMethod").val();
var row = $(formSettings.label).appendTo(container);
var shortField = $('<input/>',{
class: "node-input-group-short",
type: "text",
style: formSettings.style,
pattern: formSettings.regex
}).appendTo(row);
var groupNumField = $('<select/>',{class: "node-input-group-groupNum", style: "width:auto; margin-left: 5px; text-align: center;"}).appendTo(row);
groupNumField.append($("<option></option>").val('0').text('Group 0'));
groupNumField.append($("<option></option>").val('1').text('Group 1'));
groupNumField.append($("<option></option>").val('2').text('Group 2'));
groupNumField.append($("<option></option>").val('3').text('Group 3'));
groupNumField.append($("<option></option>").val('4').text('Group 4'));
groupNumField.append($("<option></option>").val('5').text('Group 5'));
groupNumField.append($("<option></option>").val('6').text('Group 6'));
groupNumField.append($("<option></option>").val('7').text('Group 7'));
groupNumField.append($("<option></option>").val('8').text('Group 8'));
groupNumField.append($("<option></option>").val('9').text('Group 9'));
groupNumField.append($("<option></option>").val('10').text('Group 10'));
groupNumField.append($("<option></option>").val('11').text('Group 11'));
groupNumField.append($("<option></option>").val('12').text('Group 12'));
groupNumField.append($("<option></option>").val('13').text('Group 13'));
groupNumField.append($("<option></option>").val('14').text('Group 14'));
groupNumField.append($("<option></option>").val('15').text('Group 15'));
groupNumField.append($("<option></option>").val('-1').text('Short'));
var row2 = $('<div>Connection:</div>').appendTo(container);
var conField = $('<select/>',{class: "node-input-group-con", style: "width:298px; margin-left: 10px; margin-top: 5px; margin-bottom: 5px; text-align: center;"}).appendTo(row2);
RED.nodes.eachConfig((n) => {
if (n.type === 'dali-connection') {
conField.append($("<option></option>").val(n.id).text(n.name));
}
});
// Populate the new stat
shortField.val(group.short);
groupNumField.val(group.groupNum);
conField.val(group.con);
}
});
$("#circuit-busy-message-row").hide();
$("#circuit-failed-message-row").hide();
// If no stat exists, create a default one
if (!node.groups) {
console.log('Test Point A');
node.groups = [group = {short: '', groupNum: '0', con: ''}];
}
// Populate list with all saved filters
setTimeout(() => {
for (let i = 0; i < node.groups.length; i++) {
let group = node.groups[i];
$("#node-input-groups-container").editableList('addItem', group);
}
}, 50);
//repopule list using change address regex
function repopulate() {
let groups = $("#node-input-groups-container").editableList('items');
entries = [];
groups.each(function (i) {
var group = $(this);
let short = group.find(".node-input-group-short").val();
let con = group.find(".node-input-group-con").val();
let groupNum = group.find(".node-input-group-groupNum").val();
entries.push({short: short, groupNum: groupNum, con: con});
});
$("#node-input-groups-container").editableList('empty');
for (let i = 0; i < entries.length; i++) {
let entry = entries[i];
$("#node-input-groups-container").editableList('addItem', entry);
}
}
$("#node-input-selectionMethod").change(function() {
updateContainerSettings();
repopulate()
});
},
oneditresize(size) {
var rows = $("#dialog-form>div:not(.node-input-groups-container-row)");
var height = size.height;
for (var i=0; i<rows.size(); i++) {
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-input-groups-container-row");
height -= 4 * ((parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom"))));
$("#node-input-groups-container").editableList('height',height);
},
oneditsave: function() {
let groups = $("#node-input-groups-container").editableList('items');
let node = this;
node.groups= [];
groups.each(function (i) {
var group = $(this);
let short = group.find(".node-input-group-short").val();
let con = group.find(".node-input-group-con").val();
let groupNum = group.find(".node-input-group-groupNum").val();
node.groups.push({short: short, groupNum: groupNum, con: con});
});
}
});
</script>
<script type="text/html" data-help-name="dali collection">
<p>MOBiUS DALI Collection.</p>
<h3>Configuration Page</h3>
<dl class="message-properties">
<dt>Configure Connections <span class="property-type">connection</span></dt>
<dd>Allows for configuration of DALI cricuits.</dd>
<dt>Selection Method <span class="property-type">choice</span></dt>
<dd>The method to select DALI fittings.</dd>
<dt>Addresses / Instances <span class="property-type">number</span></dt>
<dd>The list of DALI short addresses (0-63) or Mobius object instances (0001-003F).</dd>
<dt>Group <span class="property-type">number</span></dt>
<dd>The DALI group number.</dd>
<dt>Connection <span class="property-type">number</span></dt>
<dd>The connection to the DALI Circuit.</dd>
</dl>
<h3>Input: </h3>
<dl class="message-properties">
<dt>payload.level <span class="property-type">number</span></dt>
<dd>The desired lighting level (0-100%).</dd>
</dl>
<h3>Output</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">object</span></dt>
<dd>A breakdown of the number of failures related to LED lamps.</dd>
</dl>
<h4>Overview</h4>
<p>Sends lighting level commands to all addresses within collection. Automatically checks the error status of all
luminaires within collection and reports this at the specified interval.
</p>
<h4>Grouping</h4>
<p>DALI groups can be configured within the node configuration. The node will automatically send DALI grouping commands
to ensure the DALI devices are within the correct groups. The node will also performing a full ungrouping process at
the specified interval. Following any ungrouping process the node will perform a regrouping process.
</p>
<h4>Address Range</h4>
<p>Short address range to be input in any valid format involving commas and dashes
e.g. ( 0-63 ) or ( 0,1 ) or ( 0, 1, 10-20 ). Examples involving any address < 0 or > 63 are invalid.
examples starting or ending in a comma or dash are invalid e.g. ( ,1 ) or ( 1, 2, ) or ( 1, 2, 3-5, 8- ).
Any example containing letters, symbols or further punctuation are invalid.
The same principle applies to instance selection e.g. (0001-0005, 0008) etc.</p>
<p align="center" style="color:#000080">iaconnects © 2020</p>
<br>
<p align="center" style="color:#000080">ER 2020</p>
</script>