mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
74d8958526
12
README.md
12
README.md
@ -2,6 +2,8 @@
|
||||
|
||||
A visual tool for wiring the Internet of Things.
|
||||
|
||||
![Screenshot](http://nodered.org/images/node-red-screenshot.png "Node-RED: A visual tool for wiring the Internet of Things")
|
||||
|
||||
## Quick Start
|
||||
|
||||
Check out [INSTALL](INSTALL.md) for full instructions on getting started.
|
||||
@ -16,6 +18,8 @@ Check out [INSTALL](INSTALL.md) for full instructions on getting started.
|
||||
|
||||
More documentation can be found [here](http://nodered.org/docs).
|
||||
|
||||
For further help, or general discussion, there is also a [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
|
||||
## Browser Support
|
||||
|
||||
The Node-RED editor runs in the browser. We routinely develop and test using
|
||||
@ -28,9 +32,11 @@ list.
|
||||
|
||||
### Reporting issues
|
||||
|
||||
Please raise any bug reports or feature requests on the project's issue
|
||||
tracker. Be sure to search the list to see if your issue has already
|
||||
been raised.
|
||||
Please raise any bug reports on the project's [issue tracker](https://github.com/node-red/node-red/issues?state=open).
|
||||
Be sure to search the list to see if your issue has already been raised.
|
||||
|
||||
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red)
|
||||
first.
|
||||
|
||||
### Creating new nodes
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
<!-- Sample html file that corresponds to the 99-sample.js file -->
|
||||
<!-- This creates and configures the onscreen elements of the node -->
|
||||
|
||||
<!-- If you use this as a template, replace IBM Corp. with your own name. -->
|
||||
|
||||
<!-- First, the content of the edit dialog is defined. -->
|
||||
|
||||
<script type="text/x-red" data-template-name="sample">
|
||||
@ -24,7 +26,7 @@
|
||||
|
||||
<!-- Each of the following divs creates a field in the edit dialog. -->
|
||||
<!-- Generally, there should be an input for each property of the node. -->
|
||||
<!-- The for and id attributes identify the corresponding property -->
|
||||
<!-- The for and id attributes identify the corresponding property -->
|
||||
<!-- (with the 'node-input-' prefix). -->
|
||||
<!-- The available icon classes are defined in Twitter Bootstrap -->
|
||||
<div class="form-row">
|
||||
@ -38,7 +40,6 @@
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
@ -14,38 +14,39 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
// If you use this as a template, replace IBM Corp. with your own name.
|
||||
|
||||
// Sample Node-RED node file
|
||||
|
||||
// Require main module
|
||||
var RED = require("../../red/red");
|
||||
|
||||
// The main node definition - most things happen in here
|
||||
function SampleNode(n) {
|
||||
function SampleNode(n) {
|
||||
// Create a RED node
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
|
||||
// Store local copies of the node configuration (as defined in the .html)
|
||||
this.topic = n.topic;
|
||||
|
||||
|
||||
// Do whatever you need to do in here - declare callbacks etc
|
||||
// Note: this sample doesn't do anything much - it will only send
|
||||
// this message once at startup...
|
||||
// Look at other real nodes for some better ideas of what to do....
|
||||
var msg = {};
|
||||
msg.topic = node.topic;
|
||||
msg.topic = this.topic;
|
||||
msg.payload = "Hello world !"
|
||||
|
||||
|
||||
// send out the message to the rest of the workspace.
|
||||
this.send(msg);
|
||||
|
||||
this.on("close", function() {
|
||||
// Called when the node is shutdown - eg on redeploy.
|
||||
// Allows ports to be closed, connections dropped etc.
|
||||
// eg: this.client.disconnect();
|
||||
});
|
||||
}
|
||||
|
||||
// Register the node by name. This must be called before overriding any of the
|
||||
// Node functions.
|
||||
RED.nodes.registerType("sample",SampleNode);
|
||||
|
||||
|
||||
SampleNode.prototype.close = function() {
|
||||
// Called when the node is shutdown - eg on redeploy.
|
||||
// Allows ports to be closed, connections dropped etc.
|
||||
// eg: this.client.disconnect();
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
category: 'advanced-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
useEyes: {value:"false"},
|
||||
useEyes: {value:false},
|
||||
name: {value:""},
|
||||
},
|
||||
inputs:1,
|
||||
|
@ -202,7 +202,7 @@
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var repeattype = "none";
|
||||
if (Number(this.repeat) != 0) {
|
||||
if (this.repeat != "") {
|
||||
repeattype = "interval";
|
||||
$("#inject-time-interval-units option").filter(function() {return $(this).val() == "s";}).attr('selected',true);
|
||||
$("#inject-time-interval-count").val(this.repeat);
|
||||
@ -210,7 +210,7 @@
|
||||
} else if (this.crontab) {
|
||||
var cronparts = this.crontab.split(" ");
|
||||
var days = cronparts[4];
|
||||
if (Number(cronparts[0]) && Number(cronparts[1])) {
|
||||
if (!isNaN(cronparts[0]) && !isNaN(cronparts[1])) {
|
||||
repeattype = "time";
|
||||
// Fixed time
|
||||
var time = cronparts[1]+":"+cronparts[0];
|
||||
|
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-func"><i class="icon-wrench"></i> Function</label>
|
||||
<input type="hidden" id="node-input-func">
|
||||
<input type="hidden" id="node-input-func" autofocus="autofocus">
|
||||
<div style="height: 250px;" class="node-text-editor" id="node-input-func-editor" ></div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@ -85,6 +85,7 @@
|
||||
editor:that.editor, // the field name the main text body goes to
|
||||
fields:['name','outputs']
|
||||
});
|
||||
$("#node-input-name").focus();
|
||||
|
||||
});
|
||||
},
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-template"><i class="icon-wrench"></i> Template</label>
|
||||
<input type="hidden" id="node-input-template">
|
||||
<input type="hidden" id="node-input-template" autofocus="autofocus">
|
||||
<div style="height: 250px;" class="node-text-editor" id="node-input-template-editor" ></div>
|
||||
</div>
|
||||
|
||||
@ -79,7 +79,7 @@
|
||||
editor:that.editor, // the field name the main text body goes to
|
||||
fields:['name']
|
||||
});
|
||||
|
||||
$("#node-input-name").focus();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
|
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-info" style="width: 100% !important;"><i class="icon-file"></i> More</label>
|
||||
<input type="hidden" id="node-input-info">
|
||||
<input type="hidden" id="node-input-info" autofocus="autofocus">
|
||||
<div style="height: 250px;" class="node-text-editor" id="node-input-info-editor" ></div>
|
||||
</div>
|
||||
<div class="form-tips">Tip: this isn't meant for War and Peace - but useful notes can be kept here.</div>
|
||||
@ -75,6 +75,7 @@
|
||||
showFoldingRuler:false,
|
||||
contents: $("#node-input-info").val()
|
||||
});
|
||||
$("#node-input-name").focus();
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
|
@ -138,7 +138,7 @@
|
||||
category: 'config',
|
||||
defaults: {
|
||||
//baud: {baud:"57600",required:true},
|
||||
repeat: {value:"25",required:true,validate:RED.validators.number()},
|
||||
repeat: {value:"50",required:true,validate:RED.validators.number()},
|
||||
device: {value:"",required:true}
|
||||
},
|
||||
label: function() {
|
||||
|
@ -25,46 +25,46 @@ function ArduinoNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.device = n.device;
|
||||
this.repeat = n.repeat||25;
|
||||
util.log("[firmata] Opening"+this.device);
|
||||
util.log("[firmata] Opening "+this.device);
|
||||
var node = this;
|
||||
|
||||
// var tou = setInterval(function() {
|
||||
// if (!arduinoReady) {
|
||||
// clearInterval(tou);
|
||||
|
||||
arduinoReady = false;
|
||||
if (thisboard == null) {
|
||||
this.board = new firmata.Board(this.device, function(err) {
|
||||
if (err) {
|
||||
util.log("[firmata] "+err);
|
||||
return;
|
||||
node.toun = setInterval(function() {
|
||||
if (!arduinoReady) {
|
||||
if (thisboard == null) {
|
||||
node.board = new firmata.Board(node.device, function(err) {
|
||||
if (err) {
|
||||
console.log("[firmata] error: ",err);
|
||||
return;
|
||||
}
|
||||
arduinoReady = true;
|
||||
thisboard = node.board;
|
||||
clearInterval(node.toun);
|
||||
util.log('[firmata] Arduino connected');
|
||||
});
|
||||
}
|
||||
arduinoReady = true;
|
||||
util.log('[firmata] Arduino connected');
|
||||
});
|
||||
thisboard = this.board;
|
||||
}
|
||||
else {
|
||||
util.log("[firmata] Arduino already connected");
|
||||
this.board = thisboard;
|
||||
console.log(this.board._events);
|
||||
this.board.removeAllListeners();
|
||||
arduinoReady = true;
|
||||
}
|
||||
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
|
||||
|
||||
// } else { util.log("[firmata] Waiting for Firmata"); }
|
||||
// }, 1000); // wait for firmata to disconnect from arduino
|
||||
|
||||
this._close = function() {
|
||||
this.on('close', function() {
|
||||
//this.board.sp.close(function() { console.log("[firmata] Serial port closed"); arduinoReady = false; });
|
||||
arduinoReady = false;
|
||||
if (node.toun) {
|
||||
clearInterval(node.toun);
|
||||
util.log("[firmata] arduino wait loop stopped");
|
||||
}
|
||||
util.log("[firmata] Stopped");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("arduino-board",ArduinoNode);
|
||||
|
||||
ArduinoNode.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
|
||||
// The Input Node
|
||||
function DuinoNodeIn(n) {
|
||||
@ -78,11 +78,13 @@ function DuinoNodeIn(n) {
|
||||
this.board = this.serverConfig.board;
|
||||
this.repeat = this.serverConfig.repeat;
|
||||
var node = this;
|
||||
|
||||
var tout = setInterval(function() {
|
||||
if (arduinoReady) {
|
||||
clearInterval(tout);
|
||||
console.log(node.state,node.pin,node.board.MODES[node.state]);
|
||||
|
||||
node.toui = setInterval(function() {
|
||||
if (thisboard != null) {
|
||||
node.board = thisboard;
|
||||
clearInterval(node.toui);
|
||||
node.toui = false;
|
||||
//console.log(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 = "";
|
||||
@ -103,23 +105,21 @@ function DuinoNodeIn(n) {
|
||||
}
|
||||
}
|
||||
else { node.log("Waiting for Arduino"); }
|
||||
}, 2000); // loop to wait for firmata to connect to arduino
|
||||
|
||||
this._close = function() {
|
||||
clearInterval(this._interval);
|
||||
util.log("[arduino] input eventlistener stopped");
|
||||
}
|
||||
}, 5000); // loop to wait for firmata to connect to arduino
|
||||
|
||||
this.on('close', function() {
|
||||
if (node.toui) {
|
||||
clearInterval(node.toui);
|
||||
util.log("[firmata] input wait loop stopped");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
util.log("[arduino] Serial Port not Configured");
|
||||
util.log("[firmata] Serial Port not Configured");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("arduino in",DuinoNodeIn);
|
||||
|
||||
DuinoNodeIn.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
|
||||
|
||||
// The Output Node
|
||||
function DuinoNodeOut(n) {
|
||||
@ -132,10 +132,10 @@ function DuinoNodeOut(n) {
|
||||
if (typeof this.serverConfig === "object") {
|
||||
this.board = this.serverConfig.board;
|
||||
var node = this;
|
||||
|
||||
|
||||
this.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
if (arduinoReady) {
|
||||
if (thisboard != null) {
|
||||
if (node.state == "OUTPUT") {
|
||||
if ((msg.payload == true)||(msg.payload == 1)||(msg.payload.toString().toLowerCase() == "on")) {
|
||||
node.board.digitalWrite(node.pin, node.board.HIGH);
|
||||
@ -161,17 +161,26 @@ function DuinoNodeOut(n) {
|
||||
}
|
||||
//else { console.log("Arduino not ready"); }
|
||||
});
|
||||
|
||||
var touo = setInterval(function() {
|
||||
if (arduinoReady) {
|
||||
clearInterval(touo);
|
||||
//console.log(node.state,node.pin,node.board.MODES[node.state]);
|
||||
|
||||
node.touo = setInterval(function() {
|
||||
if (thisboard != null) {
|
||||
clearInterval(node.touo);
|
||||
node.touo = false;
|
||||
node.board = thisboard;
|
||||
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 {
|
||||
util.log("[arduino] Serial Port not Configured");
|
||||
util.log("[firmata] Serial Port not Configured");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("arduino out",DuinoNodeOut);
|
||||
|
@ -57,7 +57,7 @@ RED.nodes.registerType("http in",HTTPIn);
|
||||
|
||||
function HTTPOut(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
var node = this;
|
||||
this.on("input",function(msg) {
|
||||
if (msg.res) {
|
||||
if (msg.headers) {
|
||||
@ -65,6 +65,8 @@ function HTTPOut(n) {
|
||||
}
|
||||
var statusCode = msg.statusCode || 200;
|
||||
msg.res.send(statusCode,msg.payload);
|
||||
} else {
|
||||
node.warn("No response object");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -80,9 +82,9 @@ function HTTPRequest(n) {
|
||||
this.on("input",function(msg) {
|
||||
|
||||
var opts = urllib.parse(msg.url||url);
|
||||
opts.method = msg.method||method;
|
||||
opts.method = (msg.method||method).toUpperCase();
|
||||
if (msg.headers) {
|
||||
opts.header = headers;
|
||||
opts.header = msg.headers;
|
||||
}
|
||||
var req = httplib.request(opts,function(res) {
|
||||
res.setEncoding('utf8');
|
||||
@ -103,7 +105,7 @@ function HTTPRequest(n) {
|
||||
msg.statusCode = err.code;
|
||||
node.send(msg);
|
||||
});
|
||||
if (msg.payload) {
|
||||
if (msg.payload && (method == "PUSH" || method == "PUT") ) {
|
||||
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
|
||||
req.write(msg.payload);
|
||||
} else if (typeof msg.payload == "number") {
|
||||
|
@ -30,7 +30,7 @@ function TcpIn(n) {
|
||||
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
||||
this.closing = false;
|
||||
var node = this;
|
||||
|
||||
|
||||
if (!node.server) {
|
||||
var buffer = null;
|
||||
var client;
|
||||
@ -41,13 +41,13 @@ function TcpIn(n) {
|
||||
buffer = (node.datatype == 'buffer')? new Buffer(0):"";
|
||||
node.log("connected to "+node.host+":"+node.port);
|
||||
});
|
||||
|
||||
|
||||
client.on('data', function (data) {
|
||||
if (node.datatype != 'buffer') {
|
||||
data = data.toString(node.datatype);
|
||||
}
|
||||
if (node.stream) {
|
||||
if ((typeof data) === "string" && node.newline != "") {
|
||||
if ((node.datatype) === "utf8" && node.newline != "") {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0;i<parts.length-1;i+=1) {
|
||||
@ -100,7 +100,7 @@ function TcpIn(n) {
|
||||
if (node.datatype != 'buffer') {
|
||||
data = data.toString(node.datatype);
|
||||
}
|
||||
|
||||
|
||||
if (node.stream) {
|
||||
if ((typeof data) === "string" && node.newline != "") {
|
||||
buffer = buffer+data;
|
||||
@ -128,21 +128,21 @@ function TcpIn(n) {
|
||||
node.send(msg);
|
||||
buffer = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
socket.on('error',function(err) {
|
||||
node.log(err);
|
||||
});
|
||||
});
|
||||
server.listen(node.port);
|
||||
node.log('listening on port '+node.port);
|
||||
|
||||
|
||||
this._close = function() {
|
||||
this.closing = true;
|
||||
server.close();
|
||||
node.log('stopped listening on port '+node.port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tcp in",TcpIn);
|
||||
@ -150,4 +150,3 @@ RED.nodes.registerType("tcp in",TcpIn);
|
||||
TcpIn.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
|
||||
|
176
nodes/io/32-udp.html
Normal file
176
nodes/io/32-udp.html
Normal file
@ -0,0 +1,176 @@
|
||||
<!--
|
||||
Copyright 2013 IBM Corp.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- The Input Node -->
|
||||
<script type="text/x-red" data-template-name="udp in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="icon-inbox"></i> Listen</label>
|
||||
on port <input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
||||
for <select id="node-input-multicast" style='width:40%'>
|
||||
<option value="false">udp messages</option>
|
||||
<option value="true">multicast messages</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-group">
|
||||
<label for="node-input-group"><i class="icon-list"></i> Group</label>
|
||||
<input type="text" id="node-input-group" placeholder="225.0.18.83">
|
||||
</div>
|
||||
<div class="form-row node-input-iface">
|
||||
<label for="node-input-iface"><i class="icon-random"></i> Interface</label>
|
||||
<input type="text" id="node-input-iface" placeholder="eth0">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-datatype"><i class="icon-file"></i> Output</label>
|
||||
<select id="node-input-datatype" style="width: 70%;">
|
||||
<option value="buffer">a Buffer</option>
|
||||
<option value="utf8">a String</option>
|
||||
<option value="base64">a Base64 encoded string</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-tips">Tip: Make sure your firewall will allow the data in.</div>
|
||||
<script>
|
||||
$("#node-input-multicast").change(function() {
|
||||
var id = $("#node-input-multicast option:selected").val();
|
||||
if (id == "false") {
|
||||
$(".node-input-group").hide();
|
||||
$(".node-input-iface").hide();
|
||||
}
|
||||
else {
|
||||
$(".node-input-group").show();
|
||||
$(".node-input-iface").show();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="udp in">
|
||||
<p>A udp input node, that produces a <b>msg.payload</b> containing a <i>BUFFER</i>, string, or base64 encoded string. Supports multicast.</p>
|
||||
<p>It also provides <b>msg.fromip</b> in the form ipaddress:port .</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('udp in',{
|
||||
category: 'input',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
host: {value:""},
|
||||
iface: {value:""},
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
datatype: {value:"buffer",required:true},
|
||||
multicast: {value:"false"},
|
||||
group: {value:"",validate:function(v) { return (this.multicast !== "true")||v.length > 0;} }
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge-dash.png",
|
||||
label: function() {
|
||||
if (this.multicast=="false") {
|
||||
return this.name||"udp "+this.port;
|
||||
}
|
||||
else return this.name||"udp "+(this.group+":"+this.port);
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!-- The Output Node -->
|
||||
<script type="text/x-red" data-template-name="udp out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="icon-envelope"></i> Send a</label>
|
||||
<select id="node-input-multicast" style='width:40%'>
|
||||
<option value="false">udp message</option>
|
||||
<option value="broad">broadcast message</option>
|
||||
<option value="multi">multicast message</option>
|
||||
</select>
|
||||
to port <input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
||||
</div>
|
||||
<div class="form-row node-input-addr">
|
||||
<label for="node-input-addr" id="node-input-addr-label"><i class="icon-list"></i> Address</label>
|
||||
<input type="text" id="node-input-addr" placeholder="destination ip" style="width: 70%;">
|
||||
</div>
|
||||
<div class="form-row node-input-iface">
|
||||
<label for="node-input-iface"><i class="icon-random"></i> Interface</label>
|
||||
<input type="text" id="node-input-iface" placeholder="eth0">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-base64" placeholder="base64" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-base64" style="width: 70%;">Decode Base64 encoded payload ?</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<script>
|
||||
$("#node-input-multicast").change(function() {
|
||||
var id = $("#node-input-multicast option:selected").val();
|
||||
console.log(id,$("#node-input-addr")[0].placeholder);
|
||||
if (id !== "multi") {
|
||||
$(".node-input-iface").hide();
|
||||
$("#node-input-addr-label").html('<i class="icon-list"></i> Address');
|
||||
$("#node-input-addr")[0].placeholder = 'destination ip';
|
||||
}
|
||||
else {
|
||||
$(".node-input-iface").show();
|
||||
$("#node-input-addr-label").html('<i class="icon-list"></i> Group');
|
||||
$("#node-input-addr")[0].placeholder = '225.0.18.83';
|
||||
}
|
||||
if (id === "broad") {
|
||||
$("#node-input-addr")[0].placeholder = '255.255.255.255';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="udp out">
|
||||
<p>This node sends <b>msg.payload</b> to the designated udp host and port. Supports multicast.</p>
|
||||
<p>If you select broadcast either set the address to the local broadcast ip address, or maybe try 255.255.255.255, which is the global broadcast address.</p>
|
||||
<p>On some systems you may need to be root to use broadcast.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('udp out',{
|
||||
category: 'output',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
addr: {value:"",required:true},
|
||||
//group: {value:""},
|
||||
iface: {value:""},
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
base64: {value:false,required:true},
|
||||
multicast: {value:"false"}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge-dash.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||"udp "+(this.addr+":"+this.port);
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
115
nodes/io/32-udp.js
Normal file
115
nodes/io/32-udp.js
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Copyright 2013 IBM Corp.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var RED = require("../../red/red");
|
||||
var dgram = require('dgram');
|
||||
|
||||
// The Input Node
|
||||
function UDPin(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.group = n.group;
|
||||
this.port = n.port;
|
||||
this.host = n.host || null;
|
||||
this.datatype = n.datatype;
|
||||
this.iface = n.iface || null;
|
||||
this.multicast = n.multicast;
|
||||
var node = this;
|
||||
|
||||
var server = dgram.createSocket('udp4');
|
||||
|
||||
server.on("error", function (err) {
|
||||
console.log("udp listener error:\n" + err.stack);
|
||||
server.close();
|
||||
});
|
||||
|
||||
server.on('message', function (message, remote) {
|
||||
var msg;
|
||||
if (node.datatype =="base64") { msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port }; }
|
||||
else if (node.datatype =="utf8") { msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port }; }
|
||||
else { msg = { payload:message, fromip:remote.address+':'+remote.port }; }
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
server.on('listening', function () {
|
||||
var address = server.address();
|
||||
node.log('udp listener at ' + address.address + ":" + address.port);
|
||||
if (node.multicast == "true") {
|
||||
server.setBroadcast(true)
|
||||
server.setMulticastTTL(128);
|
||||
server.addMembership(node.group,node.iface);
|
||||
node.log("udp multicast group "+node.group);
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
try {
|
||||
server.close();
|
||||
node.log('udp listener stopped');
|
||||
}
|
||||
catch (err) { console.log(err); }
|
||||
});
|
||||
|
||||
server.bind(node.port,node.host);
|
||||
}
|
||||
RED.nodes.registerType("udp in",UDPin);
|
||||
|
||||
|
||||
// The Output Node
|
||||
function UDPout(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
//this.group = n.group;
|
||||
this.port = n.port;
|
||||
this.base64 = n.base64;
|
||||
this.addr = n.addr;
|
||||
this.iface = n.iface || null;
|
||||
this.multicast = n.multicast;
|
||||
var node = this;
|
||||
|
||||
var sock = dgram.createSocket('udp4'); // only use ipv4 for now
|
||||
sock.bind(node.port); // have to bind before you can enable broadcast...
|
||||
if (this.multicast != "false") {
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
if (this.multicast == "multi") {
|
||||
sock.setMulticastTTL(128);
|
||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||
node.log('udp multicast ready : '+node.addr+":"+node.port);
|
||||
}
|
||||
else node.log('udp broadcast ready : '+node.addr+":"+node.port);
|
||||
}
|
||||
else node.log('udp ready : '+node.addr+":"+node.port);
|
||||
|
||||
node.on("input", function(msg) {
|
||||
if (msg.payload != null) {
|
||||
//console.log("UDP:",msg.payload);
|
||||
var message;
|
||||
if (node.base64) { message = new Buffer(b64string, 'base64'); }
|
||||
else { message = new Buffer(""+msg.payload); }
|
||||
console.log("UDP send :",node.addr,node.port);
|
||||
sock.send(message, 0, message.length, node.port, node.addr, function(err, bytes) {
|
||||
if (err) node.error("udp : "+err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
try {
|
||||
sock.close();
|
||||
node.log('udp output stopped');
|
||||
}
|
||||
catch (err) { console.log(err); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("udp out",UDPout);
|
@ -29,8 +29,8 @@
|
||||
pathname += "/";
|
||||
}
|
||||
var callback = encodeURIComponent(location.protocol+"//"+location.hostname+":"+location.port+pathname+"twitter/"+twitterConfigNodeId+"/auth/callback");
|
||||
|
||||
$("#node-config-twitter-row").html('Click <a id="node-config-twitter-start" href="/twitter/'+twitterConfigNodeId+'/auth?callback='+callback+'" target="_blank">here</a> to authenticate with Twitter.');
|
||||
|
||||
$("#node-config-twitter-row").html('Click <a id="node-config-twitter-start" href="/twitter/'+twitterConfigNodeId+'/auth?callback='+callback+'" target="_blank"><b>here</b></a> to authenticate with Twitter.');
|
||||
$("#node-config-twitter-start").click(function() {
|
||||
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
|
||||
});
|
||||
@ -102,34 +102,33 @@
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="twitter in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-twitter"><i class="icon-user"></i> Twitter</label>
|
||||
<div class="form-row">
|
||||
<label for="node-input-twitter"><i class="icon-user"></i> Log in as</label>
|
||||
<input type="text" id="node-input-twitter">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-user"><i class="icon-search"></i> Search</label>
|
||||
<select type="text" id="node-input-user" style="display: inline-block; vertical-align: middle; width:60%;">
|
||||
<option value="false">all public tweets</option>
|
||||
<option value="true">the tweets of who you follow</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tags"><i class="icon-tag"></i> Tags</label>
|
||||
<input type="text" id="node-input-tags" placeholder="comma-separated tags">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-user" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-user" style="width: 70%;">Tick to use user stream<br/>(rather than status/filter)</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
|
||||
<input type="text" id="node-input-topic" placeholder="Topic">
|
||||
<label for="node-input-tags"><i class="icon-tags"></i> for</label>
|
||||
<input type="text" id="node-input-tags" placeholder="comma-separated words, @ids, #tags">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-tips">Tip: the Senders name gets appended to the topic heirarchy
|
||||
</div>
|
||||
<div class="form-tips">Tip: Use commas without spaces between multiple search terms. Comma = OR, Space = AND.
|
||||
<br/>The Twitter API WILL NOT deliver 100% of all tweets.
|
||||
<br/>Tweets of who you follow will include their retweets and favourites.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="twitter in">
|
||||
<p>Twitter input node. Watches the public stream for tweets containing the configured search term.</p>
|
||||
<p>Sets the <b>msg.topic</b> to the configured topic and then appends the senders screen name.</p>
|
||||
<p>Twitter input node. Watches either the public or the user's stream for tweets containing the configured search term.</p>
|
||||
<p>Sets the <b>msg.topic</b> to <i>tweets/</i> and then appends the senders screen name.</p>
|
||||
<p>Sets <b>msg.location</b> to the tweeters location if known.</p>
|
||||
</script>
|
||||
|
||||
@ -140,7 +139,7 @@
|
||||
defaults: {
|
||||
twitter: {type:"twitter-credentials",required:true},
|
||||
tags: {value:"",required:true},
|
||||
user: {value:false},
|
||||
user: {value:"false",required:true},
|
||||
name: {value:""},
|
||||
topic: {value:"tweets"}
|
||||
},
|
||||
|
@ -24,14 +24,13 @@ function TwitterNode(n) {
|
||||
}
|
||||
RED.nodes.registerType("twitter-credentials",TwitterNode);
|
||||
|
||||
|
||||
function TwitterInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.active = true;
|
||||
this.user = n.user;
|
||||
this.tags = n.tags.replace(/ /g,'');
|
||||
this.twitter = n.twitter;
|
||||
this.topic = n.topic;
|
||||
this.topic = n.topic||"tweets";
|
||||
this.twitterConfig = RED.nodes.getNode(this.twitter);
|
||||
var credentials = RED.nodes.getCredentials(this.twitter);
|
||||
|
||||
@ -47,11 +46,12 @@ function TwitterInNode(n) {
|
||||
if (this.tags !== "") {
|
||||
try {
|
||||
var thing = 'statuses/filter';
|
||||
if (this.user) { thing = 'user'; }
|
||||
if (this.user == "true") { thing = 'user'; }
|
||||
function setupStream() {
|
||||
if (node.active) {
|
||||
twit.stream(thing, { track: [node.tags] }, function(stream) {
|
||||
//twit.stream('user', { track: [node.tags] }, function(stream) {
|
||||
//twit.stream('site', { track: [node.tags] }, function(stream) {
|
||||
//twit.stream('statuses/filter', { track: [node.tags] }, function(stream) {
|
||||
node.stream = stream;
|
||||
stream.on('data', function(tweet) {
|
||||
@ -101,8 +101,6 @@ TwitterInNode.prototype.close = function() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function TwitterOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.topic = n.topic;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
<script type="text/x-red" data-template-name="notify">
|
||||
<div class="form-row">
|
||||
<label for="node-input-title"><i class="icon-tag"></i> Title</label>
|
||||
<label for="node-input-title"><i class="icon-flag"></i> Title</label>
|
||||
<input type="text" id="node-input-title" placeholder="Node-RED">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
|
@ -37,7 +37,7 @@ if (pushkey) {
|
||||
function ProwlNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.title = n.title;
|
||||
this.priority = n.priority * 1;
|
||||
this.priority = parseInt(n.priority);
|
||||
if (this.priority > 2) this.priority = 2;
|
||||
if (this.priority < -2) this.priority = -2;
|
||||
var node = this;
|
||||
|
@ -65,12 +65,12 @@
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-tips">Sending complete object will stringify the whole msg object before sending.</div>
|
||||
<div class="form-tips">Sending the complete object will stringify the whole msg object before sending.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="irc out">
|
||||
<p>Connects to a channel on an IRC server</p>
|
||||
<p>If you send something with NO msg.topic it will go to the channel - otherwise it will go to the id in the <b>msg.topic</b> field.</p>
|
||||
<p>Sends messages to a channel on an IRC server</p>
|
||||
<p>If you send something with NO <b>msg.topic</b> it will go to the configured channel - otherwise it will go to the id in the <b>msg.topic</b> field.</p>
|
||||
<p>You can either just send the <b>msg.payload</b>, or you can send the complete <b>msg</b> object.</p>
|
||||
</script>
|
||||
|
||||
@ -103,7 +103,7 @@
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-channel"><i class="icon-tasks"></i> Channel</label>
|
||||
<input type="text" id="node-config-input-channel" placeholder="#testing1234">
|
||||
<input type="text" id="node-config-input-channel" placeholder="#node-red">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-nickname"><i class="icon-tasks"></i> Nickname</label>
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
var RED = require("../../red/red");
|
||||
var irc = require("irc");
|
||||
var util = require("util");
|
||||
|
||||
// The Server Definition - this opens (and closes) the connection
|
||||
function IRCServerNode(n) {
|
||||
@ -23,40 +24,38 @@ function IRCServerNode(n) {
|
||||
this.server = n.server;
|
||||
this.channel = n.channel;
|
||||
this.nickname = n.nickname;
|
||||
this.ircclient = new irc.Client(this.server, this.nickname, {
|
||||
channels: [this.channel]
|
||||
this.ircclient = null;
|
||||
this.on("close", function() {
|
||||
if (this.ircclient != null) {
|
||||
this.ircclient.disconnect();
|
||||
}
|
||||
});
|
||||
this._close = function() {
|
||||
this.ircclient.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("irc-server",IRCServerNode);
|
||||
|
||||
IRCServerNode.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
|
||||
|
||||
// The Input Node
|
||||
function IrcInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.ircserver = n.ircserver;
|
||||
this.serverConfig = RED.nodes.getNode(this.ircserver);
|
||||
if (this.serverConfig.ircclient == null) {
|
||||
this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
|
||||
channels: [this.serverConfig.channel]
|
||||
});
|
||||
this.serverConfig.ircclient.addListener('error', function(message) {
|
||||
util.log('[irc] '+ JSON.stringify(message));
|
||||
});
|
||||
}
|
||||
this.ircclient = this.serverConfig.ircclient;
|
||||
var node = this;
|
||||
|
||||
|
||||
this.ircclient.addListener('message', function (from, to, message) {
|
||||
console.log(from + ' => ' + to + ': ' + message);
|
||||
var msg = { "topic":from, "to":to, "payload":message };
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
this.ircclient.addListener('error', function(message) {
|
||||
node.error(JSON.stringify(message));
|
||||
});
|
||||
|
||||
}
|
||||
RED.nodes.registerType("irc in",IrcInNode);
|
||||
|
||||
@ -66,12 +65,20 @@ function IrcOutNode(n) {
|
||||
this.sendAll = n.sendObject;
|
||||
this.ircserver = n.ircserver;
|
||||
this.serverConfig = RED.nodes.getNode(this.ircserver);
|
||||
this.ircclient = this.serverConfig.ircclient;
|
||||
this.channel = this.serverConfig.channel;
|
||||
if (this.serverConfig.ircclient == null) {
|
||||
this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
|
||||
channels: [this.serverConfig.channel]
|
||||
});
|
||||
this.serverConfig.ircclient.addListener('error', function(message) {
|
||||
util.log('[irc] '+ JSON.stringify(message));
|
||||
});
|
||||
}
|
||||
this.ircclient = this.serverConfig.ircclient;
|
||||
var node = this;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
console.log(msg);
|
||||
//console.log(msg,node.channel);
|
||||
if (node.sendAll) {
|
||||
node.ircclient.say(node.channel, JSON.stringify(msg));
|
||||
}
|
||||
|
@ -14,8 +14,17 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var orig=console.warn;
|
||||
console.warn=(function() { // suppress warning from stringprep when not needed)
|
||||
var orig=console.warn;
|
||||
return function() {
|
||||
//orig.apply(console, arguments);
|
||||
};
|
||||
})();
|
||||
|
||||
var RED = require("../../red/red");
|
||||
var xmpp = require('simple-xmpp');
|
||||
console.warn = orig;
|
||||
|
||||
try {
|
||||
var xmppkey = require("../../settings").xmpp || require("../../../xmppkeys.js");
|
||||
@ -97,17 +106,13 @@ function XmppNode(n) {
|
||||
}
|
||||
});
|
||||
|
||||
this._close = function() {
|
||||
this.on("close", function() {
|
||||
xmpp.setPresence('offline');
|
||||
//xmpp.conn.end();
|
||||
// TODO - DCJ NOTE... this is not good. It leaves the connection up over a restart - which will end up with bad things happening...
|
||||
// (but requires the underlying xmpp lib to be fixed (which does have an open bug request on fixing the close method)).
|
||||
this.warn("Due to an underlying bug in the xmpp library this does not disconnect old sessions. This is bad... A restart would be better.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("xmpp",XmppNode);
|
||||
|
||||
XmppNode.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
|
BIN
public/icons/bluetooth.png
Normal file
BIN
public/icons/bluetooth.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
@ -143,8 +143,34 @@ RED.editor = function() {
|
||||
var changes = {};
|
||||
var changed = false;
|
||||
var wasDirty = RED.view.dirty();
|
||||
|
||||
|
||||
if (editing_node._def.oneditsave) {
|
||||
var oldValues = {};
|
||||
for (var d in editing_node._def.defaults) {
|
||||
if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
|
||||
oldValues[d] = editing_node[d];
|
||||
} else {
|
||||
oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
|
||||
}
|
||||
}
|
||||
editing_node._def.oneditsave.call(editing_node);
|
||||
|
||||
for (var d in editing_node._def.defaults) {
|
||||
if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") {
|
||||
if (oldValues[d] !== editing_node[d]) {
|
||||
changes[d] = oldValues[d];
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
|
||||
changes[d] = oldValues[d];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (editing_node._def.defaults) {
|
||||
@ -177,7 +203,6 @@ RED.editor = function() {
|
||||
changes[d] = editing_node[d];
|
||||
editing_node[d] = newValue;
|
||||
changed = true;
|
||||
RED.view.dirty(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -185,6 +210,7 @@ RED.editor = function() {
|
||||
|
||||
var removedLinks = updateNodeProperties(editing_node);
|
||||
if (changed) {
|
||||
RED.view.dirty(true);
|
||||
RED.history.push({t:'edit',node:editing_node,changes:changes,links:removedLinks,dirty:wasDirty});
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,10 @@ RED.palette = function() {
|
||||
container:'body',
|
||||
content: $(($("script[data-help-name|='"+nt+"']").html()||"<p>no information available</p>").trim())[0]
|
||||
});
|
||||
|
||||
$(d).click(function() {
|
||||
var help = '<div class="node-help">'+($("script[data-help-name|='"+d.type+"']").html()||"")+"</div>";
|
||||
$("#tab-info").html(help);
|
||||
});
|
||||
$(d).draggable({
|
||||
helper: 'clone',
|
||||
appendTo: 'body',
|
||||
|
@ -649,7 +649,13 @@ RED.view = function() {
|
||||
//mainRect.on("touchend",nodeMouseUp);
|
||||
|
||||
if (d._def.icon) {
|
||||
var icon = node.append("image").attr("xlink:href","icons/"+d._def.icon).attr("class","node_icon").attr("x",0).attr("y",0).attr("width","15").attr("height",function(d){return Math.min(50,d.h);});
|
||||
var icon = node.append("image")
|
||||
.attr("xlink:href","icons/"+d._def.icon)
|
||||
.attr("class","node_icon")
|
||||
.attr("x",0).attr("y",function(d){return (d.h-Math.min(50,d.h))/2;})
|
||||
.attr("width","15")
|
||||
.attr("height", function(d){return Math.min(50,d.h);});
|
||||
|
||||
if (d._def.align) {
|
||||
icon.attr('class','node_icon node_icon_'+d._def.align);
|
||||
}
|
||||
@ -747,7 +753,7 @@ RED.view = function() {
|
||||
var port = d3.select(this);
|
||||
port.attr("y",function(d){return (d.h/2)-5;})
|
||||
});
|
||||
thisNode.selectAll(".node_icon").attr("height",function(d){return Math.min(50,d.h);});
|
||||
thisNode.selectAll(".node_icon").attr("height",function(d){return Math.min(50,d.h);}).attr("y",function(d){return (d.h-Math.min(50,d.h))/2;});
|
||||
|
||||
thisNode.selectAll('.node_right_button_group').attr("transform",function(d){return "translate("+(d.w-100)+","+0+")";});
|
||||
thisNode.selectAll('.node_right_button').attr("transform",function(d){return "translate("+(d.w-100)+","+0+")";}).attr("fill",function(d) {
|
||||
|
26
red.js
26
red.js
@ -21,7 +21,6 @@ var crypto = require("crypto");
|
||||
var settings = require("./settings");
|
||||
var RED = require("./red/red.js");
|
||||
|
||||
|
||||
var server;
|
||||
var app = express();
|
||||
|
||||
@ -49,11 +48,30 @@ if (settings.httpAuth) {
|
||||
);
|
||||
}
|
||||
|
||||
settings.flowFile = process.argv[2] || settings.flowFile;
|
||||
|
||||
var red = RED.init(server,settings);
|
||||
app.use(settings.httpRoot,red);
|
||||
|
||||
|
||||
server.listen(settings.uiPort);
|
||||
RED.start();
|
||||
util.log('[red] Server now running at http'+(settings.https?'s':'')+'://127.0.0.1:'+settings.uiPort+settings.httpRoot);
|
||||
|
||||
server.listen(settings.uiPort,function() {
|
||||
util.log('[red] Server now running at http'+(settings.https?'s':'')+'://127.0.0.1:'+settings.uiPort+settings.httpRoot);
|
||||
});
|
||||
|
||||
process.on('uncaughtException',function(err) {
|
||||
if (err.errno === "EADDRINUSE") {
|
||||
util.log('[red] Unable to listen on http'+(settings.https?'s':'')+'://127.0.0.1:'+settings.uiPort+settings.httpRoot);
|
||||
util.log('[red] Error: port in use');
|
||||
} else {
|
||||
util.log('[red] Uncaught Exception:');
|
||||
util.log(err.stack);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('SIGINT', function () {
|
||||
RED.stop();
|
||||
util.log('[red] Exiting Node-RED. Thank you.');
|
||||
process.exit();
|
||||
});
|
||||
|
35
red/nodes.js
35
red/nodes.js
@ -42,7 +42,6 @@ function getCallerFilename(type) {
|
||||
return stack[0].getFileName();
|
||||
}
|
||||
|
||||
|
||||
var registry = (function() {
|
||||
var nodes = {};
|
||||
var logHandlers = [];
|
||||
@ -91,7 +90,6 @@ var node_type_registry = (function() {
|
||||
var obj = {
|
||||
register: function(type,node) {
|
||||
util.inherits(node, Node);
|
||||
|
||||
var callerFilename = getCallerFilename(type);
|
||||
if (callerFilename == null) {
|
||||
util.log("["+type+"] unable to determine filename");
|
||||
@ -117,7 +115,6 @@ var node_type_registry = (function() {
|
||||
result += node_configs[nt];
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
@ -176,7 +173,6 @@ Node.prototype.send = function(msg) {
|
||||
}
|
||||
module.exports.Node = Node;
|
||||
|
||||
|
||||
Node.prototype.receive = function(msg) {
|
||||
this.emit("input",msg);
|
||||
}
|
||||
@ -197,9 +193,6 @@ Node.prototype.error = function(msg) {
|
||||
this.emit("log",o);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var credentials = {};
|
||||
var credentialsFile = "credentials.json";
|
||||
if (fs.existsSync(credentialsFile)) {
|
||||
@ -225,8 +218,6 @@ module.exports.deleteCredentials = function(id) {
|
||||
delete credentials[id];
|
||||
saveCredentialsFile();
|
||||
}
|
||||
|
||||
|
||||
module.exports.createNode = function(node,def) {
|
||||
Node.call(node,def);
|
||||
}
|
||||
@ -257,12 +248,9 @@ module.exports.load = function() {
|
||||
});
|
||||
}
|
||||
loadNodes(__dirname+"/../nodes");
|
||||
|
||||
//events.emit("nodes-loaded");
|
||||
}
|
||||
|
||||
|
||||
|
||||
var activeConfig = null;
|
||||
var missingTypes = [];
|
||||
|
||||
@ -279,10 +267,15 @@ events.on('type-registered',function(type) {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports.getNode = function(nid) {
|
||||
return registry.get(nid);
|
||||
}
|
||||
|
||||
module.exports.closedown = function() {
|
||||
util.log("[red] Closing Down Nodes");
|
||||
registry.clear();
|
||||
}
|
||||
|
||||
module.exports.setConfig = function(conf) {
|
||||
if (activeConfig&&activeConfig.length > 0) {
|
||||
util.log("[red] Stopping flows");
|
||||
@ -293,7 +286,6 @@ module.exports.setConfig = function(conf) {
|
||||
}
|
||||
|
||||
var parseConfig = function() {
|
||||
|
||||
missingTypes = [];
|
||||
for (var i in activeConfig) {
|
||||
var type = activeConfig[i].type;
|
||||
@ -307,7 +299,6 @@ var parseConfig = function() {
|
||||
for (var i in missingTypes) {
|
||||
util.log("[red] - "+missingTypes[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -317,19 +308,18 @@ var parseConfig = function() {
|
||||
var nn = null;
|
||||
var nt = node_type_registry.get(activeConfig[i].type);
|
||||
if (nt) {
|
||||
try {
|
||||
nn = new nt(activeConfig[i]);
|
||||
}
|
||||
catch (err) {
|
||||
util.log("[red] "+activeConfig[i].type+" : "+err);
|
||||
}
|
||||
try {
|
||||
nn = new nt(activeConfig[i]);
|
||||
}
|
||||
catch (err) {
|
||||
util.log("[red] "+activeConfig[i].type+" : "+err);
|
||||
}
|
||||
}
|
||||
// console.log(nn);
|
||||
if (nn == null) {
|
||||
util.log("[red] unknown type: "+activeConfig[i].type);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up any orphaned credentials
|
||||
var deletedCredentials = false;
|
||||
for (var c in credentials) {
|
||||
@ -343,5 +333,4 @@ var parseConfig = function() {
|
||||
saveCredentialsFile();
|
||||
}
|
||||
events.emit("nodes-started");
|
||||
|
||||
}
|
||||
|
12
red/red.js
12
red/red.js
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var events = require("./events");
|
||||
var events = require("./events");
|
||||
var server = require("./server");
|
||||
var nodes = require("./nodes");
|
||||
var library = require("./library");
|
||||
@ -24,23 +24,23 @@ var settings = null;
|
||||
var events = require("events");
|
||||
|
||||
var RED = {
|
||||
|
||||
|
||||
init: function(httpServer,userSettings) {
|
||||
settings = userSettings;
|
||||
server.init(httpServer,settings);
|
||||
library.init();
|
||||
return server.app;
|
||||
},
|
||||
|
||||
|
||||
start: server.start,
|
||||
|
||||
nodes: nodes,
|
||||
library: library,
|
||||
events: events
|
||||
events: events,
|
||||
stop: nodes.closedown,
|
||||
};
|
||||
|
||||
RED.__defineGetter__("app", function() { return server.app });
|
||||
RED.__defineGetter__("server", function() { return server.server });
|
||||
RED.__defineGetter__("settings", function() { return settings });
|
||||
|
||||
module.exports = RED;
|
||||
module.exports = RED;
|
||||
|
@ -18,9 +18,9 @@ var fs = require('fs');
|
||||
var util = require('util');
|
||||
var createUI = require("./ui");
|
||||
var redNodes = require("./nodes");
|
||||
var host = require('os').hostname();
|
||||
//TODO: relocated user dir
|
||||
var rulesfile = process.argv[2] || 'flows_'+host+'.json';
|
||||
|
||||
var flowfile = '';
|
||||
|
||||
var app = null;
|
||||
var server = null;
|
||||
@ -29,6 +29,8 @@ function createServer(_server,settings) {
|
||||
server = _server;
|
||||
app = createUI(settings);
|
||||
|
||||
flowfile = settings.flowFile || 'flows_'+require('os').hostname()+'.json';
|
||||
|
||||
//TODO: relocated user dir
|
||||
fs.exists("lib/",function(exists) {
|
||||
if (!exists) {
|
||||
@ -43,9 +45,9 @@ function createServer(_server,settings) {
|
||||
});
|
||||
|
||||
app.get("/flows",function(req,res) {
|
||||
fs.exists(rulesfile, function (exists) {
|
||||
fs.exists(flowfile, function (exists) {
|
||||
if (exists) {
|
||||
res.sendfile(rulesfile);
|
||||
res.sendfile(flowfile);
|
||||
} else {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.write("[]");
|
||||
@ -62,7 +64,7 @@ function createServer(_server,settings) {
|
||||
req.on('end', function() {
|
||||
res.writeHead(204, {'Content-Type': 'text/plain'});
|
||||
res.end();
|
||||
fs.writeFile(rulesfile, fullBody, function(err) {
|
||||
fs.writeFile(flowfile, fullBody, function(err) {
|
||||
if(err) {
|
||||
util.log(err);
|
||||
} else {
|
||||
@ -87,14 +89,14 @@ function start() {
|
||||
util.log("------------------------------------------");
|
||||
|
||||
|
||||
fs.exists(rulesfile, function (exists) {
|
||||
fs.exists(flowfile, function (exists) {
|
||||
if (exists) {
|
||||
util.log("[red] Loading flows : "+rulesfile);
|
||||
fs.readFile(rulesfile,'utf8',function(err,data) {
|
||||
util.log("[red] Loading flows : "+flowfile);
|
||||
fs.readFile(flowfile,'utf8',function(err,data) {
|
||||
redNodes.setConfig(JSON.parse(data));
|
||||
});
|
||||
} else {
|
||||
util.log("[red] Flows file not found : "+rulesfile);
|
||||
util.log("[red] Flows file not found : "+flowfile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ module.exports = {
|
||||
serialReconnectTime: 15000,
|
||||
debugMaxLength: 1000,
|
||||
|
||||
// The file containing the flows. If not set, it defaults to flows_<hostname>.json
|
||||
//flowFile: 'flows.json',
|
||||
|
||||
// You can protect the user interface with a userid and password by using the following property
|
||||
// the password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
|
||||
//httpAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},
|
||||
|
Loading…
Reference in New Issue
Block a user