mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Move all nodes into core subdirectory
This makes it easier to distinguish core nodes from those added later
This commit is contained in:
51
nodes/core/analysis/72-sentiment.html
Normal file
51
nodes/core/analysis/72-sentiment.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="sentiment">
|
||||
<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">Adds <b>msg.sentiment.score</b> as the anaylsis result.
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="sentiment">
|
||||
<p>Analyses the <b>msg.payload</b> and adds a <b>msg.sentiment</b> object that contains the resulting AFINN-111 sentiment score as <b>msg.sentiment.score</b>.</p>
|
||||
<p>A score greater than zero is positive and less than zero is negative.</p>
|
||||
<p>Score can range from -5 to +5.</p>
|
||||
<p>See <a href="https://github.com/thisandagain/sentiment/blob/master/README.md" target="_new">the Sentiment docs here</a>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('sentiment',{
|
||||
category: 'analysis-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "arrow-in.png",
|
||||
label: function() {
|
||||
return this.name||"sentiment";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
32
nodes/core/analysis/72-sentiment.js
Normal file
32
nodes/core/analysis/72-sentiment.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var sentiment = require('sentiment');
|
||||
|
||||
function SentimentNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.on("input", function(msg) {
|
||||
var node = this;
|
||||
sentiment(msg.payload, function (err, result) {
|
||||
msg.sentiment = result;
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("sentiment",SentimentNode);
|
53
nodes/core/analysis/73-parsexml.html
Normal file
53
nodes/core/analysis/73-parsexml.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="xml2js">
|
||||
<div class="form-row">
|
||||
<label>Use Console</label>
|
||||
<input type="checkbox" id="node-input-useEyes" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-useEyes" style="width: 70%;">Debug output in console ?</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>
|
||||
<div class="form-tips">Uses xml2js to process xml into javascript object.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="xml2js">
|
||||
<p>A function that parses the <b>msg.payload</b> using the xml2js library. Places the result in the payload.</p>
|
||||
<p>See <a href="https://github.com/Leonidas-from-XIV/node-xml2js/blob/master/README.md" target="_new">the xml2js docs <i>here</i></a> for more information.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('xml2js',{
|
||||
category: 'advanced-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
useEyes: {value:false},
|
||||
name: {value:""},
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "arrow-in.png",
|
||||
label: function() {
|
||||
return this.name||"xml2json";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
49
nodes/core/analysis/73-parsexml.js
Normal file
49
nodes/core/analysis/73-parsexml.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var util = require("util");
|
||||
var parseString = require('xml2js').parseString;
|
||||
var gotEyes = false;
|
||||
try {
|
||||
var eyes = require("eyes");
|
||||
gotEyes = true;
|
||||
} catch(e) {
|
||||
util.log("[73-parsexml.js] Note: Module 'eyes' not installed. (not needed, but useful)");
|
||||
}
|
||||
|
||||
function Xml2jsNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.useEyes = n.useEyes;
|
||||
var node = this;
|
||||
this.on("input", function(msg) {
|
||||
try {
|
||||
parseString(msg.payload, function (err, result) {
|
||||
if (err) { node.error(err); }
|
||||
else {
|
||||
msg.payload = result;
|
||||
node.send(msg);
|
||||
if (node.useEyes == true) {
|
||||
if (gotEyes == true) { eyes.inspect(msg); }
|
||||
else { node.log(JSON.stringify(msg)); }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) { util.log("[73-parsexml.js] "+e); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("xml2js",Xml2jsNode);
|
51
nodes/core/analysis/74-js2xml.html
Normal file
51
nodes/core/analysis/74-js2xml.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="json2xml">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-list"></i> XML Root</label>
|
||||
<input type="text" id="node-input-root" placeholder="object"></input>
|
||||
</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"></input>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="json2xml">
|
||||
<p>A function that parses the <b>msg.payload</b> using the js2xmlparser library. Places the result back in <b>msg.payload</b>.</p>
|
||||
<p>See the <a href="https://github.com/michaelkourlas/node-js2xmlparser" target="_new">js2xmlparser docs</a> for more information.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('json2xml',{
|
||||
category: 'advanced-function',
|
||||
color:"#E6E0F8",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
root: {value:"object"},
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "arrow-in.png",
|
||||
label: function() {
|
||||
return this.name||"json2xml";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
36
nodes/core/analysis/74-js2xml.js
Normal file
36
nodes/core/analysis/74-js2xml.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var js2xmlparser = require("js2xmlparser");
|
||||
|
||||
function Js2XmlNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.root = n.root;
|
||||
var node = this;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
try {
|
||||
var root = node.root || typeof msg.payload;
|
||||
if (typeof msg.payload !== "object") { msg.payload = '"'+msg.payload+'"'; }
|
||||
console.log(root, typeof msg.payload,msg.payload);
|
||||
msg.payload = js2xmlparser(root, msg.payload);
|
||||
node.send(msg);
|
||||
}
|
||||
catch(e) { console.log(e); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("json2xml",Js2XmlNode);
|
69
nodes/core/deprecated/30-socketin.html
Normal file
69
nodes/core/deprecated/30-socketin.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="socket in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-transport"><i class="icon-tasks"></i> Type</label>
|
||||
<select type="text" id="node-input-transport" style="width: 150px;">
|
||||
<option value="http">http listen</option>
|
||||
<option value="tcp">tcp server</option>
|
||||
<!-- <option value="tcpc">tcp client</option> -->
|
||||
<option value="udp">udp socket</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="icon-random"></i> Port</label>
|
||||
<input type="text" id="node-input-port" placeholder="Port">
|
||||
</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">
|
||||
</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: sends the received data as a Buffer object.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="socket in">
|
||||
<p>Provides a input node for http, tcp or udp sockets. Topic is optional. These are server like sockets.</p>
|
||||
<p>The TCP and UDP sockets produce a <i>BUFFER</i> object msg.payload and NOT a String. If you need a String then use .toString() on msg.payload in your next function block.</p>
|
||||
<p>TCP and UDP sockets also provide <b>msg.fromip</b> of the form ipaddress:port</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('socket in',{
|
||||
category: 'deprecated',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
topic: {value:""},
|
||||
port: {value:"",required:true},
|
||||
transport: {value:"tcp",required:true}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge-dash.png",
|
||||
label: function() {
|
||||
return this.name||this.topic||("socket "+this.transport+":"+this.port);
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
152
nodes/core/deprecated/30-socketin.js
Normal file
152
nodes/core/deprecated/30-socketin.js
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
|
||||
function SocketIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.warn("node type deprecated - will be removed in a future release");
|
||||
this.port = n.port;
|
||||
this.topic = n.topic;
|
||||
this.trans = (n.transport||n.trans||"").toLowerCase();
|
||||
var node = this;
|
||||
if (this.trans == "http") {
|
||||
var http = require('http');
|
||||
var server = http.createServer(function (req, res) {
|
||||
//node.log("http "+req.url);
|
||||
var msg = {topic:node.topic,payload:req.url.slice(1)};
|
||||
node.send(msg);
|
||||
res.writeHead(304, {'Content-Type': 'text/plain'});
|
||||
res.end('\n');
|
||||
}).listen(node.port);
|
||||
server.on('error', function (e) {
|
||||
if (e.code == 'EADDRINUSE') {
|
||||
setTimeout(node.error('TCP port is already in use - please reconfigure socket.'),250);
|
||||
}
|
||||
else { console.log(e); }
|
||||
server = null;
|
||||
});
|
||||
node.log('http listener at http://127.0.0.1:'+node.port+'/');
|
||||
|
||||
this._close = function() {
|
||||
if (server) server.close();
|
||||
node.log('http listener stopped');
|
||||
}
|
||||
}
|
||||
|
||||
if (this.trans == "tcp") {
|
||||
var net = require('net');
|
||||
var server = net.createServer(function (socket) {
|
||||
var buffer = null;
|
||||
socket.on('data', function (chunk) {
|
||||
if (buffer == null) {
|
||||
buffer = chunk;
|
||||
} else {
|
||||
buffer = Buffer.concat([buffer,chunk]);
|
||||
}
|
||||
});
|
||||
socket.on('end', function() {
|
||||
var msg = {topic:node.topic, payload:buffer, fromip:socket.remoteAddress+':'+socket.remotePort};
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
server.on('error', function (e) {
|
||||
if (e.code == 'EADDRINUSE') {
|
||||
setTimeout(node.error('TCP port is already in use - please reconfigure socket.'),250);
|
||||
}
|
||||
else { console.log(e); }
|
||||
server = null;
|
||||
});
|
||||
server.listen(node.port);
|
||||
node.log('tcp listener on port :'+node.port);
|
||||
|
||||
this._close = function() {
|
||||
if (server) server.close();
|
||||
node.log('tcp listener stopped');
|
||||
}
|
||||
}
|
||||
|
||||
if (this.trans == "tcpc") {
|
||||
var net = require('net');
|
||||
var client;
|
||||
var to;
|
||||
function setupTcpClient() {
|
||||
node.log('tcpc connecting to port :'+node.port);
|
||||
client = net.connect({port: node.port}, function() {
|
||||
node.log("tcpc connected");
|
||||
});
|
||||
|
||||
client.on('data', function (data) {
|
||||
var msg = {topic:node.topic, payload:data};
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
client.on('end', function() {
|
||||
node.log("tcpc socket ended");
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
node.log('tcpc socket closed');
|
||||
to = setTimeout(setupTcpClient, 10000); //Try to reconnect
|
||||
});
|
||||
|
||||
client.on('error', function() {
|
||||
node.log('tcpc socket error');
|
||||
client = null;
|
||||
to = setTimeout(setupTcpClient, 10000); //Try to reconnect
|
||||
});
|
||||
}
|
||||
setupTcpClient();
|
||||
|
||||
this._close = function() {
|
||||
if (client) client.end();
|
||||
//client.destroy();
|
||||
clearTimeout(to);
|
||||
node.log('tcpc stopped client');
|
||||
}
|
||||
setupTcpClient();
|
||||
}
|
||||
|
||||
if (this.trans == "udp") {
|
||||
var dgram = require('dgram');
|
||||
var server = dgram.createSocket('udp4');
|
||||
server.on('listening', function () {
|
||||
var address = server.address();
|
||||
node.log('udp listener at ' + address.address + ":" + address.port);
|
||||
});
|
||||
server.on('message', function (message, remote) {
|
||||
var msg = {topic:node.topic,payload:message,fromip:remote.address+':'+remote.port};
|
||||
node.send(msg);
|
||||
});
|
||||
server.on('error', function (e) {
|
||||
console.log(e);
|
||||
server = null;
|
||||
});
|
||||
server.bind(node.port);
|
||||
|
||||
this._close = function() {
|
||||
if (server) server.close();
|
||||
node.log('udp listener stopped');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RED.nodes.registerType("socket in",SocketIn);
|
||||
|
||||
SocketIn.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
66
nodes/core/deprecated/30-socketout.html
Normal file
66
nodes/core/deprecated/30-socketout.html
Normal file
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="socket out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-host"><i class="icon-bookmark"></i> Host</label>
|
||||
<input type="text" id="node-input-host" placeholder="localhost" style="width: 40%;" >
|
||||
|
||||
<label for="node-input-port" style="margin-left: 10px; width: 35px;"> Port</label>
|
||||
<input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-transport"><i class="icon-tasks"></i> Type</label>
|
||||
<select type="text" id="node-input-transport" style="width: 150px;">
|
||||
<option value="http">http</option>
|
||||
<option value="tcp">tcp</option>
|
||||
<option value="udp">udp</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>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="socket out">
|
||||
<p>Provides a choice of http, tcp or udp output connections. All connect, send their <b>msg.payload</b> and disconnect.</p>
|
||||
<p>To use broadcast select udp and set the host to be either the subnet broadcast address required or 255.255.255.255</p>
|
||||
<p>If you need a response from an http request use the httpget node instead.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('socket out',{
|
||||
category: 'deprecated',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
host: {value:"127.0.0.1",required:true},
|
||||
port: {value:"",required:true},
|
||||
name: {value:""},
|
||||
transport: {value:"tcp",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge-dash.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.topic||("socket "+this.transport+":"+this.port);
|
||||
},
|
||||
labelStyle: function() {
|
||||
return (this.name||!this.topic)?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
65
nodes/core/deprecated/30-socketout.js
Normal file
65
nodes/core/deprecated/30-socketout.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
|
||||
function SocketOut(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.warn("node type deprecated - will be removed in a future release");
|
||||
this.host = n.host;
|
||||
this.port = n.port * 1;
|
||||
this.name = n.name;
|
||||
this.trans = n.transport||n.trans||"";
|
||||
var node = this;
|
||||
this.on("input", function(msg) {
|
||||
if (msg != null) {
|
||||
if (this.trans == "http") {
|
||||
var http = require("http");
|
||||
http.get(msg.payload, function(res) {
|
||||
node.log("http : response : " + res.statusCode);
|
||||
}).on('error', function(e) {
|
||||
node.error("http : error : " + e.message);
|
||||
});
|
||||
}
|
||||
if (this.trans == "tcp") {
|
||||
var net = require('net');
|
||||
var client = new net.Socket();
|
||||
client.on('error', function (err) {
|
||||
node.error('tcp : '+err);
|
||||
});
|
||||
client.connect(this.port, this.host, function() {
|
||||
try { client.end(msg.payload); }
|
||||
catch (e) { node.error(e); }
|
||||
});
|
||||
}
|
||||
if (this.trans == "udp") {
|
||||
var dgram = require('dgram');
|
||||
var sock = dgram.createSocket('udp4'); // only use ipv4 for now
|
||||
sock.bind(this.port); // have to bind before you can enable broadcast...
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
var buf = new Buffer(msg.payload);
|
||||
sock.send(buf, 0, buf.length, this.port, this.host, function(err, bytes) {
|
||||
if (err) node.error("udp : "+err);
|
||||
//util.log('[socket out] udp :' +bytes);
|
||||
sock.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
var node = this;
|
||||
}
|
||||
|
||||
RED.nodes.registerType("socket out",SocketOut);
|
131
nodes/core/deprecated/32-multicast.html
Normal file
131
nodes/core/deprecated/32-multicast.html
Normal file
@@ -0,0 +1,131 @@
|
||||
<!--
|
||||
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="multicast in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="icon-tasks"></i> Group</label>
|
||||
<input type="text" id="node-input-group" placeholder="225.0.18.83" style="width: 40%;">
|
||||
<label for="node-input-port" style="margin-left: 10px; width: 35px;"> Port</label>
|
||||
<input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-iface"><i class="icon-globe"></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%;">Base64 encode 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>
|
||||
<div class="form-tips">Tip: sends the received data as a Buffer object (not a String).<br/>Make sure your firewall will allow the data in.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="multicast in">
|
||||
<p>A multicast udp input node, that produces a <b>msg.payload</b> containing a <i>BUFFER</i> object and NOT a String.</p>
|
||||
<p>If you need a String then use <i>.toString()</i> on <b>msg.payload</b> in your next function block.</p>
|
||||
<p>It also provides <b>msg.fromip</b> of the form ipaddress:port .</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('multicast in',{
|
||||
category: 'deprecated',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
group: {value:"",required:true},
|
||||
host: {value:""},
|
||||
iface: {value:""},
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
base64: {value:false,required:true},
|
||||
multicast: {value:"true"}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge-dash.png",
|
||||
label: function() {
|
||||
if ((this.group!="") & (this.port!="")) {
|
||||
return this.name||(this.group+":"+this.port);
|
||||
}
|
||||
else { return "multicast in"; }
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- The Output Node -->
|
||||
<script type="text/x-red" data-template-name="multicast out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="icon-tasks"></i> Group</label>
|
||||
<input type="text" id="node-input-group" placeholder="225.0.18.83" style="width: 40%;">
|
||||
<label for="node-input-port" style="margin-left: 10px; width: 35px;"> Port</label>
|
||||
<input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-iface"><i class="icon-globe"></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>
|
||||
|
||||
<script type="text/x-red" data-help-name="multicast out">
|
||||
<p>This node sends <b>msg.payload</b> to the designated multicast group and port.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('multicast out',{
|
||||
category: 'deprecated',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
group: {value:"",required:true},
|
||||
host: {value:""},
|
||||
iface: {value:""},
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
base64: {value:false,required:true},
|
||||
multicast: {value:"true"}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge-dash.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
if ((this.group!="") & (this.port!="")) {
|
||||
return this.name||(this.group+":"+this.port);
|
||||
}
|
||||
else { return "multicast out"; }
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
119
nodes/core/deprecated/32-multicast.js
Normal file
119
nodes/core/deprecated/32-multicast.js
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var dgram = require('dgram');
|
||||
|
||||
// The Input Node
|
||||
function MCastIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.warn("node type deprecated - will be removed in a future release");
|
||||
this.group = n.group;
|
||||
this.port = n.port;
|
||||
this.host = n.host || null;
|
||||
this.base64 = n.base64;
|
||||
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.base64) { msg = { payload:message.toString('base64'), 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) {
|
||||
server.setBroadcast(true)
|
||||
server.setMulticastTTL(128);
|
||||
server.addMembership(node.group,node.iface);
|
||||
node.log("udp multicast group "+node.group);
|
||||
}
|
||||
});
|
||||
|
||||
//server.bind(node.port,node.host);
|
||||
server.bind(node.port,node.host);
|
||||
|
||||
this._close = function() {
|
||||
server.close();
|
||||
node.log('udp listener stopped');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MCastIn.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
RED.nodes.registerType("multicast in",MCastIn);
|
||||
|
||||
// The Output Node
|
||||
function MCastOut(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.warn("node type deprecated");
|
||||
this.group = n.group;
|
||||
this.port = n.port;
|
||||
this.host = n.host || null;
|
||||
this.base64 = n.base64;
|
||||
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...
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
sock.setMulticastTTL(128);
|
||||
sock.addMembership(node.group,node.iface); // Add to the multicast group
|
||||
node.log('udp multicaster ready on '+node.group+":"+node.port);
|
||||
|
||||
node.on("input", function(msg) {
|
||||
if (msg.payload != null) {
|
||||
console.log("MCast:",msg.payload);
|
||||
var message;
|
||||
if (node.base64) {
|
||||
message = new Buffer(msg.payload,'base64');
|
||||
}
|
||||
else {
|
||||
message = new Buffer(msg.payload);
|
||||
}
|
||||
sock.send(message, 0, message.length, node.port, node.group, function(err, bytes) {
|
||||
if (err) node.error("udp : "+err);
|
||||
//util.log('[socket out] udp :' +bytes);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this._close = function() {
|
||||
sock.close();
|
||||
node.log('udp multicaster stopped');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RED.nodes.registerType("multicast out",MCastOut);
|
||||
|
||||
MCastOut.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
69
nodes/core/deprecated/35-rpi-gpio-in.html
Normal file
69
nodes/core/deprecated/35-rpi-gpio-in.html
Normal file
@@ -0,0 +1,69 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-gpio in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="icon-asterisk"></i> Pin</label>
|
||||
<select type="text" id="node-input-pin" style="width: 150px;">
|
||||
<option value="7">7</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="15">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="18">18</option>
|
||||
<option value="22">22</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-row">
|
||||
<label for="node-input-resistor"><i class=" icon-resize-full"></i> Resistor?</label>
|
||||
<select type="text" id="node-input-resistor" style="width: 150px;">
|
||||
<option value="no">no</option>
|
||||
<option value="pullup">pullup</option>
|
||||
<option value="pulldown">pulldown</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-tips">Tip: if pull up/down resistor is selected, the <code>gpio-admin</code> command <em>must</em> be used
|
||||
to do the actual enabling. If 'no' resistor is selected, nothing further needs to be done
|
||||
to use this node. See <code>man gpio-admin</code> for more details.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('rpi-gpio in',{
|
||||
category: 'deprecated',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:""},
|
||||
resistor: { value: "no"},
|
||||
pin: {value:"",required:true},
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "rpi.png",
|
||||
label: function() {
|
||||
return this.name||"Pin: "+this.pin;
|
||||
//+(this.resistor == "no"?"":" ("+(this.resistor=="pullup"?"":"↓")+")");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
70
nodes/core/deprecated/35-rpi-gpio-in.js
Normal file
70
nodes/core/deprecated/35-rpi-gpio-in.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var gpio = require("pi-gpio");
|
||||
|
||||
function GPIOInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.warn("node type deprecated - will be removed in a future release");
|
||||
this.buttonState = -1;
|
||||
this.pin = n.pin;
|
||||
this.resistor = n.resistor;
|
||||
|
||||
var node = this;
|
||||
|
||||
if (this.pin) {
|
||||
var setupPin = function(err) {
|
||||
if (err) {
|
||||
node.error(err);
|
||||
} else {
|
||||
node._interval = setInterval(function(){
|
||||
gpio.read(node.pin, function(err, value) {
|
||||
if(err){
|
||||
node.error(err);
|
||||
} else{
|
||||
if(node.buttonState !== value){
|
||||
var previousState = node.buttonState;
|
||||
node.buttonState = value;
|
||||
if (previousState !== -1) {
|
||||
var msg = {payload:node.buttonState};
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
};
|
||||
if (this.resistor == "no") {
|
||||
gpio.open(this.pin,"input",setupPin());
|
||||
} else {
|
||||
// Assume enabled externally via gpio-admin
|
||||
setupPin();
|
||||
}
|
||||
} else {
|
||||
this.error("Invalid GPIO pin: "+this.pin);
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("rpi-gpio in",GPIOInNode);
|
||||
|
||||
GPIOInNode.prototype.close = function() {
|
||||
clearInterval(this._interval);
|
||||
if (this.resistor == "no") {
|
||||
gpio.close(this.pin);
|
||||
}
|
||||
}
|
59
nodes/core/deprecated/35-rpi-gpio-out.html
Normal file
59
nodes/core/deprecated/35-rpi-gpio-out.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-gpio out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="icon-asterisk"></i> Pin</label>
|
||||
<select type="text" id="node-input-pin" style="width: 150px;">
|
||||
<option value="7">7</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="15">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="18">18</option>
|
||||
<option value="22">22</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>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('rpi-gpio out',{
|
||||
category: 'deprecated',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:""},
|
||||
resistor: { value: "no"},
|
||||
pin: {value:"",required:true},
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "rpi.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||"Pin: "+this.pin;
|
||||
//+(this.resistor == "no"?"":" ("+(this.resistor=="pullup"?"":"↓")+")");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
48
nodes/core/deprecated/35-rpi-gpio-out.js
Normal file
48
nodes/core/deprecated/35-rpi-gpio-out.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var gpio = require("pi-gpio");
|
||||
|
||||
function GPIOOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.warn("node type deprecated - will be removed in a future release");
|
||||
this.pin = n.pin;
|
||||
|
||||
var node = this;
|
||||
|
||||
if (this.pin) {
|
||||
gpio.open(this.pin,"output",function(err) {
|
||||
if (err) {
|
||||
node.error(err);
|
||||
} else {
|
||||
node.on("input",function(msg) {
|
||||
gpio.write(node.pin,msg.payload,function(err) {
|
||||
if (err) node.error(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.error("Invalid GPIO pin: "+this.pin);
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
|
||||
|
||||
GPIOOutNode.prototype.close = function() {
|
||||
gpio.close(this.pin);
|
||||
}
|
150
nodes/core/hardware/35-arduino.html
Normal file
150
nodes/core/hardware/35-arduino.html
Normal file
@@ -0,0 +1,150 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<script type="text/x-red" data-template-name="arduino in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-arduino"><i class="icon-tasks"></i> Arduino</label>
|
||||
<input type="text" id="node-input-arduino">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="icon-asterisk"></i> Pin</label>
|
||||
<input type="text" id="node-input-pin" placeholder="2">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-state"><i class="icon-wrench"></i> Type</label>
|
||||
<select type="text" id="node-input-state" style="width: 150px;">
|
||||
<option value="INPUT">Digital pin</option>
|
||||
<option value="ANALOG">Analogue pin</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"><b>Note:</b> You cannot use the same pin for both output and input.</div>
|
||||
</script>
|
||||
|
||||
<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>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>You can set the sample rate in ms from 20 to 65535.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('arduino in',{
|
||||
category: 'advanced-input',
|
||||
color:"#3fadb5",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
pin: {value:"",required:true},
|
||||
state: {value:"INPUT",required:true},
|
||||
arduino: {type:"arduino-board",required:true}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "arduino.png",
|
||||
label: function() {
|
||||
var 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-template-name="arduino out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-arduino"><i class="icon-tasks"></i> Arduino</label>
|
||||
<input type="text" id="node-input-arduino">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="icon-asterisk"></i> Pin</label>
|
||||
<input type="text" id="node-input-pin" placeholder="13">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-state"><i class="icon-wrench"></i> Type</label>
|
||||
<select type="text" id="node-input-state" style="width: 150px;">
|
||||
<option value="OUTPUT">Digital (0/1)</option>
|
||||
<option value="PWM">Analogue (0-255)</option>
|
||||
<option value="SERVO">Servo (0-180)</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"><b>Note:</b> You cannot use the same pin for both output and input.</div>
|
||||
</script>
|
||||
|
||||
<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>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 type="text/javascript">
|
||||
RED.nodes.registerType('arduino out',{
|
||||
category: 'advanced-output',
|
||||
color:"#3fadb5",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
pin: {value:""},
|
||||
state: {value:"",required:true},
|
||||
arduino: {type:"arduino-board",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "arduino.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||"Pin: "+this.pin;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="arduino-board">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-device"><i class="icon-bullhorn"></i> Arduino Port</label>
|
||||
<input type="text" id="node-config-input-device" placeholder="/dev/ttyUSB0" style="width:50%;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<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 type="text/javascript">
|
||||
RED.nodes.registerType('arduino-board',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
//baud: {baud:"57600",required:true},
|
||||
repeat: {value:"50",required:true,validate:RED.validators.number()},
|
||||
device: {value:"",required:true}
|
||||
},
|
||||
label: function() {
|
||||
return this.device||"arduino";
|
||||
}
|
||||
});
|
||||
</script>
|
187
nodes/core/hardware/35-arduino.js
Normal file
187
nodes/core/hardware/35-arduino.js
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var util = require("util");
|
||||
var firmata = require("firmata");
|
||||
var arduinoReady = false;
|
||||
var thisboard = null;
|
||||
|
||||
// The Board Definition - this opens (and closes) the connection
|
||||
function ArduinoNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.device = n.device;
|
||||
this.repeat = n.repeat||25;
|
||||
util.log("[firmata] Opening "+this.device);
|
||||
var node = this;
|
||||
|
||||
node.toun = setInterval(function() {
|
||||
if (!arduinoReady) {
|
||||
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() {
|
||||
//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);
|
||||
|
||||
|
||||
// The Input Node
|
||||
function DuinoNodeIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.buttonState = -1;
|
||||
this.pin = n.pin;
|
||||
this.state = n.state;
|
||||
this.arduino = n.arduino;
|
||||
this.serverConfig = RED.nodes.getNode(this.arduino);
|
||||
if (typeof this.serverConfig === "object") {
|
||||
this.board = this.serverConfig.board;
|
||||
this.repeat = this.serverConfig.repeat;
|
||||
var node = this;
|
||||
|
||||
node.toui = setInterval(function() {
|
||||
if (thisboard != null) {
|
||||
node.board = thisboard;
|
||||
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") {
|
||||
node.board.analogRead(node.pin, function(data) {
|
||||
var msg = {payload:data, topic:"A"+node.pin};
|
||||
if (data != oldrdg) {
|
||||
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) {
|
||||
clearInterval(node.toui);
|
||||
util.log("[firmata] input wait loop stopped");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
util.log("[firmata] Serial Port not Configured");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("arduino in",DuinoNodeIn);
|
||||
|
||||
|
||||
// The Output Node
|
||||
function DuinoNodeOut(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.buttonState = -1;
|
||||
this.pin = n.pin;
|
||||
this.state = n.state;
|
||||
this.arduino = n.arduino;
|
||||
this.serverConfig = RED.nodes.getNode(this.arduino);
|
||||
if (typeof this.serverConfig === "object") {
|
||||
this.board = this.serverConfig.board;
|
||||
var node = this;
|
||||
|
||||
this.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
if (node.board != 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);
|
||||
}
|
||||
if ((msg.payload == false)||(msg.payload == 0)||(msg.payload.toString().toLowerCase() == "off")) {
|
||||
node.board.digitalWrite(node.pin, node.board.LOW);
|
||||
}
|
||||
}
|
||||
if (node.state == "PWM") {
|
||||
msg.payload = msg.payload * 1;
|
||||
if ((msg.payload >= 0) && (msg.payload <= 255)) {
|
||||
//console.log(msg.payload, node.pin);
|
||||
node.board.servoWrite(node.pin, msg.payload);
|
||||
}
|
||||
}
|
||||
if (node.state == "SERVO") {
|
||||
msg.payload = msg.payload * 1;
|
||||
if ((msg.payload >= 0) && (msg.payload <= 180)) {
|
||||
//console.log(msg.payload, node.pin);
|
||||
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 {
|
||||
util.log("[firmata] Serial Port not Configured");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("arduino out",DuinoNodeOut);
|
126
nodes/core/hardware/36-rpi-gpio.html
Normal file
126
nodes/core/hardware/36-rpi-gpio.html
Normal file
@@ -0,0 +1,126 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-gpio in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="icon-asterisk"></i> GPIO Pin</label>
|
||||
<select type="text" id="node-input-pin" style="width: 150px;">
|
||||
<option value="-">select pin</option>
|
||||
<option value="7">7</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="15">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="18">18</option>
|
||||
<option value="22">22</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-intype"><i class=" icon-resize-full"></i> Resistor?</label>
|
||||
<select type="text" id="node-input-intype" style="width: 150px;">
|
||||
<option value="tri">none</option>
|
||||
<option value="up">pullup</option>
|
||||
<option value="down">pulldown</option>
|
||||
<!--<option value="tri">tristate</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: Only Digital I/O is supported - input must be 0 or 1.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="rpi-gpio in">
|
||||
<p>Raspberry Pi input node. Generates a <b>msg.payload</b> with either a 0 or 1 depending on the state of the input pin. Requires the gpio command to work.</p>
|
||||
<p>You may also enable the input pullup resitor or the pulldown resistor.</p>
|
||||
<p>The <b>msg.topic</b> is set to <i>pi/{the pin number}</i></p>
|
||||
<p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
|
||||
<p><b>Note:</b> This node currently polls the pin every 250mS. This is not ideal as it loads the cpu, and will be rewritten shortly to try to use interrupts.</p>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('rpi-gpio in',{
|
||||
category: 'advanced-input',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:"" },
|
||||
intype: { value: "in" },
|
||||
pin: { value:"",required:true,validate:RED.validators.number() },
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "rpi.png",
|
||||
label: function() {
|
||||
return this.name||"Pin: "+this.pin ;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="rpi-gpio out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-pin"><i class="icon-asterisk"></i> GPIO Pin</label>
|
||||
<select type="text" id="node-input-pin" style="width: 150px;">
|
||||
<option value="-">select pin</option>
|
||||
<option value="7">7</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
<option value="13">13</option>
|
||||
<option value="15">15</option>
|
||||
<option value="16">16</option>
|
||||
<option value="18">18</option>
|
||||
<option value="22">22</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: Only Digital I/O is supported - input must be 0 or 1.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="rpi-gpio out">
|
||||
<p>Raspberry Pi output node. Expects a <b>msg.payload</b> with either a 0 or 1 (or true or false). Requires the gpio command to work.</p>
|
||||
<p>Will set the selected physical pin high or low depending on the value passed in.</p>
|
||||
<p><b>Note:</b> we are using the actual physical pin numbers on connector P1 as they are easier to locate.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('rpi-gpio out',{
|
||||
category: 'advanced-output',
|
||||
color:"#c6dbef",
|
||||
defaults: {
|
||||
name: { value:"" },
|
||||
pin: { value:"",required:true,validate:RED.validators.number() },
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "rpi.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||"Pin: "+this.pin;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
143
nodes/core/hardware/36-rpi-gpio.js
Normal file
143
nodes/core/hardware/36-rpi-gpio.js
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var util = require("util");
|
||||
var exec = require('child_process').exec;
|
||||
var fs = require('fs');
|
||||
|
||||
if (!fs.existsSync("/usr/local/bin/gpio")) {
|
||||
exec("cat /proc/cpuinfo | grep BCM27",function(err,stdout,stderr) {
|
||||
if (stdout.indexOf('BCM27') > -1) {
|
||||
util.log('[36-rpi-gpio.js] Error: Cannot find Wiring-Pi "gpio" command. http://wiringpi.com/download-and-install/');
|
||||
}
|
||||
// else not on a Pi so don't worry anyone with needless messages.
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Map physical P1 pins to Gordon's Wiring-Pi Pins (as they should be V1/V2 tolerant)
|
||||
var pintable = {
|
||||
// Physical : WiringPi
|
||||
"7":"7",
|
||||
"11":"0",
|
||||
"12":"1",
|
||||
"13":"2",
|
||||
"15":"3",
|
||||
"16":"4",
|
||||
"18":"5",
|
||||
"22":"6"
|
||||
}
|
||||
var tablepin = {
|
||||
// WiringPi : Physical
|
||||
"7":"7",
|
||||
"0":"11",
|
||||
"1":"12",
|
||||
"2":"13",
|
||||
"3":"15",
|
||||
"4":"16",
|
||||
"5":"18",
|
||||
"6":"22"
|
||||
}
|
||||
|
||||
function GPIOInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.buttonState = -1;
|
||||
this.pin = pintable[n.pin];
|
||||
this.intype = n.intype;
|
||||
var node = this;
|
||||
|
||||
if (this.pin) {
|
||||
exec("gpio mode "+node.pin+" "+node.intype, function(err,stdout,stderr) {
|
||||
if (err) node.error(err);
|
||||
else {
|
||||
node._interval = setInterval( function() {
|
||||
exec("gpio read "+node.pin, function(err,stdout,stderr) {
|
||||
if (err) node.error(err);
|
||||
else {
|
||||
if (node.buttonState !== Number(stdout)) {
|
||||
var previousState = node.buttonState;
|
||||
node.buttonState = Number(stdout);
|
||||
if (previousState !== -1) {
|
||||
var msg = {topic:"pi/"+tablepin[node.pin], payload:node.buttonState};
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.error("Invalid GPIO pin: "+this.pin);
|
||||
}
|
||||
}
|
||||
|
||||
function GPIOOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.pin = pintable[n.pin];
|
||||
var node = this;
|
||||
|
||||
if (this.pin) {
|
||||
process.nextTick(function() {
|
||||
exec("gpio mode "+node.pin+" out", function(err,stdout,stderr) {
|
||||
if (err) node.error(err);
|
||||
else {
|
||||
node.on("input", function(msg) {
|
||||
if (msg.payload === "true") msg.payload = true;
|
||||
if (msg.payload === "false") msg.payload = false;
|
||||
var out = Number(msg.payload);
|
||||
if ((out == 0)|(out == 1)) {
|
||||
exec("gpio write "+node.pin+" "+out, function(err,stdout,stderr) {
|
||||
if (err) node.error(err);
|
||||
});
|
||||
}
|
||||
else node.warn("Invalid input - not 0 or 1");
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.error("Invalid GPIO pin: "+this.pin);
|
||||
}
|
||||
}
|
||||
|
||||
exec("gpio mode 0 in",function(err,stdout,stderr) {
|
||||
if (err) {
|
||||
util.log('[36-rpi-gpio.js] Error: "gpio" command failed for some reason.');
|
||||
}
|
||||
exec("gpio mode 1 in");
|
||||
exec("gpio mode 2 in");
|
||||
exec("gpio mode 3 in");
|
||||
exec("gpio mode 4 in");
|
||||
exec("gpio mode 5 in");
|
||||
exec("gpio mode 6 in");
|
||||
exec("gpio mode 7 in",function(err,stdout,stderr) {
|
||||
RED.nodes.registerType("rpi-gpio in",GPIOInNode);
|
||||
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
|
||||
|
||||
GPIOInNode.prototype.close = function() {
|
||||
clearInterval(this._interval);
|
||||
}
|
||||
|
||||
GPIOOutNode.prototype.close = function() {
|
||||
exec("gpio mode "+this.pin+" in");
|
||||
}
|
||||
|
||||
});
|
||||
});
|
121
nodes/core/io/10-mqtt.html
Normal file
121
nodes/core/io/10-mqtt.html
Normal file
@@ -0,0 +1,121 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="icon-tag"></i> Broker</label>
|
||||
<input type="text" id="node-input-broker">
|
||||
</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">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt in">
|
||||
<p>MQTT input node. Connects to the specified broker and subscribes to the specified topic. The topic may contain MQTT wildcards.</p>
|
||||
<p>Outputs an object called <b>msg</b> containing <b>msg.topic, msg.payload, msg.qos</b> and <b>msg.retain</b>. <b>msg.payload</b> is a String.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt in',{
|
||||
category: 'input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
topic: {value:"",required:true},
|
||||
broker: {type:"mqtt-broker", required:true}
|
||||
},
|
||||
color:"#c6dbef",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge.png",
|
||||
label: function() {
|
||||
return this.name||this.topic||"mqtt";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="icon-tag"></i> Broker</label>
|
||||
<input type="text" id="node-input-broker">
|
||||
</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">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt out">
|
||||
<p>Connects to a MQTT broker and publishes <b>msg.payload</b> either to the <b>msg.topic</b> OR to the topic specified in the edit window. The value in the edit window has precedence.</p>
|
||||
<p><b>msg.qos</b> and <b>msg.retain</b> may also optionally have been set. If not set they are set to 0 and false respectively.</p>
|
||||
<p>If <b>msg.payload</b> contains a buffer or an object it will be stringified before being sent.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt out',{
|
||||
category: 'output',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
topic: {value:""},
|
||||
broker: {type:"mqtt-broker", required:true}
|
||||
},
|
||||
color:"#c6dbef",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.topic||"mqtt";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt-broker">
|
||||
<div class="form-row node-input-broker">
|
||||
<label for="node-config-input-broker"><i class="icon-bookmark"></i> Broker</label>
|
||||
<input class="input-append-left" type="text" id="node-config-input-broker" placeholder="Broker" style="width: 40%;" >
|
||||
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
|
||||
<input type="text" id="node-config-input-port" placeholder="Port" style="width:45px">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt-broker',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
broker: {value:"localhost",required:true},
|
||||
port: {value:1883,required:true,validate:RED.validators.number()}
|
||||
},
|
||||
label: function() {
|
||||
return this.broker+":"+this.port;
|
||||
}
|
||||
});
|
||||
</script>
|
90
nodes/core/io/10-mqtt.js
Normal file
90
nodes/core/io/10-mqtt.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var connectionPool = require("./lib/mqttConnectionPool");
|
||||
var util = require("util");
|
||||
|
||||
function MQTTBrokerNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.broker = n.broker;
|
||||
this.port = n.port;
|
||||
}
|
||||
RED.nodes.registerType("mqtt-broker",MQTTBrokerNode);
|
||||
|
||||
|
||||
function MQTTInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.topic = n.topic;
|
||||
this.broker = n.broker;
|
||||
this.brokerConfig = RED.nodes.getNode(this.broker);
|
||||
if (this.brokerConfig) {
|
||||
this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port);
|
||||
var node = this;
|
||||
this.client.subscribe(this.topic,2,function(topic,payload,qos,retain) {
|
||||
var msg = {topic:topic,payload:payload,qos:qos,retain:retain};
|
||||
if ((node.brokerConfig.broker == "localhost")||(node.brokerConfig.broker == "127.0.0.1")) {
|
||||
msg._topic = topic;
|
||||
}
|
||||
node.send(msg);
|
||||
});
|
||||
this.client.connect();
|
||||
} else {
|
||||
this.error("missing broker configuration");
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("mqtt in",MQTTInNode);
|
||||
|
||||
MQTTInNode.prototype.close = function() {
|
||||
if (this.client) {
|
||||
this.client.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function MQTTOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.topic = n.topic;
|
||||
this.broker = n.broker;
|
||||
|
||||
this.brokerConfig = RED.nodes.getNode(this.broker);
|
||||
|
||||
if (this.brokerConfig) {
|
||||
this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port);
|
||||
this.on("input",function(msg) {
|
||||
if (msg != null) {
|
||||
if (this.topic) {
|
||||
msg.topic = this.topic;
|
||||
}
|
||||
this.client.publish(msg);
|
||||
}
|
||||
});
|
||||
this.client.connect();
|
||||
} else {
|
||||
this.error("missing broker configuration");
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("mqtt out",MQTTOutNode);
|
||||
|
||||
MQTTOutNode.prototype.close = function() {
|
||||
if (this.client) {
|
||||
this.client.disconnect();
|
||||
}
|
||||
}
|
||||
|
195
nodes/core/io/21-httpin.html
Normal file
195
nodes/core/io/21-httpin.html
Normal file
@@ -0,0 +1,195 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="http in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-method"><i class="icon-tasks"></i> Method</label>
|
||||
<select type="text" id="node-input-method" style="width: 150px;">
|
||||
<option value="get">GET</option>
|
||||
<option value="post">POST</option>
|
||||
<option value="put">PUT</option>
|
||||
<option value="delete">DELETE</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="icon-globe"></i> url</label>
|
||||
<input type="text" id="node-input-url" placeholder="/url">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="http in">
|
||||
<p>Provides an input node for http requests, allowing the creation of simple web services.</p>
|
||||
<p>The resulting message has the following properties:
|
||||
<ul>
|
||||
<li>msg.req : <a href="http://expressjs.com/api.html#req">http request</a></li>
|
||||
<li>msg.res : <a href="http://expressjs.com/api.html#res">http response</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>For POST/PUT requests, the body is available under <code>msg.req.body</code>. This
|
||||
uses the <a href="http://expressjs.com/api.html#bodyParser">Express bodyParser middleware</a> to parse the content to a JSON object.
|
||||
</p>
|
||||
<p>
|
||||
By default, this expects the body of the request to be url encoded:
|
||||
<pre>foo=bar&this=that</pre>
|
||||
</p>
|
||||
<p>
|
||||
To send JSON encoded data to the node, the content-type header of the request must be set to
|
||||
<code>application/json</code>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Note: </b>This node does not send any response to the http request. This should be done with
|
||||
a subsequent HTTP Response node, or Function node.
|
||||
In the case of a Function node, the <a href="http://expressjs.com/api.html#res">Express response documentation</a>
|
||||
describes how this should be done. For example:
|
||||
<pre>msg.res.send(200, 'Thanks for the request ');<br/>return msg;</pre>
|
||||
</p>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('http in',{
|
||||
category: 'input',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
url: {value:"",required:true},
|
||||
method: {value:"get",required:true}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||(this.url?("["+this.method+"] "+this.url):"http");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="http response">
|
||||
<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">The messages sent to this node <b>must</b> originate from an <i>http input</i> node</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="http response">
|
||||
<p>Sends responses back to http requests received from an HTTP Input node.</p>
|
||||
<p>The response can be customised using the following message properties:</p>
|
||||
<ul>
|
||||
<li><code>payload</code> is sent as the body of the reponse</li>
|
||||
<li><code>statusCode</code>, if set, is used as the response status code (default: 200)</li>
|
||||
<li><code>headers</code>, if set, should be an object containing field/value
|
||||
pairs to be added as response headers.</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('http response',{
|
||||
category: 'output',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
align: "right",
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||"http";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="http request">
|
||||
<div class="form-row">
|
||||
<label for="node-input-method"><i class="icon-tasks"></i> Method</label>
|
||||
<select type="text" id="node-input-method" style="width: 150px;">
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-url"><i class="icon-tasks"></i> URL</label>
|
||||
<input type="text" id="node-input-url" placeholder="http://">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="http request">
|
||||
<p>Provides a node for making http requests.</p>
|
||||
<p>The URL and HTTP method can be configured in the node, but also
|
||||
overridden by the incoming message:
|
||||
<ul>
|
||||
<li><code>url</code>, if set, is used as the url of the request</li>
|
||||
<li><code>method</code>, if set, is used as the HTTP method of the request. Must be one of <code>GET</code>, <code>PUT</code>, <code>POST</code> or <code>DELETE</code> (default: GET)</li>
|
||||
<li><code>headers</code>, if set, should be an object containing field/value
|
||||
pairs to be added as request headers</li>
|
||||
<li><code>payload</code> is sent as the body of the request</li>
|
||||
</ul>
|
||||
|
||||
The output message contains the following properties:
|
||||
<ul>
|
||||
<li><code>payload</code> is the body of the response</li>
|
||||
<li><code>statusCode</code> is the status code of the response, or the error code if the request could not be completed</li>
|
||||
<li><code>headers</code> is an object containing the response headers</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('http request',{
|
||||
category: 'function',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
method:{value:"GET"},
|
||||
url:{value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
align: "right",
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||"http request";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
124
nodes/core/io/21-httpin.js
Normal file
124
nodes/core/io/21-httpin.js
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var util = require("util");
|
||||
var http = require("http");
|
||||
var https = require("https");
|
||||
var urllib = require("url");
|
||||
var express = require("express");
|
||||
var jsonParser = express.json();
|
||||
var urlencParser = express.urlencoded();
|
||||
|
||||
function HTTPIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.url = n.url;
|
||||
this.method = n.method;
|
||||
|
||||
var node = this;
|
||||
this.callback = function(req,res) {
|
||||
if (node.method == "post") { node.send({req:req,res:res,payload:req.body}); }
|
||||
else if (node.method == "get") { node.send({req:req,res:res,payload:req.query}); }
|
||||
else node.send({req:req,res:res});
|
||||
}
|
||||
if (this.method == "get") {
|
||||
RED.app.get(this.url,this.callback);
|
||||
} else if (this.method == "post") {
|
||||
RED.app.post(this.url,jsonParser,urlencParser,this.callback);
|
||||
} else if (this.method == "put") {
|
||||
RED.app.put(this.url,jsonParser,urlencParser,this.callback);
|
||||
} else if (this.method == "delete") {
|
||||
RED.app.delete(this.url,this.callback);
|
||||
}
|
||||
|
||||
this.on("close",function() {
|
||||
var routes = RED.app.routes[this.method];
|
||||
for (var i in routes) {
|
||||
if (routes[i].path == this.url) {
|
||||
routes.splice(i,1);
|
||||
//break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
msg.res.set(msg.headers);
|
||||
}
|
||||
var statusCode = msg.statusCode || 200;
|
||||
msg.res.send(statusCode,msg.payload);
|
||||
} else {
|
||||
node.warn("No response object");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("http response",HTTPOut);
|
||||
|
||||
function HTTPRequest(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var url = n.url;
|
||||
var method = n.method || "GET";
|
||||
var httplib = (/^https/.test(url))?https:http;
|
||||
var node = this;
|
||||
this.on("input",function(msg) {
|
||||
|
||||
var opts = urllib.parse(msg.url||url);
|
||||
opts.method = (msg.method||method).toUpperCase();
|
||||
if (msg.headers) {
|
||||
opts.headers = msg.headers;
|
||||
}
|
||||
var req = httplib.request(opts,function(res) {
|
||||
res.setEncoding('utf8');
|
||||
msg.statusCode = res.statusCode;
|
||||
msg.headers = res.headers;
|
||||
msg.payload = "";
|
||||
res.on('data',function(chunk) {
|
||||
msg.payload += chunk;
|
||||
});
|
||||
res.on('end',function() {
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
req.on('error',function(err) {
|
||||
msg.payload = err.toString();
|
||||
msg.statusCode = err.code;
|
||||
node.send(msg);
|
||||
});
|
||||
if (msg.payload && (method == "POST" || method == "PUT") ) {
|
||||
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
|
||||
req.write(msg.payload);
|
||||
} else if (typeof msg.payload == "number") {
|
||||
req.write(msg.payload+"");
|
||||
} else {
|
||||
req.write(JSON.stringify(msg.payload));
|
||||
}
|
||||
}
|
||||
req.end();
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("http request",HTTPRequest);
|
53
nodes/core/io/23-watch.html
Normal file
53
nodes/core/io/23-watch.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="watch">
|
||||
<div class="form-row node-input-filename">
|
||||
<label for="node-input-files"><i class="icon-file"></i> File(s)</label>
|
||||
<input type="text" id="node-input-files" placeholder="File(s) or Directory">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="watch">
|
||||
<p>Watches a file or directory for any changes.</p>
|
||||
<p>You can enter a list of comma separated files, or directories if you like. You will need to put " around any that have spaces in.</p>
|
||||
<p>The filename of the file that actually changed is put into <b>msg.payload</b>, while a stringified version of the watched criteria is returned in <b>msg.topic</b>.</p>
|
||||
<p>Of course in Linux, <i>everything</i> could be a file and thus watched...</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('watch',{
|
||||
category: 'advanced-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
files: {value:"",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "watch.png",
|
||||
label: function() {
|
||||
return this.name||this.files;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
45
nodes/core/io/23-watch.js
Normal file
45
nodes/core/io/23-watch.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var notify = require("fs.notify");
|
||||
|
||||
function WatchNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.files = n.files.split(",");
|
||||
for (var f in this.files) {
|
||||
this.files[f] = this.files[f].trim();
|
||||
}
|
||||
var node = this;
|
||||
var notifications = new notify(this.files);
|
||||
notifications.on('change', function (file) {
|
||||
node.log('file changed '+file);
|
||||
var msg = { payload: file, topic: JSON.stringify(node.files) };
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
this._close = function() {
|
||||
notifications.close();
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("watch",WatchNode);
|
||||
|
||||
WatchNode.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
|
148
nodes/core/io/25-serial.html
Normal file
148
nodes/core/io/25-serial.html
Normal file
@@ -0,0 +1,148 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="serial in">
|
||||
<div class="form-row node-input-serial">
|
||||
<label for="node-input-serial"><i class="icon-bullhorn"></i> Serial Port</label>
|
||||
<input type="text" id="node-input-serial">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="serial in">
|
||||
<p>Reads data from a local serial port.</p>
|
||||
<p>Keeps reading from the serial port until it sees \n (default) or the character(s) requested. Only sets <b>msg.payload</b>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('serial in',{
|
||||
category: 'input',
|
||||
defaults: {
|
||||
name: {name:""},
|
||||
serial: {type:"serial-port",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "serial.png",
|
||||
label: function() {
|
||||
var serialNode = RED.nodes.node(this.serial);
|
||||
return this.name||(serialNode?serialNode.label():"serial");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="serial out">
|
||||
<div class="form-row node-input-serial">
|
||||
<label for="node-input-serial"><i class="icon-bullhorn"></i> Serial Port</label>
|
||||
<input type="text" id="node-input-serial">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="serial out">
|
||||
<p>Provides a connection to an outbound serial port.</p>
|
||||
<p>Only the <b>msg.payload</b> is sent.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('serial out',{
|
||||
category: 'output',
|
||||
defaults: {
|
||||
name: {name:""},
|
||||
serial: {type:"serial-port",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "serial.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
var serialNode = RED.nodes.node(this.serial);
|
||||
return this.name||(serialNode?serialNode.label():"serial");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="serial-port">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-serialport"><i class="icon-bullhorn"></i> Serial Port</label>
|
||||
<input type="text" id="node-config-input-serialport" placeholder="/dev/ttyUSB0" style="width:50%;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-serialbaud"><i class="icon-wrench"></i> Baud Rate</label>
|
||||
<select type="text" id="node-config-input-serialbaud" style="width: 150px;">
|
||||
<option value="115200">115200</option>
|
||||
<option value="57600">57600</option>
|
||||
<option value="38400">38400</option>
|
||||
<option value="19200">19200</option>
|
||||
<option value="9600">9600</option>
|
||||
<option value="4800">4800</option>
|
||||
<option value="2400">2400</option>
|
||||
<option value="1800">1800</option>
|
||||
<option value="1200">1200</option>
|
||||
<option value="600">600</option>
|
||||
<option value="300">300</option>
|
||||
<option value="200">200</option>
|
||||
<option value="150">150</option>
|
||||
<option value="134">134</option>
|
||||
<option value="110">110</option>
|
||||
<option value="75">75</option>
|
||||
<option value="50">50</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-newline"><i class="icon-text-width"></i> New line</label>
|
||||
<input type="text" id="node-config-input-newline">
|
||||
</div>
|
||||
<!--
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||
</div>
|
||||
-->
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('serial-port',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
//name: {value:""},
|
||||
serialport: {value:"",required:true},
|
||||
serialbaud: {value:57600,required:true},
|
||||
newline: {value:"\\n"}
|
||||
},
|
||||
label: function() {
|
||||
//return this.name||this.serialport;
|
||||
return this.serialport+":"+this.serialbaud;
|
||||
}
|
||||
});
|
||||
</script>
|
195
nodes/core/io/25-serial.js
Normal file
195
nodes/core/io/25-serial.js
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var settings = RED.settings;
|
||||
var events = require("events");
|
||||
var util = require("util");
|
||||
var serialp = require("serialport");
|
||||
|
||||
// TODO: 'serialPool' should be encapsulated in SerialPortNode
|
||||
|
||||
function SerialPortNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.serialport = n.serialport;
|
||||
this.serialbaud = n.serialbaud * 1;
|
||||
this.newline = n.newline;
|
||||
}
|
||||
RED.nodes.registerType("serial-port",SerialPortNode);
|
||||
|
||||
|
||||
function SerialOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.serial = n.serial;
|
||||
this.serialConfig = RED.nodes.getNode(this.serial);
|
||||
|
||||
if (this.serialConfig) {
|
||||
var node = this;
|
||||
try {
|
||||
node.port = serialPool.get(this.serialConfig.serialport,this.serialConfig.serialbaud,this.serialConfig.newline);
|
||||
} catch(err) {
|
||||
this.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
node.on("input",function(msg) {
|
||||
//console.log("{",msg,"}");
|
||||
node.port.write(msg.payload,function(err,res) {
|
||||
if (err) {
|
||||
node.error(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.error("missing serial config");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("serial out",SerialOutNode);
|
||||
|
||||
|
||||
SerialOutNode.prototype.close = function() {
|
||||
if (this.serialConfig) {
|
||||
serialPool.close(this.serialConfig.serialport);
|
||||
}
|
||||
}
|
||||
|
||||
function SerialInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.serial = n.serial;
|
||||
this.serialConfig = RED.nodes.getNode(this.serial);
|
||||
|
||||
if (this.serialConfig) {
|
||||
var node = this;
|
||||
try {
|
||||
this.port = serialPool.get(this.serialConfig.serialport,this.serialConfig.serialbaud,this.serialConfig.newline);
|
||||
} catch(err) {
|
||||
this.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.port.on('data', function(msg) {
|
||||
// console.log("{",msg,"}");
|
||||
var m = { "payload": msg };
|
||||
node.send(m);
|
||||
});
|
||||
} else {
|
||||
this.error("missing serial config");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("serial in",SerialInNode);
|
||||
|
||||
|
||||
SerialInNode.prototype.close = function() {
|
||||
if (this.serialConfig) {
|
||||
try {
|
||||
serialPool.close(this.serialConfig.serialport);
|
||||
} catch(err) {
|
||||
}
|
||||
this.warn("Deploying with serial-port nodes is known to occasionally cause Node-RED to hang. This is due to an open issue with the underlying module.");
|
||||
}
|
||||
}
|
||||
|
||||
var serialPool = function() {
|
||||
var connections = {};
|
||||
return {
|
||||
get:function(port,baud,newline,callback) {
|
||||
var id = port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = function() {
|
||||
var obj = {
|
||||
_emitter: new events.EventEmitter(),
|
||||
serial: null,
|
||||
_closing: false,
|
||||
tout: null,
|
||||
on: function(a,b) { this._emitter.on(a,b); },
|
||||
close: function(cb) { this.serial.close(cb)},
|
||||
write: function(m,cb) { this.serial.write(m,cb)},
|
||||
}
|
||||
newline = newline.replace("\\n","\n").replace("\\r","\r");
|
||||
var setupSerial = function() {
|
||||
try {
|
||||
if (newline == "") {
|
||||
obj.serial = new serialp.SerialPort(port,{
|
||||
baudrate: baud,
|
||||
parser: serialp.parsers.raw
|
||||
});
|
||||
}
|
||||
else {
|
||||
obj.serial = new serialp.SerialPort(port,{
|
||||
baudrate: baud,
|
||||
parser: serialp.parsers.readline(newline)
|
||||
});
|
||||
}
|
||||
obj.serial.on('error', function(err) {
|
||||
util.log("[serial] serial port "+port+" error "+err);
|
||||
obj.tout = setTimeout(function() {
|
||||
setupSerial();
|
||||
},settings.serialReconnectTime);
|
||||
});
|
||||
obj.serial.on('close', function() {
|
||||
if (!obj._closing) {
|
||||
util.log("[serial] serial port "+port+" closed unexpectedly");
|
||||
obj.tout = setTimeout(function() {
|
||||
setupSerial();
|
||||
},settings.serialReconnectTime);
|
||||
}
|
||||
});
|
||||
obj.serial.on('open',function() {
|
||||
util.log("[serial] serial port "+port+" opened at "+baud+" baud");
|
||||
obj.serial.flush();
|
||||
obj._emitter.emit('ready');
|
||||
});
|
||||
obj.serial.on('data',function(d) {
|
||||
if (typeof d !== "string") {
|
||||
d = d.toString();
|
||||
for (i=0; i<d.length; i++) {
|
||||
obj._emitter.emit('data',d.charAt(i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj._emitter.emit('data',d);
|
||||
}
|
||||
});
|
||||
} catch(err) { console.log("Booo!",err,"Booo!"); }
|
||||
}
|
||||
setupSerial();
|
||||
return obj;
|
||||
}();
|
||||
}
|
||||
return connections[id];
|
||||
},
|
||||
close: function(port) {
|
||||
if (connections[port]) {
|
||||
if (connections[port].tout != null) clearTimeout(connections[port].tout);
|
||||
connections[port]._closing = true;
|
||||
try {
|
||||
connections[port].close(function() {
|
||||
util.log("[serial] serial port closed");
|
||||
});
|
||||
} catch(err) { };
|
||||
}
|
||||
delete connections[port];
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
RED.app.get("/serialports",function(req,res) {
|
||||
serialp.list(function (err, ports) {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.write(JSON.stringify(ports));
|
||||
res.end();
|
||||
});
|
||||
});
|
187
nodes/core/io/31-tcpin.html
Normal file
187
nodes/core/io/31-tcpin.html
Normal file
@@ -0,0 +1,187 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="tcp in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-server"><i class="icon-resize-small"></i> Type</label>
|
||||
<select id="node-input-server" style="width:120px; margin-right:5px;">
|
||||
<option value="server">Listen on</option>
|
||||
<option value="client">Connect to</option>
|
||||
</select>
|
||||
port <input type="text" id="node-input-port" style="width: 50px">
|
||||
</div>
|
||||
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
|
||||
at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 40%;">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label><i class="icon-th"></i> Output</label>
|
||||
a
|
||||
<select id="node-input-datamode" style="width:110px;">
|
||||
<option value="stream">stream of</option>
|
||||
<option value="single">single</option>
|
||||
</select>
|
||||
<select id="node-input-datatype" style="width:140px;">
|
||||
<option value="buffer">Buffer</option>
|
||||
<option value="utf8">String</option>
|
||||
<option value="base64">Base64 String</option>
|
||||
</select>
|
||||
payload<span id="node-input-datamode-plural">s</span>
|
||||
</div>
|
||||
|
||||
<div id="node-row-newline" class="form-row hidden" style="padding-left: 110px;">
|
||||
delimited by <input type="text" id="node-input-newline" style="width: 110px;">
|
||||
</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">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp in">
|
||||
<p>Provides a choice of tcp inputs. Can either connect to a remote tcp port,
|
||||
or accept incoming connections.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp in',{
|
||||
category: 'input',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
server: {value:"server",required:true},
|
||||
host: {value:"",validate:function(v) { return (this.server == "server")||v.length > 0;} },
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
datamode:{value:"stream"},
|
||||
datatype:{value:"buffer"},
|
||||
newline:{value:""},
|
||||
topic: {value:""},
|
||||
name: {value:""},
|
||||
base64: {/*deprecated*/ value:false,required:true}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge-dash.png",
|
||||
label: function() {
|
||||
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var updateOptions = function() {
|
||||
var sockettype = $("#node-input-server option:selected").val();
|
||||
if (sockettype == "client") {
|
||||
$("#node-input-host-row").show();
|
||||
} else {
|
||||
$("#node-input-host-row").hide();
|
||||
}
|
||||
var datamode = $("#node-input-datamode option:selected").val();
|
||||
var datatype = $("#node-input-datatype option:selected").val();
|
||||
if (datamode == "stream") {
|
||||
$("#node-input-datamode-plural").show();
|
||||
if (datatype == "utf8") {
|
||||
$("#node-row-newline").show();
|
||||
} else {
|
||||
$("#node-row-newline").hide();
|
||||
}
|
||||
} else {
|
||||
$("#node-input-datamode-plural").hide();
|
||||
$("#node-row-newline").hide();
|
||||
}
|
||||
};
|
||||
updateOptions();
|
||||
$("#node-input-server").change(updateOptions);
|
||||
$("#node-input-datatype").change(updateOptions);
|
||||
$("#node-input-datamode").change(updateOptions);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="tcp out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-beserver"><i class="icon-resize-small"></i> Type</label>
|
||||
<select id="node-input-beserver" style="width:120px; margin-right:5px;">
|
||||
<option value="server">Listen on</option>
|
||||
<option value="client">Connect to</option>
|
||||
</select>
|
||||
port <input type="text" id="node-input-port" style="width: 50px">
|
||||
</div>
|
||||
|
||||
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
|
||||
at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 40%;">
|
||||
</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 message ?</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp out">
|
||||
<p>Provides a choice of tcp outputs. Can either connect to a remote tcp port,
|
||||
or accept incoming connections.</p>
|
||||
<p>Only <b>msg.payload</b> is sent.</p>
|
||||
<p>If <b>msg.payload</b> is a string containing a base64 encoding of binary
|
||||
data, the Base64 decoding option will cause it to be converted back to binary
|
||||
before being sent.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp out',{
|
||||
category: 'output',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
host: {value:"",validate:function(v) { return (this.beserver == "server")||v.length > 0;} },
|
||||
port: {value:"",required:true},
|
||||
beserver: {value:"client",required:true},
|
||||
base64: {value:false,required:true},
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge-dash.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return (this.name)?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var updateOptions = function() {
|
||||
var sockettype = $("#node-input-beserver option:selected").val();
|
||||
if (sockettype == "client") {
|
||||
$("#node-input-host-row").show();
|
||||
} else {
|
||||
$("#node-input-host-row").hide();
|
||||
}
|
||||
};
|
||||
updateOptions();
|
||||
$("#node-input-beserver").change(updateOptions);
|
||||
}
|
||||
});
|
||||
</script>
|
253
nodes/core/io/31-tcpin.js
Normal file
253
nodes/core/io/31-tcpin.js
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||
var net = require('net');
|
||||
|
||||
function TcpIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.host = n.host;
|
||||
this.port = n.port * 1;
|
||||
this.topic = n.topic;
|
||||
this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
|
||||
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
|
||||
this.base64 = n.base64;
|
||||
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;
|
||||
var reconnectTimeout;
|
||||
function setupTcpClient() {
|
||||
node.log("connecting to "+node.host+":"+node.port);
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
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 ((node.datatype) === "utf8" && node.newline != "") {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0;i<parts.length-1;i+=1) {
|
||||
var msg = {topic:node.topic, payload:parts[i]};
|
||||
node.send(msg);
|
||||
}
|
||||
buffer = parts[parts.length-1];
|
||||
} else {
|
||||
var msg = {topic:node.topic, payload:data};
|
||||
node.send(msg);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data) === "string") {
|
||||
buffer = buffer+data;
|
||||
} else {
|
||||
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
client.on('end', function() {
|
||||
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
|
||||
var msg = {topic:node.topic,payload:buffer};
|
||||
node.send(msg);
|
||||
buffer = null;
|
||||
}
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
node.log("connection lost to "+node.host+":"+node.port);
|
||||
if (!node.closing) {
|
||||
reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
|
||||
}
|
||||
});
|
||||
|
||||
client.on('error', function(err) {
|
||||
node.log(err);
|
||||
});
|
||||
}
|
||||
setupTcpClient();
|
||||
|
||||
this.on('close', function() {
|
||||
this.closing = true;
|
||||
client.end();
|
||||
clearTimeout(reconnectTimeout);
|
||||
});
|
||||
} else {
|
||||
var server = net.createServer(function (socket) {
|
||||
var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
|
||||
socket.on('data', function (data) {
|
||||
if (node.datatype != 'buffer') {
|
||||
data = data.toString(node.datatype);
|
||||
}
|
||||
|
||||
if (node.stream) {
|
||||
if ((typeof data) === "string" && node.newline != "") {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0;i<parts.length-1;i+=1) {
|
||||
var msg = {topic:node.topic, payload:parts[i],ip:socket.remoteAddress,port:socket.remotePort};
|
||||
node.send(msg);
|
||||
}
|
||||
buffer = parts[parts.length-1];
|
||||
} else {
|
||||
var msg = {topic:node.topic, payload:data};
|
||||
node.send(msg);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data) === "string") {
|
||||
buffer = buffer+data;
|
||||
} else {
|
||||
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
socket.on('end', function() {
|
||||
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
|
||||
var msg = {topic:node.topic,payload:buffer};
|
||||
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.on('close', function() {
|
||||
this.closing = true;
|
||||
server.close();
|
||||
node.log('stopped listening on port '+node.port);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tcp in",TcpIn);
|
||||
|
||||
function TcpOut(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.host = n.host;
|
||||
this.port = n.port * 1;
|
||||
this.base64 = n.base64;
|
||||
this.beserver = n.beserver;
|
||||
this.name = n.name;
|
||||
this.closing = false;
|
||||
var node = this;
|
||||
|
||||
if (!node.beserver||node.beserver=="client") {
|
||||
var reconnectTimeout;
|
||||
var client = null;
|
||||
var connected = false;
|
||||
|
||||
function setupTcpClient() {
|
||||
node.log("connecting to "+node.host+":"+node.port);
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
connected = true;
|
||||
node.log("connected to "+node.host+":"+node.port);
|
||||
});
|
||||
|
||||
client.on('error', function (err) {
|
||||
node.log('error : '+err);
|
||||
});
|
||||
|
||||
client.on('end', function (err) {
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
node.log("connection lost to "+node.host+":"+node.port);
|
||||
connected = false;
|
||||
client.destroy();
|
||||
if (!node.closing) {
|
||||
reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
setupTcpClient();
|
||||
|
||||
|
||||
node.on("input", function(msg) {
|
||||
if (connected && msg.payload != null) {
|
||||
if (Buffer.isBuffer(msg.payload)) {
|
||||
client.write(msg.payload);
|
||||
} else if (typeof msg.payload === "string" && node.base64) {
|
||||
client.write(new Buffer(msg.payload,'base64'));
|
||||
} else {
|
||||
client.write(new Buffer(""+msg.payload));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
this.closing = true;
|
||||
client.end();
|
||||
clearTimeout(reconnectTimeout);
|
||||
});
|
||||
|
||||
} else {
|
||||
var connectedSockets = [];
|
||||
var server = net.createServer(function (socket) {
|
||||
var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
|
||||
node.log("connection from "+remoteDetails);
|
||||
connectedSockets.push(socket);
|
||||
socket.on('close',function() {
|
||||
node.log("connection closed from "+remoteDetails);
|
||||
connectedSockets.splice(connectedSockets.indexOf(socket),1);
|
||||
});
|
||||
socket.on('error',function() {
|
||||
node.log("socket error from "+remoteDetails);
|
||||
connectedSockets.splice(connectedSockets.indexOf(socket),1);
|
||||
});
|
||||
|
||||
});
|
||||
node.on("input", function(msg) {
|
||||
if (msg.payload != null) {
|
||||
var buffer;
|
||||
if (Buffer.isBuffer(msg.payload)) {
|
||||
buffer = msg.payload;
|
||||
} else if (typeof msg.payload === "string" && node.base64) {
|
||||
buffer = new Buffer(msg.payload,'base64');
|
||||
} else {
|
||||
buffer = new Buffer(""+msg.payload);
|
||||
}
|
||||
for (var i = 0; i<connectedSockets.length;i+=1) {
|
||||
connectedSockets[i].write(buffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(node.port);
|
||||
node.log('listening on port '+node.port);
|
||||
|
||||
node.on('close', function() {
|
||||
server.close();
|
||||
node.log('stopped listening on port '+node.port);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tcp out",TcpOut);
|
||||
|
||||
|
178
nodes/core/io/32-udp.html
Normal file
178
nodes/core/io/32-udp.html
Normal file
@@ -0,0 +1,178 @@
|
||||
<!--
|
||||
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.ip</b> and <b>msg.port</b> to the ip address and port from which the message was received.</b>
|
||||
<p>On some systems you may need to be root to use ports below 1024 and/or broadcast.</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>
|
||||
<div class="form-tips">Tip: leave address and port blank if you want to set using <b>msg.ip</b> and <b>msg.port</b>.</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>You may also use <b>msg.ip</b> and <b>msg.port</b> to set the destination values.<br/><b>Note</b>: the statically configured values have precedence.</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 ports below 1024 and/or broadcast.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('udp out',{
|
||||
category: 'output',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
addr: {value:""},
|
||||
iface: {value:""},
|
||||
port: {value:""},
|
||||
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>
|
124
nodes/core/io/32-udp.js
Normal file
124
nodes/core/io/32-udp.js
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/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);
|
||||
if ((err.code == "EACCES") && (node.port < 1024)) { node.error("UDP access error, you may need root access for ports below 1024"); }
|
||||
else { node.error("UDP error : "+err.code); }
|
||||
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, ip:remote.address, port: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) {
|
||||
var add = node.addr || msg.ip || "";
|
||||
var por = node.port || msg.port || 0;
|
||||
if (add == "") { node.warn("udp: ip address not set"); }
|
||||
else if (por == 0) { node.warn("udp: port not set"); }
|
||||
else if (isNaN(por) || (por < 1) || (por > 65535)) { node.warn("udp: port number not valid"); }
|
||||
else {
|
||||
var message;
|
||||
if (node.base64) { message = new Buffer(b64string, 'base64'); }
|
||||
else if (msg.payload instanceof Buffer) { message = msg.payload; }
|
||||
else { message = new Buffer(""+msg.payload); }
|
||||
console.log("UDP send :",add,por,msg.payload.toString());
|
||||
sock.send(message, 0, message.length, por, add, 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);
|
61
nodes/core/io/90-httpget.html
Normal file
61
nodes/core/io/90-httpget.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="httpget">
|
||||
<div class="form-tips"><b>Deprecated</b>: please use the <i>http request</i> node.</div>
|
||||
<br>
|
||||
<div class="form-row">
|
||||
<label for="node-input-baseurl"><i class="icon-tasks"></i> Base URL</label>
|
||||
<input type="text" id="node-input-baseurl" placeholder="http(s)://url">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-append"><i class="icon-tasks"></i> Append</label>
|
||||
<input type="text" id="node-input-append" placeholder="">
|
||||
</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">The <b>Base URL</b> gets prepended to whatever payload is passed in. Leave blank if you pass in a full url.<br/>The append gets added to the end after any payload.<br/>The output Topic is the same as the input Topic.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="httpget">
|
||||
<p>Performs an HTTP or HTTPS GET and returns the fetched page.</p>
|
||||
<p>The return code is placed in <b>msg.rc</b>, and the full text of the result is in <b>msg.payload</b>.</p>
|
||||
<p>The <b>msg.payload</b> is added to the base url, and then the optional append is added after.</p>
|
||||
<p>This is mostly suitable for small pages as large results will need a lot of parsing....</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('httpget',{
|
||||
category: 'advanced-function',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
baseurl: {value:""},
|
||||
append: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||this.baseurl;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
52
nodes/core/io/90-httpget.js
Normal file
52
nodes/core/io/90-httpget.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
|
||||
function HttpGet(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.baseurl = n.baseurl || "";
|
||||
this.append = n.append || "";
|
||||
var node = this;
|
||||
if (this.baseurl.substring(0,5) === "https") { var http = require("https"); }
|
||||
else { var http = require("http"); }
|
||||
this.on("input", function(msg) {
|
||||
msg._payload = msg.payload;
|
||||
//util.log("[httpget] "+this.baseurl+msg.payload+this.append);
|
||||
http.get(this.baseurl+msg.payload+this.append, function(res) {
|
||||
node.log("Http response: " + res.statusCode);
|
||||
msg.rc = res.statusCode;
|
||||
msg.payload = "";
|
||||
if ((msg.rc != 200) && (msg.rc != 404)) {
|
||||
node.send(msg);
|
||||
}
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', function(chunk) {
|
||||
msg.payload += chunk;
|
||||
});
|
||||
res.on('end', function() {
|
||||
node.send(msg);
|
||||
});
|
||||
}).on('error', function(e) {
|
||||
//node.error(e);
|
||||
msg.rc = 503;
|
||||
msg.payload = e;
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("httpget",HttpGet);
|
225
nodes/core/io/lib/mqtt.js
Normal file
225
nodes/core/io/lib/mqtt.js
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* 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 util = require("util");
|
||||
var mqtt = require("mqtt");
|
||||
var events = require("events");
|
||||
|
||||
//var Client = module.exports.Client = function(
|
||||
|
||||
var port = 1883;
|
||||
var host = "localhost";
|
||||
|
||||
function MQTTClient(port,host) {
|
||||
this.port = port||1883;
|
||||
this.host = host||"localhost";
|
||||
this.messageId = 1;
|
||||
this.pendingSubscriptions = {};
|
||||
this.inboundMessages = {};
|
||||
this.lastOutbound = (new Date()).getTime();
|
||||
this.lastInbound = (new Date()).getTime();
|
||||
this.connected = false;
|
||||
|
||||
this._nextMessageId = function() {
|
||||
this.messageId += 1;
|
||||
if (this.messageId > 0xFFFF) {
|
||||
this.messageId = 1;
|
||||
}
|
||||
return this.messageId;
|
||||
}
|
||||
events.EventEmitter.call(this);
|
||||
}
|
||||
util.inherits(MQTTClient, events.EventEmitter);
|
||||
|
||||
MQTTClient.prototype.connect = function(options) {
|
||||
var self = this;
|
||||
options = options||{};
|
||||
self.options = options;
|
||||
self.options.keepalive = options.keepalive||15;
|
||||
self.options.clean = self.options.clean||true;
|
||||
self.options.protocolId = 'MQIsdp';
|
||||
self.options.protocolVersion = 3;
|
||||
|
||||
self.client = mqtt.createConnection(this.port,this.host,function(err,client) {
|
||||
if (err) {
|
||||
self.emit('connectionlost',err);
|
||||
return;
|
||||
}
|
||||
client.on('close',function(e) {
|
||||
clearInterval(self.watchdog);
|
||||
if (self.connected) {
|
||||
self.connected = false;
|
||||
self.emit('connectionlost',e);
|
||||
} else {
|
||||
self.emit('disconnect');
|
||||
}
|
||||
});
|
||||
client.on('error',function(e) {
|
||||
clearInterval(self.watchdog);
|
||||
if (self.connected) {
|
||||
self.connected = false;
|
||||
self.emit('connectionlost',e);
|
||||
}
|
||||
});
|
||||
client.on('connack',function(packet) {
|
||||
if (packet.returnCode == 0) {
|
||||
self.watchdog = setInterval(function(self) {
|
||||
var now = (new Date()).getTime();
|
||||
if (now - self.lastOutbound > self.options.keepalive*500 || now - self.lastInbound > self.options.keepalive*500) {
|
||||
if (self.pingOutstanding) {
|
||||
// DO DISCONNECT
|
||||
} else {
|
||||
self.lastOutbound = (new Date()).getTime();
|
||||
self.lastInbound = (new Date()).getTime();
|
||||
self.pingOutstanding = true;
|
||||
self.client.pingreq();
|
||||
}
|
||||
}
|
||||
|
||||
},self.options.keepalive*500,self);
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
self.connected = true;
|
||||
self.emit('connect');
|
||||
} else {
|
||||
self.connected = false;
|
||||
self.emit('connectionlost');
|
||||
}
|
||||
});
|
||||
client.on('suback',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
var topic = self.pendingSubscriptions[packet.messageId];
|
||||
self.emit('subscribe',topic,packet.granted[0]);
|
||||
delete self.pendingSubscriptions[packet.messageId];
|
||||
});
|
||||
client.on('unsuback',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
var topic = self.pendingSubscriptions[packet.messageId];
|
||||
self.emit('unsubscribe',topic,packet.granted[0]);
|
||||
delete self.pendingSubscriptions[packet.messageId];
|
||||
});
|
||||
client.on('publish',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
if (packet.qos < 2) {
|
||||
var p = packet;
|
||||
self.emit('message',p.topic,p.payload,p.qos,p.retain);
|
||||
} else {
|
||||
self.inboundMessages[packet.messageId] = packet;
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.pubrec(packet);
|
||||
}
|
||||
if (packet.qos == 1) {
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.puback(packet);
|
||||
}
|
||||
});
|
||||
|
||||
client.on('pubrel',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
var p = self.inboundMessages[packet.messageId];
|
||||
self.emit('message',p.topic,p.payload,p.qos,p.retain);
|
||||
delete self.inboundMessages[packet.messageId];
|
||||
self.lastOutbound = (new Date()).getTime()
|
||||
self.client.pubcomp(packet);
|
||||
});
|
||||
|
||||
client.on('puback',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
// outbound qos-1 complete
|
||||
});
|
||||
|
||||
client.on('pubrec',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
self.lastOutbound = (new Date()).getTime()
|
||||
self.client.pubrel(packet);
|
||||
});
|
||||
client.on('pubcomp',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
// outbound qos-2 complete
|
||||
});
|
||||
client.on('pingresp',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
self.pingOutstanding = false;
|
||||
});
|
||||
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
client.connect(self.options);
|
||||
});
|
||||
}
|
||||
|
||||
MQTTClient.prototype.subscribe = function(topic,qos) {
|
||||
var self = this;
|
||||
if (self.connected) {
|
||||
var options = {
|
||||
subscriptions:[{topic:topic,qos:qos}],
|
||||
messageId: self._nextMessageId()
|
||||
};
|
||||
this.pendingSubscriptions[options.messageId] = topic;
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.subscribe(options);
|
||||
}
|
||||
}
|
||||
MQTTClient.prototype.unsubscribe = function(topic) {
|
||||
var self = this;
|
||||
if (self.connected) {
|
||||
var options = {
|
||||
topic:topic,
|
||||
messageId: self._nextMessageId()
|
||||
};
|
||||
this.pendingSubscriptions[options.messageId] = topic;
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.unsubscribe(options);
|
||||
}
|
||||
}
|
||||
|
||||
MQTTClient.prototype.publish = function(topic,payload,qos,retain) {
|
||||
var self = this;
|
||||
if (self.connected) {
|
||||
|
||||
if (Buffer.isBuffer(payload)) {
|
||||
payload = payload.toString();
|
||||
} else if (typeof payload === "object") {
|
||||
payload = JSON.stringify(payload);
|
||||
} else if (typeof payload !== "string") {
|
||||
payload = ""+payload;
|
||||
}
|
||||
var options = {
|
||||
topic: topic,
|
||||
payload: payload,
|
||||
qos: qos||0,
|
||||
retain:retain||false
|
||||
};
|
||||
if (options.qos != 0) {
|
||||
options.messageId = self._nextMessageId();
|
||||
}
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.publish(options);
|
||||
}
|
||||
}
|
||||
|
||||
MQTTClient.prototype.disconnect = function() {
|
||||
var self = this;
|
||||
if (this.connected) {
|
||||
this.connected = false;
|
||||
this.client.disconnect();
|
||||
}
|
||||
}
|
||||
MQTTClient.prototype.isConnected = function() {
|
||||
return this.connected;
|
||||
}
|
||||
module.exports.createClient = function(port,host) {
|
||||
var mqtt_client = new MQTTClient(port,host);
|
||||
return mqtt_client;
|
||||
}
|
||||
|
120
nodes/core/io/lib/mqttConnectionPool.js
Normal file
120
nodes/core/io/lib/mqttConnectionPool.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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 util = require("util");
|
||||
var mqtt = require("./mqtt");
|
||||
var settings = require(process.env.NODE_RED_HOME+"/red/red").settings;
|
||||
|
||||
var connections = {};
|
||||
|
||||
function matchTopic(ts,t) {
|
||||
var re = new RegExp("^"+ts.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/#$/,".*"));
|
||||
return re.test(t);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: function(broker,port) {
|
||||
var id = broker+":"+port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = function() {
|
||||
var client = mqtt.createClient(port,broker);
|
||||
client.setMaxListeners(0);
|
||||
var options = {keepalive:15,clientId:'mqtt_' + (1+Math.random()*4294967295).toString(16)};
|
||||
var queue = [];
|
||||
var subscriptions = [];
|
||||
var connecting = false;
|
||||
var obj = {
|
||||
_instances: 0,
|
||||
publish: function(msg) {
|
||||
if (client.isConnected()) {
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
} else {
|
||||
if (!connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
queue.push(msg);
|
||||
}
|
||||
},
|
||||
subscribe: function(topic,qos,callback) {
|
||||
subscriptions.push({topic:topic,qos:qos,callback:callback});
|
||||
client.on('message',function(mtopic,mpayload,mqos,mretain) {
|
||||
if (matchTopic(topic,mtopic)) {
|
||||
callback(mtopic,mpayload,mqos,mretain);
|
||||
}
|
||||
});
|
||||
if (client.isConnected()) {
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
},
|
||||
on: function(a,b){
|
||||
client.on(a,b);
|
||||
},
|
||||
once: function(a,b){
|
||||
client.once(a,b);
|
||||
},
|
||||
connect: function() {
|
||||
if (!client.isConnected() && !connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
},
|
||||
disconnect: function() {
|
||||
this._instances -= 1;
|
||||
if (this._instances == 0) {
|
||||
client.disconnect();
|
||||
client = null;
|
||||
delete connections[id];
|
||||
}
|
||||
}
|
||||
};
|
||||
client.on('connect',function() {
|
||||
|
||||
util.log('[mqtt] connected to broker tcp://'+broker+':'+port);
|
||||
|
||||
connecting = false;
|
||||
for (var s in subscriptions) {
|
||||
var topic = subscriptions[s].topic;
|
||||
var qos = subscriptions[s].qos;
|
||||
var callback = subscriptions[s].callback;
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
//console.log("connected - publishing",queue.length,"messages");
|
||||
while(queue.length) {
|
||||
var msg = queue.shift();
|
||||
//console.log(msg);
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
}
|
||||
});
|
||||
client.on('connectionlost', function(err) {
|
||||
util.log('[mqtt] connection lost to broker tcp://'+broker+':'+port);
|
||||
setTimeout(function() {
|
||||
if (client) {
|
||||
client.connect(options);
|
||||
}
|
||||
}, settings.mqttReconnectTime||5000);
|
||||
});
|
||||
client.on('disconnect', function() {
|
||||
util.log('[mqtt] disconnected from broker tcp://'+broker+':'+port);
|
||||
});
|
||||
|
||||
return obj
|
||||
}();
|
||||
}
|
||||
connections[id]._instances += 1;
|
||||
return connections[id];
|
||||
}
|
||||
};
|
||||
|
199
nodes/core/logic/10-switch.html
Normal file
199
nodes/core/logic/10-switch.html
Normal file
@@ -0,0 +1,199 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="switch">
|
||||
<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-row" style="padding-top:10px;">
|
||||
If msg.<input type="text" id="node-input-property" style="width: 200px;"/>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div id="node-input-rule-container-div" style="border-radius: 5px; height: 310px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;">
|
||||
<ol id="node-input-rule-container" style=" list-style-type:none; margin: 0;">
|
||||
</ol>
|
||||
</div>
|
||||
<a href="#" class="btn btn-mini" id="node-input-add-rule" style="margin-top: 4px;"><i class="icon-plus"></i> Add</a>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="switch">
|
||||
<p>A simple function node to route messages based on its properties.</p>
|
||||
<p>When a message arrives, the selected property is evaluated against each
|
||||
of the defined rules. The message is then sent to the output of <i>all</i>
|
||||
rules that pass.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('switch',{
|
||||
color:"#E2D96E",
|
||||
category: 'function',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
property: {value: "payload",required:true},
|
||||
rules:{value:[{t:"eq",v:""}]},
|
||||
outputs:{value:1}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "switch.png",
|
||||
label: function() {
|
||||
return this.name;
|
||||
},
|
||||
oneditprepare: function() {
|
||||
|
||||
var operators = [
|
||||
{v:"eq",t:"=="},
|
||||
{v:"neq",t:"!="},
|
||||
{v:"lt",t:"<"},
|
||||
{v:"lte",t:"<="},
|
||||
{v:"gt",t:">"},
|
||||
{v:"gte",t:">="},
|
||||
{v:"btwn",t:"is between"},
|
||||
{v:"cont",t:"contains"},
|
||||
{v:"regex",t:"matches regex"},
|
||||
{v:"true",t:"is true"},
|
||||
{v:"false",t:"is false"},
|
||||
{v:"null",t:"is null"},
|
||||
{v:"nnull",t:"is not null"}
|
||||
];
|
||||
|
||||
function generateRule(i,rule) {
|
||||
var container = $('<li/>',{style:"margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;"});
|
||||
var row = $('<div/>').appendTo(container);
|
||||
var row2 = $('<div/>',{style:"padding-top: 5px; text-align: right;"}).appendTo(container);
|
||||
|
||||
var selectField = $('<select/>',{style:"width:120px; margin-left: 5px; text-align: center;"}).appendTo(row);
|
||||
for (var d in operators) {
|
||||
selectField.append($("<option></option>").val(operators[d].v).text(operators[d].t));
|
||||
}
|
||||
|
||||
var valueField = $('<input/>',{class:"node-input-rule-value",type:"text",style:"margin-left: 5px; width: 145px;"}).appendTo(row);
|
||||
|
||||
var btwnField = $('<span/>').appendTo(row);
|
||||
var btwnValueField = $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px; width: 50px;"}).appendTo(btwnField);
|
||||
btwnField.append(" and ");
|
||||
var btwnValue2Field = $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"width: 50px;margin-left:2px;"}).appendTo(btwnField);
|
||||
|
||||
|
||||
var finalspan = $('<span/>',{style:"float: right; margin-top: 3px;margin-right: 10px;"}).appendTo(row);
|
||||
finalspan.append(' send to <span class="node-input-rule-index">'+i+'</span> ');
|
||||
|
||||
selectField.change(function() {
|
||||
var type = selectField.children("option:selected").val();
|
||||
if (type.length < 4) {
|
||||
selectField.css({"width":"60px"});
|
||||
} else if (type === "regex") {
|
||||
selectField.css({"width":"147px"});
|
||||
} else {
|
||||
selectField.css({"width":"120px"});
|
||||
}
|
||||
if (type === "btwn") {
|
||||
valueField.hide();
|
||||
btwnField.show();
|
||||
} else {
|
||||
btwnField.hide();
|
||||
if (type === "true" || type === "false" || type === "null" || type === "nnull") {
|
||||
valueField.hide();
|
||||
} else {
|
||||
valueField.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var deleteButton = $('<a/>',{href:"#",class:"btn btn-mini", style:"margin-left: 5px;"}).appendTo(finalspan);
|
||||
$('<i/>',{class:"icon-remove"}).appendTo(deleteButton);
|
||||
|
||||
deleteButton.click(function() {
|
||||
container.css({"background":"#fee"});
|
||||
container.fadeOut(300, function() {
|
||||
$(this).remove();
|
||||
$("#node-input-rule-container").children().each(function(i) {
|
||||
$(this).find(".node-input-rule-index").html(i+1);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
$("#node-input-rule-container").append(container);
|
||||
|
||||
selectField.find("option").filter(function() {return $(this).val() == rule.t;}).attr('selected',true);
|
||||
if (rule.t == "btwn") {
|
||||
btwnValueField.val(rule.v);
|
||||
btwnValue2Field.val(rule.v2);
|
||||
} else if (rule.v) {
|
||||
valueField.val(rule.v);
|
||||
}
|
||||
selectField.change();
|
||||
|
||||
}
|
||||
|
||||
$("#node-input-add-rule").click(function() {
|
||||
generateRule($("#node-input-rule-container").children().length+1,{t:"",v:"",v2:""});
|
||||
$("#node-input-rule-container-div").scrollTop($("#node-input-rule-container-div").get(0).scrollHeight);
|
||||
|
||||
});
|
||||
|
||||
for (var i=0;i<this.rules.length;i++) {
|
||||
var rule = this.rules[i];
|
||||
generateRule(i+1,rule);
|
||||
}
|
||||
|
||||
function switchDialogResize(ev,ui) {
|
||||
$("#node-input-rule-container-div").css("height",(ui.size.height-260)+"px");
|
||||
};
|
||||
|
||||
$( "#dialog" ).on("dialogresize", switchDialogResize);
|
||||
$( "#dialog" ).one("dialogopen", function(ev) {
|
||||
var size = $( "#dialog" ).dialog('option','sizeCache-switch');
|
||||
if (size) {
|
||||
switchDialogResize(null,{size:size});
|
||||
}
|
||||
});
|
||||
$( "#dialog" ).one("dialogclose", function(ev,ui) {
|
||||
$( "#dialog" ).off("dialogresize",switchDialogResize);
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
var rules = $("#node-input-rule-container").children();
|
||||
var ruleset;
|
||||
|
||||
var node = this;
|
||||
node.rules= [];
|
||||
|
||||
rules.each(function(i) {
|
||||
var rule = $(this);
|
||||
var type = rule.find("select option:selected").val();
|
||||
var r = {t:type};
|
||||
if (!(type === "true" || type === "false" || type === "null" || type === "nnull")) {
|
||||
if (type === "btwn") {
|
||||
r.v = rule.find(".node-input-rule-btwn-value").val();
|
||||
r.v2 = rule.find(".node-input-rule-btwn-value2").val();
|
||||
} else {
|
||||
r.v = rule.find(".node-input-rule-value").val();
|
||||
}
|
||||
}
|
||||
node.rules.push(r);
|
||||
|
||||
});
|
||||
|
||||
node.outputs = node.rules.length;
|
||||
|
||||
}
|
||||
});
|
||||
</script>
|
64
nodes/core/logic/10-switch.js
Normal file
64
nodes/core/logic/10-switch.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
|
||||
var operators = {
|
||||
'eq':function(a,b) { return a == b; },
|
||||
'neq':function(a,b) { return a != b; },
|
||||
'lt':function(a,b) { return a < b; },
|
||||
'lte':function(a,b) { return a <= b; },
|
||||
'gt':function(a,b) { return a > b; },
|
||||
'gte':function(a,b) { return a >= b; },
|
||||
'btwn':function(a,b,c) { return a >= b && a <= c; },
|
||||
'cont':function(a,b) { return (a+"").indexOf(b) != -1; },
|
||||
'regex': function(a,b) { return (a+"").match(new RegExp(b)); },
|
||||
'true': function(a) { return a === true; },
|
||||
'false': function(a) { return a === false; },
|
||||
'null': function(a) { return a === null; },
|
||||
'nnull': function(a) { return a !== null; }
|
||||
};
|
||||
|
||||
|
||||
function SwitchNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.rules = n.rules;
|
||||
this.property = n.property;
|
||||
|
||||
var propertyParts = n.property.split(".");
|
||||
|
||||
var node = this;
|
||||
|
||||
this.on('input',function(msg) {
|
||||
var onward = [];
|
||||
var prop = propertyParts.reduce(function(obj,i) {
|
||||
return obj[i]
|
||||
},msg);
|
||||
for (var i=0;i<node.rules.length;i+=1) {
|
||||
var rule = node.rules[i];
|
||||
if (operators[rule.t](prop,rule.v,rule.v2)) {
|
||||
onward.push(msg);
|
||||
} else {
|
||||
onward.push(null);
|
||||
}
|
||||
}
|
||||
this.send(onward);
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("switch",SwitchNode);
|
||||
|
192
nodes/core/social/27-twitter.html
Normal file
192
nodes/core/social/27-twitter.html
Normal file
@@ -0,0 +1,192 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="twitter-credentials">
|
||||
<div class="form-row" id="node-config-twitter-row"></div>
|
||||
<input type="hidden" id="node-config-input-screen_name">
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var twitterConfigNodeId = null;
|
||||
var twitterConfigNodeIntervalId = null;
|
||||
|
||||
function showTwitterAuthStart() {
|
||||
var pathname = document.location.pathname;
|
||||
if (pathname.slice(-1) != "/") {
|
||||
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"><b>here</b></a> to authenticate with Twitter.');
|
||||
$("#node-config-twitter-start").click(function() {
|
||||
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
|
||||
});
|
||||
}
|
||||
function updateTwitterScreenName(sn) {
|
||||
$("#node-config-input-screen_name").val(sn);
|
||||
$("#node-config-twitter-row").html('<label><i class="icon-user"></i> Twitter ID</label><span class="input-xlarge uneditable-input">'+sn+'</span>');
|
||||
}
|
||||
function pollTwitterCredentials(e) {
|
||||
$.getJSON('twitter/'+twitterConfigNodeId,function(data) {
|
||||
if (data.sn) {
|
||||
updateTwitterScreenName(data.sn);
|
||||
twitterConfigNodeIntervalId = null;
|
||||
} else {
|
||||
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
|
||||
}
|
||||
})
|
||||
}
|
||||
RED.nodes.registerType('twitter-credentials',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
screen_name: {value:""},
|
||||
access_token: {value: ""},
|
||||
access_token_secret: {value:""}
|
||||
},
|
||||
label: function() {
|
||||
return this.screen_name;
|
||||
},
|
||||
exportable: false,
|
||||
oneditprepare: function() {
|
||||
twitterConfigNodeId = this.id;
|
||||
if (!this.screen_name || this.screen_name == "") {
|
||||
showTwitterAuthStart();
|
||||
} else {
|
||||
$.getJSON('twitter/'+twitterConfigNodeId,function(data) {
|
||||
if (data.sn) {
|
||||
updateTwitterScreenName(data.sn);
|
||||
} else {
|
||||
showTwitterAuthStart();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (twitterConfigNodeIntervalId) {
|
||||
window.clearTimeout(twitterConfigNodeIntervalId);
|
||||
}
|
||||
},
|
||||
oneditcancel: function(adding) {
|
||||
if (twitterConfigNodeIntervalId) {
|
||||
window.clearTimeout(twitterConfigNodeIntervalId);
|
||||
}
|
||||
if (adding) {
|
||||
$.ajax({
|
||||
url: 'twitter/'+this.id,
|
||||
type: 'DELETE',
|
||||
success: function(result) {}
|
||||
});
|
||||
}
|
||||
},
|
||||
ondelete: function() {
|
||||
$.ajax({
|
||||
url: 'twitter/'+this.id,
|
||||
type: 'DELETE',
|
||||
success: function(result) {}
|
||||
});
|
||||
}
|
||||
});
|
||||
</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> 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-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: 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 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>
|
||||
<p>Sets <b>msg.tweet</b> to the full tweet object as documented by <a href="https://dev.twitter.com/docs/platform-objects/tweets">Twitter</a>.
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('twitter in',{
|
||||
category: 'social-input',
|
||||
color:"#C0DEED",
|
||||
defaults: {
|
||||
twitter: {type:"twitter-credentials",required:true},
|
||||
tags: {value:"",required:true},
|
||||
user: {value:"false",required:true},
|
||||
name: {value:""},
|
||||
topic: {value:"tweets"}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "twitter.png",
|
||||
label: function() {
|
||||
return this.name||this.tags;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="twitter out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-twitter"><i class="icon-user"></i> Twitter</label>
|
||||
<input type="text" id="node-input-twitter">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="twitter out">
|
||||
<p>Twitter out node. Tweets the <b>msg.payload</b>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('twitter out',{
|
||||
category: 'social-output',
|
||||
color:"#C0DEED",
|
||||
defaults: {
|
||||
twitter: {type:"twitter-credentials",required:true},
|
||||
name: {value:"Tweet"}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "twitter.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name;
|
||||
}
|
||||
});
|
||||
</script>
|
209
nodes/core/social/27-twitter.js
Normal file
209
nodes/core/social/27-twitter.js
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var ntwitter = require('ntwitter');
|
||||
var OAuth= require('oauth').OAuth;
|
||||
|
||||
function TwitterNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.screen_name = n.screen_name;
|
||||
}
|
||||
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||"tweets";
|
||||
this.twitterConfig = RED.nodes.getNode(this.twitter);
|
||||
var credentials = RED.nodes.getCredentials(this.twitter);
|
||||
|
||||
if (credentials && credentials.screen_name == this.twitterConfig.screen_name) {
|
||||
var twit = new ntwitter({
|
||||
consumer_key: "OKjYEd1ef2bfFolV25G5nQ",
|
||||
consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
|
||||
access_token_key: credentials.access_token,
|
||||
access_token_secret: credentials.access_token_secret
|
||||
});
|
||||
|
||||
var node = this;
|
||||
if (this.tags !== "") {
|
||||
try {
|
||||
var thing = 'statuses/filter';
|
||||
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) {
|
||||
//console.log(tweet.user);
|
||||
if (tweet.user !== undefined) {
|
||||
var where = tweet.user.location||"";
|
||||
var la = tweet.lang || tweet.user.lang;
|
||||
//console.log(tweet.user.location,"=>",tweet.user.screen_name,"=>",pay);
|
||||
var msg = { topic:node.topic+"/"+tweet.user.screen_name, payload:tweet.text, location:where, lang:la, tweet:tweet };
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
stream.on('error', function(tweet) {
|
||||
node.warn(tweet);
|
||||
setTimeout(setupStream,5000);
|
||||
});
|
||||
stream.on('destroy', function (response) {
|
||||
if (this.active) {
|
||||
node.warn("twitter ended unexpectedly");
|
||||
setTimeout(setupStream,5000);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
setupStream();
|
||||
}
|
||||
catch (err) {
|
||||
node.error(err);
|
||||
}
|
||||
} else {
|
||||
this.error("Invalid tag property");
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
this.error("missing twitter credentials");
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("twitter in",TwitterInNode);
|
||||
|
||||
TwitterInNode.prototype.close = function() {
|
||||
if (this.stream) {
|
||||
this.active = false;
|
||||
this.stream.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
function TwitterOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.topic = n.topic;
|
||||
this.twitter = n.twitter;
|
||||
this.twitterConfig = RED.nodes.getNode(this.twitter);
|
||||
var credentials = RED.nodes.getCredentials(this.twitter);
|
||||
var node = this;
|
||||
|
||||
if (credentials && credentials.screen_name == this.twitterConfig.screen_name) {
|
||||
var twit = new ntwitter({
|
||||
consumer_key: "OKjYEd1ef2bfFolV25G5nQ",
|
||||
consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
|
||||
access_token_key: credentials.access_token,
|
||||
access_token_secret: credentials.access_token_secret
|
||||
}).verifyCredentials(function (err, data) {
|
||||
if (err) {
|
||||
node.error("Error verifying credentials: " + err);
|
||||
} else {
|
||||
node.on("input", function(msg) {
|
||||
if (msg != null) {
|
||||
if (msg.payload.length > 140) {
|
||||
msg.payload = msg.payload.slice(0,139);
|
||||
node.warn("Tweet greater than 140 : truncated");
|
||||
}
|
||||
twit.updateStatus(msg.payload, function (err, data) {
|
||||
if (err) node.error(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("twitter out",TwitterOutNode);
|
||||
|
||||
|
||||
|
||||
var oa = new OAuth(
|
||||
"https://api.twitter.com/oauth/request_token",
|
||||
"https://api.twitter.com/oauth/access_token",
|
||||
"OKjYEd1ef2bfFolV25G5nQ",
|
||||
"meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
|
||||
"1.0",
|
||||
null,
|
||||
"HMAC-SHA1"
|
||||
);
|
||||
|
||||
var credentials = {};
|
||||
|
||||
RED.app.get('/twitter/:id', function(req,res) {
|
||||
var credentials = RED.nodes.getCredentials(req.params.id);
|
||||
if (credentials) {
|
||||
res.send(JSON.stringify({sn:credentials.screen_name}));
|
||||
} else {
|
||||
res.send(JSON.stringify({}));
|
||||
}
|
||||
});
|
||||
|
||||
RED.app.delete('/twitter/:id', function(req,res) {
|
||||
RED.nodes.deleteCredentials(req.params.id);
|
||||
res.send(200);
|
||||
});
|
||||
|
||||
RED.app.get('/twitter/:id/auth', function(req, res){
|
||||
var credentials = {};
|
||||
oa.getOAuthRequestToken({
|
||||
oauth_callback: req.query.callback
|
||||
},function(error, oauth_token, oauth_token_secret, results){
|
||||
if (error) {
|
||||
console.log(error);
|
||||
res.send("yeah no. didn't work.")
|
||||
}
|
||||
else {
|
||||
credentials.oauth_token = oauth_token;
|
||||
credentials.oauth_token_secret = oauth_token_secret;
|
||||
res.redirect('https://twitter.com/oauth/authorize?oauth_token='+oauth_token)
|
||||
RED.nodes.addCredentials(req.params.id,credentials);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
RED.app.get('/twitter/:id/auth/callback', function(req, res, next){
|
||||
|
||||
var credentials = RED.nodes.getCredentials(req.params.id);
|
||||
credentials.oauth_verifier = req.query.oauth_verifier;
|
||||
|
||||
oa.getOAuthAccessToken(
|
||||
credentials.oauth_token,
|
||||
credentials.token_secret,
|
||||
credentials.oauth_verifier,
|
||||
function(error, oauth_access_token, oauth_access_token_secret, results){
|
||||
if (error){
|
||||
console.log(error);
|
||||
res.send("yeah something broke.");
|
||||
} else {
|
||||
credentials = {};
|
||||
credentials.access_token = oauth_access_token;
|
||||
credentials.access_token_secret = oauth_access_token_secret;
|
||||
credentials.screen_name = "@"+results.screen_name;
|
||||
RED.nodes.addCredentials(req.params.id,credentials);
|
||||
res.send("<html><head></head><body>Authorised - you can close this window and return to Node-RED</body></html>");
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
57
nodes/core/social/32-feedparse.html
Normal file
57
nodes/core/social/32-feedparse.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="feedparse">
|
||||
<div class="form-row">
|
||||
<label for="node-input-url"><i class="icon-globe"></i> Feed url</label>
|
||||
<input type="text" id="node-input-url">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-interval"><i class="icon-repeat"></i> Repeat <span style="font-size: 0.9em;">(M)</span></label>
|
||||
<input type="text" id="node-input-interval" placeholder="minutes">
|
||||
</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"></div> -->
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="feedparse">
|
||||
<p>Monitors an RSS/atom feed for new entries.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('feedparse',{
|
||||
category: 'advanced-input',
|
||||
color:"#C0DEED",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
url: {value:"", required:true},
|
||||
interval: { value:15, required: true,validate:RED.validators.number()}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "feed.png",
|
||||
label: function() {
|
||||
return this.name||this.url;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
75
nodes/core/social/32-feedparse.js
Normal file
75
nodes/core/social/32-feedparse.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var FeedParser = require("feedparser");
|
||||
var request = require("request");
|
||||
|
||||
function FeedParseNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.url = n.url;
|
||||
this.interval = (parseInt(n.interval)||15)*60000;
|
||||
var node = this;
|
||||
this.interval_id = null;
|
||||
this.seen = {};
|
||||
if (this.url !== "") {
|
||||
var getFeed = function() {
|
||||
request(node.url,function(err) {
|
||||
if (err) node.error(err);
|
||||
})
|
||||
.pipe(new FeedParser({feedurl:node.url}))
|
||||
.on('error', function(error) {
|
||||
node.error(error);
|
||||
})
|
||||
.on('meta', function (meta) {})
|
||||
.on('article', function (article) {
|
||||
if (!(article.guid in node.seen) || ( node.seen[article.guid] != 0 && node.seen[article.guid] != article.date.getTime())) {
|
||||
node.seen[article.guid] = article.date?article.date.getTime():0;
|
||||
var msg = {
|
||||
topic:article.origlink||article.link,
|
||||
payload: article.description,
|
||||
article: {
|
||||
summary:article.summary,
|
||||
link:article.link,
|
||||
date: article.date,
|
||||
pubdate: article.pubdate,
|
||||
author: article.author,
|
||||
guid: article.guid,
|
||||
}
|
||||
};
|
||||
node.send(msg);
|
||||
}
|
||||
})
|
||||
.on('end', function () {
|
||||
});
|
||||
};
|
||||
this.interval_id = setInterval(getFeed,node.interval);
|
||||
getFeed();
|
||||
|
||||
} else {
|
||||
this.error("Invalid url");
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("feedparse",FeedParseNode);
|
||||
|
||||
FeedParseNode.prototype.close = function() {
|
||||
if (this.interval_id != null) {
|
||||
clearInterval(this.interval_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
50
nodes/core/social/61-email.html
Normal file
50
nodes/core/social/61-email.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="email">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-envelope"></i> To</label>
|
||||
<input type="text" id="node-input-name" placeholder="email@address.com">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="email">
|
||||
<p>Sends the <b>msg.payload</b> as an email, with a subject of <b>msg.topic</b>.</p>
|
||||
<p>It sends the message to the configured recipient <i>only</i>.</p>
|
||||
<p><b>msg.topic</b> is used to set the subject of the email, and <b>msg.payload</b> is the body text.</p>
|
||||
<p>Uses the nodemailer module - you also need to pre-configure your email SMTP settings in ../../emailkeys.js - see INSTALL file for details.</p>
|
||||
<p><pre>module.exports = { service: "Gmail", user: "blahblah@gmail.com", pass: "password", server: "imap.gmail.com", port: "993" }</pre></p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('email',{
|
||||
category: 'social-output',
|
||||
color:"#c7e9c0",
|
||||
defaults: {
|
||||
name: {value:"",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "envelope.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return (this.name||!this.topic)?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
55
nodes/core/social/61-email.js
Normal file
55
nodes/core/social/61-email.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var nodemailer = require("nodemailer");
|
||||
var emailkey = require(process.env.NODE_RED_HOME+"/../emailkeys.js");
|
||||
|
||||
var smtpTransport = nodemailer.createTransport("SMTP",{
|
||||
service: emailkey.service,
|
||||
auth: {
|
||||
user: emailkey.user,
|
||||
pass: emailkey.pass
|
||||
}
|
||||
});
|
||||
|
||||
function EmailNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.topic = n.topic;
|
||||
this.name = n.name;
|
||||
var node = this;
|
||||
this.on("input", function(msg) {
|
||||
//node.log("email :",this.id,this.topic," received",msg.payload);
|
||||
if (msg != null) {
|
||||
|
||||
smtpTransport.sendMail({
|
||||
from: emailkey.user, // sender address
|
||||
to: node.name, // comma separated list of receivers
|
||||
subject: msg.topic, // Subject line
|
||||
text: msg.payload // plaintext body
|
||||
}, function(error, response) {
|
||||
if (error) {
|
||||
node.error(error);
|
||||
} else {
|
||||
node.log("Message sent: " + response.message);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("email",EmailNode);
|
54
nodes/core/social/61-imap.html
Normal file
54
nodes/core/social/61-imap.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="imap">
|
||||
<div class="form-row node-input-repeat">
|
||||
<label for="node-input-repeat"><i class="icon-repeat"></i>Repeat (S)</label>
|
||||
<input type="text" id="node-input-repeat" placeholder="300">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="imap">
|
||||
<p>Repeatedly gets a <b>single email</b> from an IMAP server and forwards on as a msg if not already seen.</p>
|
||||
<p>The subject is loaded into <b>msg.topic</b> and <b>msg.payload</b> is the body text. <b>msg.from</b> is also set if you need it.</p>
|
||||
<p>Uses the imap module - you also need to pre-configure your email settings in ../../emailkeys.js - see INSTALL file for details.</p>
|
||||
<p><pre>module.exports = { service: "Gmail", user: "blahblah@gmail.com", pass: "password", server: "imap.gmail.com", port: "993" }</pre></p>
|
||||
<p><b>Note:</b> this node <i>only</i> gets the most recent single email from the inbox, so set the repeat (polling) time appropriately.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('imap',{
|
||||
category: 'social-input',
|
||||
color:"#c7e9c0",
|
||||
defaults: {
|
||||
repeat: {value:"300",required:true},
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "envelope.png",
|
||||
label: function() {
|
||||
return this.name||"IMAP";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return (this.name||!this.topic)?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
108
nodes/core/social/61-imap.js
Normal file
108
nodes/core/social/61-imap.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var Imap = require('imap');
|
||||
var util = require('util');
|
||||
var oldmail = {};
|
||||
|
||||
try {
|
||||
var emailkey = RED.settings.email || require(process.env.NODE_RED_HOME+"/../emailkeys.js");
|
||||
} catch(err) {
|
||||
throw new Error("Failed to load Email credentials");
|
||||
}
|
||||
|
||||
var imap = new Imap({
|
||||
user: emailkey.user,
|
||||
password: emailkey.pass,
|
||||
host: emailkey.server||"imap.gmail.com",
|
||||
port: emailkey.port||"993",
|
||||
secure: true
|
||||
});
|
||||
|
||||
function fail(err) {
|
||||
util.log('[imap] : ' + err);
|
||||
}
|
||||
|
||||
function openInbox(cb) {
|
||||
imap.connect(function(err) {
|
||||
if (err) fail(err);
|
||||
imap.openBox('INBOX', true, cb);
|
||||
});
|
||||
}
|
||||
|
||||
function ImapNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.name = n.name;
|
||||
this.repeat = n.repeat * 1000;
|
||||
var node = this;
|
||||
this.interval_id = null;
|
||||
|
||||
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
|
||||
this.log("repeat = "+this.repeat);
|
||||
this.interval_id = setInterval( function() {
|
||||
node.emit("input",{});
|
||||
}, this.repeat );
|
||||
}
|
||||
|
||||
this.on("input", function(msg) {
|
||||
openInbox(function(err, mailbox) {
|
||||
if (err) fail(err);
|
||||
imap.seq.fetch(mailbox.messages.total + ':*', { struct: false },
|
||||
{ headers: ['from', 'subject'],
|
||||
body: true,
|
||||
cb: function(fetch) {
|
||||
fetch.on('message', function(msg) {
|
||||
//node.log('Saw message no. ' + msg.seqno);
|
||||
var pay = {};
|
||||
var body = '';
|
||||
msg.on('headers', function(hdrs) {
|
||||
pay.from = hdrs.from[0];
|
||||
pay.topic = hdrs.subject[0];
|
||||
});
|
||||
msg.on('data', function(chunk) {
|
||||
body += chunk.toString('utf8');
|
||||
});
|
||||
msg.on('end', function() {
|
||||
pay.payload = body;
|
||||
if ((pay.topic !== oldmail.topic)|(pay.payload !== oldmail.payload)) {
|
||||
oldmail = pay;
|
||||
//node.log("From: "+pay.from);
|
||||
node.log("Subj: "+pay.topic);
|
||||
//node.log("Body: "+pay.payload);
|
||||
node.send(pay);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}, function(err) {
|
||||
if (err) node.log("Err : "+err);
|
||||
//node.log("Done fetching messages.");
|
||||
imap.logout();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
this.on("close", function() {
|
||||
if (this.interval_id != null) {
|
||||
clearInterval(this.interval_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("imap",ImapNode);
|
130
nodes/core/social/91-irc.html
Normal file
130
nodes/core/social/91-irc.html
Normal file
@@ -0,0 +1,130 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="irc in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-ircserver"><i class="icon-tasks"></i> IRC Server</label>
|
||||
<input type="text" id="node-input-ircserver">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="irc in">
|
||||
<p>Connects to a channel on an IRC server</p>
|
||||
<p>Any messages on that channel will appear on the <b>msg.payload</b> at the output, while <b>msg.topic</b> will contain who it is from.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('irc in',{
|
||||
category: 'social-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
ircserver: {type:"irc-server", required:true}
|
||||
},
|
||||
color:"Silver",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "hash.png",
|
||||
label: function() {
|
||||
var ircNode = RED.nodes.node(this.ircserver);
|
||||
return this.name||(ircNode?ircNode.label():"irc");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="irc out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-ircserver"><i class="icon-tasks"></i> IRC Server</label>
|
||||
<input type="text" id="node-input-ircserver">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-sendObject"><i class="icon-check"></i> Action</label>
|
||||
<select type="text" id="node-input-sendObject" style="display: inline-block; vertical-align: middle; width:70%;">
|
||||
<option value="pay">Send msg.payload to channel</option>
|
||||
<option value="true">Send msg.payload to id in msg.topic</option>
|
||||
<option value="false">Send complete msg object to channel</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">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>Sends messages to a channel on an IRC server</p>
|
||||
<p>You can send just the <b>msg.payload</b>, or the complete <b>msg</b> object to the selected channel,
|
||||
or you can select to use <b>msg.topic</b> to send the <b>msg.payload</b> to a specific user in the channel (private conversation).</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('irc out',{
|
||||
category: 'social-output',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
sendObject: {value:"pay", required:true},
|
||||
ircserver: {type:"irc-server", required:true}
|
||||
},
|
||||
color:"Silver",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "hash.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name || (this.ircserver)?RED.nodes.node(this.ircserver).label():"irc";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="irc-server">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-server"><i class="icon-tasks"></i> IRC Server</label>
|
||||
<input type="text" id="node-config-input-server" placeholder="irc.UK-IRC.net">
|
||||
</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="#node-red">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-nickname"><i class="icon-tasks"></i> Nickname</label>
|
||||
<input type="text" id="node-config-input-nickname" placeholder="joe123">
|
||||
</div>
|
||||
<div class="form-tips">The channel to join must start with a # (as per normal irc rules...)</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('irc-server',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
channel: {value:"",required:true,validate:RED.validators.regex(/^#/)},
|
||||
server: {value:"",required:true},
|
||||
nickname: {value:"",required:true}
|
||||
},
|
||||
label: function() {
|
||||
return this.server+":"+this.channel;
|
||||
}
|
||||
});
|
||||
</script>
|
98
nodes/core/social/91-irc.js
Normal file
98
nodes/core/social/91-irc.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var irc = require("irc");
|
||||
var util = require("util");
|
||||
|
||||
// The Server Definition - this opens (and closes) the connection
|
||||
function IRCServerNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.server = n.server;
|
||||
this.channel = n.channel;
|
||||
this.nickname = n.nickname;
|
||||
this.ircclient = null;
|
||||
this.on("close", function() {
|
||||
if (this.ircclient != null) {
|
||||
this.ircclient.disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("irc-server",IRCServerNode);
|
||||
|
||||
// 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) {
|
||||
//util.log(from + ' => ' + to + ': ' + message);
|
||||
var msg = { "topic":from, "to":to, "payload":message };
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
}
|
||||
RED.nodes.registerType("irc in",IrcInNode);
|
||||
|
||||
// The Output Node
|
||||
function IrcOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.sendAll = n.sendObject;
|
||||
this.ircserver = n.ircserver;
|
||||
this.serverConfig = RED.nodes.getNode(this.ircserver);
|
||||
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,node.channel);
|
||||
if (msg._topic) { delete msg._topic; }
|
||||
if (node.sendAll == "false") {
|
||||
node.ircclient.say(node.channel, JSON.stringify(msg));
|
||||
}
|
||||
else {
|
||||
if (typeof msg.payload === "object") { msg.payload = JSON.stringify(msg.payload); }
|
||||
if (node.sendAll == "pay") {
|
||||
node.ircclient.say(node.channel, msg.payload);
|
||||
}
|
||||
else {
|
||||
var to = msg.topic || node.channel;
|
||||
node.ircclient.say(to, msg.payload);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("irc out",IrcOutNode);
|
58
nodes/core/storage/28-tail.html
Normal file
58
nodes/core/storage/28-tail.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="tail">
|
||||
<div class="form-row node-input-filename">
|
||||
<label for="node-input-filename"><i class="icon-file"></i> Filename</label>
|
||||
<input type="text" id="node-input-filename" placeholder="Filename">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-split" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-split" style="width: 70%;">Split lines if we see \n ?</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>
|
||||
<div class="form-tips">WON'T work on Windows.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tail">
|
||||
<p>Tails (watches for things to be added) to the configured file. (Linux/Mac ONLY)</p>
|
||||
<p>This won't work on Windows filesystems (as it relies on the tail -f command) so we will probably have to hide it in future.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tail',{
|
||||
category: 'storage-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
split: {value:false},
|
||||
filename: {value:"",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "file.png",
|
||||
label: function() {
|
||||
return this.name||this.filename;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
56
nodes/core/storage/28-tail.js
Normal file
56
nodes/core/storage/28-tail.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var fs = require("fs");
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
function TailNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.filename = n.filename;
|
||||
this.split = n.split;
|
||||
var node = this;
|
||||
|
||||
var err = "";
|
||||
var tail = spawn("tail", ["-f", this.filename]);
|
||||
tail.stdout.on("data", function (data) {
|
||||
var msg = {topic:node.filename};
|
||||
if (node.split) {
|
||||
var strings = data.toString().split("\n");
|
||||
for (s in strings) {
|
||||
if (strings[s] != "") {
|
||||
msg.payload = strings[s];
|
||||
node.send(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.payload = data.toString();
|
||||
node.send(msg);
|
||||
}
|
||||
});
|
||||
|
||||
tail.stderr.on("data", function(data) {
|
||||
node.warn(data.toString());
|
||||
});
|
||||
|
||||
this.on("close", function() {
|
||||
if (tail) tail.kill();
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tail",TailNode);
|
66
nodes/core/storage/50-file.html
Normal file
66
nodes/core/storage/50-file.html
Normal file
@@ -0,0 +1,66 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="file">
|
||||
<div class="form-row node-input-filename">
|
||||
<label for="node-input-filename"><i class="icon-file"></i> Filename</label>
|
||||
<input type="text" id="node-input-filename" placeholder="Filename">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-appendNewline" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-appendNewline" style="width: 70%;">Append newline ?</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-overwriteFile" placeholder="Name" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-overwriteFile" style="width: 70%;">Overwrite complete file ?</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="file">
|
||||
<p>Writes the <b>msg.payload</b> to the file specified, e.g. to create a log.</p>
|
||||
<p>A newline is added to every message. But this can be turned off if required, for example, to allow binary files to be written.</p>
|
||||
<p>The default behaviour is to append to the file. This can be changed to overwrite the file each time, for example if you want to output a "static" web page or report.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('file',{
|
||||
category: 'storage-output',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
filename: {value:"",required:true},
|
||||
appendNewline: {value:true},
|
||||
overwriteFile: {value:false}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "file.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.filename;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
47
nodes/core/storage/50-file.js
Normal file
47
nodes/core/storage/50-file.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var fs = require("fs");
|
||||
|
||||
function FileNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.filename = n.filename;
|
||||
this.appendNewline = n.appendNewline;
|
||||
this.overwriteFile = n.overwriteFile;
|
||||
var node = this;
|
||||
this.on("input",function(msg) {
|
||||
var data = msg.payload;
|
||||
if (this.appendNewline) {
|
||||
data += "\n";
|
||||
}
|
||||
if (this.overwriteFile) {
|
||||
fs.writeFile(this.filename, data, function (err) {
|
||||
if (err) node.warn('Failed to write to file : '+err);
|
||||
//console.log('Message written to file',this.filename);
|
||||
});
|
||||
}
|
||||
else {
|
||||
fs.appendFile(this.filename, data, function (err) {
|
||||
if (err) node.warn('Failed to append to file : '+err);
|
||||
//console.log('Message appended to file',this.filename);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("file",FileNode);
|
105
nodes/core/storage/65-redisout.html
Normal file
105
nodes/core/storage/65-redisout.html
Normal file
@@ -0,0 +1,105 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="redis out">
|
||||
<div class="form-row node-input-hostname">
|
||||
<label for="node-input-hostname"><i class="icon-bookmark"></i> Host</label>
|
||||
<input class="input-append-left" type="text" id="node-input-hostname" placeholder="127.0.0.1" style="width: 40%;" ><button id="node-input-hostname-lookup" class="btn input-append-right"><span class="caret"></span></button>
|
||||
<label for="node-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
|
||||
<input type="text" id="node-input-port" placeholder="6379" style="width:45px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-key"><i class="icon-briefcase"></i> Key</label>
|
||||
<input type="text" id="node-input-key" placeholder="Redis Key">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-type"><i class="icon-th"></i> Type</label>
|
||||
<select type="text" id="node-input-structtype" style="width: 150px;">
|
||||
<option value="string">String</option>
|
||||
<option value="hash">Hash</option>
|
||||
<option value="set">Set</option>
|
||||
<option value="list">List</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">
|
||||
If key is blank, the topic will be used as the key.<br>
|
||||
If type is hash, payload should be field=value.
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="redis out">
|
||||
<p>A Redis output node. Options include Hash, Set, List and String.</p>
|
||||
<p>To run this you need a local Redis server running. For details see <a href="http://redis.io/" target="_new">the Redis site</a>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('redis out',{
|
||||
category: 'storage-output',
|
||||
color:"#ffaaaa",
|
||||
defaults: {
|
||||
hostname: { value:"127.0.0.1",required:true},
|
||||
port: { value: 6379,required:true},
|
||||
name: {value:""},
|
||||
key: {value:""},
|
||||
structtype: {value:"",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "redis.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.key+" ("+this.structtype+")";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var availableServers = [];
|
||||
var matchedServers = {};
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (node.type == "redis out" && node.hostname && node.port && !matchedServers[node.hostname+":"+node.port]) {
|
||||
var label = node.hostname+":"+node.port;
|
||||
matchedServers[label] = true;
|
||||
availableServers.push({
|
||||
label:label,
|
||||
value:node.hostname,
|
||||
port:node.port
|
||||
});
|
||||
}
|
||||
});
|
||||
$( "#node-input-hostname" ).autocomplete({
|
||||
minLength: 0,
|
||||
source: availableServers,
|
||||
select: function( event, ui ) {
|
||||
$("#node-input-port").val(ui.item.port);
|
||||
}
|
||||
});
|
||||
var tt = this;
|
||||
tt._acOpen = false;
|
||||
$( "#node-input-hostname" ).on( "autocompleteclose", function( event, ui ) { tt._acOpen = false;} );
|
||||
$( "#node-input-hostname-lookup" ).click(function(e) {
|
||||
if (tt._acOpen) {
|
||||
$( "#node-input-hostname" ).autocomplete( "close");
|
||||
} else {
|
||||
$( "#node-input-hostname" ).autocomplete( "search", "" );
|
||||
}
|
||||
tt._acOpen = !tt._acOpen;
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
96
nodes/core/storage/65-redisout.js
Normal file
96
nodes/core/storage/65-redisout.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var util = require("util");
|
||||
var redis = require("redis");
|
||||
|
||||
var hashFieldRE = /^([^=]+)=(.*)$/;
|
||||
|
||||
var redisConnectionPool = function() {
|
||||
var connections = {};
|
||||
var obj = {
|
||||
get: function(host,port) {
|
||||
var id = host+":"+port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = redis.createClient(port,host);
|
||||
connections[id].on("error",function(err) {
|
||||
util.log("[redis] "+err);
|
||||
});
|
||||
connections[id].on("connect",function() {
|
||||
util.log("[redis] connected to "+host+":"+port);
|
||||
});
|
||||
connections[id]._id = id;
|
||||
connections[id]._nodeCount = 0;
|
||||
}
|
||||
connections[id]._nodeCount += 1;
|
||||
return connections[id];
|
||||
},
|
||||
close: function(connection) {
|
||||
connection._nodeCount -= 1;
|
||||
if (connection._nodeCount == 0) {
|
||||
if (connection) {
|
||||
clearTimeout(connection.retry_timer);
|
||||
connection.end();
|
||||
}
|
||||
delete connections[connection._id];
|
||||
}
|
||||
}
|
||||
};
|
||||
return obj;
|
||||
}();
|
||||
|
||||
|
||||
function RedisOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.port = n.port||"6379";
|
||||
this.hostname = n.hostname||"127.0.0.1";
|
||||
this.key = n.key;
|
||||
this.structtype = n.structtype;
|
||||
|
||||
this.client = redisConnectionPool.get(this.hostname,this.port);
|
||||
|
||||
this.on("input", function(msg) {
|
||||
if (msg != null) {
|
||||
var k = this.key || msg.topic;
|
||||
if (k) {
|
||||
if (this.structtype == "string") {
|
||||
this.client.set(k,msg.payload);
|
||||
} else if (this.structtype == "hash") {
|
||||
var r = hashFieldRE.exec(msg.payload);
|
||||
if (r) {
|
||||
this.client.hset(k,r[1],r[2]);
|
||||
} else {
|
||||
this.warn("Invalid payload for redis hash");
|
||||
}
|
||||
} else if (this.structtype == "set") {
|
||||
this.client.sadd(k,msg.payload);
|
||||
} else if (this.structtype == "list") {
|
||||
this.client.rpush(k,msg.payload);
|
||||
}
|
||||
} else {
|
||||
this.warn("No key or topic set");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("redis out",RedisOutNode);
|
||||
|
||||
RedisOutNode.prototype.close = function() {
|
||||
redisConnectionPool.close(this.client);
|
||||
}
|
||||
|
163
nodes/core/storage/66-mongodb.html
Normal file
163
nodes/core/storage/66-mongodb.html
Normal file
@@ -0,0 +1,163 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<script type="text/x-red" data-template-name="mongodb">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-hostname"><i class="icon-bookmark"></i> Host</label>
|
||||
<input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" >
|
||||
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
|
||||
<input type="text" id="node-config-input-port" placeholder="27017" style="width:45px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-db"><i class="icon-briefcase"></i> Database</label>
|
||||
<input type="text" id="node-config-input-db" placeholder="test">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mongodb',{
|
||||
category: 'config',
|
||||
color:"rgb(218, 196, 180)",
|
||||
defaults: {
|
||||
hostname: { value:"127.0.0.1",required:true},
|
||||
port: { value: 27017,required:true},
|
||||
db: { value:"",required:true},
|
||||
name: { value:"" }
|
||||
},
|
||||
label: function() {
|
||||
return this.name||this.hostname+":"+this.port+"//"+this.db;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="mongodb out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-mongodb"><i class="icon-tag"></i> Server</label>
|
||||
<input type="text" id="node-input-mongodb">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-collection"><i class="icon-briefcase"></i> Collection</label>
|
||||
<input type="text" id="node-input-collection" placeholder="collection">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-operation"><i class="icon-wrench"></i> Operation</label>
|
||||
<select type="text" id="node-input-operation" style="display: inline-block; vertical-align: top;">
|
||||
<option value=store>save</option>
|
||||
<option value=insert>insert</option>
|
||||
<option value=delete>remove</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-payonly">
|
||||
<label> </label>
|
||||
<input type="checkbox" id="node-input-payonly" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;">
|
||||
<label for="node-input-payonly" style="width: 70%;">Only store msg.payload object ?</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-operation").change(function() {
|
||||
var id = $("#node-input-operation option:selected").val();
|
||||
if (id == "delete") $(".node-input-payonly").hide();
|
||||
else $(".node-input-payonly").show();
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mongodb out">
|
||||
<p>A simple MongoDB output node. Stores the <b>msg</b> object in a chosen collection.</p>
|
||||
<p>By default MongoDB creates an <i>_id</i> property as the primary key - so repeated injections of the same <b>msg</b> will result in many database entries.</p>
|
||||
<p>If this is NOT the desired behaviour - ie you want repeated entries to overwrite, then you must set the <b>msg._id</b> property to be a constant by the use of a previous function node.</p>
|
||||
<p>This could be a unique constant or you could create one based on some other msg property.</p>
|
||||
<p>Currently we do not limit or cap the collection size at all... this may well change.</p>
|
||||
<p>You can also choose to <b>remove</b> items. To do so the <b>msg.payload</b> <i>MUST</i> contain an object that will select the items(s) to remove.
|
||||
A blank object will delete <i>all of the objects</i> in the collection. You have been warned...</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mongodb out',{
|
||||
category: 'storage-output',
|
||||
color:"rgb(218, 196, 180)",
|
||||
defaults: {
|
||||
mongodb: { type:"mongodb",required:true},
|
||||
name: {value:""},
|
||||
collection: {value:"",required:true},
|
||||
payonly: {value:false},
|
||||
operation: {value:"store"}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "mongodb.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
var mongoNode = RED.nodes.node(this.mongodb);
|
||||
return this.name||(mongoNode?mongoNode.label()+"//"+this.collection:"mongodb");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="mongodb in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-mongodb"><i class="icon-tag"></i> Server</label>
|
||||
<input type="text" id="node-input-mongodb">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-collection"><i class="icon-briefcase"></i> Collection</label>
|
||||
<input type="text" id="node-input-collection" placeholder="collection">
|
||||
</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>
|
||||
|
||||
<script type="text/x-red" data-help-name="mongodb in">
|
||||
<p>Queries a MongoDB collection by using the <b>msg.payload</b> to be a MongoDB query statement as per the .find() function.</p>
|
||||
<p>You may also (via a function) set a <b>msg.projection</b> object to constrain the returned fields, a <b>msg.sort</b> object and a <b>msg.limit</b> object.</p>
|
||||
<p>All are optional - see the <a href="http://docs.mongodb.org/manual/reference/method/db.collection.find/" target="new"><i>MongoDB find docs</i></a> for examples.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mongodb in',{
|
||||
category: 'storage-input',
|
||||
color:"rgb(218, 196, 180)",
|
||||
defaults: {
|
||||
mongodb: { type:"mongodb",required:true},
|
||||
name: {value:""},
|
||||
collection: {value:"",required:true}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "mongodb.png",
|
||||
label: function() {
|
||||
var mongoNode = RED.nodes.node(this.mongodb);
|
||||
return this.name||(mongoNode?mongoNode.label()+"//"+this.collection:"mongodb");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
125
nodes/core/storage/66-mongodb.js
Normal file
125
nodes/core/storage/66-mongodb.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 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(process.env.NODE_RED_HOME+"/red/red");
|
||||
var mongo = require('mongodb');
|
||||
|
||||
function MongoNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.hostname = n.hostname;
|
||||
this.port = n.port;
|
||||
this.db = n.db;
|
||||
this.name = n.name;
|
||||
}
|
||||
RED.nodes.registerType("mongodb",MongoNode);
|
||||
|
||||
|
||||
function MongoOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.collection = n.collection;
|
||||
this.mongodb = n.mongodb;
|
||||
this.payonly = n.payonly || false;
|
||||
this.operation = n.operation;
|
||||
this.mongoConfig = RED.nodes.getNode(this.mongodb);
|
||||
|
||||
if (this.mongoConfig) {
|
||||
var node = this;
|
||||
this.clientDb = new mongo.Db(node.mongoConfig.db, new mongo.Server(node.mongoConfig.hostname, node.mongoConfig.port, {}), {w: 1});
|
||||
this.clientDb.open(function(err,cli) {
|
||||
if (err) { node.error(err); }
|
||||
else {
|
||||
node.clientDb.collection(node.collection,function(err,coll) {
|
||||
if (err) { node.error(err); }
|
||||
else {
|
||||
node.on("input",function(msg) {
|
||||
if (node.operation == "store") {
|
||||
delete msg._topic;
|
||||
if (node.payonly) {
|
||||
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
|
||||
coll.save(msg.payload,function(err,item){ if (err){node.error(err);} });
|
||||
}
|
||||
else coll.save(msg,function(err,item){if (err){node.error(err);}});
|
||||
}
|
||||
else if (node.operation == "insert") {
|
||||
delete msg._topic;
|
||||
if (node.payonly) {
|
||||
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
|
||||
coll.insert(msg.payload,function(err,item){ if (err){node.error(err);} });
|
||||
}
|
||||
else coll.insert(msg,function(err,item){if (err){node.error(err);}});
|
||||
}
|
||||
if (node.operation == "delete") {
|
||||
coll.remove(msg.payload, {w:1}, function(err, items){ if (err) node.error(err); });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.error("missing mongodb configuration");
|
||||
}
|
||||
|
||||
this.on("close", function() {
|
||||
if (this.clientDb) {
|
||||
this.clientDb.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("mongodb out",MongoOutNode);
|
||||
|
||||
|
||||
function MongoInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.collection = n.collection;
|
||||
this.mongodb = n.mongodb;
|
||||
this.mongoConfig = RED.nodes.getNode(this.mongodb);
|
||||
|
||||
if (this.mongoConfig) {
|
||||
var node = this;
|
||||
this.clientDb = new mongo.Db(node.mongoConfig.db, new mongo.Server(node.mongoConfig.hostname, node.mongoConfig.port, {}), {w: 1});
|
||||
this.clientDb.open(function(err,cli) {
|
||||
if (err) { node.error(err); }
|
||||
else {
|
||||
node.clientDb.collection(node.collection,function(err,coll) {
|
||||
if (err) { node.error(err); }
|
||||
else {
|
||||
node.on("input",function(msg) {
|
||||
msg.projection = msg.projection || {};
|
||||
coll.find(msg.payload,msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) {
|
||||
if (err) { node.error(err); }
|
||||
msg.payload = items;
|
||||
delete msg.projection;
|
||||
delete msg.sort;
|
||||
delete msg.limit;
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.error("missing mongodb configuration");
|
||||
}
|
||||
|
||||
this.on("close", function() {
|
||||
if (this.clientDb) {
|
||||
this.clientDb.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("mongodb in",MongoInNode);
|
Reference in New Issue
Block a user