Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serial port connect/disconnect, configurable reconnect time #1012

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 23 additions & 2 deletions io/serialport/25-serial.html
Expand Up @@ -213,8 +213,15 @@
</div>
<div class="form-row" style="padding-left:18px; margin-bottom:18px;">
<span data-i18n="serial.label.responsetimeout"></span>
<input type="text" id="node-config-input-responsetimeout" style="width:60px; height:28px;">
<input type="text" id="node-config-input-responsetimeout" style="width:90px; height:28px;">
<span data-i18n="serial.label.ms"></span>
</div>
<div class="form-row" style="margin-bottom:18px;">
<label for="node-config-input-autoConnect"><span data-i18n="serial.label.autoconnect"></span></label>
<input type="checkbox" id="node-config-input-autoConnect" style="width:auto; margin-bottom: 4px;"/>
<span data-i18n="serial.label.serialReconnectTime"></span>
<input type="number" id="node-config-input-serialReconnectTime" style="width:60px; height:28px;">
<span data-i18n="serial.label.sec"></span>
</div>
</div>
<div class="form-tips" id="tip-waitfor" hidden><span data-i18n="serial.tip.waitfor"></span></div>
Expand Down Expand Up @@ -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;
Expand All @@ -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},
Expand Down Expand Up @@ -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);
Expand Down
76 changes: 63 additions & 13 deletions io/serialport/25-serial.js
Expand Up @@ -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

Expand All @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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() {
Expand All @@ -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');
});

Expand Down Expand Up @@ -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;
});
}
}
}
}());
Expand Down
3 changes: 3 additions & 0 deletions io/serialport/locales/en-US/25-serial.html
Expand Up @@ -32,6 +32,8 @@ <h3>Inputs</h3>
<dd>data to be sent via the serial port</dd>
<dt class="optional">baudrate <span class="property-type">string</span></dt>
<dd>baudrate of the serial port (optional)</dd>
<dt class="optional">action <span class="property-type">string</span></dt>
<dd>disconnect/reconnect the serial port eg. {action:"connect"} or {action:"disconnect"}(optional)</dd>
</dl>
<p>Only the <code>msg.payload</code> is sent.</p>
<p>Optionally the baudrate can be changed using <code>msg.baudrate</code>.</p>
Expand Down Expand Up @@ -62,6 +64,7 @@ <h3>Inputs</h3>
<li><code>msg.waitfor</code> 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.</li>
<li>Optionally the baudrate can be changed using <code>msg.baudrate</code></li>
<li><code>msg.action</code> disconnect/reconnect the serial port eg. {action:"connect"} or {action:"disconnect"} (optional)</li>
</ul>
<h3>Outputs</h3>
<ul>
Expand Down
5 changes: 4 additions & 1 deletion io/serialport/locales/en-US/25-serial.json
Expand Up @@ -17,11 +17,14 @@
"output": "Output",
"request": "Request",
"responsetimeout": "Default response timeout",
"serialReconnectTime": "Reconnect After",
"ms": "ms",
"sec": "Seconds",
"serial": "serial",
"none": "none",
"start": "Optionally wait for a start character of",
"startor": ", then"
"startor": ", then",
"autoconnect": "Auto Connect"
},
"placeholder": {
"serialport": "for example: /dev/ttyUSB0/"
Expand Down