node-red-contrib-modbus
Version:
The all in one Modbus TCP and Serial contribution long term supported package for Node-RED.
368 lines (326 loc) • 13.5 kB
HTML
<!--
Copyright (c) since the year 2016 Klaus Landsdorf (http://plus4nodered.com/)
All rights reserved.
node-red-contrib-modbus - The BSD 3-Clause License
@author <a>Andrea Verardi</a> (Anversoft)
--> <script type='text/javascript'> //Modbus sequences
var functions = [{
v: "FC1",
t: "FC 1: Read Coil Status"
},
{
v: "FC2",
t: "FC 2: Read Input Status"
},
{
v: "FC3",
t: "FC 3: Read Holding Registers"
},
{
v: "FC4",
t: "FC 4: Read Input Registers"
},
];
RED.nodes.registerType('modbus-flex-sequencer', {
category: 'modbus',
color: '#E9967A',
defaults: {
name: {
value: ''
},
sequences: {
value: [{
name: null,
unitid: null,
fc: functions[0].v,
address: null,
quantity: null
}],
validate: function (sequences) {
if (!sequences || sequences.length === 0) {
return false;
}
for (var i = 0; i < sequences.length; i++) {
var r = sequences[i];
if (!r.unitid || isNaN(parseInt(r.unitid, 10)) || !r.address || isNaN(parseInt(r.address, 10)) || !r
.quantity || isNaN(parseInt(r.quantity, 10))) {
return false;
}
}
return true;
}
},
server: {
type: 'modbus-client',
required: true
},
showStatusActivities: {
value: false
},
showErrors: {
value: false
},
showWarnings: {
value: true
},
logIOActivities: {
value: false
},
useIOFile: {
value: false
},
ioFile: {
value: '',
type: 'modbus-io-config',
required: false
},
useIOForPayload: {
value: false
},
emptyMsgOnFail: {
value: false
},
keepMsgProperties: {
value: false
},
delayOnStart: {
value: false
},
startDelayTime: {
value: ''
},
},
inputs: 1,
outputs: 2,
align: "left",
icon: 'modbus.png',
paletteLabel: 'Modbus-Flex-Sequencer',
//Node label
label: function () {
if (this.name) {
return this.name
} else if (this.sequences) {
return "Modbus Flex Sequencer: " + this.sequences.length
}
return 'Modbus Flex Sequencer';
},
oneditprepare: function () {
let tabs = RED.tabs.create({
id: "node-input-modbus-tabs",
onchange: function (tab) {
$("#node-input-tabs-content").children().hide()
$("#" + tab.id).show()
}
})
tabs.addTab({
id: "modbus-settings-tab",
label: this._("modbus-contrib.tabs-label.settings")
})
tabs.addTab({
id: "modbus-options-tab",
label: this._("modbus-contrib.tabs-label.options")
})
if (this.delayOnStart) {
$('#node-delay').show()
}
else {
$('#node-delay').hide()
$('#node-input-delayOnStart').prop('checked', false)
}
$('#node-input-delayOnStart').change(function () {
if ($(this).is(':checked')) {
$('#node-delay').show()
} else {
$('#node-delay').hide()
}
})
let useIOFileCheckbox = $('#node-input-useIOFile')
let modbusiofileRow = $('#modbusiofile-row')
useIOFileCheckbox.change(function () {
if ($(this).is(':checked')) {
modbusiofileRow.show()
} else {
modbusiofileRow.hide()
}
})
/*
Polling Section
*/
$('#node-input-sequences-container').css('min-width', '450px').editableList({
addItem: function (row, index, data) {
var sequence = data;
if (!sequence.hasOwnProperty('fc')) {
sequence = {
name: null,
unitid: null,
fc: functions[0].v,
address: null,
quantity: null
};
}
row.css({
overflow: 'hidden',
whiteSpace: 'nowrap'
});
let fragment = document.createDocumentFragment();
var row0 = $('<div/>', {
class: "form-row",
})
.appendTo(fragment);
var row1 = $('<div/>', {
class: "form-row",
})
.appendTo(fragment);
var row2 = $('<div/>', {
class: "form-row",
})
.appendTo(fragment);
var row3 = $('<div/>', {
class: "form-row",
})
.appendTo(fragment);
var row4 = $('<div/>', {
class: "form-row",
})
.appendTo(fragment);
$('<label/>')
.text("Name")
.appendTo(row0);
var sequenceNameProperty = $('<input/>', {
class: "node-input-sequencename",
type: "text",
placeholder: "Sequence " + index
})
.appendTo(row0)
$('<label/>')
.text("Function")
.appendTo(row1);
var selectFunctionProperty = $('<select/>', {
class: "node-input-function",
})
.appendTo(row1);
for (var i = 0; i < 4; i++) {
selectFunctionProperty.append($("<option></option>").val(functions[i].v).text(functions[i].t));
}
$('<label/>')
.text("Unit ID")
.appendTo(row2);
var unitIdProperty = $('<input/>', {
class: "node-input-unitid",
type: "text",
})
.appendTo(row2)
$('<label/>')
.text("Address")
.appendTo(row3);
var addressProperty = $('<input/>', {
class: "node-input-address",
type: "text",
placeholder: "0 - 65535"
})
.appendTo(row3)
$('<label/>')
.text("Quantity")
.appendTo(row4);
var quantityProperty = $('<input/>', {
class: "node-input-quantity",
type: "text",
placeholder: "0 - 65535"
})
.appendTo(row4)
sequenceNameProperty.val(sequence.name);
selectFunctionProperty.val(sequence.fc);
unitIdProperty.val(sequence.unitid);
addressProperty.val(sequence.address);
quantityProperty.val(sequence.quantity);
selectFunctionProperty.change();
row[0].appendChild(fragment);
},
removable: true,
sortable: true
})
if (!this.sequences) {
let sequenceMsg = {
name: null,
unitid: null,
fc: functions[0].v,
address: null,
quantity: null
};
this.sequences = [sequenceMsg];
}
for (var i = 0; i < this.sequences.length; i++) {
$("#node-input-sequences-container").editableList('addItem', this.sequences[i]);
}
},
oneditsave: function () {
var sequences = $("#node-input-sequences-container").editableList('items');
var node = this;
node.sequences = [];
sequences.each(function (i) {
var sequence = $(this);
var r = {
name: sequence.find(".node-input-sequencename").val(),
unitid: sequence.find(".node-input-unitid").val(),
fc: sequence.find(".node-input-function").val(),
address: sequence.find(".node-input-address").val(),
quantity: sequence.find(".node-input-quantity").val()
};
node.sequences.push(r);
});
},
oneditresize: function (size) {
var height = size.height;
$('#node-input-sequences-container').css("height", (height - 145) + "px");
}
}) </script> <script type='text/x-red' data-template-name='modbus-flex-sequencer'>
<div class='form-row'> <label for='node-input-name'><i class='icon-tag'></i> <span
data-i18n='node-red:common.label.name'></span></label> <input type='text' id='node-input-name' placeholder='Name'>
</div> <div class='form-row node-input-modbus-tabs-row'> <ul style='min-width:600px;margin-bottom:20px'
id='node-input-modbus-tabs'></ul> </div> <div id='node-input-tabs-content'> <div id='modbus-settings-tab'
style='display:none'> <div class='form-row' id='node-delayonstart'> <label for='node-input-delayOnStart'
style='width:160px'> <i class='fa fa-power-off'></i> <span data-i18n='modbus-contrib.label.delayOnStart'></span></label>
<input type='checkbox' id='node-input-delayOnStart' style='width:40px'> </div> <div class='form-row' id='node-delay'>
<label for='node-input-startDelayTime'><i class='fa fa-clock-o'></i> <span
data-i18n='modbus-contrib.label.startDelayTime'></span></label> <input type='text' id='node-input-startDelayTime'
placeholder='10' style='width:80px'> </div> <div class='form-row'> <label for='node-input-server'><i class='icon-globe'>
</i> <span data-i18n='modbus-contrib.label.server'></span></label> <input type='text' id='node-input-server'> </div>
<div class='form-row node-input-sequences-container-row'> <ol id='node-input-sequences-container'></ol> </div> </div>
<div id='modbus-options-tab' style='display:none'> <div class='form-row'> <label style='min-width:190px'
for='node-input-emptyMsgOnFail'><i class='fa fa-th'></i> <span data-i18n='modbus-contrib.label.emptyMsgOnFail'></span>
</label> <input type='checkbox' id='node-input-emptyMsgOnFail' style='max-width:30px'> </div> <div class='form-row'>
<label style='min-width:190px' for='node-input-keepMsgProperties'><i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.keepMsgProperties'></span></label> <input type='checkbox'
id='node-input-keepMsgProperties' style='max-width:30px'> </div> <div class='form-row'> <label style='min-width:190px'
for='node-input-showStatusActivities'><i class='fa fa-th'></i> <span data-i18n='modbus-contrib.label.showActivities'>
</span></label> <input type='checkbox' id='node-input-showStatusActivities' style='max-width:30px'> </div> <div
class='form-row'> <label style='min-width:190px' for='node-input-showErrors'><i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.showErrors'></span></label> <input type='checkbox' id='node-input-showErrors'
style='max-width:30px'> </div> <div class='form-row'> <label style='min-width:190px' for='node-input-showWarnings'><i
class='fa fa-th'></i> <span data-i18n='modbus-contrib.label.showWarnings'></span></label> <input type='checkbox'
checked='checked' id='node-input-showWarnings' style='max-width:30px'> </div> <hr> <div class='form-row'> <label
style='min-width:190px' for='node-input-useIOFile'><i class='fa fa-file-code-o'></i> <span
data-i18n='modbus-contrib.label.useIOFile'></span></label> <input type='checkbox' id='node-input-useIOFile'
style='max-width:30px'> </div> <div id='modbusiofile-row'> <div class='form-row'> <label style='min-width:190px'
for='node-input-logIOActivities'><i class='fa fa-th'></i> <span data-i18n='modbus-contrib.label.logIOActivities'></span>
</label> <input type='checkbox' id='node-input-logIOActivities' style='max-width:30px'> </div> <div class='form-row'>
<label style='min-width:190px' for='node-input-useIOForPayload'><i class='fa fa-comment-o'></i> <span
data-i18n='modbus-contrib.label.useIOForPayload'></span></label> <input type='checkbox' id='node-input-useIOForPayload'
style='max-width:30px'> </div> <div class='form-row'> <label for='node-input-ioFile'><i class='icon-file'></i> <span
data-i18n='modbus-contrib.label.ioFile'></span></label> <input type='text' id='node-input-ioFile'> </div> </div> </div>
</div> </script> <script type='text/x-red' data-help-name='modbus-flex-sequencer'>
<p> Modbus TCP/Serial flexible input triggered auto-sequence read node with connection input parameters. </p> <p>
Connects to a Modbus TPC or serial to read coils/inputs/registers automatically in sequence. </p> <p>
Use any input to trigger the request but you can override the list using: </p> <code> msg.sequences </code> <p>
<strong>Function codes (1:4) currently supported include:</strong> </p><ul> <li>FC 1: Read Coil Status</li> <li>
FC 2: Read Input Status</li> <li>FC 3: Read Holding Registers</li> <li>FC 4: Read Input Registers</li> </ul> <p></p> <p>
<strong>Input parameter for connecting Modbus</strong> </p><ul> <li>
(mixed) fc ('FC1', 'FC2', 'FC3', 'FC4' - Or - 1:4) - Function Code</li> <li>
(integer) unitid (0..255 tcp | 0..247 serial) - Unit-ID</li> <li>(integer) address (0:65535) - The starting address</li>
<li>(integer) quantity (1:65535) - The quantity of coils/inputs/registers to be read from the starting address</li>
</ul> <p></p> <p>Output 1: data Array (PDU), modbus response Buffer, input message</p> <p>
Output 2: modbus response Buffer, data Array (PDU), input message</p> <p>Function node code example for single input:
</p> <code> msg.sequences = [ { name : "Foo", fc : 1, address : 1, unitid: 2, quantity : 6 }] return msg; </code> <p>
Function node code example for multiple inputs:</p> <code>
msg.sequences = [ { name : "Foo", fc : 1, address : 1, unitid: 2, quantity : 6 }, { name : "Bar", fc : 3, address : 0, unitid: 1, quantity : 10 }, { name : "Baz", fc : 'FC4', address : 10, unitid: 3, quantity : 46 }] return msg;
</code> </script>