mirror of
https://github.com/node-red/node-red-nodes.git
synced 2025-12-26 23:16:47 +01:00
Update Arduino and tidy up
This commit is contained in:
@@ -4,21 +4,20 @@
|
|||||||
|
|
||||||
<script type="text/html" data-template-name="arduino-board">
|
<script type="text/html" data-template-name="arduino-board">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.search"></span></div>
|
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="arduino.label.name"></span></label>
|
||||||
|
<input type="text" id="node-config-input-name" style="width:60%;"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
<label for="node-config-input-device"><i class="fa fa-random"></i> <span data-i18n="arduino.label.port"></span></label>
|
<label for="node-config-input-device"><i class="fa fa-random"></i> <span data-i18n="arduino.label.port"></span></label>
|
||||||
<input type="text" id="node-config-input-device" style="width:60%;" data-i18n="[placeholder]arduino.placeholder.port"/>
|
<input type="text" id="node-config-input-device" style="width:60%;" data-i18n="[placeholder]arduino.placeholder.port"/>
|
||||||
<a id="node-config-lookup-serial" class="red-ui-button"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a>
|
<a id="node-config-lookup-serial" class="red-ui-button"><i id="node-config-lookup-serial-icon" class="fa fa-search"></i></a>
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.port"></span></div>
|
<div class="form-tips"><span data-i18n="[html]arduino.tip.port"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="arduino.label.name"></span></label>
|
|
||||||
<input type="text" id="node-config-input-name" style="width:60%;"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.otherboards"></span></div>
|
<div class="form-tips"><span data-i18n="[html]arduino.tip.otherboards"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-samplingInt"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.samplingInt"></span></label>
|
<label for="node-config-input-samplingInt" style="width:150px;"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.samplingInt"></span></label>
|
||||||
<input type="number" id="node-config-input-samplingInt" style="width:20%;" data-i18n="[placeholder]arduino.placeholder.samplingInt" min=10 max=65500 />
|
<input type="number" id="node-config-input-samplingInt" style="width:20%;" data-i18n="[placeholder]arduino.placeholder.samplingInt" min=10 max=65500 />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
@@ -30,55 +29,44 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
RED.nodes.registerType('arduino-board', {
|
RED.nodes.registerType('arduino-board',{
|
||||||
category: 'config',
|
category: 'config',
|
||||||
defaults: {
|
defaults: {
|
||||||
device : {value: "" , required: true },
|
device : {value: "" , required: true },
|
||||||
name : {value: "" , required: false},
|
name : {value: "" , required: false},
|
||||||
samplingInt: {value: 250 , required: false}, // will read analog inputs 4x / sec by default. Can be 19-65500
|
samplingInt: {value: 250 , required: false}, // will read analog inputs 4x / sec by default. Can be 19-65500
|
||||||
log2consol : {value: false, required: false}
|
log2consol : {value: false, required: false}
|
||||||
},
|
},
|
||||||
label: function() {
|
label: function() {
|
||||||
if (this.name !== "") return this.name
|
if (this.name !== "") return this.name
|
||||||
else return this.device || "firmata-board-" + this.id; // (bad naming :-( ) device should be: "port"
|
else return this.device || "firmata-board-" + this.id; // (bad naming :-( ) device should be: "port"
|
||||||
},
|
},
|
||||||
oneditprepare: function() {
|
oneditprepare: function() {
|
||||||
try {
|
try {
|
||||||
$("#node-config-input-device").autocomplete( "destroy" ); // Remove auto-complete functionality from an <input>.
|
$("#node-config-input-device").autocomplete( "destroy" );
|
||||||
} catch(err) { };
|
} catch(err) { };
|
||||||
|
|
||||||
$("#node-config-lookup-serial").click(async function() { // Board's serial port search function
|
$("#node-config-lookup-serial").click(function() { // Board's serial port search function
|
||||||
console.log("Serial Auto-search started.");
|
this.warn("Serial Auto-search started.");
|
||||||
$("#node-config-lookup-serial-icon").removeClass('fa-search').addClass('spinner');
|
$("#node-config-lookup-serial-icon").removeClass('fa-search');
|
||||||
$("#node-config-lookup-serial").addClass('disabled');
|
$("#node-config-lookup-serial-icon").addClass('spinner');
|
||||||
|
$("#node-config-lookup-serial") .addClass('disabled');
|
||||||
|
|
||||||
try {
|
$.getJSON('arduinoports', function(data) {
|
||||||
$.getJSON('arduinoports', async function(data, data2) {
|
this.warn('Serial Auto-search found data: %o', data);
|
||||||
console.log('Serial Auto-search found data: %o', data);
|
$("#node-config-lookup-serial-icon").removeClass('spinner');
|
||||||
console.log('Data2: %o', data2);
|
$("#node-config-lookup-serial") .removeClass('disabled');
|
||||||
|
$("#node-config-lookup-serial-icon").addClass('fa-search');
|
||||||
// UI Updates
|
let ports = data || [];
|
||||||
$("#node-config-lookup-serial-icon").removeClass('spinner').addClass('fa-search');
|
$("#node-config-input-device").autocomplete({
|
||||||
$("#node-config-lookup-serial").removeClass('disabled');
|
source: ports,
|
||||||
// Ensure ports is an array (fallback to empty array)
|
minLength: 0,
|
||||||
ports = data || [];
|
close: function( event, ui ) {
|
||||||
|
this.warn("Serial Auto-search closing.");
|
||||||
$("#node-config-input-device").autocomplete({
|
$("#node-config-input-device").autocomplete( "destroy" );
|
||||||
source: ports,
|
}
|
||||||
minLength: 0,
|
}).autocomplete("search", "");
|
||||||
close: function(event, ui) {
|
});
|
||||||
console.log("Serial Auto-search closing.");
|
|
||||||
$("#node-config-input-device").autocomplete("destroy");
|
|
||||||
}
|
|
||||||
}).autocomplete("search", "");
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching serial ports:', error);
|
|
||||||
|
|
||||||
// Reset UI on error
|
|
||||||
$("#node-config-lookup-serial-icon").removeClass('spinner').addClass('fa-search');
|
|
||||||
$("#node-config-lookup-serial").removeClass('disabled');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -89,6 +77,10 @@
|
|||||||
In - node
|
In - node
|
||||||
-->
|
-->
|
||||||
<script type="text/html" data-template-name="arduino in">
|
<script type="text/html" data-template-name="arduino in">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
|
||||||
|
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
|
||||||
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
|
<label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
|
||||||
<input type="text" id="node-input-arduino">
|
<input type="text" id="node-input-arduino">
|
||||||
@@ -102,20 +94,12 @@
|
|||||||
<option value="STRING" data-i18n="arduino.state.in.string"></option>
|
<option value="STRING" data-i18n="arduino.state.in.string"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.io"></span></div>
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.pin"></span></label>
|
<label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.pin"></span></label>
|
||||||
<input type="number" min="0" max="99" id="node-input-pin" style="width:20%;" placeholder="2">
|
<input type="number" min="0" max="99" id="node-input-pin" style="width:20%;" placeholder="2">
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.pin"></span></div>
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
|
|
||||||
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
|
|
||||||
</div>
|
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.more-at-help"></span></div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label><span data-i18n="[html]arduino.version"></span></label>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-tips"><span data-i18n="[html]arduino.tip.pin"></span></div>
|
||||||
|
<div class="form-tips"><span data-i18n="[html]arduino.tip.io"></span></div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@@ -159,7 +143,7 @@
|
|||||||
<p> </p>
|
<p> </p>
|
||||||
<p>[b]Type:[/b] Can be: [Digital in] / [Digital Pullup in] / [Analogue in] / [String]</p>
|
<p>[b]Type:[/b] Can be: [Digital in] / [Digital Pullup in] / [Analogue in] / [String]</p>
|
||||||
<p>[b]Pin:[/b] a number between 0 and the highest GPIO</p>
|
<p>[b]Pin:[/b] a number between 0 and the highest GPIO</p>
|
||||||
<p>[b]Warning:[/b] Analogue pins are counted from 0 ! (Not the actual GPIO port.) For example RPi-Pico: [0,1,2,3] where 3 is the built-in Temp reader.</p>
|
<p>[b]Warning:[/b] Analogue pins are counted from 0. (Not the actual GPIO port.) For example RPi-Pico: [0,1,2,3] where 3 is the built-in Temp reader.</p>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
|
|
||||||
<h3>The "in" node:</h3>
|
<h3>The "in" node:</h3>
|
||||||
@@ -169,7 +153,7 @@
|
|||||||
<p>The sampling interval (frequency), at which data is being collected and sent to host, is set on board's firmata side. If not, default value is: <b>19ms</b> </p>
|
<p>The sampling interval (frequency), at which data is being collected and sent to host, is set on board's firmata side. If not, default value is: <b>19ms</b> </p>
|
||||||
<p>The connection between the board(s) and the host can be Wifi, BlueTooth, USB.\n <i>(But the base protocol through those is: Serial port transfer. Default baudRate: 57600 .) Usually: USB port.</i></p>
|
<p>The connection between the board(s) and the host can be Wifi, BlueTooth, USB.\n <i>(But the base protocol through those is: Serial port transfer. Default baudRate: 57600 .) Usually: USB port.</i></p>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
|
|
||||||
<h3>Change Log + More info:</h3>
|
<h3>Change Log + More info:</h3>
|
||||||
<p> see: https://github.com/node-red/node-red-nodes/blob/master/hardware/Arduino/README.md </p>
|
<p> see: https://github.com/node-red/node-red-nodes/blob/master/hardware/Arduino/README.md </p>
|
||||||
</script>
|
</script>
|
||||||
@@ -177,6 +161,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<script type="text/html" data-template-name="arduino out">
|
<script type="text/html" data-template-name="arduino out">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
|
||||||
|
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
|
||||||
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
|
<label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
|
||||||
<input type="text" id="node-input-arduino">
|
<input type="text" id="node-input-arduino">
|
||||||
@@ -195,16 +183,9 @@
|
|||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.pin"></span></label>
|
<label for="node-input-pin"><i class="fa fa-circle"></i> <span data-i18n="arduino.label.pin"></span></label>
|
||||||
<input type="number" min="0" max="99" id="node-input-pin" style="width:20%;" placeholder="13">
|
<input type="number" min="0" max="99" id="node-input-pin" style="width:20%;" placeholder="13">
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.pin"></span></div>
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
|
|
||||||
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-tips"><span data-i18n="[html]arduino.tip.pin"></span></div>
|
||||||
<div class="form-tips"><span data-i18n="[html]arduino.tip.io"></span></div>
|
<div class="form-tips"><span data-i18n="[html]arduino.tip.io"></span></div>
|
||||||
<div class="form-row">
|
|
||||||
<label><span data-i18n="[html]arduino.version"></span></label>
|
|
||||||
</div>
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="arduino out">
|
<script type="text/x-red" data-help-name="arduino out">
|
||||||
@@ -222,10 +203,10 @@
|
|||||||
<li>- <b>reset</b> - to reset the board, if `msg.payoload = true or 1`</li>
|
<li>- <b>reset</b> - to reset the board, if `msg.payoload = true or 1`</li>
|
||||||
<li>- <b>Sampling interval</b> - to set a new time (10ms - 65535ms) how fast analogue input data will be transfered</li>
|
<li>- <b>Sampling interval</b> - to set a new time (10ms - 65535ms) how fast analogue input data will be transfered</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Digital, PWM, Servo will expects a value in `msg.payload`. </p>
|
<p>Digital, PWM, Servo will expects a value in `msg.payload`. </p>
|
||||||
<p>The pin number must be set in the properties (config) panel before Deploy.</p>
|
<p>The pin number must be set in the properties (config) panel before Deploy.</p>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
<p>You can also send `msg.payoload = "reset"` to any Output Node without pre-configuring it, to reset the board.</p>
|
<p>You can also send `msg.payoload = "reset"` to any Output Node without pre-configuring it, to reset the board.</p>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@@ -235,7 +216,7 @@
|
|||||||
color:"#3fadb5",
|
color:"#3fadb5",
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
pin: {value:"", validate: function(v) {
|
pin: {value:"",validate: function(v) {
|
||||||
var ct = $("#node-input-state").val() || this.state;
|
var ct = $("#node-input-state").val() || this.state;
|
||||||
return ct === 'STRING' || (v !== '');
|
return ct === 'STRING' || (v !== '');
|
||||||
}},
|
}},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
************************************************************
|
************************************************************
|
||||||
This is a "Firmata protocol" based communication between
|
This is a "Firmata protocol" based communication between
|
||||||
Node-RED and a connected board running firmata firmware.
|
Node-RED and a connected board running firmata firmware.
|
||||||
It is working with many boards, not just Arduino.
|
It is working with many boards, not just Arduino.
|
||||||
https://github.com/node-red/node-red-nodes
|
https://github.com/node-red/node-red-nodes
|
||||||
************************************************************
|
************************************************************
|
||||||
|
|
||||||
@@ -10,10 +10,10 @@
|
|||||||
1. First, the in/Out nodes will wait, until the "Main-board" = FirmataBoard is:
|
1. First, the in/Out nodes will wait, until the "Main-board" = FirmataBoard is:
|
||||||
- connecting
|
- connecting
|
||||||
- than getting the Version-info from board
|
- than getting the Version-info from board
|
||||||
- after success -> those "child-Nodes" getting notified by this event: nodeIn.on(c_brdStateChanged, function()
|
- after success -> those "child-Nodes" getting notified by this event: nodeIn.on(c_brdStateChanged, function()
|
||||||
- the firmware-level board name is getting stored at: brdNode.FirmwareName
|
- the firmware-level board name is getting stored at: brdNode.FirmwareName
|
||||||
See: Const BdStates ... and ... function startBoardLoopTimer()
|
See: Const BdStates ... and ... function startBoardLoopTimer()
|
||||||
|
|
||||||
1.2 If it fails, because of:
|
1.2 If it fails, because of:
|
||||||
- no board is set
|
- no board is set
|
||||||
- no COM-port is set
|
- no COM-port is set
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
3. TODO: periodically do a TEST to see, if the connection still lives?
|
3. TODO: periodically do a TEST to see, if the connection still lives?
|
||||||
|
|
||||||
! Warning:
|
! Warning:
|
||||||
board.Ready gets true, once Firmata: version+capabilities finished reading.
|
board.Ready gets true, once Firmata: version+capabilities finished reading.
|
||||||
|
|
||||||
Firmata's: board.Pins[] array record structure:
|
Firmata's: board.Pins[] array record structure:
|
||||||
{
|
{
|
||||||
@@ -68,17 +68,17 @@ Todo: (later)
|
|||||||
- flushDigitalPorts() = setting array of ports at once, not one-by-one
|
- flushDigitalPorts() = setting array of ports at once, not one-by-one
|
||||||
- 1x queryPinState() vs. digitalRead() ... at startup? Need to investigate
|
- 1x queryPinState() vs. digitalRead() ... at startup? Need to investigate
|
||||||
- digitalRead() adds a Listener
|
- digitalRead() adds a Listener
|
||||||
- Firmware-Name: show board name on Node-RED panel, which was set at firmata firmware at startup:
|
- Firmware-Name: show board name on Node-RED panel, which was set at firmata firmware at startup:
|
||||||
get-name function?
|
get-name function?
|
||||||
- update Baudrate during run via: transport.update() ... see:
|
- update Baudrate during run via: transport.update() ... see:
|
||||||
|
|
||||||
new module name: red-firmata
|
new module name: red-firmata
|
||||||
- put / get functions
|
- put / get functions
|
||||||
- type identify by number, not string "ANALOG"
|
- type identify by number, not string "ANALOG"
|
||||||
|
|
||||||
RED.events.on('runtime-state', handleRuntimeState) in the onpalleteadd function.
|
RED.events.on('runtime-state', handleRuntimeState) in the onpalleteadd function.
|
||||||
After the first time it detects obj.state === 'start'
|
After the first time it detects obj.state === 'start'
|
||||||
|
|
||||||
Other ideas (later):
|
Other ideas (later):
|
||||||
|
|
||||||
- flushDigitalPorts() = setting array of ports at once, not one-by-one
|
- flushDigitalPorts() = setting array of ports at once, not one-by-one
|
||||||
@@ -99,14 +99,14 @@ Memo for debugging:
|
|||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
"use strict";
|
"use strict";
|
||||||
const { SerialPort } = require('serialport'); // changed format SP -> to {SP} at v9 => v10. See: https://serialport.io/docs/guide-upgrade
|
const SP = require('serialport');
|
||||||
const firmataBoard = require('./lib/firmata');
|
const firmataBoard = require('./lib/firmata');
|
||||||
|
|
||||||
|
|
||||||
let moreLogs = RED.settings.verbose || false; // enable this for "debugging"
|
let moreLogs = RED.settings.verbose || false; // enable this for "debugging"
|
||||||
|
|
||||||
// "global" constants: (these are used at Emitters too)
|
// "global" constants: (these are used at Emitters too)
|
||||||
const c_fbr = " -- FirmataBoard:"; // this is used to print consol-log messages equally.
|
const c_fbr = " -- FirmataBoard:"; // this is used to print consol-log messages equally.
|
||||||
const c_ANALOG = "ANALOG";
|
const c_ANALOG = "ANALOG";
|
||||||
const c_INPUT = "INPUT" ;
|
const c_INPUT = "INPUT" ;
|
||||||
const c_PULLUP = "PULLUP"; // also input, with resistor activated
|
const c_PULLUP = "PULLUP"; // also input, with resistor activated
|
||||||
@@ -122,7 +122,7 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
|
|
||||||
const c_invalidPin = "Invalid pin: ";
|
const c_invalidPin = "Invalid pin: ";
|
||||||
const c_brdStateChanged = "BrdStatCh"; // used by board-emitter + children's .on() Combined with BoardNode's
|
const c_brdStateChanged = "BrdStatCh"; // used by board-emitter + children's .on() Combined with BoardNode's
|
||||||
const c_brdReady = "brdReady" ; // same as ^c_brdStateCh..
|
const c_brdReady = "brdReady" ; // same as ^c_brdStateCh..
|
||||||
|
|
||||||
// state types of the Firmata Board:
|
// state types of the Firmata Board:
|
||||||
@@ -138,28 +138,28 @@ module.exports = function(RED) {
|
|||||||
OK : 3 // Ready
|
OK : 3 // Ready
|
||||||
});
|
});
|
||||||
|
|
||||||
const c_ring = "ring";
|
const c_ring = "ring";
|
||||||
const c_dot = "dot" ;
|
const c_dot = "dot" ;
|
||||||
const c_red = "red" ;
|
const c_red = "red" ;
|
||||||
const c_green = "green" ;
|
const c_green = "green" ;
|
||||||
const c_yellow = "yellow";
|
const c_yellow = "yellow";
|
||||||
const c_blue = "blue" ;
|
const c_blue = "blue" ;
|
||||||
const c_grey = "grey" ;
|
const c_grey = "grey" ;
|
||||||
|
|
||||||
// global error handling for uncaught errors:
|
// global error handling for uncaught errors:
|
||||||
process.on('uncaughtException', (err, origin) => {
|
process.on('uncaughtException', (err, origin) => {
|
||||||
const e = "!!! Unhandled error in: [35-arduino.js] node-red module. >> " + err + " >> ORIGIN: [%o]";
|
const e = "!!! Unhandled error in: [35-arduino.js] node-red module. >> " + err + " >> ORIGIN: [%o]";
|
||||||
try {
|
try {
|
||||||
this.error( e, origin );
|
this.error( e, origin );
|
||||||
} catch (rrr) {
|
} catch (rrr) {
|
||||||
console.error( e, origin );
|
console.error( e, origin );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
RED.events.on("deploy", function() { // sadly this is not getting triggered on DEPLOY button click :-(
|
// RED.events.on("deploy", function() { // sadly this is not getting triggered on DEPLOY button click :-(
|
||||||
console.log(c_fbr + "MAIN - deploy happened!"); // manual says: "A new flow has been deployed" https://nodered.org/docs/api/ui/events/
|
// console.log(c_fbr + "MAIN - deploy happened!"); // manual says: "A new flow has been deployed" https://nodered.org/docs/api/ui/events/
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
function resetBoard(_brdNode){
|
function resetBoard(_brdNode){
|
||||||
@@ -172,7 +172,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
_brdNode.error(c_fbr + "sending: reset failed. Error: " + err);
|
_brdNode.error(c_fbr + "sending: reset failed. Error: " + err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ module.exports = function(RED) {
|
|||||||
const ndStats = Object.freeze({ // (freeze = immutable record)
|
const ndStats = Object.freeze({ // (freeze = immutable record)
|
||||||
noBoard : -3, // no firmata Board specified
|
noBoard : -3, // no firmata Board specified
|
||||||
wrongPin : -2, // Error
|
wrongPin : -2, // Error
|
||||||
pinConflict : -1, // Error: multiple nodes are set with same pin
|
pinConflict : -1, // Error: multiple nodes are set with same pin
|
||||||
start : 0,
|
start : 0,
|
||||||
equalsBoard : 1, // the node will reflect it's parent-board's status. Like: "no COM port set"
|
equalsBoard : 1, // the node will reflect it's parent-board's status. Like: "no COM port set"
|
||||||
OK : 3
|
OK : 3
|
||||||
@@ -189,16 +189,16 @@ module.exports = function(RED) {
|
|||||||
function updateNodeStatus(_n, new_stat) {
|
function updateNodeStatus(_n, new_stat) {
|
||||||
if (_n.parentNode == null) new_stat = ndStats.noBoard;
|
if (_n.parentNode == null) new_stat = ndStats.noBoard;
|
||||||
|
|
||||||
if (((_n.parentNode != null) && (_n.parentNode.b_stat !== BdStates.OK))
|
if (((_n.parentNode != null) && (_n.parentNode.b_stat !== BdStates.OK))
|
||||||
|| (new_stat === ndStats.equalsBoard) ) // if the main board has some error, it has priority, Except: [noBoard, missingPin pinConflict]
|
|| (new_stat === ndStats.equalsBoard) ) // if the main board has some error, it has priority, Except: [noBoard, missingPin pinConflict]
|
||||||
{
|
{
|
||||||
_n.n_status = ndStats.equalsBoard;
|
_n.n_status = ndStats.equalsBoard;
|
||||||
switch (_n.parentNode.b_stat) {
|
switch (_n.parentNode.b_stat) {
|
||||||
case BdStates.permanentError: _n.status({fill:c_red , shape:c_ring, text:"Permanent Error: Board!"}); break; // -9
|
case BdStates.permanentError: _n.status({fill:c_red , shape:c_ring, text:"Permanent Error: Board"}); break; // -9
|
||||||
case BdStates.portNotSet : _n.status({fill:c_red , shape:c_ring, text:"Error: Port not set!"}); break; // -4
|
case BdStates.portNotSet : _n.status({fill:c_red , shape:c_ring, text:"Error: Port not set"}); break; // -4
|
||||||
case BdStates.unknownError : _n.status({fill:c_red , shape:c_ring, text:"Unknown Error: Board!"}); break; // -3
|
case BdStates.unknownError : _n.status({fill:c_red , shape:c_ring, text:"Unknown Error: Board"}); break; // -3
|
||||||
case BdStates.disconnected : _n.status({fill:c_red , shape:c_ring, text:"Disconnected!"}); break;
|
case BdStates.disconnected : _n.status({fill:c_red , shape:c_ring, text:"Disconnected"}); break;
|
||||||
case BdStates.tryReconnect : _n.status({fill:c_red , shape:c_dot , text:"Try Reconnecting.."}); break;
|
case BdStates.tryReconnect : _n.status({fill:c_red , shape:c_dot , text:"Reconnecting.."}); break;
|
||||||
case BdStates.gettingVersion: _n.status({fill:c_blue , shape:c_dot , text:"Getting name+version"}); break;
|
case BdStates.gettingVersion: _n.status({fill:c_blue , shape:c_dot , text:"Getting name+version"}); break;
|
||||||
case BdStates.connecting : _n.status({fill:c_grey , shape:c_dot , text:"node-red:common.status.connecting"}); break;
|
case BdStates.connecting : _n.status({fill:c_grey , shape:c_dot , text:"node-red:common.status.connecting"}); break;
|
||||||
default : _n.status({}); break;
|
default : _n.status({}); break;
|
||||||
@@ -208,9 +208,9 @@ module.exports = function(RED) {
|
|||||||
if (_n.n_status === new_stat) return;
|
if (_n.n_status === new_stat) return;
|
||||||
_n.n_status = new_stat;
|
_n.n_status = new_stat;
|
||||||
switch (new_stat) {
|
switch (new_stat) {
|
||||||
case ndStats.noBoard : _n.status({fill:c_red , shape:c_ring, text:"Error: No Board!"}); break; // -3
|
case ndStats.noBoard : _n.status({fill:c_red , shape:c_ring, text:"Error: No board"}); break; // -3
|
||||||
case ndStats.wrongPin : _n.status({fill:c_red , shape:c_ring, text:"Error: Pin not set!"}); break; // -2
|
case ndStats.wrongPin : _n.status({fill:c_red , shape:c_ring, text:"Error: Pin not set"}); break; // -2
|
||||||
case ndStats.pinConflict : _n.status({fill:c_red , shape:c_ring, text:"Error: Pin Conflict!"}); break; // -1
|
case ndStats.pinConflict : _n.status({fill:c_red , shape:c_ring, text:"Error: Pin conflict"}); break; // -1
|
||||||
case ndStats.start : _n.status({fill:c_grey , shape:c_ring, text:"...start"}); break; // 0
|
case ndStats.start : _n.status({fill:c_grey , shape:c_ring, text:"...start"}); break; // 0
|
||||||
// case ndStats.equalsBoard : = 1
|
// case ndStats.equalsBoard : = 1
|
||||||
case ndStats.OK : _n.status({fill:c_green , shape:c_ring, text:"OK"}); break; // +3
|
case ndStats.OK : _n.status({fill:c_green , shape:c_ring, text:"OK"}); break; // +3
|
||||||
@@ -221,12 +221,12 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
function pinAlreadyUsed (_parentNode, _newNode) { // Check, if there is already a Node registered with same pin -> report pin-conflict
|
function pinAlreadyUsed (_parentNode, _newNode) { // Check, if there is already a Node registered with same pin -> report pin-conflict
|
||||||
if (_parentNode.myChirdren.length === 0) return false;
|
if (_parentNode.myChirdren.length === 0) return false;
|
||||||
if (([c_RESET, c_STRING, c_SYSEX, c_INTER]).includes(_newNode.pinType)) return false;
|
if (([c_RESET, c_STRING, c_SYSEX, c_INTER]).includes(_newNode.type)) return false;
|
||||||
|
|
||||||
let _pin = _newNode.pin;
|
let _pin = _newNode.pin;
|
||||||
if (_newNode.pinType === c_ANALOG) {
|
if (_newNode.type === c_ANALOG) {
|
||||||
if (_newNode.pin >= _parentNode.board.analogPins.length) return false; // wrong pin number
|
if (_newNode.pin >= _parentNode.board.analogPins.length) return false; // wrong pin number
|
||||||
_pin = _parentNode.board.analogPins[_newNode.pin]; // get from the reference Like: [26,27,28,29] _pin=3 -> _pin=29
|
_pin = _parentNode.board.analogPins[_newNode.pin]; // get from the reference Like: [26,27,28,29] _pin=3 -> _pin=29
|
||||||
}
|
}
|
||||||
for (let i = 0; i < _parentNode.myChirdren.length; i++) {
|
for (let i = 0; i < _parentNode.myChirdren.length; i++) {
|
||||||
const _ch = _parentNode.myChirdren[i];
|
const _ch = _parentNode.myChirdren[i];
|
||||||
@@ -239,7 +239,7 @@ module.exports = function(RED) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _ch.pinType === c_ANALOG) {
|
if ( _ch.type === c_ANALOG) {
|
||||||
if (_pin === _parentNode.board.analogPins[_ch.pin]) return reportErrorAndExit(); // found similar! Exit
|
if (_pin === _parentNode.board.analogPins[_ch.pin]) return reportErrorAndExit(); // found similar! Exit
|
||||||
} else {
|
} else {
|
||||||
if (_pin === _ch.pin) return reportErrorAndExit(); // found similar! Exit
|
if (_pin === _ch.pin) return reportErrorAndExit(); // found similar! Exit
|
||||||
@@ -266,21 +266,21 @@ module.exports = function(RED) {
|
|||||||
let brdNode = this;
|
let brdNode = this;
|
||||||
brdNode.b_stat = BdStates.start; // the status of the board
|
brdNode.b_stat = BdStates.start; // the status of the board
|
||||||
brdNode.name = _setup.name || "";
|
brdNode.name = _setup.name || "";
|
||||||
brdNode.samplingInt= _setup.samplingInt || 200;
|
brdNode.samplingInt= _setup.samplingInt || 250;
|
||||||
if ((_setup.log2consol || moreLogs) === true) moreLogs = true;
|
if ((_setup.log2consol || moreLogs) === true) moreLogs = true;
|
||||||
brdNode.port = _setup.device || ""; // port path. Like: "COM3" or "/dev/serial/by-id/usb-Arduino_RaspberryPi_Pico_076461E62D414FE3-if00"
|
brdNode.port = _setup.device || ""; // port path. Like: "COM3" or "/dev/serial/by-id/usb-Arduino_RaspberryPi_Pico_076461E62D414FE3-if00"
|
||||||
// see also: "n.settings.serialport.path" . Sadly the original HTML is named it "device" :-(
|
// see also: "n.settings.serialport.path" . Sadly the original HTML is named it "device" :-(
|
||||||
brdNode.FirmwareName = "";
|
brdNode.FirmwareName = "";
|
||||||
brdNode.board = null; // the actual Firmata-Board
|
brdNode.board = null; // the actual Firmata-Board
|
||||||
brdNode.emitBaseStr = "" + brdNode.id + "-"; // for generating unique string to emit + subcribe to it.
|
brdNode.emitBaseStr = "" + brdNode.id + "-"; // for generating unique string to emit + subcribe to it.
|
||||||
brdNode.myChirdren = [];
|
brdNode.myChirdren = [];
|
||||||
brdNode.loop = null; // timer
|
brdNode.loop = null; // timer
|
||||||
brdNode.loopWaitMs = 0; // How many millisecond to wait until re-trying. This will grow in time dynimically, up to: 10sec
|
brdNode.loopWaitMs = 0; // How many millisecond to wait until re-trying. This will grow in time dynimically, up to: 10sec
|
||||||
brdNode.closing = false; //TODO: used to distinguish between normal close (true) or unwanted disconnection (cable / wifi)
|
brdNode.closing = false; //TODO: used to distinguish between normal close (true) or unwanted disconnection (cable / wifi)
|
||||||
|
|
||||||
const startOptions = {
|
const startOptions = {
|
||||||
samplingInterval: brdNode.samplingInt,
|
samplingInterval: brdNode.samplingInt,
|
||||||
serialport: {
|
serialport: {
|
||||||
baudRate: 57600, // TODO: test, if it would be possible to increase speed during run via fimata.Update()
|
baudRate: 57600, // TODO: test, if it would be possible to increase speed during run via fimata.Update()
|
||||||
path : brdNode.port
|
path : brdNode.port
|
||||||
}
|
}
|
||||||
@@ -312,23 +312,23 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
const _t = brdNode.board.transport; // shorter form
|
const _t = brdNode.board.transport; // shorter form
|
||||||
// if everything is fine. Startup already happened once, (and no disconnection since than,) so no need to run more times.
|
// if everything is fine. Startup already happened once, (and no disconnection since than,) so no need to run more times.
|
||||||
if ((brdNode.b_stat === BdStates.OK) && (brdNode.board != null) && (brdNode.board.isReady) && (_t.isOpen)) {
|
if ((brdNode.b_stat === BdStates.OK) && (brdNode.board != null) && (brdNode.board.isReady) && (_t.isOpen)) {
|
||||||
if (moreLogs) console.info(c_fbr + " is already running fine. No need to start again. Port:" + brdNode.port );
|
if (moreLogs) console.info(c_fbr + " is already running fine. No need to start again. Port:" + brdNode.port );
|
||||||
// TODO: send a test: queryPinState(pin, callback)
|
// TODO: send a test: queryPinState(pin, callback)
|
||||||
brdNode.b_stat = BdStates.OK;
|
brdNode.b_stat = BdStates.OK;
|
||||||
brdNode.loopWaitMs = 0; // reset
|
brdNode.loopWaitMs = 0; // reset
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _newState = BdStates.connecting; // first time start
|
let _newState = BdStates.connecting; // first time start
|
||||||
if (brdNode.b_stat < 0)
|
if (brdNode.b_stat < 0)
|
||||||
_newState = BdStates.tryReconnect;
|
_newState = BdStates.tryReconnect;
|
||||||
else
|
else
|
||||||
if (!_t.opening && _t.isOpen && !brdNode.board.isReady)
|
if (!_t.opening && _t.isOpen && !brdNode.board.isReady)
|
||||||
_newState = BdStates.gettingVersion; // first time start
|
_newState = BdStates.gettingVersion; // first time start
|
||||||
|
|
||||||
updateBrdState( _newState );
|
updateBrdState( _newState );
|
||||||
if (!_t.opening && !_t.isOpen) // if not opening and not opened
|
if (!_t.opening && !_t.isOpen) // if not opening and not opened
|
||||||
_t.open();
|
_t.open();
|
||||||
|
|
||||||
startBoardLoopTimer(); // increase time and check again
|
startBoardLoopTimer(); // increase time and check again
|
||||||
@@ -343,7 +343,7 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
if (brdNode.board === null) {// if board does not exists yet ...
|
if (brdNode.board === null) {// if board does not exists yet ...
|
||||||
brdNode.b_stat = BdStates.connecting; // first time start
|
brdNode.b_stat = BdStates.connecting; // first time start
|
||||||
if (moreLogs) brdNode.log(c_fbr + "creating new instance. Port:" + brdNode.port + " | Sampling-interval=" + brdNode.samplingInt);
|
if (moreLogs) brdNode.log(c_fbr + "creating new instance. Port:" + brdNode.port + " | Sampling-interval=" + brdNode.samplingInt);
|
||||||
|
|
||||||
// creating new board, starting async promice to report state changes:
|
// creating new board, starting async promice to report state changes:
|
||||||
brdNode.board = new firmataBoard(brdNode.port, startOptions, function(e) { // (port, options, callback)
|
brdNode.board = new firmataBoard(brdNode.port, startOptions, function(e) { // (port, options, callback)
|
||||||
@@ -384,7 +384,7 @@ module.exports = function(RED) {
|
|||||||
// Firmata-board emitters:
|
// Firmata-board emitters:
|
||||||
brdNode.board.on('error', function(err) {
|
brdNode.board.on('error', function(err) {
|
||||||
updateBrdState(BdStates.unknownError);
|
updateBrdState(BdStates.unknownError);
|
||||||
if (moreLogs) brdNode.error(c_fbr + ' Error: ' + JSON.stringify(err) ); //+
|
if (moreLogs) brdNode.error(c_fbr + ' Error: ' + JSON.stringify(err) ); //+
|
||||||
});
|
});
|
||||||
|
|
||||||
// "connect" is called, once serial communication is established. After that queryFirmware is called. See: "ready"
|
// "connect" is called, once serial communication is established. After that queryFirmware is called. See: "ready"
|
||||||
@@ -395,17 +395,17 @@ module.exports = function(RED) {
|
|||||||
updateBrdState(BdStates.OK);
|
updateBrdState(BdStates.OK);
|
||||||
else {
|
else {
|
||||||
if (brdNode.board.versionReceived) brdNode.warn("versionReceived but FirmwareName=[]");
|
if (brdNode.board.versionReceived) brdNode.warn("versionReceived but FirmwareName=[]");
|
||||||
updateBrdState(BdStates.gettingVersion);
|
updateBrdState(BdStates.gettingVersion);
|
||||||
startBoardLoopTimer();
|
startBoardLoopTimer();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// "ready" event is called, after the Firmware name+version + capabilities got querried within 5000ms successfully
|
// "ready" event is called, after the Firmware name+version + capabilities got querried within 5000ms successfully
|
||||||
brdNode.board.on('ready', function() {
|
brdNode.board.on('ready', function() {
|
||||||
brdNode.closing = false;
|
brdNode.closing = false;
|
||||||
brdNode.FirmwareName = brdNode.board.firmware.name;
|
brdNode.FirmwareName = brdNode.board.firmware.name;
|
||||||
updateBrdState(BdStates.OK);
|
updateBrdState(BdStates.OK);
|
||||||
brdNode.log(RED._("arduino.status.connected",{device:brdNode.port}) +
|
brdNode.log(RED._("arduino.status.connected",{device:brdNode.port}) +
|
||||||
" Firmware name:[" + brdNode.FirmwareName + "] " +
|
" Firmware name:[" + brdNode.FirmwareName + "] " +
|
||||||
RED._("arduino.status.version",{version: brdNode.board.version.major +"."+ brdNode.board.version.minor}));
|
RED._("arduino.status.version",{version: brdNode.board.version.major +"."+ brdNode.board.version.minor}));
|
||||||
// notifying all children
|
// notifying all children
|
||||||
@@ -416,61 +416,65 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
brdNode.board.on('close', function(removed, done) { // Firmata (transport) closing
|
brdNode.board.on('close', function(removed, done) { // Firmata (transport) closing
|
||||||
// todo : removed
|
// todo : removed
|
||||||
updateBrdState(BdStates.disconnected);
|
updateBrdState(BdStates.disconnected);
|
||||||
resetBoard(brdNode); // this will try to send a "last minute" signal to the board to: reset.
|
resetBoard(brdNode); // this will try to send a "last minute" signal to the board to: reset.
|
||||||
if ( ! brdNode.closing) brdNode.error(RED._("arduino.status.portclosed"));
|
if ( ! brdNode.closing) brdNode.error(RED._("arduino.status.portclosed"));
|
||||||
if (done !== undefined) done();
|
if (done) { done(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
brdNode.board.on('disconnect', function() {
|
brdNode.board.on('disconnect', function() {
|
||||||
updateBrdState(BdStates.disconnected);
|
updateBrdState(BdStates.disconnected);
|
||||||
if (moreLogs) brdNode.log(c_fbr + "Disconnected. Port:" + brdNode.port + " Firmware Name: ["+ brdNode.FirmwareName +"]");
|
if (moreLogs) brdNode.log(c_fbr + "Disconnected. Port:" + brdNode.port + " Firmware Name: ["+ brdNode.FirmwareName +"]");
|
||||||
if ( ! brdNode.closing) startBoardLoopTimer(); // do not start, if proper closing is happening
|
if ( ! brdNode.closing) startBoardLoopTimer(); // do not start, if proper closing is happening
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
//debugger
|
debugger
|
||||||
|
|
||||||
|
|
||||||
// START board initialization the first time
|
// START board initialization the first time
|
||||||
startupBrd();
|
startupBrd();
|
||||||
|
|
||||||
if (brdNode.loop == null)
|
if (brdNode.loop == null) {
|
||||||
startBoardLoopTimer();
|
startBoardLoopTimer();
|
||||||
else
|
}
|
||||||
if (moreLogs) brdNode.log(c_fbr + "already present. Loop start skipped. ");
|
else {
|
||||||
|
if (moreLogs) {
|
||||||
|
brdNode.log(c_fbr + "already present. Loop start skipped. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// brdNode.removeAllListeners('close');
|
// brdNode.removeAllListeners('close');
|
||||||
brdNode.on('close', function(removed, done) { // the Node itself is getting destoyed memo: function(done) did not work, TypeError
|
brdNode.on('close', function(removed, done) { // the Node itself is getting destoyed memo: function(done) did not work, TypeError
|
||||||
brdNode.closing = true;
|
brdNode.closing = true;
|
||||||
if (!removed) updateBrdState(BdStates.disconnected); // this will notify clients too
|
if (!removed) updateBrdState(BdStates.disconnected); // this will notify clients too
|
||||||
clearTimeout(brdNode.loop); brdNode.loop = null;
|
clearTimeout(brdNode.loop); brdNode.loop = null;
|
||||||
if ((brdNode.board == null) || (brdNode.board.transport == null) ) {
|
if ((brdNode.board == null) || (brdNode.board.transport == null) ) {done(); return; }
|
||||||
if (done !== undefined) done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brdNode.board.transport.closing) {
|
if (brdNode.board.transport.closing) {
|
||||||
if (moreLogs) { brdNode.log(c_fbr + "Nothing to do, because this port is already closing: " + brdNode.port); }
|
if (moreLogs) { brdNode.log(c_fbr + "Nothing to do, because this port is already closing: " + brdNode.port); }
|
||||||
if (done !== undefined) done();
|
if (done) { done(); }
|
||||||
return;// EXIT
|
return;// EXIT
|
||||||
};
|
};
|
||||||
|
|
||||||
if (moreLogs) { brdNode.log(c_fbr + "Trying to close port:" + brdNode.port); }
|
if (moreLogs) { brdNode.log(c_fbr + "Trying to close port:" + brdNode.port); }
|
||||||
|
|
||||||
if (brdNode.board.transport.isOpen) {
|
if (brdNode.board.transport.isOpen) {
|
||||||
//resetBoard(brdNode);
|
//resetBoard(brdNode);
|
||||||
try {
|
try {
|
||||||
brdNode.board.transport.close(function(err) {
|
brdNode.board.transport.close(function(err) {
|
||||||
if (moreLogs) { brdNode.log(RED._("arduino.status.portclosed") + err?"Err: ":"" , err); }
|
if (moreLogs) { brdNode.log(RED._("arduino.status.portclosed") + err?"Err: ":"" , err); }
|
||||||
});
|
});
|
||||||
if (done !== undefined) done();
|
if (done) { done(); }
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
if (moreLogs) { brdNode.error("Could not close port: " + brdNode.port + (e?"Err: ":"") , e); }
|
if (moreLogs) { brdNode.error("Could not close port: " + brdNode.port + (e?"Err: ":"") , e); }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (done) { done(); }
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else { if (done !== undefined) done(); return;}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// *** REGISTERING the (parent) board node *** //
|
// *** REGISTERING the (parent) board node *** //
|
||||||
@@ -481,18 +485,18 @@ module.exports = function(RED) {
|
|||||||
/**
|
/**
|
||||||
* The Input (child) Node
|
* The Input (child) Node
|
||||||
*
|
*
|
||||||
* pinType: can be ANALOG, DIGITAL ... (Warning! in html it is called "state")
|
* type: can be ANALOG, DIGITAL ... (Warning! in html it is called "state")
|
||||||
*/
|
*/
|
||||||
function DuinoNodeIn(_setupIn) {
|
function DuinoNodeIn(_setupIn) {
|
||||||
RED.nodes.createNode(this, _setupIn); // n = setupNode
|
RED.nodes.createNode(this, _setupIn); // n = setupNode
|
||||||
let nodeIn = this;
|
let nodeIn = this;
|
||||||
nodeIn.n_status = ndStats.start;
|
nodeIn.n_status = ndStats.start;
|
||||||
nodeIn.pin = _setupIn.pin;
|
nodeIn.pin = _setupIn.pin;
|
||||||
nodeIn.pinType = _setupIn.state; // "state" is a wrong naming at the html definition. It is the current "Type" of the Pin. (Like: "ANALOG" or "PWM"...)
|
nodeIn.type = _setupIn.state; // "state" is a wrong naming at the html definition. It is the current type of the Pin. (Like: "ANALOG" or "PWM"...)
|
||||||
nodeIn.parentNode = RED.nodes.getNode(_setupIn.arduino); // n.arduino = The ArduinoNode's ID. It is defined at `package.json`: "node-red": {... "nodes": { "arduino": "35-arduino.js" }
|
nodeIn.parentNode = RED.nodes.getNode(_setupIn.arduino); // n.arduino = The ArduinoNode's ID. It is defined at `package.json`: "node-red": {... "nodes": { "arduino": "35-arduino.js" }
|
||||||
let loopIn = null; // timer
|
let loopIn = null; // timer
|
||||||
|
|
||||||
// The creation process
|
// The creation process
|
||||||
if (typeof nodeIn.parentNode === "object") {
|
if (typeof nodeIn.parentNode === "object") {
|
||||||
nodeIn.frmBoard = nodeIn.parentNode.board; // a shorter reference the parent-node's Firmata-Board class
|
nodeIn.frmBoard = nodeIn.parentNode.board; // a shorter reference the parent-node's Firmata-Board class
|
||||||
if (nodeIn.frmBoard == null) {
|
if (nodeIn.frmBoard == null) {
|
||||||
@@ -506,9 +510,9 @@ module.exports = function(RED) {
|
|||||||
updateNodeStatus(nodeIn, nodeIn.n_status);
|
updateNodeStatus(nodeIn, nodeIn.n_status);
|
||||||
});
|
});
|
||||||
|
|
||||||
// *** first initialization *** //
|
// *** first initialization *** //
|
||||||
let startupIn = function() {
|
let startupIn = function() {
|
||||||
if (moreLogs) console.info(c_fbr + "Node-In created." + (nodeIn.name ? " Name=["+ nodeIn.name +"]" : "") + " Pin=" + nodeIn.pin + " Type=" + nodeIn.pinType);
|
if (moreLogs) console.info(c_fbr + "Node-In created." + (nodeIn.name ? " Name=["+ nodeIn.name +"]" : "") + " Pin=" + nodeIn.pin + " Type=" + nodeIn.type);
|
||||||
if (loopIn !== null) {clearTimeout(loopIn); loopIn = null};
|
if (loopIn !== null) {clearTimeout(loopIn); loopIn = null};
|
||||||
//nodeIn.frmBoard.setMaxListeners(0); Deleted 2025-03-17. DO NOT USE THIS ! See: https://stackoverflow.com/a/44143119
|
//nodeIn.frmBoard.setMaxListeners(0); Deleted 2025-03-17. DO NOT USE THIS ! See: https://stackoverflow.com/a/44143119
|
||||||
// nodeIn.frmBoard.setMaxListeners(11); // no need either
|
// nodeIn.frmBoard.setMaxListeners(11); // no need either
|
||||||
@@ -516,35 +520,35 @@ module.exports = function(RED) {
|
|||||||
updateNodeStatus(nodeIn, ndStats.equalsBoard);
|
updateNodeStatus(nodeIn, ndStats.equalsBoard);
|
||||||
|
|
||||||
let doit = function() {
|
let doit = function() {
|
||||||
if (pinAlreadyUsed(nodeIn.parentNode, nodeIn) === true) return; // EXIT; // pin-conflict check
|
if (pinAlreadyUsed(nodeIn.parentNode, nodeIn) === true) return; // EXIT; // pin-conflict check
|
||||||
if (moreLogs) console.info(c_fbr + "Node-In init started." + (nodeIn.name ? " Name=["+ nodeIn.name +"]" : "") + " Pin=" + nodeIn.pin + " Type=" + nodeIn.pinType);
|
if (moreLogs) console.info(c_fbr + "Node-In init started." + (nodeIn.name ? " Name=["+ nodeIn.name +"]" : "") + " Pin=" + nodeIn.pin + " Type=" + nodeIn.type);
|
||||||
let goodPin = (nodeIn.pin != null) && !isNaN(nodeIn.pin) && (nodeIn.pin >=0) && (nodeIn.pin < nodeIn.frmBoard.pins.length);
|
let goodPin = (nodeIn.pin != null) && !isNaN(nodeIn.pin) && (nodeIn.pin >=0) && (nodeIn.pin < nodeIn.frmBoard.pins.length);
|
||||||
if (goodPin === true && nodeIn.pinType === c_ANALOG) {
|
if (goodPin === true && nodeIn.type === c_ANALOG) {
|
||||||
goodPin = ( nodeIn.pin in nodeIn.frmBoard.analogPins ); // found analogue pin
|
goodPin = ( nodeIn.pin in nodeIn.frmBoard.analogPins ); // found analogue pin
|
||||||
if (!goodPin){ nodeIn.error( c_invalidPin + nodeIn.pin
|
if (!goodPin){ nodeIn.error( c_invalidPin + nodeIn.pin
|
||||||
+ (nodeIn.frmBoard.analogPins ? ". Only these analogue pin numbers are allowed: [0.."
|
+ (nodeIn.frmBoard.analogPins ? ". Only these analogue pin numbers are allowed: [0.."
|
||||||
+ (nodeIn.frmBoard.analogPins.length-1) + "]/n Reference GPIOs:" + nodeIn.frmBoard.analogPins
|
+ (nodeIn.frmBoard.analogPins.length-1) + "]/n Reference GPIOs:" + nodeIn.frmBoard.analogPins
|
||||||
: "NO analogue pins are allowed with this firmware / board!"));
|
: "NO analogue pins are allowed with this firmware / board!"));
|
||||||
//console.log('pins: %o', nodeIn.board.analogPins); // TESTS
|
//console.log('pins: %o', nodeIn.board.analogPins); // TESTS
|
||||||
//const jsonString = JSON.stringify(node.board.pins);
|
//const jsonString = JSON.stringify(node.board.pins);
|
||||||
//console.log( jsonString );
|
//console.log( jsonString );
|
||||||
//node.error( jsonString ); // test
|
//node.error( jsonString ); // test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (goodPin === true) {
|
if (goodPin === true) {
|
||||||
try {
|
try {
|
||||||
if (nodeIn.pinType === c_ANALOG) { nodeIn.frmBoard.pinMode(nodeIn.pin, 0x02); } else
|
if (nodeIn.type === c_ANALOG) { nodeIn.frmBoard.pinMode(nodeIn.pin, 0x02); } else
|
||||||
if (nodeIn.pinType === c_INPUT ) { nodeIn.frmBoard.pinMode(nodeIn.pin, 0x00); } else
|
if (nodeIn.type === c_INPUT ) { nodeIn.frmBoard.pinMode(nodeIn.pin, 0x00); } else
|
||||||
if (nodeIn.pinType === c_PULLUP) { nodeIn.frmBoard.pinMode(nodeIn.pin, 0x0B); }
|
if (nodeIn.type === c_PULLUP) { nodeIn.frmBoard.pinMode(nodeIn.pin, 0x0B); }
|
||||||
updateNodeStatus(nodeIn, ndStats.OK);
|
updateNodeStatus(nodeIn, ndStats.OK);
|
||||||
} catch (setPinError) {
|
} catch (setPinError) {
|
||||||
updateNodeStatus(nodeIn, ndStats.wrongPin);
|
updateNodeStatus(nodeIn, ndStats.wrongPin);
|
||||||
nodeIn.error(c_fbr + "Input Pin ["+ nodeIn.pin +"] setting error:" + setPinError);
|
nodeIn.error(c_fbr + "Input Pin ["+ nodeIn.pin +"] setting error:" + setPinError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribing to pin-event listeners. These will call at firmata-io.js: board.addListener(`analog-read-${pin}`, callback);
|
// subscribing to pin-event listeners. These will call at firmata-io.js: board.addListener(`analog-read-${pin}`, callback);
|
||||||
if (nodeIn.pinType === c_ANALOG) {
|
if (nodeIn.type === c_ANALOG) {
|
||||||
nodeIn.frmBoard.analogRead(nodeIn.pin, function(v) {
|
nodeIn.frmBoard.analogRead(nodeIn.pin, function(v) {
|
||||||
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
||||||
if (v !== nodeIn.oldval) {
|
if (v !== nodeIn.oldval) {
|
||||||
@@ -553,7 +557,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else
|
} else
|
||||||
if (nodeIn.pinType === c_INPUT) {
|
if (nodeIn.type === c_INPUT) {
|
||||||
nodeIn.frmBoard.digitalRead(nodeIn.pin, function(v) {
|
nodeIn.frmBoard.digitalRead(nodeIn.pin, function(v) {
|
||||||
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
||||||
if (v !== nodeIn.oldval) {
|
if (v !== nodeIn.oldval) {
|
||||||
@@ -563,7 +567,7 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
// nodeIn.frmBoard.queryPinState(nodeIn.pin, callback); // TODO ?
|
// nodeIn.frmBoard.queryPinState(nodeIn.pin, callback); // TODO ?
|
||||||
} else
|
} else
|
||||||
if (nodeIn.pinType === c_PULLUP) {
|
if (nodeIn.type === c_PULLUP) {
|
||||||
nodeIn.frmBoard.digitalRead(nodeIn.pin, function(v) {
|
nodeIn.frmBoard.digitalRead(nodeIn.pin, function(v) {
|
||||||
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
||||||
if (v !== nodeIn.oldval) {
|
if (v !== nodeIn.oldval) {
|
||||||
@@ -573,7 +577,7 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
// nodeIn.frmBoard.queryPinState(nodeIn.pin); // TODO ?
|
// nodeIn.frmBoard.queryPinState(nodeIn.pin); // TODO ?
|
||||||
} else
|
} else
|
||||||
if (nodeIn.pinType == c_STRING) {
|
if (nodeIn.type == c_STRING) {
|
||||||
nodeIn.frmBoard.on('string', function(v) {
|
nodeIn.frmBoard.on('string', function(v) {
|
||||||
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
if (nodeIn.n_status !== ndStats.OK) updateNodeStatus(nodeIn, ndStats.OK);
|
||||||
// if (v !== nodeIn.oldval) { //OMG! deleted 2025-03-17
|
// if (v !== nodeIn.oldval) { //OMG! deleted 2025-03-17
|
||||||
@@ -591,16 +595,16 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
|
|
||||||
// wait first, until Board's capabilities are reported. Configure child node after that.
|
// wait first, until Board's capabilities are reported. Configure child node after that.
|
||||||
if (nodeIn.frmBoard.isReady) {
|
if (nodeIn.frmBoard.isReady) {
|
||||||
doit();
|
doit();
|
||||||
} else {
|
} else {
|
||||||
nodeIn.once(c_brdReady, function() {
|
nodeIn.once(c_brdReady, function() {
|
||||||
doit();
|
doit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if (loopIn === null) {
|
if (loopIn === null) {
|
||||||
if (moreLogs) console.info(c_fbr + "Timeout set for loop. Name="+ nodeIn.name + " Pin=" + nodeIn.pin + " State=" + nodeIn.pinType);
|
if (moreLogs) console.info(c_fbr + "Timeout set for loop. Name="+ nodeIn.name + " Pin=" + nodeIn.pin + " State=" + nodeIn.type);
|
||||||
loopIn = setTimeout(function() { if (nodeIn.running === false) { startupIn(); } }, 4500);
|
loopIn = setTimeout(function() { if (nodeIn.running === false) { startupIn(); } }, 4500);
|
||||||
loopIn.name = "startupIN-timeout";
|
loopIn.name = "startupIN-timeout";
|
||||||
}
|
}
|
||||||
@@ -614,10 +618,10 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodeIn.on('close', function(removed, done) { // if remove === true -> it means this Node is getting deleted
|
nodeIn.on('close', function(removed, done) { // if remove === true -> it means this Node is getting deleted
|
||||||
clearTimeout(loopIn);
|
clearTimeout(loopIn);
|
||||||
if (removed) {removeFromChildren(nodeIn);}
|
if (removed) {removeFromChildren(nodeIn);}
|
||||||
else {updateNodeStatus(nodeIn, ndStats.equalsBoard);}
|
else {updateNodeStatus(nodeIn, ndStats.equalsBoard);}
|
||||||
if (done !== undefined) done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
RED.nodes.registerType("arduino in", DuinoNodeIn);
|
RED.nodes.registerType("arduino in", DuinoNodeIn);
|
||||||
@@ -626,32 +630,17 @@ module.exports = function(RED) {
|
|||||||
/**
|
/**
|
||||||
* The Output (child) Node
|
* The Output (child) Node
|
||||||
*
|
*
|
||||||
* pinType: can be ANALOG, DIGITAL ... (Warning! in html "pinType" is called "state")
|
* type: can be ANALOG, DIGITAL ... (Warning! in html "type" is called "state")
|
||||||
*/
|
*/
|
||||||
function DuinoNodeOut(_setupOut) {
|
function DuinoNodeOut(_setupOut) {
|
||||||
RED.nodes.createNode(this, _setupOut);
|
RED.nodes.createNode(this, _setupOut);
|
||||||
let nodeOut = this;
|
let nodeOut = this;
|
||||||
nodeOut.n_status = ndStats.start;
|
nodeOut.n_status = ndStats.start;
|
||||||
nodeOut.pin = _setupOut.pin;
|
nodeOut.pin = _setupOut.pin;
|
||||||
nodeOut.pinType = _setupOut.state; // "state" is a wrong naming at the html definition. It is the current type of the Pin. (Like: "ANALOG" or "PWM"...)
|
nodeOut.type = _setupOut.state; // "state" is a wrong naming at the html definition. It is the current type of the Pin. (Like: "ANALOG" or "PWM"...)
|
||||||
nodeOut.parentNode = RED.nodes.getNode(_setupOut.arduino); // _setupOut.arduino = The board config. It is defined at `package.json`: "node-red": {... "nodes": { "arduino": "35-arduino.js" }
|
nodeOut.parentNode = RED.nodes.getNode(_setupOut.arduino); // _setupOut.arduino = The board config. It is defined at `package.json`: "node-red": {... "nodes": { "arduino": "35-arduino.js" }
|
||||||
let loopOut = null; // timer
|
let loopOut = null; // timer
|
||||||
|
|
||||||
// create an event-listener outside the scope of normal inputs, for "override-reset"
|
|
||||||
if (nodeOut.pinType === c_RESET) {
|
|
||||||
nodeOut.on("input", function(msg, send, done) {
|
|
||||||
if ( Boolean(msg.payload) === true) {
|
|
||||||
try {
|
|
||||||
resetBoard(nodeOut.parentNode);
|
|
||||||
if (moreLogs) nodeOut.warn(c_fbr + "... sending reset from NR");
|
|
||||||
} catch (_error) {
|
|
||||||
nodeOut.error(c_fbr + "Could not send RESET to the board.", _error);
|
|
||||||
};
|
|
||||||
if (done !== undefined) done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test to see, what's inside:
|
// Test to see, what's inside:
|
||||||
//console.log("ou- _setupOut.arduino: %o", _setupOut.arduino);
|
//console.log("ou- _setupOut.arduino: %o", _setupOut.arduino);
|
||||||
//console.log("/n ====================================================================================== /n", n.arduino);
|
//console.log("/n ====================================================================================== /n", n.arduino);
|
||||||
@@ -659,8 +648,8 @@ module.exports = function(RED) {
|
|||||||
//console.log("/n ====================================================================================== /n", n.arduino);
|
//console.log("/n ====================================================================================== /n", n.arduino);
|
||||||
//console.log("ou- type of serverConfig: " + typeof nodeOut.boardConfig);
|
//console.log("ou- type of serverConfig: " + typeof nodeOut.boardConfig);
|
||||||
|
|
||||||
// The creation process
|
// The creation process
|
||||||
if (typeof nodeOut.parentNode === "object") {
|
if (typeof nodeOut.parentNode === "object") {
|
||||||
nodeOut.frmBoard = nodeOut.parentNode.board; // a shorter reference directly to Firmata class
|
nodeOut.frmBoard = nodeOut.parentNode.board; // a shorter reference directly to Firmata class
|
||||||
if (nodeOut.frmBoard == null) {
|
if (nodeOut.frmBoard == null) {
|
||||||
updateNodeStatus(nodeOut, ndStats.noBoard);
|
updateNodeStatus(nodeOut, ndStats.noBoard);
|
||||||
@@ -674,26 +663,26 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let startupOut = function() {
|
let startupOut = function() {
|
||||||
if (moreLogs) console.info(c_fbr + "Node-Out created." + (nodeOut.name ? " Name=["+ nodeOut.name + "]" : "") + " Pin=" + nodeOut.pin + " Type=" + nodeOut.pinType);
|
if (moreLogs) console.info(c_fbr + "Node-Out created." + (nodeOut.name ? " Name=["+ nodeOut.name + "]" : "") + " Pin=" + nodeOut.pin + " Type=" + nodeOut.type);
|
||||||
if (loopOut !== null) {clearTimeout(loopOut); loopOut = null};
|
if (loopOut !== null) {clearTimeout(loopOut); loopOut = null};
|
||||||
|
|
||||||
updateNodeStatus(nodeOut, ndStats.equalsBoard);
|
updateNodeStatus(nodeOut, ndStats.equalsBoard);
|
||||||
|
|
||||||
let doit = function() {
|
let doit = function() {
|
||||||
if (pinAlreadyUsed(nodeOut.parentNode, nodeOut) === true) return; // EXIT; // pin-conflict check
|
if (pinAlreadyUsed(nodeOut.parentNode, nodeOut) === true) return; // EXIT; // pin-conflict check
|
||||||
if (moreLogs) console.info(c_fbr + "Node-Out init started." + (nodeOut.name ? " Name=["+ nodeOut.name + "]" : "") + " Pin=" + nodeOut.pin + " Type=" + nodeOut.pinType);
|
if (moreLogs) console.info(c_fbr + "Node-Out init started." + (nodeOut.name ? " Name=["+ nodeOut.name + "]" : "") + " Pin=" + nodeOut.pin + " Type=" + nodeOut.type);
|
||||||
|
|
||||||
if ((nodeOut.pin != null) && !isNaN(nodeOut.pin) && nodeOut.pin >=0 && nodeOut.pin < nodeOut.frmBoard.pins.length) {
|
if ((nodeOut.pin != null) && !isNaN(nodeOut.pin) && nodeOut.pin >=0 && nodeOut.pin < nodeOut.frmBoard.pins.length) {
|
||||||
if (nodeOut.pinType === c_OUTPUT) { nodeOut.frmBoard.pinMode(nodeOut.pin, 0x01); }
|
if (nodeOut.type === c_OUTPUT) { nodeOut.frmBoard.pinMode(nodeOut.pin, 0x01); }
|
||||||
if (nodeOut.pinType === c_PWM ) { nodeOut.frmBoard.pinMode(nodeOut.pin, 0x03); }
|
if (nodeOut.type === c_PWM ) { nodeOut.frmBoard.pinMode(nodeOut.pin, 0x03); }
|
||||||
if (nodeOut.pinType === c_SERVO ) { nodeOut.frmBoard.pinMode(nodeOut.pin, 0x04); }
|
if (nodeOut.type === c_SERVO ) { nodeOut.frmBoard.pinMode(nodeOut.pin, 0x04); }
|
||||||
|
|
||||||
updateNodeStatus(nodeOut, ndStats.OK);
|
updateNodeStatus(nodeOut, ndStats.OK);
|
||||||
|
|
||||||
nodeOut.on("input", function(msg, send, done) {
|
nodeOut.on("input", function(msg, send, done) {
|
||||||
if ((msg == null) || (msg.payload == null)) { // NULL input -> send warning & exit
|
if ((msg == null) || (msg.payload == null)) { // NULL input -> send warning & exit
|
||||||
nodeOut.warn("msg.payload must not be null!");
|
nodeOut.warn("msg.payload must not be null!");
|
||||||
if (done !== undefined) done();
|
done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,7 +692,7 @@ module.exports = function(RED) {
|
|||||||
updateNodeStatus(nodeOut, ndStats.equalsBoard);
|
updateNodeStatus(nodeOut, ndStats.equalsBoard);
|
||||||
resetBoard(nodeOut.parentNode);
|
resetBoard(nodeOut.parentNode);
|
||||||
} else
|
} else
|
||||||
if (nodeOut.pinType === c_OUTPUT) {
|
if (nodeOut.type === c_OUTPUT) {
|
||||||
const str = msg.payload.toString();
|
const str = msg.payload.toString();
|
||||||
if ((msg.payload === true ) || (str === "1") || (str.toLowerCase() === "on")) {
|
if ((msg.payload === true ) || (str === "1") || (str.toLowerCase() === "on")) {
|
||||||
nodeOut.frmBoard.digitalWrite(nodeOut.pin, nodeOut.frmBoard.HIGH);
|
nodeOut.frmBoard.digitalWrite(nodeOut.pin, nodeOut.frmBoard.HIGH);
|
||||||
@@ -712,42 +701,42 @@ module.exports = function(RED) {
|
|||||||
nodeOut.frmBoard.digitalWrite(nodeOut.pin, nodeOut.frmBoard.LOW);
|
nodeOut.frmBoard.digitalWrite(nodeOut.pin, nodeOut.frmBoard.LOW);
|
||||||
};
|
};
|
||||||
} else
|
} else
|
||||||
if (nodeOut.pinType === c_PWM) {
|
if (nodeOut.type === c_PWM) {
|
||||||
msg.payload = parseInt((msg.payload * 1) + 0.5); // round to int
|
msg.payload = parseInt((msg.payload * 1) + 0.5); // round to int
|
||||||
if ((msg.payload >= 0) && (msg.payload <= 255)) {
|
if ((msg.payload >= 0) && (msg.payload <= 255)) {
|
||||||
nodeOut.frmBoard.analogWrite(nodeOut.pin, msg.payload);
|
nodeOut.frmBoard.analogWrite(nodeOut.pin, msg.payload);
|
||||||
} else nodeOut.warn("PWM value must be: 0..255");
|
} else nodeOut.warn("PWM value must be: 0..255");
|
||||||
} else
|
} else
|
||||||
if (nodeOut.pinType === c_SERVO) {
|
if (nodeOut.type === c_SERVO) {
|
||||||
msg.payload = parseInt((msg.payload * 1) + 0.5);
|
msg.payload = parseInt((msg.payload * 1) + 0.5);
|
||||||
if ((msg.payload >= 0) && (msg.payload <= 180)) {
|
if ((msg.payload >= 0) && (msg.payload <= 180)) {
|
||||||
nodeOut.frmBoard.servoWrite(nodeOut.pin, msg.payload);
|
nodeOut.frmBoard.servoWrite(nodeOut.pin, msg.payload);
|
||||||
} else nodeOut.warn("PWM value must be: 0..180");
|
} else nodeOut.warn("PWM value must be: 0..180");
|
||||||
} else
|
} else
|
||||||
if (nodeOut.pinType === c_SYSEX) {
|
if (nodeOut.type === c_SYSEX) {
|
||||||
nodeOut.frmBoard.sysexCommand(msg.payload);
|
nodeOut.frmBoard.sysexCommand(msg.payload);
|
||||||
} else
|
} else
|
||||||
if (nodeOut.pinType === c_STRING) {
|
if (nodeOut.type === c_STRING) {
|
||||||
nodeOut.frmBoard.sendString(msg.payload.toString());
|
nodeOut.frmBoard.sendString(msg.payload.toString());
|
||||||
} else
|
} else
|
||||||
/* if (nodeOut.pinType === c_RESET) {
|
if (nodeOut.type === c_RESET) {
|
||||||
if ( Boolean(msg.payload) === true) {
|
if ( Boolean(msg.payload) === true) {
|
||||||
updateNodeStatus(nodeOut, ndStats.equalsBoard);
|
updateNodeStatus(nodeOut, ndStats.equalsBoard);
|
||||||
resetBoard(nodeOut.parentNode);
|
resetBoard(nodeOut.parentNode);
|
||||||
}
|
}
|
||||||
} else */
|
} else
|
||||||
if (nodeOut.pinType === c_INTER) {
|
if (nodeOut.type === c_INTER) {
|
||||||
const i = 0 + msg.payload;
|
const i = 0 + msg.payload;
|
||||||
if (i < 10 || i > 65535) {
|
if (i < 10 || i > 65535) {
|
||||||
nodeOut.warn("Invalid new interval input value (10-65535): ["+ msg.payload +"]");
|
nodeOut.warn("Invalid new interval input value (10-65535): ["+ msg.payload +"]");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
nodeOut.samplingInterval = i;
|
nodeOut.samplingInterval = i;
|
||||||
nodeOut.frmBoard.setSamplingInterval(i);
|
nodeOut.frmBoard.setSamplingInterval(i);
|
||||||
nodeOut.status({fill:c_yellow, shape:c_ring, text:"Interval= " + i});
|
nodeOut.status({fill:c_yellow, shape:c_ring, text:"Interval= " + i});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (done !== undefined) done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -756,12 +745,12 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeOut.frmBoard.isReady) {
|
if (nodeOut.frmBoard.isReady) {
|
||||||
doit();
|
doit();
|
||||||
} else {
|
} else {
|
||||||
nodeOut.once(c_brdReady, function() {
|
nodeOut.once(c_brdReady, function() {
|
||||||
doit();
|
doit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if (loopOut === null) {
|
if (loopOut === null) {
|
||||||
@@ -774,7 +763,7 @@ module.exports = function(RED) {
|
|||||||
startupOut();
|
startupOut();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
updateNodeStatus(nodeOut, ndStats.noBoard);
|
updateNodeStatus(nodeOut, ndStats.noBoard);
|
||||||
nodeOut.warn(c_fbr + "Out: " + RED._("arduino.errors.portnotconf"));
|
nodeOut.warn(c_fbr + "Out: " + RED._("arduino.errors.portnotconf"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,79 +771,25 @@ module.exports = function(RED) {
|
|||||||
clearTimeout(loopOut);
|
clearTimeout(loopOut);
|
||||||
if (removed === true) {removeFromChildren(nodeOut);}
|
if (removed === true) {removeFromChildren(nodeOut);}
|
||||||
else {updateNodeStatus(nodeOut, ndStats.equalsBoard);};
|
else {updateNodeStatus(nodeOut, ndStats.equalsBoard);};
|
||||||
if (done !== undefined) done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
RED.nodes.registerType("arduino out", DuinoNodeOut);
|
RED.nodes.registerType("arduino out", DuinoNodeOut);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listing serial ports (used at Board-configuration, by clicking the SEARCH button on the right side of port editbox)
|
* Listing serial ports (used at Board-configuration)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
RED.httpAdmin.get("/arduinoports", RED.auth.needsPermission("arduino.read"), function(req, res) {
|
RED.httpAdmin.get("/arduinoports", RED.auth.needsPermission("arduino.read"), function(req, res) {
|
||||||
/*
|
SP.list().then(
|
||||||
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
const serialList = await SerialPort.list();
|
|
||||||
ports => {
|
ports => {
|
||||||
const a = ports.map(p => p.comName);
|
const a = ports.map(p => p.comName);
|
||||||
res.json(a);
|
res.json(a);
|
||||||
this.log(c_fbr + "Serial ports list:", a);
|
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
this.error('Error listing serial ports', err);
|
this.log('Error listing serial ports', err)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
)
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
*/
|
|
||||||
// Firmata Example (not working ! because SerialPort changed to async) : https://github.com/yokobond/firmata-io#with-a-transport-instance
|
|
||||||
|
|
||||||
let _arr = ["-- no ports found --"];
|
|
||||||
async function listSerialPorts() {
|
|
||||||
try {
|
|
||||||
const ports = await SerialPort.list();
|
|
||||||
console.log('Available Ports:', ports);
|
|
||||||
if ((ports != null) && (Array.isArray(ports)) && ports.length !== 0)
|
|
||||||
_arr = ports.map(p => p.path);
|
|
||||||
res.json(_arr);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error listing ports:', err);
|
|
||||||
_arr.push( err.toString );
|
|
||||||
res.json(_arr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listSerialPorts();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Expected result of each port in the array:
|
|
||||||
interface PortInfo {
|
|
||||||
path: string;
|
|
||||||
manufacturer: string | undefined;
|
|
||||||
serialNumber: string | undefined;
|
|
||||||
pnpId: string | undefined;
|
|
||||||
locationId: string | undefined;
|
|
||||||
productId: string | undefined;
|
|
||||||
vendorId: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
For example on windows:
|
|
||||||
[
|
|
||||||
{
|
|
||||||
path: 'COM3',
|
|
||||||
manufacturer: 'Microsoft',
|
|
||||||
serialNumber: '6&35CA52AB&0&0000',
|
|
||||||
pnpId: 'USB\\VID_2E8A&PID_00C0&MI_00\\6&35CA52AB&0&0000',
|
|
||||||
locationId: '0000.0014.0000.001.000.000.000.000.000',
|
|
||||||
friendlyName: 'Soros USB-eszköz (COM3)',
|
|
||||||
vendorId: '2E8A',
|
|
||||||
productId: '00C0'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
*/
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,11 @@ _Typically plugged in to the host via USB to extend: I/O + analogue + I2C + OneW
|
|||||||
See the [main documentation](http://nodered.org/docs/hardware/arduino.html) for
|
See the [main documentation](http://nodered.org/docs/hardware/arduino.html) for
|
||||||
details and examples of how to use this node.
|
details and examples of how to use this node.
|
||||||
|
|
||||||
See list of changes and latest features (with pictures) at: [NR's forum](https://discourse.nodered.org/t/announce-node-red-node-arduino-firmata-remastered-v1-3-3/96317).
|
|
||||||
|
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Either use the Menu - Manage Palette option,
|
Either use the Menu - Manage Palette option or run the following command in your Node-RED user directory - typically `~/.node-red`
|
||||||
or run the following command in your Node-RED user directory - typically `~/.node-red`
|
|
||||||
|
|
||||||
npm i --unsafe-perm node-red-node-arduino
|
npm i --unsafe-perm node-red-node-arduino
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"arduino": {
|
"arduino": {
|
||||||
"version": "version: 1.3.4-20250331",
|
|
||||||
"label": {
|
"label": {
|
||||||
"pin": "Pin:",
|
"pin": "Pin:",
|
||||||
"type": "Type:",
|
"type": "Type:",
|
||||||
@@ -36,12 +35,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tip": {
|
"tip": {
|
||||||
"io": "<b>Note:</b> You cannot use the same pin for both output and input!",
|
"io": "<b>Note:</b> You cannot use the same pin for both output and input",
|
||||||
"port": "<p>On Unix/linux systems, it is recommended to choose the serial port at: <b>by-id</b> path, so it works always, no matter which USB port it gets re-plugged.</p><p><i>(It will look like this:</i> <code>/dev/serial/by-id/usb-Arduino_RPi_Pico_0764FE3-if00</code>)</p>",
|
"port": "<p>On Unix/linux systems, it is recommended to choose the serial port at: <b>by-id</b> path, so it is fixed, no matter if the USB gets re-plugged.</p><p><i>(It will look like this:</i> <code>/dev/serial/by-id/usb-Arduino_RPi_Pico_0764FE3-if00</code>)</p>",
|
||||||
"search": "<b>Tip:</b> Use search button to try to auto-detect serial port.",
|
"search": "<b>Tip:</b> Use search button to try to auto-detect serial port.",
|
||||||
"pin": "<b>Analogue pins:</b> usually between: <b>0..7</b><br>RPi-Pico has a built-in temperature reader at: <b>A03</b>",
|
"pin": "<b>Analogue pins:</b> usually between: <b>0..7</b><br>RPi-Pico has a built-in temperature reader at: <b>A03</b>",
|
||||||
"log2consol": "<b>To view Logs:</b> If you started node-red in a console, you will be able to see them there. Otherwise type in a consol/terminal:<code> node-red-log </code>",
|
"log2consol": "<b>To view Logs:</b> If you started node-red in a console, you will be able to see them there. Otherwise type in a console/terminal:<code> node-red-log </code>",
|
||||||
"otherboards": "To use this module with [Raspberry Pi - Pico] / [ESP32], you need to flash to the chip a [Configurable-Firmata] firmware: https://github.com/firmata/ConfigurableFirmata",
|
"otherboards": "To use this module with Raspberry Pi Pico or ESP32, you need to flash the chip with a Configurable-Firmata firmware e.g. https://github.com/firmata/ConfigurableFirmata",
|
||||||
"more-at-help": "See more info at the Help tab."
|
"more-at-help": "See more info at the Help tab."
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-node-arduino",
|
"name": "node-red-node-arduino",
|
||||||
"version": "1.3.4-20250331",
|
"version": "2.0.0",
|
||||||
"description": "A Node-RED Node, to talk to a chip as I/O extender, which is running Firmata firmware",
|
"description": "A Node-RED Node, to talk to a chip as I/O extender, which is running Firmata firmware",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"serialport": "^12.0.0"
|
"serialport": "^12.0.0"
|
||||||
@@ -28,16 +28,16 @@
|
|||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Dave Conway-Jones (version <= 1.1)",
|
"name": "Dave Conway-Jones",
|
||||||
"email": "dceejay@gmail.com",
|
"email": "dceejay@gmail.com",
|
||||||
"url": "http://nodered.org"
|
"url": "http://nodered.org"
|
||||||
},
|
},
|
||||||
"contributors": [{
|
"contributors": [{
|
||||||
"name": "PizzaProgram (from version 1.2+ 2025-03-21)",
|
"name": "PizzaProgram (from version 2)",
|
||||||
"email": "info@pizzaprogram.hu",
|
"email": "info@pizzaprogram.hu",
|
||||||
"url": "https://pizzaprogram.hu"
|
"url": "https://pizzaprogram.hu"
|
||||||
}],
|
}],
|
||||||
|
|
||||||
"foreground-scripts": true
|
"foreground-scripts": true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user