node-red-node-arduino
Version:
A Node-RED Node, to talk to a chip as I/O extender, which is running Firmata firmware
250 lines (228 loc) • 12.4 kB
HTML
<!--
This is THE board, which is running Firmata firmware. Tipically an Arduino or RPi-Pico
-->
<script type="text/html" data-template-name="arduino-board">
<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">
<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"/>
<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>
<div class="form-row">
<div class="form-tips"><span data-i18n="[html]arduino.tip.otherboards"></span></div>
</div>
<div class="form-row">
<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 /> mS
</div>
<div class="form-row">
<label for="node-config-input-log2consol"><i class="icon-bookmark"></i>Log to console</label>
<input type="checkbox" id="node-config-input-log2consol">
<div class="form-tips"><span data-i18n="[html]arduino.tip.log2consol"></span></div>
</div>
<!-- arduino.tip.... strings are stored at: 35-arduino.json file -->
</script>
<script type="text/javascript">
RED.nodes.registerType('arduino-board',{
category: 'config',
defaults: {
device : {value: "" , required: true },
name : {value: "" , required: false},
samplingInt: {value: 250 , required: false}, // will read analog inputs 4x / sec by default. Can be 19-65500
log2consol : {value: false, required: false}
},
label: function() {
if (this.name !== "") return this.name
else return this.device || "firmata-board-" + this.id; // (bad naming :-( ) device should be: "port"
},
oneditprepare: function() {
try {
$("#node-config-input-device").autocomplete( "destroy" ); // Remove auto-complete functionality from an <input>.
} catch(err) { };
$("#node-config-lookup-serial").click(async function() { // Board's serial port search function
console.log("Serial Auto-search started.");
$("#node-config-lookup-serial-icon").removeClass('fa-search').addClass('spinner');
$("#node-config-lookup-serial").addClass('disabled');
try {
$.getJSON('arduinoports', async function(data, data2) {
//console.log('Serial Auto-search found data: %o', data);
//console.log('Data2: %o', data2);
// UI Updates
$("#node-config-lookup-serial-icon").removeClass('spinner').addClass('fa-search');
$("#node-config-lookup-serial").removeClass('disabled');
// Ensure ports is an array (fallback to empty array)
ports = data || [];
$("#node-config-input-device").autocomplete({
source: ports,
minLength: 0,
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');
}
});
}
});
</script>
<!--
In - node
-->
<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">
<label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
<input type="text" id="node-input-arduino">
</div>
<div class="form-row">
<label for="node-input-state"><i class="fa fa-wrench"></i> <span data-i18n="arduino.label.type"></span></label>
<select type="text" id="node-input-state" style="width:200px;">
<option value="INPUT" data-i18n="arduino.state.in.digital"></option>
<option value="PULLUP" data-i18n="arduino.state.in.pullup"></option>
<option value="ANALOG" data-i18n="arduino.state.in.analogue"></option>
<option value="STRING" data-i18n="arduino.state.in.string"></option>
</select>
</div>
<div class="form-row">
<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">
</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 type="text/javascript">
RED.nodes.registerType('arduino in',{
category: 'Arduino',
color:"#3fadb5",
defaults: {
name: {value:""},
pin: {value:"",validate: function(v) {
var ct = $("#node-input-state").val() || this.state;
return ct === 'STRING' || (v !== '');
}},
state: {value:"INPUT",required:true},
arduino: {type:"arduino-board"}
},
inputs:0,
outputs:1,
icon: "arduino.png",
label: function() {
if (this.state === "STRING") { return "String"; }
let a = "";
if (this.state === "ANALOG") { a = "A"; }
return this.name || "Pin: " + a + this.pin;
},
labelStyle: function() {
return this.name ? "node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-help-name="arduino in">
<p>This is a "Firmata protocol" based communication, between Node-RED and a connected (Arduino, ESP32, RPi-Pico, etc..) board(s), running firmata firmware. </p>
<p>It is working with many boards, not just Arduino. </p>
<p>This node's code is at: https://github.com/node-red/node-red-nodes/tree/master/hardware/Arduino </p>
<p> </p>
<h3>Settings:</h3>
<p>[b]Arduino:[/b] You can create a new "board", or choose from previously created. That will represent the chip or board connected.</p>
<p>On Unix/linux systems, it is recommended to choose the COM port at "by-serial", 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_RaspberryPi_Pico_076461E62D414FE3-if00</code>)</p>
<p> </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]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>
<h3>The "in" node:</h3>
<p>In = Input means: the board which is running firmata is getting data from input pins.</p>
<p>Then it is sending those data to the host controller, which runs Node-RED.</p>
<p> </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> </p>
<h3>Change Log + More info:</h3>
<p> see: https://github.com/node-red/node-red-nodes/blob/master/hardware/Arduino/README.md </p>
</script>
<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">
<label for="node-input-arduino"><i class="fa fa-tasks"></i> Arduino</label>
<input type="text" id="node-input-arduino">
</div>
<div class="form-row">
<label for="node-input-state"><i class="fa fa-wrench"></i> <span data-i18n="arduino.label.type"></span></label>
<select type="text" id="node-input-state" style="width:200px;">
<option value="OUTPUT" data-i18n="arduino.state.out.digital"></option>
<option value="PWM" data-i18n="arduino.state.out.analogue"></option>
<option value="SERVO" data-i18n="arduino.state.out.servo"></option>
<option value="STRING" data-i18n="arduino.state.out.string"></option>
<option value="RESET" data-i18n="arduino.state.out.reset"></option>
<option value="INTERVAL" data-i18n="arduino.state.out.interval"></option>
</select>
</div>
<div class="form-row">
<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">
</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 type="text/x-red" data-help-name="arduino out">
<p>... First read the help at "Arduino in".</p>
<p>This node's code is at: https://github.com/node-red/node-red-nodes/tree/master/hardware/Arduino </p>
<p> </p>
<h3>The "in" node:</h3>
<p>Out = Output means: you can set individual pins to turn LOW / HIGH / or "x %"=PWM=fast pulses to control voltage.</p>
<p>You can select:</p><ul>
<li>- <b>Digital</b> - accepts 0, 1, true, false, on, off</li>
<li>- <b>Analogue</b> (PWM) - accepts Integer 0 to 255</li>
<li>- <b>Servo</b> - accepts Integer 0 - 180</li>
<li>- <b>String</b> - to send a *String* to the Arduino</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>
</ul>
<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> </p>
<p>You can also send `msg.payoload = "reset"` to any Output Node without pre-configuring it, to reset the board.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('arduino out', {
category: 'Arduino',
color:"#3fadb5",
defaults: {
name: {value:""},
pin: {value:"", validate: function(v) {
var ct = $("#node-input-state").val() || this.state;
return ct === 'STRING' || (v !== '');
}},
state: {value:"",required:true},
arduino: {type:"arduino-board"}
},
inputs:1,
outputs:0,
icon: "arduino.png",
align: "right",
label: function() {
if (this.state === "STRING") { return "String"; }
return this.name||"Pin: "+this.pin;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>