1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Update Arduino to a better supported npm, that supports callbacks

for inputs... (less processor load). Also adds connected status to
visualisation.
This commit is contained in:
Dave C-J 2014-05-23 15:35:55 +01:00
parent db125974c0
commit dcc0adf2f7
2 changed files with 105 additions and 122 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2013 IBM Corp. Copyright 2013,2014 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -38,6 +38,7 @@
<script type="text/x-red" data-help-name="arduino in"> <script type="text/x-red" data-help-name="arduino in">
<p>Arduino input node. Connects to local Arduino and monitors the selected pin for changes. Uses <a href="http://firmata.org/" target="_new"><i>Firmata</i>.</a></p> <p>Arduino input node. Connects to local Arduino and monitors the selected pin for changes. Uses <a href="http://firmata.org/" target="_new"><i>Firmata</i>.</a></p>
<p>The Arduino must be loaded with the Standard Firmata sketch available in the Arduino examples.</p>
<p>You can select either Digital or Analogue input. Outputs the value read as <b>msg.payload</b> and the pin number as <b>msg.topic</b>.</p> <p>You can select either Digital or Analogue input. Outputs the value read as <b>msg.payload</b> and the pin number as <b>msg.topic</b>.</p>
<p>It only outputs on a change of value - fine for digital inputs, but you can get a lot of data from analogue pins which you must then handle.</p> <p>It only outputs on a change of value - fine for digital inputs, but you can get a lot of data from analogue pins which you must then handle.</p>
<p>You can set the sample rate in ms from 20 to 65535.</p> <p>You can set the sample rate in ms from 20 to 65535.</p>
@ -51,7 +52,7 @@
name: {value:""}, name: {value:""},
pin: {value:"",required:true}, pin: {value:"",required:true},
state: {value:"INPUT",required:true}, state: {value:"INPUT",required:true},
arduino: {type:"arduino-board",required:true} arduino: {type:"arduino-board"}
}, },
inputs:0, inputs:0,
outputs:1, outputs:1,
@ -78,7 +79,7 @@
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-state"><i class="icon-wrench"></i> Type</label> <label for="node-input-state"><i class="icon-wrench"></i> Type</label>
<select type="text" id="node-input-state" style="width: 150px;"> <select type="text" id="node-input-state" style="width: 200px;">
<option value="OUTPUT">Digital (0/1)</option> <option value="OUTPUT">Digital (0/1)</option>
<option value="PWM">Analogue (0-255)</option> <option value="PWM">Analogue (0-255)</option>
<option value="SERVO">Servo (0-180)</option> <option value="SERVO">Servo (0-180)</option>
@ -93,6 +94,7 @@
<script type="text/x-red" data-help-name="arduino out"> <script type="text/x-red" data-help-name="arduino out">
<p>Arduino output node. Connects to local Arduino and writes to the selected digital pin. Uses <a href="http://firmata.org/" target="_new"><i>Firmata</i>.</a></p> <p>Arduino output node. Connects to local Arduino and writes to the selected digital pin. Uses <a href="http://firmata.org/" target="_new"><i>Firmata</i>.</a></p>
<p>The Arduino must be loaded with the Standard Firmata sketch available in the Arduino examples.</p>
<p>You can select Digital, Analogue (PWM) or Servo type outputs. Expects a numeric value in <b>msg.payload</b>. The pin number is set in the properties panel.</p> <p>You can select Digital, Analogue (PWM) or Servo type outputs. Expects a numeric value in <b>msg.payload</b>. The pin number is set in the properties panel.</p>
</script> </script>
@ -102,9 +104,9 @@
color:"#3fadb5", color:"#3fadb5",
defaults: { defaults: {
name: {value:""}, name: {value:""},
pin: {value:""}, pin: {value:"",required:true},
state: {value:"",required:true}, state: {value:"",required:true},
arduino: {type:"arduino-board",required:true} arduino: {type:"arduino-board"}
}, },
inputs:1, inputs:1,
outputs:0, outputs:0,
@ -122,29 +124,48 @@
<script type="text/x-red" data-template-name="arduino-board"> <script type="text/x-red" data-template-name="arduino-board">
<div class="form-row"> <div class="form-row">
<label for="node-config-input-device"><i class="icon-bullhorn"></i> Arduino Port</label> <label for="node-config-input-device"><i class="icon-random"></i> Port</label>
<input type="text" id="node-config-input-device" placeholder="/dev/ttyUSB0" style="width:50%;"> <input type="text" id="node-config-input-device" style="width:60%;" placeholder="/dev/ttyUSB0"/>
<a id="node-config-lookup-serial" class="btn"><i id="node-config-lookup-serial-icon" class="icon icon-search"></i></a>
</div> </div>
<div class="form-row"> <div class="form-tips"><b>Tip:</b> Leave blank for auto detect on first serial port.</div>
<label for="node-config-input-repeat"><i class="icon-repeat"></i> Sample (ms)</label>
<input type="text" id="node-config-input-repeat" placeholder="25">
</div>
<!-- <div class="form-row">
<label for="node-config-input-baud"><i class="icon-bullhorn"></i> Baudrate</label>
<input type="text" id="node-config-input-baud" placeholder="115200" style="width:50%;">
</div> -->
</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: {
//baud: {baud:"57600",required:true}, device: {value:""}
repeat: {value:"50",required:true,validate:RED.validators.number()},
device: {value:"",required:true}
}, },
label: function() { label: function() {
return this.device||"arduino"; return this.device||"arduino";
},
oneditprepare: function() {
try {
$("#node-config-input-device").autocomplete( "destroy" );
} catch(err) { }
$("#node-config-lookup-serial").click(function() {
$("#node-config-lookup-serial-icon").removeClass('icon-search');
$("#node-config-lookup-serial-icon").addClass('spinner');
$("#node-config-lookup-serial").addClass('disabled');
$.getJSON('arduinoports',function(data) {
$("#node-config-lookup-serial-icon").addClass('icon-search');
$("#node-config-lookup-serial-icon").removeClass('spinner');
$("#node-config-lookup-serial").removeClass('disabled');
var ports = [];
$.each(data, function(i, port){
ports.push(port);
});
$("#node-config-input-device").autocomplete({
source:ports,
minLength:0,
close: function( event, ui ) {
$("#node-config-input-device").autocomplete( "destroy" );
}
}).autocomplete("search","");
});
});
} }
}); });
</script> </script>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2013 IBM Corp. * Copyright 2013,2014 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,53 +15,33 @@
**/ **/
module.exports = function(RED) { module.exports = function(RED) {
"use strict";
var util = require("util"); var util = require("util");
var firmata = require("firmata"); var ArduinoFirmata = require('arduino-firmata');
var arduinoReady = false;
var thisboard = null;
// The Board Definition - this opens (and closes) the connection // The Board Definition - this opens (and closes) the connection
function ArduinoNode(n) { function ArduinoNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.device = n.device; this.device = n.device || null;
this.repeat = n.repeat||25; this.repeat = n.repeat||25;
util.log("[firmata] Opening "+this.device); //node.log("opening connection "+this.device);
var node = this; var node = this;
node.toun = setInterval(function() { node.board = new ArduinoFirmata();
if (!arduinoReady) { node.board.connect(node.device);
if (thisboard == null) {
node.board = new firmata.Board(node.device, function(err) {
if (err) {
util.log("[firmata] error: "+err);
return;
}
arduinoReady = true;
thisboard = node.board;
clearInterval(node.toun);
util.log('[firmata] Arduino connected');
});
}
else {
node.board = thisboard;
node.board.removeAllListeners();
arduinoReady = true;
clearInterval(node.toun);
node.toun = false;
util.log("[firmata] Arduino already connected");
}
} else { util.log("[firmata] Waiting for Firmata"); }
}, 10000); // wait for firmata to connect to arduino
this.on('close', function() { node.board.on('connect', function(){
//this.board.sp.close(function() { console.log("[firmata] Serial port closed"); arduinoReady = false; }); node.log("version "+node.board.boardVersion);
arduinoReady = false; })
if (node.toun) {
clearInterval(node.toun); node.on('close', function() {
util.log("[firmata] arduino wait loop stopped"); if (node.board) {
try {
node.board.close(function() {
node.log("port closed");
});
} catch(e) { }
} }
util.log("[firmata] Stopped");
}); });
} }
RED.nodes.registerType("arduino-board",ArduinoNode); RED.nodes.registerType("arduino-board",ArduinoNode);
@ -77,46 +57,35 @@ module.exports = function(RED) {
this.serverConfig = RED.nodes.getNode(this.arduino); this.serverConfig = RED.nodes.getNode(this.arduino);
if (typeof this.serverConfig === "object") { if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board; this.board = this.serverConfig.board;
this.repeat = this.serverConfig.repeat; //this.repeat = this.serverConfig.repeat;
var node = this; var node = this;
node.status({fill:"red",shape:"ring",text:"connecting"},true);
node.toui = setInterval(function() { node.board.on('connect', function() {
if (thisboard != null) { node.status({fill:"green",shape:"dot",text:"connected"},true);
node.board = thisboard; //console.log("i",node.state,node.pin);
clearInterval(node.toui);
node.toui = false;
//console.log("i",node.state,node.pin,node.board.MODES[node.state]);
node.board.pinMode(node.pin, node.board.MODES[node.state]);
node.board.setSamplingInterval(node.repeat);
var oldrdg = "";
if (node.state == "ANALOG") { if (node.state == "ANALOG") {
node.board.analogRead(node.pin, function(data) { node.board.on('analogChange', function(e) {
var msg = {payload:data, topic:"A"+node.pin}; if (e.pin == node.pin) {
if (data != oldrdg) { var msg = {payload:e.value, topic:"A"+e.pin};
node.send(msg); node.send(msg);
oldrdg = data;
} }
}); });
}
else {
node.board.digitalRead(node.pin, function(data) {
var msg = {payload:data, topic:node.pin};
node.send(msg);
});
}
}
else { node.log("Waiting for Arduino"); }
}, 5000); // loop to wait for firmata to connect to arduino
this.on('close', function() { }
if (node.toui) { else {
clearInterval(node.toui); node.board.pinMode(node.pin, ArduinoFirmata.INPUT);
util.log("[firmata] input wait loop stopped"); node.board.on('digitalChange', function(e) {
if (e.pin == node.pin) {
var msg = {payload:e.value, topic:e.pin};
node.send(msg);
}
});
} }
}); });
} }
else { else {
util.log("[firmata] Serial Port not Configured"); util.log("[Firmata-arduino] port not configured");
} }
} }
RED.nodes.registerType("arduino in",DuinoNodeIn); RED.nodes.registerType("arduino in",DuinoNodeIn);
@ -133,16 +102,19 @@ module.exports = function(RED) {
if (typeof this.serverConfig === "object") { if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board; this.board = this.serverConfig.board;
var node = this; var node = this;
node.status({fill:"red",shape:"ring",text:"connecting"},true);
this.on("input", function(msg) { node.board.on('connect', function() {
//console.log(msg); node.status({fill:"green",shape:"dot",text:"connected"},true);
if (node.board != null) { //console.log("o",node.state,node.pin);
node.board.pinMode(node.pin, node.state);
node.on("input", function(msg) {
if (node.state == "OUTPUT") { if (node.state == "OUTPUT") {
if ((msg.payload == true)||(msg.payload == 1)||(msg.payload.toString().toLowerCase() == "on")) { if ((msg.payload == true)||(msg.payload == 1)||(msg.payload.toString().toLowerCase() == "on")) {
node.board.digitalWrite(node.pin, node.board.HIGH); node.board.digitalWrite(node.pin, true);
} }
if ((msg.payload == false)||(msg.payload == 0)||(msg.payload.toString().toLowerCase() == "off")) { if ((msg.payload == false)||(msg.payload == 0)||(msg.payload.toString().toLowerCase() == "off")) {
node.board.digitalWrite(node.pin, node.board.LOW); node.board.digitalWrite(node.pin, false);
} }
} }
if (node.state == "PWM") { if (node.state == "PWM") {
@ -159,31 +131,21 @@ module.exports = function(RED) {
node.board.servoWrite(node.pin, msg.payload); node.board.servoWrite(node.pin, msg.payload);
} }
} }
}
//else { console.log("Arduino not ready"); }
}); });
node.touo = setInterval(function() {
if (thisboard != null) {
clearInterval(node.touo);
node.touo = false;
node.board = thisboard;
//console.log("o",node.state,node.pin,node.board.MODES[node.state]);
node.board.pinMode(node.pin, node.board.MODES[node.state]);
}
else { util.log("[firmata] waiting for arduino to connect"); }
}, 5000); // loop to wait for firmata to connect to arduino
this.on('close', function() {
if (node.touo) {
clearInterval(node.touo);
util.log("[firmata] output wait loop stopped");
}
}); });
} }
else { else {
util.log("[firmata] Serial Port not Configured"); util.log("[Firmata-arduino] port not configured");
} }
} }
RED.nodes.registerType("arduino out",DuinoNodeOut); RED.nodes.registerType("arduino out",DuinoNodeOut);
RED.httpAdmin.get("/arduinoports",function(req,res) {
ArduinoFirmata.list(function (err, ports) {
//console.log(JSON.stringify(ports));
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(JSON.stringify(ports));
res.end();
});
});
} }