diff --git a/hardware/BBB/icons/BBB.png b/hardware/BBB/icons/BBB.png index 0f228774..18c2ca9f 100644 Binary files a/hardware/BBB/icons/BBB.png and b/hardware/BBB/icons/BBB.png differ diff --git a/hardware/Pi/37-rpi-piface.js b/hardware/Pi/37-rpi-piface.js index f0e8fd66..17a1482f 100644 --- a/hardware/Pi/37-rpi-piface.js +++ b/hardware/Pi/37-rpi-piface.js @@ -19,14 +19,12 @@ 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('[37-rpi-piface.js] Error: Cannot find Wiring-Pi "gpio" command'); - } - // else not on a Pi so don't worry anyone with needless messages. - }); - return; +if (!fs.existsSync("/dev/ttyAMA0")) { // unlikely if not on a Pi + throw "Info : Ignoring Raspberry Pi specific node."; +} + +if (!fs.existsSync("/usr/local/bin/gpio")) { // gpio command not installed + throw "Info : Can't find Raspberry Pi wiringPi gpio command."; } // Map names of pins to Gordon's gpio PiFace pin numbers @@ -109,13 +107,16 @@ function PiFACEInNode(n) { } } }); - }, 250); + }, 200); } }); } else { node.error("Invalid PiFACE pin: "+node.pin); } + node.on("close", function() { + clearInterval(node._interval); + }); } function PiFACEOutNode(n) { @@ -141,21 +142,10 @@ function PiFACEOutNode(n) { } - exec("gpio load spi",function(err,stdout,stderr) { if (err) { util.log('[37-rpi-piface.js] Error: "gpio load spi" command failed for some reason.'); } - exec("gpio -p reset",function(err,stdout,stderr) { - if (err) { - util.log('[37-rpi-piface.js] Error: "gpio -p reset" command failed for some reason.'); - } - RED.nodes.registerType("rpi-piface in",PiFACEInNode); - RED.nodes.registerType("rpi-piface out",PiFACEOutNode); - PiFACEInNode.prototype.close = function() { - clearInterval(this._interval); - } - PiFACEOutNode.prototype.close = function() { - } - }); + RED.nodes.registerType("rpi-piface in",PiFACEInNode); + RED.nodes.registerType("rpi-piface out",PiFACEOutNode); }); diff --git a/hardware/Pi/38-rpi-pibrella.html b/hardware/Pi/38-rpi-pibrella.html index f949e8ab..ffbe3ac8 100644 --- a/hardware/Pi/38-rpi-pibrella.html +++ b/hardware/Pi/38-rpi-pibrella.html @@ -18,7 +18,7 @@
- + diff --git a/hardware/Pi/38-rpi-pibrella.js b/hardware/Pi/38-rpi-pibrella.js index 1a254f3e..ad2c3339 100644 --- a/hardware/Pi/38-rpi-pibrella.js +++ b/hardware/Pi/38-rpi-pibrella.js @@ -67,7 +67,7 @@ function PibrellaIn(n) { this.pin = pintable[n.pin]; var node = this; - if (this.pin) { + if (node.pin) { exec("gpio mode "+node.pin+" in", function(err,stdout,stderr) { if (err) node.error(err); else { @@ -90,11 +90,11 @@ function PibrellaIn(n) { }); } else { - this.error("Invalid GPIO pin: "+this.pin); + node.error("Invalid GPIO pin: "+node.pin); } - this.on("close", function() { - clearInterval(this._interval); + node.on("close", function() { + clearInterval(node._interval); }); } @@ -103,7 +103,7 @@ function PibrellaOut(n) { this.pin = pintable[n.pin]; var node = this; - if (this.pin == "1") { + if (node.pin == "1") { exec("gpio mode 1 pwm"); process.nextTick(function() { exec("gpio pwm-ms"); @@ -121,7 +121,7 @@ function PibrellaOut(n) { }); }); } - else if (this.pin) { + else if (node.pin) { process.nextTick(function() { exec("gpio mode "+node.pin+" out", function(err,stdout,stderr) { if (err) node.error(err); @@ -142,31 +142,31 @@ function PibrellaOut(n) { }); } else { - this.error("Invalid GPIO pin: "+this.pin); + node.error("Invalid GPIO pin: "+node.pin); } - this.on("close", function() { - exec("gpio mode "+this.pin+" in"); + node.on("close", function() { + exec("gpio mode "+node.pin+" in"); }); } -exec("gpio mode 0 out",function(err,stdout,stderr) { - if (err) { - util.log('[36-rpi-gpio.js] Error: "gpio" command failed for some reason.'); - } - exec("gpio mode 1 out"); - exec("gpio mode 2 out"); - exec("gpio mode 3 out"); - exec("gpio mode 4 out"); - exec("gpio mode 5 out"); - exec("gpio mode 6 out"); - exec("gpio mode 7 out"); - exec("gpio mode 10 in"); - exec("gpio mode 11 in"); - exec("gpio mode 12 in"); - exec("gpio mode 13 in"); - exec("gpio mode 14 in"); -}); +//exec("gpio mode 0 out",function(err,stdout,stderr) { + //if (err) { + //util.log('[36-rpi-gpio.js] Error: "gpio" command failed for some reason.'); + //} + //exec("gpio mode 1 out"); + //exec("gpio mode 2 out"); + //exec("gpio mode 3 out"); + //exec("gpio mode 4 out"); + //exec("gpio mode 5 out"); + //exec("gpio mode 6 out"); + //exec("gpio mode 7 out"); + //exec("gpio mode 10 in"); + //exec("gpio mode 11 in"); + //exec("gpio mode 12 in"); + //exec("gpio mode 13 in"); + //exec("gpio mode 14 in"); +//}); RED.nodes.registerType("rpi-pibrella in",PibrellaIn); RED.nodes.registerType("rpi-pibrella out",PibrellaOut); diff --git a/hardware/Pi/78-ledborg.html b/hardware/Pi/78-ledborg.html index 55d128fe..86ce75e4 100644 --- a/hardware/Pi/78-ledborg.html +++ b/hardware/Pi/78-ledborg.html @@ -27,7 +27,7 @@

See the PiBorg site for more information.

You can also now use a msg.payload in the standard hex format "#rrggbb". The clip levels are :

0x00 - 0x57 = off
0x58 - 0xA7 = 50%
0xA8 - 0xFF = fully on

-

You can also use the @cheerlight colour names - red, amber, green, blue, cyan, magenta, yeloow, orange, pink, purple, +

You can also use the @cheerlight colour names - red, amber, green, blue, cyan, magenta, yellow, orange, pink, purple, white, warmwhite, black

diff --git a/io/rawserial/26-rawserial.html b/io/rawserial/26-rawserial.html index c7b7c362..5bf3a7e3 100644 --- a/io/rawserial/26-rawserial.html +++ b/io/rawserial/26-rawserial.html @@ -16,17 +16,43 @@ diff --git a/io/rawserial/26-rawserial.js b/io/rawserial/26-rawserial.js index da53dfe8..0a991fed 100644 --- a/io/rawserial/26-rawserial.js +++ b/io/rawserial/26-rawserial.js @@ -29,36 +29,67 @@ if (!plat.match(/^win/)) { function RawSerialInNode(n) { RED.nodes.createNode(this,n); this.port = n.port; - this.split = n.split||null; - if (this.split == '\\n') this.split = "\n"; - if (this.split == '\\r') this.split = "\r"; + this.splitc = n.splitc||null; + this.out = n.out||"char"; + this.bin = n.bin||false; + if (this.splitc == '\\n') this.splitc = "\n"; + if (this.splitc == '\\r') this.splitc = "\r"; + if (!isNaN(parseInt(this.splitc))) { this.splitc = parseInt(this.splitc); } var node = this; var setupSerial = function() { node.inp = fs.createReadStream(pre+node.port); - node.log("opened "+pre+node.port); - node.inp.setEncoding('utf8'); + node.log("open "+pre+node.port); + node.tout = null; var line = ""; + var buf = new Buffer(32768); + var i = 0; node.inp.on('data', function (data) { - if (node.split != null) { - if (data == node.split) { - node.send({payload:line}); - line = ""; + for (var z = 0; z < data.length; z++) { + if ((node.out === "time") && (node.splitc != 0)) { + if (node.tout) { + i += 1; + buf[i] = data[z]; + } + else { + node.tout = setTimeout(function () { + node.tout = null; + var m = new Buffer(i+1); + buf.copy(m,0,0,i+1); + if (node.bin !== "true") { m = m.toString(); } + node.send({"payload": m}); + }, node.splitc); + i = 0; + buf[0] = data[z]; + } + } + else if ((node.out == "char") && (node.splitc != null)) { + buf[i] = data[z]; + i += 1; + if ((data[z] === node.splitc.charCodeAt(0)) || (i === 32768)) { + var m = new Buffer(i); + buf.copy(m,0,0,i); + if (node.bin !== "true") { m = m.toString(); } + node.send({"payload":m}); + i = 0; + } + } + else { + if (node.bin !== "true") { node.send({"payload": String.fromCharCode(data[z])}); } + else { node.send({"payload": new Buffer([data[z]])});} } - else { line += data; } } - else { node.send({payload:data}); } }); //node.inp.on('end', function (error) {console.log("End", error);}); node.inp.on('close', function (error) { - util.log("[rawserial] "+node.port+" closed"); + node.log(node.port+" closed"); node.tout = setTimeout(function() { setupSerial(); },settings.serialReconnectTime); }); node.inp.on('error', function(error) { - if (error.code == "ENOENT") { util.log("[rawserial] port "+node.port+" not found"); } - else { util.log("[rawserial] "+node.port+" error "+error); } + if (error.code == "ENOENT") { node.log(node.port+" not found"); } + else { node.log(node.port+" error "+error); } node.tout = setTimeout(function() { setupSerial(); },settings.serialReconnectTime); @@ -87,18 +118,18 @@ function RawSerialOutNode(n) { node.oup.write(msg.payload); } }); - node.oup.on('open', function (error) { util.log("[rawserial] opened "+node.port); }); - node.oup.on('end', function (error) { console.log("End",error); }); + node.oup.on('open', function (error) { node.log("opened "+node.port); }); + node.oup.on('end', function (error) { node.log("end :"+error); }); node.oup.on('close', function (error) { - util.log("[rawserial] "+node.port+" closed"); + node.log(node.port+" closed"); node.tout = setTimeout(function() { setupSerial(); },settings.serialReconnectTime); }); node.oup.on('error', function(error) { - if (error.code == "EACCES") { util.log("[rawserial] can't access port "+node.port); } - else if (error.code == "EIO") { util.log("[rawserial] can't write to port "+node.port); } - else { util.log("[rawserial] "+node.port+" error "+error); } + if (error.code == "EACCES") { node.log("can't access port "+node.port); } + else if (error.code == "EIO") { node.log("can't write to port "+node.port); } + else { node.log(node.port+" error "+error); } node.tout = setTimeout(function() { setupSerial(); },settings.serialReconnectTime); diff --git a/io/stomp/18-stomp.html b/io/stomp/18-stomp.html new file mode 100644 index 00000000..86ba6337 --- /dev/null +++ b/io/stomp/18-stomp.html @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + diff --git a/io/stomp/18-stomp.js b/io/stomp/18-stomp.js new file mode 100644 index 00000000..adbadb8e --- /dev/null +++ b/io/stomp/18-stomp.js @@ -0,0 +1,180 @@ +/** + * Copyright 2014 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. + **/ + +module.exports = function(RED) { + "use strict"; + var StompClient = require('stomp-client'); + var querystring = require('querystring'); + + function StompServerNode(n) { + RED.nodes.createNode(this,n); + this.server = n.server; + this.port = n.port; + this.name = n.name; + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.username = credentials.user; + this.password = credentials.password; + } + } + RED.nodes.registerType("stomp-server",StompServerNode); + + RED.httpAdmin.get('/stomp-server/:id',function(req,res) { + var credentials = RED.nodes.getCredentials(req.params.id); + if (credentials) { + res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")})); + } else { + res.send(JSON.stringify({})); + } + }); + + RED.httpAdmin.delete('/stomp-server/:id',function(req,res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); + }); + + RED.httpAdmin.post('/stomp-server/:id',function(req,res) { + var body = ""; + req.on('data', function(chunk) { + body+=chunk; + }); + req.on('end', function(){ + var newCreds = querystring.parse(body); + var credentials = RED.nodes.getCredentials(req.params.id)||{}; + if (newCreds.user == null || newCreds.user == "") { + delete credentials.user; + } else { + credentials.user = newCreds.user; + } + if (newCreds.password == "") { + delete credentials.password; + } else { + credentials.password = newCreds.password||credentials.password; + } + RED.nodes.addCredentials(req.params.id,credentials); + res.send(200); + }); + }); + + + function StompInNode(n) { + RED.nodes.createNode(this,n); + this.server = n.server; + this.topic = n.topic; + + this.serverConfig = RED.nodes.getNode(this.server); + this.host = this.serverConfig.server; + this.port = this.serverConfig.port; + this.userid = this.serverConfig.username; + this.password = this.serverConfig.password; + + var node = this; + var msg = {topic:this.topic}; + var closing = false; + + node.client = new StompClient(node.host, node.port, node.userid, node.password, '1.0'); + node.status({fill:"grey",shape:"ring",text:"connecting"}); + + var doConnect = function() { + node.client.connect(function(sessionId) { + node.status({fill:"green",shape:"dot",text:"connected"}); + node.log('subscribed to: '+node.topic); + node.client.subscribe(node.topic, function(body, headers) { + msg.payload = JSON.parse(body); + node.send(msg); + }); + }, function(error) { + node.status({fill:"grey",shape:"dot",text:"error"}); + node.warn(error); + }); + } + + node.client.on("disconnect", function() { + node.status({fill:"red",shape:"ring",text:"disconnected"}); + if (!closing) { + setTimeout( function () { doConnect(); }, 15000); + } + }); + + node.client.on("error", function(error) { + node.status({fill:"grey",shape:"dot",text:"error"}); + node.log(error); + }); + + doConnect(); + + node.on("close", function(done) { + closing = true; + if (node.client) { + node.client.on("disconnect", function() { + done(); + }); + //node.client.unsubscribe(node.topic); + node.client.disconnect(); + } else { done(); } + }); + } + RED.nodes.registerType("stomp in",StompInNode); + + + function StompOutNode(n) { + RED.nodes.createNode(this,n); + this.server = n.server; + this.topic = n.topic; + + this.serverConfig = RED.nodes.getNode(this.server); + this.host = this.serverConfig.server; + this.port = this.serverConfig.port; + this.userid = this.serverConfig.username; + this.password = this.serverConfig.password; + + var node = this; + var msg = {topic:this.topic}; + var closing = false; + + node.client = new StompClient(node.host, node.port, node.userid, node.password, '1.0'); + node.status({fill:"grey",shape:"ring",text:"connecting"}); + + node.client.connect( function(sessionId) { + node.status({fill:"green",shape:"dot",text:"connected"}); + }, function(error) { + node.status({fill:"grey",shape:"dot",text:"error"}); + node.warn(error); + }); + + node.client.on("disconnect", function() { + node.status({fill:"red",shape:"ring",text:"disconnected"}); + if (!closing) { + setTimeout( function () { node.client.connect(); }, 15000); + } + }); + + node.client.on("error", function(error) { + node.log(error); + }); + + node.on("input", function(msg) { + node.client.publish(node.topic || msg.topic, msg.payload); + }); + + node.on("close", function(done) { + closing = true; + if (client) { client.disconnect(); } + }); + } + RED.nodes.registerType("stomp out",StompOutNode); + +} diff --git a/social/music/69-mpd.html b/social/music/69-mpd.html index acfc07be..b06bd5e7 100644 --- a/social/music/69-mpd.html +++ b/social/music/69-mpd.html @@ -24,7 +24,7 @@ + + + + + + + + + + + + + + diff --git a/social/pusher/114-pusher.js b/social/pusher/114-pusher.js new file mode 100644 index 00000000..e9908df3 --- /dev/null +++ b/social/pusher/114-pusher.js @@ -0,0 +1,158 @@ +/** +* pusher.js +* Subscription module for the Pusher service (www.pusher.com) +* Requires 'pusher' and 'pusher-client' modules. +* +* Copyright 2014 Charalampos Doukas, @BuildingIoT +* +* 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 Pusher = require('pusher'); +var PusherClient = require('pusher-client'); + +// Require main module +var RED = require(process.env.NODE_RED_HOME+"/red/red"); + +//node for subscribing to an event/channel + function PusherNode(n) { + // Create a RED node + RED.nodes.createNode(this,n); + + var node = this; + var credentials = RED.nodes.getCredentials(n.id); + + if ((credentials) && (credentials.hasOwnProperty("pusherappkey_sub"))) { this.appkey = credentials.pusherappkey_sub; } + else { this.error("No Pusher app key set for input node"); } + + //get parameters from user + this.channel = n.channel; + this.eventname = n.eventname; + + //create a subscription to the channel and event defined by user + var socket = new PusherClient(''+this.appkey); + var my_channel = socket.subscribe(''+this.channel); + socket.bind(''+this.eventname, + function(data) { + var msg = {}; + if (data.hasOwnProperty("payload")) { msg.payload = data.payload; } + else { msg.payload = data; } + node.send(msg); + } + ); + + this.on("close", function() { + socket.disconnect(); + }); +} + +//Node for sending Pusher events +function PusherNodeSend(n) { + // Create a RED node + RED.nodes.createNode(this,n); + + var node = this; + + var credentials = RED.nodes.getCredentials(n.id); + + if ((credentials) && (credentials.hasOwnProperty("pusherappid"))) { this.appid = credentials.pusherappid; } + else { this.error("No Pusher api token set"); } + if ((credentials) && (credentials.hasOwnProperty("pusherappsecret"))) { this.appsecret = credentials.pusherappsecret; } + else { this.error("No Pusher user secret set"); } + if ((credentials) && (credentials.hasOwnProperty("pusherappkey"))) { this.appkey = credentials.pusherappkey; } + else { this.error("No Pusher user key set"); } + + //get parameters from user + this.channel = n.channel; + this.eventname = n.eventname; + + var pusher = new Pusher({ + appId: this.appid, + key: this.appkey, + secret: this.appsecret + }); + + this.on("input", function(msg){ + pusher.trigger(this.channel, this.eventname, { + "payload": msg.payload + }); + }); + + this.on("close", function() { + }); + } + + //debugging on the output: +var displayResult = function(result) { + node.log(result); +}; + +var displayError = function(err) { + node.log("Error: "+err); +}; + +RED.nodes.registerType("pusher in",PusherNode); +RED.nodes.registerType("pusher out",PusherNodeSend); + +var querystring = require('querystring'); + +RED.httpAdmin.get('/pusher/:id',function(req,res) { + var credentials = RED.nodes.getCredentials(req.params.id); + if (credentials) { + res.send(JSON.stringify({pusherappid:credentials.pusherappid,pusherappsecret:credentials.pusherappsecret, pusherappkey:credentials.pusherappkey, pusherappkey_sub:credentials.pusherappkey_sub})); + } else { + res.send(JSON.stringify({})); + } +}); + +RED.httpAdmin.delete('/pusher/:id',function(req,res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.httpAdmin.post('/pusher/:id',function(req,res) { + var body = ""; + req.on('data', function(chunk) { + body+=chunk; + }); + req.on('end', function(){ + var newCreds = querystring.parse(body); + var credentials = RED.nodes.getCredentials(req.params.id)||{}; + + if (newCreds.pusherappid == null || newCreds.pusherappid == "") { + delete credentials.pusherappid; + } else { + credentials.pusherappid = newCreds.pusherappid; + } + if (newCreds.pusherappkey == "") { + delete credentials.pusherappkey; + } else { + credentials.pusherappkey = newCreds.pusherappkey||credentials.pusherappkey; + } + + if (newCreds.pusherappsecret == "") { + delete credentials.pusherappsecret; + } else { + credentials.pusherappsecret = newCreds.pusherappsecret||credentials.pusherappsecret; + } + + if (newCreds.pusherappkey_sub == "") { + delete credentials.pusherappkey_sub; + } else { + credentials.pusherappkey_sub = newCreds.pusherappkey_sub||credentials.pusherappkey_sub; + } + + RED.nodes.addCredentials(req.params.id,credentials); + res.send(200); + }); +}); diff --git a/social/pusher/icons/pusher.png b/social/pusher/icons/pusher.png new file mode 100644 index 00000000..04bc1635 Binary files /dev/null and b/social/pusher/icons/pusher.png differ diff --git a/social/twilio/icons/twilio.png b/social/twilio/icons/twilio.png index ada41a2c..f8f91a59 100644 Binary files a/social/twilio/icons/twilio.png and b/social/twilio/icons/twilio.png differ diff --git a/social/xmpp/92-xmpp.html b/social/xmpp/92-xmpp.html index 92180fb4..0c0bb387 100644 --- a/social/xmpp/92-xmpp.html +++ b/social/xmpp/92-xmpp.html @@ -1,5 +1,5 @@ - + + + + + + - @@ -84,6 +128,10 @@
+
+ + +
@@ -92,6 +140,7 @@
+
Note: Using credentials from global xmppkey.js file.