UNPKG

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
<!-- 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>