diff --git a/io/serialport/25-serial.html b/io/serialport/25-serial.html index 30469ddd7..39e40cc69 100644 --- a/io/serialport/25-serial.html +++ b/io/serialport/25-serial.html @@ -213,8 +213,15 @@
- + +
+
+ + + + +
@@ -245,7 +252,9 @@ bin: {value:"false"}, out: {value:"char"}, addchar: {value:""}, - responsetimeout: {value: 10000} + responsetimeout: {value: 10000}, + serialReconnectTime: {value: ""}, + autoConnect: {value: true} }, label: function() { this.serialbaud = this.serialbaud || 57600; @@ -255,6 +264,13 @@ return this.serialport+":"+this.serialbaud+"-"+this.databits+this.parity.charAt(0).toUpperCase()+this.stopbits; }, oneditprepare: function() { + if(typeof this.autoConnect === "undefined"){ this.autoConnect = true; } + var defReconnectTime = RED.settings.serialReconnectTime || 15000; + $('#node-config-input-serialReconnectTime').attr('placeholder',Math.round(defReconnectTime/1000)); + var reconnectms = $('#node-config-input-serialReconnectTime').val(); + if(reconnectms){ + $('#node-config-input-serialReconnectTime').val(Math.round(reconnectms/1000)); + } var previous = null; var blist = [ {value:"230400",label:"230400",hasValue:false}, @@ -353,6 +369,11 @@ }); }, oneditsave: function() { + var reconnectms = $('#node-config-input-serialReconnectTime').val(); + if(reconnectms){ + $('#node-config-input-serialReconnectTime').val(reconnectms*1000); + } + var mytype = $("#node-config-input-serialbaud").typedInput('type'); if (mytype !== "other") { $("#node-config-input-serialbaud").typedInput('value',mytype); diff --git a/io/serialport/25-serial.js b/io/serialport/25-serial.js index 64093ceb9..4a10d8b92 100644 --- a/io/serialport/25-serial.js +++ b/io/serialport/25-serial.js @@ -5,7 +5,6 @@ module.exports = function(RED) { var events = require("events"); const { SerialPort } = require('serialport'); var bufMaxSize = 32768; // Max serial buffer size, for inputs... - const serialReconnectTime = settings.serialReconnectTime || 15000; // TODO: 'serialPool' should be encapsulated in SerialPortNode @@ -27,6 +26,8 @@ module.exports = function(RED) { this.out = n.out || "char"; this.waitfor = n.waitfor || ""; this.responsetimeout = n.responsetimeout || 10000; + this.serialReconnectTime = n.serialReconnectTime || settings.serialReconnectTime || 15000; + this.autoConnect = (typeof n.autoConnect === "undefined")? true : n.autoConnect; } RED.nodes.registerType("serial-port",SerialPortNode); @@ -42,7 +43,16 @@ module.exports = function(RED) { node.port = serialPool.get(this.serialConfig); node.on("input",function(msg) { - if (msg.hasOwnProperty("baudrate")) { + if (msg.hasOwnProperty("action") && this.serialConfig) { + if(msg.action == "disconnect"){ + serialPool.disconnect(this.serialConfig.serialport); + node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"}); + }else if(msg.action == "connect"){ + serialPool.connect(this.serialConfig.serialport); + } + return; + } + if (msg.hasOwnProperty("baudrate")) { var baud = parseInt(msg.baudrate); if (isNaN(baud)) { node.error(RED._("serial.errors.badbaudrate"),msg); @@ -135,6 +145,15 @@ module.exports = function(RED) { node.port = serialPool.get(this.serialConfig); // Serial Out node.on("input",function(msg) { + if (msg.hasOwnProperty("action") && this.serialConfig) { + if(msg.action == "disconnect"){ + serialPool.disconnect(this.serialConfig.serialport); + node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"}); + }else if(msg.action == "connect"){ + serialPool.connect(this.serialConfig.serialport); + } + return; + } if (msg.hasOwnProperty("baudrate")) { var baud = parseInt(msg.baudrate); if (isNaN(baud)) { @@ -255,11 +274,17 @@ module.exports = function(RED) { var obj = { _emitter: new events.EventEmitter(), serial: null, + isOpen: false, + forceDc: false, + autoConnect: serialConfig.autoConnect, + _autoConnect: serialConfig.autoConnect, _closing: false, tout: null, queue: [], on: function(a,b) { this._emitter.on(a,b); }, close: function(cb) { this.serial.close(cb); }, + connect: function() { setupSerial(); }, + disconnect: function(cb) { this.serial.close(cb); }, encodePayload: function (payload) { if (!Buffer.isBuffer(payload)) { if (typeof payload === "object") { @@ -350,30 +375,38 @@ module.exports = function(RED) { olderr = err.toString(); RED.log.error("[serialconfig:"+serialConfig.id+"] "+RED._("serial.errors.error",{port:port,error:olderr}), {}); } - obj.tout = setTimeout(function() { - setupSerial(); - }, serialReconnectTime); + if(obj._autoConnect){ + obj.tout = setTimeout(function() { + setupSerial(); + }, serialConfig.serialReconnectTime); + } } }); obj.serial.on('error', function(err) { RED.log.error("[serialconfig:"+serialConfig.id+"] "+RED._("serial.errors.error",{port:port,error:err.toString()}), {}); obj._emitter.emit('closed'); + obj.isOpen = false; if (obj.tout) { clearTimeout(obj.tout); } - obj.tout = setTimeout(function() { - setupSerial(); - }, serialReconnectTime); + if(obj._autoConnect){ + obj.tout = setTimeout(function() { + setupSerial(); + }, serialConfig.serialReconnectTime); + } }); obj.serial.on('close', function() { if (!obj._closing) { - if (olderr !== "unexpected") { + if (olderr !== "unexpected" && obj.forceDc == false) { olderr = "unexpected"; RED.log.error("[serialconfig:"+serialConfig.id+"] "+RED._("serial.errors.unexpected-close",{port:port}), {}); } + obj.isOpen = false; obj._emitter.emit('closed'); - if (obj.tout) { clearTimeout(obj.tout); } - obj.tout = setTimeout(function() { - setupSerial(); - }, serialReconnectTime); + if(obj._autoConnect){ + if (obj.tout) { clearTimeout(obj.tout); } + obj.tout = setTimeout(function() { + setupSerial(); + }, serialConfig.serialReconnectTime); + } } }); obj.serial.on('open',function() { @@ -388,6 +421,7 @@ module.exports = function(RED) { if (dtr != "none" || rts != "none" || cts != "none" || dsr != "none") { obj.serial.set(flags); } if (obj.tout) { clearTimeout(obj.tout); obj.tout = null; } //obj.serial.flush(); + obj.isOpen = true; obj._emitter.emit('ready'); }); @@ -483,6 +517,22 @@ module.exports = function(RED) { else { done(); } + }, + connect: function(port) { + if (connections[port] && connections[port].isOpen == false ) { + connections[port]._autoConnect = connections[port].autoConnect; // restore original auto connect config + connections[port].connect(); + } + }, + disconnect: function(port) { + if (connections[port] && connections[port].isOpen == true) { + connections[port]._autoConnect = false; // disable auto connect on manual disconnect + connections[port].forceDc = true; // to prevent logging as an unexpected error + connections[port].disconnect(function() { + RED.log.info(RED._("serial.errors.closed",{port:port}), {}); + connections[port].forceDc = false; + }); + } } } }()); diff --git a/io/serialport/locales/en-US/25-serial.html b/io/serialport/locales/en-US/25-serial.html index 9094acce7..740b15a96 100644 --- a/io/serialport/locales/en-US/25-serial.html +++ b/io/serialport/locales/en-US/25-serial.html @@ -32,6 +32,8 @@

Inputs

data to be sent via the serial port
baudrate string
baudrate of the serial port (optional)
+
action string
+
disconnect/reconnect the serial port eg. {action:"connect"} or {action:"disconnect"}(optional)

Only the msg.payload is sent.

Optionally the baudrate can be changed using msg.baudrate.

@@ -62,6 +64,7 @@

Inputs

  • msg.waitfor must be a single character, escape code, or hex code. If set, the node will wait until it matches that character in the stream and then start the output.
  • Optionally the baudrate can be changed using msg.baudrate
  • +
  • msg.action disconnect/reconnect the serial port eg. {action:"connect"} or {action:"disconnect"} (optional)
  • Outputs