node-red-contrib-modbus
Version:
The all in one Modbus TCP and Serial contribution long term supported package for Node-RED.
327 lines (295 loc) • 18.2 kB
HTML
<!--
Copyright (c) since the year 2016 Klaus Landsdorf (http://plus4nodered.com/)
Copyright 2016 - Jason D. Harper, Argonne National Laboratory
Copyright 2015,2016 - Mika Karaila, Valmet Automation Inc.
All rights reserved.
node-red-contrib-modbus
@author <a href="mailto:klaus.landsdorf@bianco-royal.de">Klaus Landsdorf</a> (Bianco Royal)
--> <script type='text/javascript'> RED.nodes.registerType('modbus-client', {
category: 'config',
defaults: {
name: {value: ''},
clienttype: {value: 'tcp', required: true},
bufferCommands: {value: true},
stateLogEnabled: {value: false},
queueLogEnabled: {value: false},
failureLogEnabled: {value: true},
tcpHost: {value: '127.0.0.1', required: true},
tcpPort: {value: 502, required: true, validate: RED.validators.number()},
tcpType: {value: 'DEFAULT', required: true},
serialPort: {value: '/dev/ttyUSB', required: true},
serialType: {value: 'RTU-BUFFERD', required: true},
serialBaudrate: {value: 9600, required: true, validate: RED.validators.number()},
serialDatabits: {value: 8, required: true, validate: RED.validators.number()},
serialStopbits: {value: 1, required: true, validate: RED.validators.number()},
serialParity: {value: 'none', required: true},
serialConnectionDelay: {value: 100},
serialAsciiResponseStartDelimiter: {value: '0x3A'},
unit_id: {value: 1},
commandDelay: {value: 1},
clientTimeout: {value: 1000},
reconnectOnTimeout: {value: true},
reconnectTimeout: {value: 2000},
parallelUnitIdsAllowed: {value: true},
showErrors: {value: false},
showWarnings: {value: true},
showLogs: {value: true}
},
label: function () {
let node = this
if (node.clienttype == 'tcp') {
return node.name || 'modbus-tcp@' + node.tcpHost + ':' + node.tcpPort
} else {
return node.name || 'modbus-serial@' + node.serialPort + ':' + node.serialBaudrate
}
},
oneditprepare: function () {
let previous = null
let node = this
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-queues-tab",
label: this._("modbus-contrib.tabs-label.queues")
})
tabs.addTab({
id: "modbus-options-tab",
label: this._("modbus-contrib.tabs-label.options")
})
node.ports = []
let clientTypeSelector = $('#node-config-input-clienttype')
let serialTypeSelector = $('#node-config-input-serialType')
let inputsSerial = $('#node-inputs-modbus-serial')
let inputsSerialExtras = $('#node-inputs-modbus-serial-extras')
let inputsAsciiExtras = $('#node-inputs-ascii-extras')
let inputsTCP = $('#node-inputs-modbus-tcp')
clientTypeSelector.on('focus', function () {
previous = this.value
}).change(function () {
if (previous == null) {
previous = $('#node-config-input-clienttype').val()
}
if (node.unit_id) {
node.unit_id = parseInt(node.unit_id)
}
if (node.commandDelay) {
node.commandDelay = parseInt(node.commandDelay)
}
if (node.clientTimeout) {
node.clientTimeout = parseInt(node.clientTimeout)
}
if (node.reconnectTimeout) {
node.reconnectTimeout = parseInt(node.reconnectTimeout)
}
switch (clientTypeSelector.val()) {
case 'tcp':
inputsSerialExtras.hide()
inputsSerial.hide()
inputsTCP.show()
if (node.tcpHost) {
node.tcpHost.required = true
node.tcpPort.required = true
if (node.tcpType) {
node.tcpType.required = true
}
}
if (node.serialPort) {
node.serialPort.required = false
if (node.serialType) {
node.serialType.required = false
}
node.serialBaudrate.required = false
}
if (node.serialDatabits) {
node.serialDatabits.required = false
node.serialStopbits.required = false
node.serialParity.required = false
}
break
case 'serial':
case 'simpleser':
if (clientTypeSelector.val() === 'simpleser') {
inputsSerialExtras.hide()
node.serialDatabits.value = 8
node.serialStopbits.value = 1
node.serialParity.value = 'none'
} else {
inputsSerialExtras.show()
}
inputsSerial.show()
inputsTCP.hide()
if (node.tcpHost) {
node.tcpHost.required = false
node.tcpPort.required = false
if (node.tcpType) {
node.tcpType.required = false
}
}
if (node.serialPort) {
node.serialPort.required = true
if (node.serialType) {
node.serialType.required = true
}
node.serialBaudrate.required = true
}
if (node.serialDatabits) {
node.serialDatabits.required = true
node.serialStopbits.required = true
node.serialParity.required = true
}
break
default:
break
}
})
serialTypeSelector.on('focus').change(function () {
if (serialTypeSelector.val() === 'ASCII') {
inputsAsciiExtras.show()
if (node.serialAsciiResponseStartDelimiter) {
node.serialAsciiResponseStartDelimiter = node.serialAsciiResponseStartDelimiter
}
} else {
inputsAsciiExtras.hide()
}
})
try {
$('#node-config-input-serialPort').autocomplete('destroy')
}
catch (err) {
}
$('#node-config-lookup-serial').click(function () {
$('#node-config-lookup-serial').addClass('disabled')
$.getJSON('modbus/serial/ports', function (data) {
$('#node-config-lookup-serial').removeClass('disabled')
node.ports = []
$.each(data, function (i, port) {
node.ports.push(port.path)
})
$('#node-config-input-serialPort').autocomplete({
source: node.ports,
minLength: 0,
close: function (event, ui) {
$('#node-config-input-serialPort').autocomplete('destroy')
}
}).autocomplete('search', '')
})
})
}
}) </script> <script type='text/x-red' data-template-name='modbus-client'>
<div class='form-row'> <ul style='background:#fff;min-width:600px;margin-bottom:20px' id='node-input-modbus-tabs'></ul>
</div> <div id='node-input-tabs-content' style='min-height:170px'> <div id='modbus-settings-tab' style='display:none'>
<div class='form-row'> <label for='node-config-input-name'><i class='icon-tag'></i> <span
data-i18n='node-red:common.label.name'></span></label> <input type='text' id='node-config-input-name'
placeholder='Name'> </div> <div class='form-row'> <label for='node-config-input-clienttype'><i class='icon-bookmark'>
</i> <span data-i18n='modbus-contrib.label.type'></span></label> <select type='text' id='node-config-input-clienttype'
style='width:140px'> <option value='tcp' select>TCP</option> <option value='simpleser'>Serial</option> <option
value='serial'>Serial Expert</option> </select> </div> <hr> <div id='node-inputs-modbus-tcp'> <div class='form-row'>
<label for='node-config-input-tcpHost'><i class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.host'></span>
</label> <input type='text' id='node-config-input-tcpHost'> </div> <div class='form-row'> <label
for='node-config-input-tcpPort'><i class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.port'></span>
</label> <input type='text' id='node-config-input-tcpPort' placeholder='502'> </div> <div class='form-row'> <label
for='node-config-input-tcpType'><i class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.tcpType'></span>
</label> <select type='text' id='node-config-input-tcpType' style='width:140px'> <option value='DEFAULT' select>DEFAULT
</option> <option value='TCP-RTU-BUFFERED'>RTU-BUFFERED</option> <option value='TELNET'>TELNET</option> <option
value='C701'>C701</option> </select> </div> </div> <div id='node-inputs-modbus-serial'> <div class='form-row'> <label
for='node-config-input-serialPort'><i class='fa fa-random'></i> <span data-i18n='modbus-contrib.label.serialport'>
</span></label> <input type='text' id='node-config-input-serialPort' style='width:60%'
placeholder='/dev/ttyUSB or COM4'> <a id='node-config-lookup-serial' class='red-ui-button'><i
id='node-config-lookup-serial-icon' class='fa fa-search'></i></a> </div> <div class='form-row'> <label
for='node-config-input-serialType'><i class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.serialType'>
</span></label> <select type='text' id='node-config-input-serialType' style='width:140px'> <option value='RTU-BUFFERD'
select>RTU-BUFFERD</option> <option value='RTU'>RTU</option> <option value='ASCII'>ASCII</option> </select> </div> <div
class='form-row'> <label for='node-config-input-serialBaudrate'><i class='icon-bookmark'></i> <span
data-i18n='modbus-contrib.label.baudRate'></span></label> <select id='node-config-input-serialBaudrate'
style='max-width:140px'> <option value='115200'>115200</option> <option value='57600'>57600</option> <option
value='38400'>38400</option> <option value='19200'>19200</option> <option value='9600'>9600</option> <option
value='4800'>4800</option> <option value='2400'>2400</option> <option value='1200'>1200</option> <option value='300'>300
</option> <option value='110'>110</option> <option value='75'>75</option> </select> </div> </div> <div
id='node-inputs-modbus-serial-extras'> <div class='form-row'> <label for='node-config-input-serialDatabits'><i
class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.dataBits'></span></label> <select
id='node-config-input-serialDatabits' style='max-width:80px'> <option value='8'>8</option> <option value='7'>7</option>
<option value='6'>6</option> <option value='5'>5</option> </select> </div> <div class='form-row'> <label
for='node-config-input-serialStopbits'><i class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.stopBits'>
</span></label> <select id='node-config-input-serialStopbits' style='max-width:80px'> <option value='1'>1</option>
<option value='1.5'>1.5</option> <option value='2'>2</option> </select> </div> <div class='form-row'> <label
for='node-config-input-serialParity'><i class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.parity'></span>
</label> <select id='node-config-input-serialParity' style='max-width:80px'> <option value='none'>None</option> <option
value='even'>Even</option> <option value='mark'>Mark</option> <option value='odd'>Odd</option> <option value='space'>
Space</option> </select> </div> <div class='form-row'> <label for='node-config-input-serialConnectionDelay'> <i
class='fa fa-random'></i> <span data-i18n='modbus-contrib.label.serialconnectiondelay'></span> </label> <input
type='text' id='node-config-input-serialConnectionDelay' style='max-width:80px' placeholder='500'> </div> </div> <div
id='node-inputs-ascii-extras'> <div class='form-row'> <label for='node-config-input-serialAsciiResponseStartDelimiter'>
<i class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.serialAsciiResponseStartDelimiter'></span></label>
<input type='text' id='node-config-input-serialAsciiResponseStartDelimiter' style='max-width:80px'
placeholder='0x3A (:)'> </div> </div> <hr> <div class='form-row'> <label for='node-config-input-unit_id'><i
class='icon-bookmark'></i> <span data-i18n='modbus-contrib.label.unitId'></span></label> <input type='text'
id='node-config-input-unit_id' style='max-width:80px'> </div> <div class='form-row'> <label
for='node-config-input-clientTimeout'><i class='icon-time'></i> <span data-i18n='modbus-contrib.label.timeout'></span>
</label> <input type='text' id='node-config-input-clientTimeout' placeholder='1000' style='max-width:80px'> </div> <div
class='form-row'> <label style='min-width:190px' for='node-config-input-reconnectOnTimeout'><i class='fa fa-th'></i>
<span data-i18n='modbus-contrib.label.reconnectOnTimeout'></span></label> <input type='checkbox'
id='node-config-input-reconnectOnTimeout' style='max-width:30px'> </div> <div class='form-row'> <label
for='node-config-input-reconnectTimeout'> <i class='icon-time'></i> <span
data-i18n='modbus-contrib.label.reconnectTimeout'></span> </label> <input type='text'
id='node-config-input-reconnectTimeout' placeholder='2000' style='max-width:80px'> </div> </div> <div
id='modbus-queues-tab' style='display:none'> <div class='form-row'> <label style='min-width:190px'
for='node-config-input-parallelUnitIdsAllowed'><i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.parallelUnitIdsAllowed'></span></label> <input type='checkbox'
id='node-config-input-parallelUnitIdsAllowed' style='max-width:30px'> <span class='tooltip-text'
data-i18n='modbus-contrib.label.parallelUnitIdsAllowedInfo'></span> </div> <div class='form-row'> <label
style='min-width:190px' for='node-config-input-queueLogEnabled'> <i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.queueLogEnabled'></span> </label> <input type='checkbox'
id='node-config-input-queueLogEnabled' style='max-width:30px'> </div> <div class='form-row'> <label
style='min-width:190px' for='node-config-input-bufferCommands'><i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.queueCommands'></span></label> <input type='checkbox'
id='node-config-input-bufferCommands' style='max-width:30px'> </div> <div class='form-row'> <label
style='min-width:190px' for='node-config-input-commandDelay'><i class='icon-time'></i> <span
data-i18n='modbus-contrib.label.commandDelay'></span></label> <input type='text' id='node-config-input-commandDelay'
placeholder='1' style='max-width:80px'> </div> </div> <div id='modbus-options-tab' style='display:none'> <div
class='form-row'> <label style='min-width:190px' for='node-config-input-stateLogEnabled'> <i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.stateLogEnabled'></span> </label> <input type='checkbox'
id='node-config-input-stateLogEnabled' style='max-width:30px'> </div> <div class='form-row'> <label
style='min-width:190px' for='node-config-input-failureLogEnabled'> <i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.failureLogEnabled'></span> </label> <input type='checkbox'
id='node-config-input-failureLogEnabled' style='max-width:30px'> </div> <div class='form-row'> <label
style='min-width:190px' for='node-config-input-showErrors'><i class='fa fa-th'></i> <span
data-i18n='modbus-contrib.label.showErrors'></span></label> <input type='checkbox' id='node-config-input-showErrors'
style='max-width:30px'> </div> <div class='form-row'> <label style='min-width:190px'
for='node-config-input-showWarnings'><i class='fa fa-th'></i> <span data-i18n='modbus-contrib.label.showWarnings'>
</span></label> <input type='checkbox' checked='checked' id='node-config-input-showWarnings' style='max-width:30px'>
</div> <div class='form-row'> <label style='min-width:190px' for='node-config-input-showLogs'><i class='fa fa-th'></i>
<span data-i18n='modbus-contrib.label.showLogs'></span></label> <input type='checkbox' checked='checked'
id='node-config-input-showLogs' style='max-width:30px'> </div> </div> </div> </script> <script type='text/x-red'
data-help-name='modbus-client'> <p><strong>
If you have many nodes on this communication (see configuration nodes), think about multiple connections to your Modbus device, please! Many devices are able to connecting multiple.
</strong></p> <p> Add a catch to your flow: <pre>
[{"id":"cdd076d5.dab728","type":"catch","z":"b245d3e4.b52de","name":"","scope":null,"x":1020,"y":40,
"wires":[["8516d63d.1c29a8"]]},{"id":"8516d63d.1c29a8","type":"debug","z":"b245d3e4.b52de","name":"",
"active":true,"console":"false","complete":"true","x":1170,"y":40,"wires":[]}]
</pre> </p> <p>
Uses ModbusRTU ('modbus-serial') to read/write by ethernet host:port or TTY register/coil/input addresses.</p> <p>
The Xstate machine ('Xstate/fsm') organizing the states to work with reconnects and a queue of commands.</p> <p> </p>
<h3>Basics</h3> <ul> <li>Type (TCP/Serial)</li> <li>
Queue commands (true/false) - with true it buffers incoming Modbus commands and send them with delay</li> <li>
Queue Work Delay (default 0 ms) - ms interval to delay sending commands from queue (sumOfWaiting=requestsPerCycle*delay)
</li> <li>
Unit-ID (default 1 [serial] or 0 [tcp]) - to set one Unit-ID for all nodes without Unit-ID. Set the Unit-ID of the Read/Write/Getter node's to empty for using this ID
</li> <li>Timeout (default 1000 ms) - ms for the command timeout on ModbusRTU command</li> <li>
Reconnect timeout (default 2000 ms) - time to wait on reconnect before next sending</li> <li>
Reconnect on timeout - should the client do a reconnect or not on timeouts</li> <li>
Parallel UnitId's allowed - handle commands in parallel per UnitId or not</li> </ul> <h3>TCP</h3> <ul> <li>
Host - IP address</li> <li>Port (default 502)</li> </ul> <h3>Serial</h3> <ul> <li>
Serial Port (/dev/tty.usbserial | COM[1..n])</li> <li>Serial Baud rate</li> <li>Serial Databits</li> <li>Serial Stopbits
</li> <li>Serial Parity</li> <li>Serial Type</li> <li>
Serial Connection delay (default 500 ms) - time to delay first command sending after reconnect</li> <li>
ASCII start delimiter (default 0x3A, colon) - Delemiter used to identify start of slave response</li> </ul> <p></p>
</script>