Tidy up PR, add status to control nodes

tweak help, readme, and feed stopped status to other nodes.
This commit is contained in:
Dave Conway-Jones 2023-11-23 12:11:59 +00:00
parent 2ddb6037c6
commit 2e52257afa
No known key found for this signature in database
GPG Key ID: 1DDB0E91A28C2643
5 changed files with 100 additions and 76 deletions

View File

@ -25,10 +25,10 @@ module.exports = function(RED) {
this.dsr = n.dsr || "none";
this.bin = n.bin || "false";
this.out = n.out || "char";
this.enable = n.enable || true;
this.enabled = n.enabled || true;
this.waitfor = n.waitfor || "";
this.responsetimeout = n.responsetimeout || 10000;
this.changePort = (serialPort) => {
serialPool.close(this.serialport,() => {});
this.serialport = serialPort.serialport || this.serialport;
@ -95,6 +95,9 @@ module.exports = function(RED) {
node.port.on('closed', function() {
node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"});
});
node.port.on('stopped', function() {
node.status({fill:"grey",shape:"ring",text:"serial.status.stopped"});
});
}
RED.nodes.registerType("serial out",SerialOutNode);
@ -117,7 +120,7 @@ module.exports = function(RED) {
this.on("close", function(done) {
serialPool.close(this.serialConfig.serialport,done);
});
});
function setCallback(node) {
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.not-connected"});
@ -132,13 +135,16 @@ module.exports = function(RED) {
node.port.on('closed', function() {
node.status({fill:"red",shape:"ring",text:"node-red:common.status.not-connected"});
});
node.port.on('stopped', function() {
node.status({fill:"grey",shape:"ring",text:"serial.status.stopped"});
});
};
setCallback(node)
}
RED.nodes.registerType("serial in",SerialInNode);
/******* REQUEST *********/
// request data and waits for reply
function SerialRequestNode(n) {
RED.nodes.createNode(this,n);
this.serial = n.serial;
@ -197,13 +203,15 @@ module.exports = function(RED) {
node.status({ fill: "red", shape: "ring", text: "serial.status.timeout" });
node.send(msgout);
});
node.port.on('ready', function () {
node.status({ fill: "green", shape: "dot", text: "node-red:common.status.connected" });
});
node.port.on('closed', function () {
node.status({ fill: "red", shape: "ring", text: "node-red:common.status.not-connected" });
});
node.port.on('stopped', function() {
node.status({fill:"grey",shape:"ring",text:"serial.status.stopped"});
});
};
setCallback(node);
}
@ -223,11 +231,11 @@ module.exports = function(RED) {
RED.nodes.registerType("serial request", SerialRequestNode);
// Serial Control Node
function PortSelectNode(n) {
// control node to stop, start, reconfigure ports
function SerialControlNode(n) {
const configProps = [
"serialport", "serialbaud", "databits", "parity", "stopbits",
"dtr", "rts", "cts", "dsr", "bin", "out"
"dtr", "rts", "cts", "dsr"
]
RED.nodes.createNode(this,n);
this.serialConfig = RED.nodes.getNode(n.serial);
@ -239,32 +247,43 @@ module.exports = function(RED) {
this.serial = n.serial;
var node = this;
node.port = serialPool.get(this.serialConfig);
node.port = serialPool.get(node.serialConfig);
node.port.on('stopped', function() {
node.status({fill:"grey",shape:"ring",text:"serial.status.stopped"});
});
node.port.on('ready', function() {
node.status({fill:"green",shape:"dot",text:node.serialConfig.serialbaud+","+node.serialConfig.databits+","+(node.serialConfig.parity.toUpperCase().substr(0,1))+","+node.serialConfig.stopbits});
});
node.on("input",function(msg) {
if (configProps.some((p) =>{return msg.payload.hasOwnProperty(p)})) {
msg.payload.enable = msg.payload.hasOwnProperty('enable') ? msg.payload.enable : true;
if (msg.hasOwnProperty("flush") && msg.flush === true) { node.port.serial.flush(); }
if (configProps.some((p) => { return msg.payload.hasOwnProperty(p) })) {
msg.payload.enabled = msg.payload.hasOwnProperty('enabled') ? msg.payload.enabled : true;
node.serialConfig.changePort(msg.payload);
}
if (msg.payload.hasOwnProperty("enable")) {
// if any of config parameters or enable property is passed, do this control
node.serialConfig.enable = msg.payload.enable;
if (msg.payload.enable === true) {
var stat = {fill:"green",shape:"dot",text:node.serialConfig.serialbaud+","+node.serialConfig.databits+","+(node.serialConfig.parity.toUpperCase().substr(0,1))+","+node.serialConfig.stopbits}
if (msg.payload.hasOwnProperty("enabled")) {
node.serialConfig.enabled = msg.payload.enabled;
if (msg.payload.enabled === true || msg.payload.enabled === "true") {
node.serialConfig.emit('start');
} else {
}
else {
serialPool.close(node.serialConfig.serialport,() => {
RED.log.info("[serialconfig:"+node.serialConfig.id+"] " + RED._("serial.stopped",{port:node.serialConfig.serialport}));
});
stat.fill = "grey";
stat.shape = "ring";
}
}
let currentConfig = {};
configProps.map((p) => {
currentConfig[p] = node.serialConfig[p];
});
currentConfig.enable = node.serialConfig.enable;
node.send({payload: currentConfig});
currentConfig.enabled = node.serialConfig.enabled;
node.status(stat);
node.send({payload:currentConfig});
});
}
RED.nodes.registerType("serial control", PortSelectNode);
RED.nodes.registerType("serial control", SerialControlNode);
var serialPool = (function() {
var connections = {};
@ -442,6 +461,9 @@ module.exports = function(RED) {
setupSerial();
}, serialReconnectTime);
}
else {
obj._emitter.emit('stopped');
}
});
obj.serial.on('open',function() {
olderr = "";

View File

@ -18,7 +18,7 @@ you to install the full set of tools in order to compile the underlying package.
## Usage
Provides three nodes - one to receive messages, and one to send, and a request node which can send then wait for a response.
Provides four nodes - one to receive messages, and one to send, a request node which can send then wait for a response, and a control node that allows dynamic control of the ports in use.
### Input
@ -56,49 +56,47 @@ Send the request message in `msg.payload` as you would do with a serial out node
For consistency with the serial in node, msg.port is also set to the name of the port selected.
### Serial Control
When the node-red starts, the flow(program) picks up the pre-programmed serial port, open it, and start the communication. But there are some cases the port needs to switch to a different port, stop, and start again. For example, in order to upload a new binary for Arduino, the serial port needs to be stopped relased from the nodered, and start it again after uploading. Or when the FTDI device re-connects after disconnected for any reason, it may be possible the port number change, and the end user of the flow can't change the port.
### Control
When the node-red starts, the flow(program) picks up the pre-programmed serial port, open it, and starts the communication. But there are some cases the port needs to switch to a different port, stop, and start again. For example, in order to upload a new binary for Arduino, the serial port needs to be stopped relased from the nodered, and start it again after uploading. Or when the FTDI device re-connects after disconnecting for any reason, it may be possible that the port number changes, and the end user of the flow can't change the port.
This `Serial Control` node provides the serial port control capability to
1. change the serial port and its configuration on the run time programatically.
2. stop the communication and releasing the serial port so, for example the Arduino can upload the new binary without shutting down the nodered.
3. start the communication after stopped with this `Serial Control` node for above reason or the like.
This node provides the ability to:
1. change the serial port and its configuration on the run time programatically.
2. stop the communication and release the serial port.
3. reopen the port and restart the communications.
In order to control the communication, send a **msg.payload** to the control node.
<p>In order to control the communication, just send these JSON messages to the control node.</p>
<pre>
{
"serialport": "/dev/tty.usbmodem1234561",
"serialport": "/dev/ttyUSB0",
"serialbaud": 115200,
"databits": 8,
"parity": "none",
"stopbits": 1
"enable": true
}
</pre>
"stopbits": 1,
"enabled": true
}
changes the serial port and the configuration on the fly.
<p>The following optional parameters will change the configuration only if they are present.</p>
<p>Any combination of them can be passed to change/control the serial communication</p>
<ul>
<li> serialport </li>
<li> serialbaud </li>
<li> databits </li>
<li> parity </li>
<li> stopbits </li>
<li> dtr </li>
<li> rts </li>
<li> cts </li>
<li> dsr </li>
<li> bin </li>
<li> out </li>
<li> enable </li>
</ul>
When the `enable` property is not present, it will default to `true`
`{"enable":true}` or `{"enable":false}` will start or stop the communication.
The following optional parameters will change the configuration only if they are present.
Any combination of them can be passed to change/control the serial communication
If `enable` is passed along with other parameters, the configuration will be changed and the port will be either started or just be remaining ready to be started(ie. stopped) later depending on its value.
- serialport
- serialbaud
- databits
- parity
- stopbits
- dtr
- rts
- cts
- dsr
- enabled
**Here is the serial control node usage example flow**
If the `enabled` property is not present, it will default to `true`.
[{"id":"dc5438a9ae7a274f","type":"serial in","z":"e010d91f3c429066","name":"","serial":"b720bb12479b6ef1","x":290,"y":500,"wires":[["be0292cc1a1f5eed"]]},{"id":"be0292cc1a1f5eed","type":"debug","z":"e010d91f3c429066","name":"debug 21","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":880,"y":500,"wires":[]},{"id":"7a51f56281c210d5","type":"inject","z":"e010d91f3c429066","name":"{\\"parity\\":\\"even\\"}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"parity\\":\\"even\\"}","payloadType":"json","x":340,"y":760,"wires":[["ca56aab57eeaefb7"]]},{"id":"ca56aab57eeaefb7","type":"serial control","z":"e010d91f3c429066","name":"","serial":"b720bb12479b6ef1","x":710,"y":720,"wires":[["1288803f89da05fd"]]},{"id":"8b3826afb08ccb52","type":"inject","z":"e010d91f3c429066","name":"usbmodem1234561 / false","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"serialport\\":\\"/dev/tty.usbmodem1234561\\",\\"enable\\":false}","payloadType":"json","x":370,"y":640,"wires":[["ca56aab57eeaefb7"]]},{"id":"e67e73f72e8f1b5e","type":"inject","z":"e010d91f3c429066","name":"usbmodem1234561, 115200","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"serialport\\":\\"/dev/tty.usbmodem1234561\\",\\"serialbaud\\":115200,\\"databits\\":8,\\"parity\\":\\"none\\",\\"stopbits\\":1}","payloadType":"json","x":380,"y":560,"wires":[["ca56aab57eeaefb7"]]},{"id":"46dc99f3c72003eb","type":"inject","z":"e010d91f3c429066","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"enable\\":false}","payloadType":"json","x":340,"y":800,"wires":[["ca56aab57eeaefb7"]]},{"id":"d5221d388f00c998","type":"inject","z":"e010d91f3c429066","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"enable\\":true}","payloadType":"json","x":340,"y":840,"wires":[["ca56aab57eeaefb7"]]},{"id":"28c6b8f294b7642a","type":"inject","z":"e010d91f3c429066","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":320,"y":880,"wires":[["ca56aab57eeaefb7"]]},{"id":"9c377da93413a7e9","type":"inject","z":"e010d91f3c429066","name":"usbmodem1234561 / true","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"serialport\\":\\"/dev/tty.usbmodem1234561\\",\\"enable\\":true}","payloadType":"json","x":370,"y":600,"wires":[["ca56aab57eeaefb7"]]},{"id":"0c6388d6a25a762b","type":"inject","z":"e010d91f3c429066","name":"AC026GAO,57600","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"serialport\\":\\"/dev/tty.usbserial-AC026GAO\\",\\"serialbaud\\":57600,\\"databits\\":8,\\"parity\\":\\"none\\",\\"stopbits\\":1}","payloadType":"json","x":350,"y":680,"wires":[["ca56aab57eeaefb7"]]},{"id":"a8b80305a8c27174","type":"inject","z":"e010d91f3c429066","name":"{\\"parity\\":\\"none\\"}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\\"parity\\":\\"none\\"}","payloadType":"json","x":340,"y":720,"wires":[["ca56aab57eeaefb7"]]},{"id":"1288803f89da05fd","type":"debug","z":"e010d91f3c429066","name":"debug 23","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":880,"y":720,"wires":[]},{"id":"b720bb12479b6ef1","type":"serial-port","name":"s1","serialport":"/dev/tty.usbmodem1234561","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"\\n","bin":"false","out":"char","addchar":"","responsetimeout":"10000"}]
`{"enabled":true}` or `{"enabled":false}` will start or stop the communication.
If `enabled` is passed along with other parameters, the configuration will be changed and the port will be either started or remain stopped, ready to be started later depending on its value.
Any input message will cause the node to output the current port configuration.

View File

@ -97,28 +97,29 @@
<script type="text/html" data-help-name="serial control">
<p>Stops, starts the serial communication and changes the serial port configuration.</p>
<p>This node provides the serial port control capability to</p>
<p>This node provides the ability to:</p>
<ul>
<li>stop the communication and releasing the serial port so, for example the Arduino can upload the new binary without shutting down the nodered.</li>
<li>start the communication after stopped with this `Serial Control` node for above reason or the like.</li>
<li>change the serial port and the configuration on the run time programatically.</li>
<li>query the serial port configuration if empty or no valid configuration parameters are passed.</li>
<li>stop the communication and release the serial port.</li>
<li>reopen the port and restart the communications.</li>
<li>change the serial port and the configuration dynamically.</li>
<li>query the serial port configuration.</li>
</ul>
<h3>Inputs</h3>
<p>In order to control the communication, just send these JSON messages to the control node.</p>
<pre>
<p>In order to control the communication, just send <b>msg.payload</b> containing.</p>
<pre>
{
"serialport": "/dev/tty.usbmodem1234561",
"serialport": "/dev/ttyUSB0",
"serialbaud": 115200,
"databits": 8,
"parity": "none",
"stopbits": 1
"enable": true
}
</pre> changes the serial port and the configuration on the fly.
"stopbits": 1,
"enabled": true
}
</pre>
<p>The following optional parameters will change the configuration only if they are present.</p>
<p>Any combination of them can be passed to change/control the serial communication</p>
<p>Any combination of them can be passed to change/control the serial communication</p>
<ul>
<li> serialport </li>
<li> serialbaud </li>
@ -129,15 +130,14 @@
<li> rts </li>
<li> cts </li>
<li> dsr </li>
<li> bin </li>
<li> out </li>
<li> enable </li>
<li> enabled </li>
</ul>
<p>When the <code>enable</code> property is not present, it will default to <code>true</code></p>
<p>If the <code>enabled</code> property is not present, it will default to <code>true</code>.</p>
<p>
<code>{"enable":true}</code> or <code>{"enable":false}</code> will start or stop the communication.</p>
<p> If <code>enable</code> is passed along with other parameters, the configuration will be changed and either be started or just be ready to be started(ie. stopped ) depending on its value. </p>
<code>{"enabled":true}</code> or <code>{"enabled":false}</code> will start or stop the communication.</p>
<p>If <code>enabled</code> is passed along with other parameters, the configuration will be changed and the
port will be either started or remain stopped, ready to be started later depending on its value.</p>
<h3>Outputs</h3>
<p><code>msg.payload</code> is the response. It contains the serial port configuration</p>
<p><code>msg.payload</code> containing the serial port configuration.</p>
</script>

View File

@ -2,7 +2,8 @@
"serial": {
"status": {
"waiting": "waiting",
"timeout": "timeout"
"timeout": "timeout",
"stopped": "stopped"
},
"label": {
"serialport": "Serial Port",

View File

@ -23,5 +23,8 @@
"name": "Dave Conway-Jones",
"email": "dceejay@gmail.com",
"url": "http://nodered.org"
}
},
"contributors" : [
"@yhur"
]
}