diff --git a/99-sample.html.demo b/99-sample.html.demo
new file mode 100644
index 00000000..e26197aa
--- /dev/null
+++ b/99-sample.html.demo
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/99-sample.js.demo b/99-sample.js.demo
new file mode 100644
index 00000000..c591185a
--- /dev/null
+++ b/99-sample.js.demo
@@ -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.
+ **/
+
+// If you use this as a template, replace IBM Corp. with your own name.
+
+// Sample Node-RED node file
+
+// Require main module
+var RED = require(process.env.NODE_RED_HOME+"/red/red");
+
+// The main node definition - most things happen in here
+function SampleNode(n) {
+ // Create a RED node
+ RED.nodes.createNode(this,n);
+
+ // Store local copies of the node configuration (as defined in the .html)
+ this.topic = n.topic;
+
+ // Do whatever you need to do in here - declare callbacks etc
+ // Note: this sample doesn't do anything much - it will only send
+ // this message once at startup...
+ // Look at other real nodes for some better ideas of what to do....
+ var msg = {};
+ msg.topic = this.topic;
+ msg.payload = "Hello world !"
+
+ // send out the message to the rest of the workspace.
+ this.send(msg);
+
+ this.on("close", function() {
+ // Called when the node is shutdown - eg on redeploy.
+ // Allows ports to be closed, connections dropped etc.
+ // eg: this.client.disconnect();
+ });
+}
+
+// Register the node by name. This must be called before overriding any of the
+// Node functions.
+RED.nodes.registerType("sample",SampleNode);
diff --git a/README.md b/README.md
index 28c37f0c..5c150f4c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Node-RED Nodes
-A collection of nodes for [Node-RED](http://nodered.org).
+A collection of nodes for [Node-RED](http://nodered.org). See below for a list.
## Installation
@@ -27,9 +27,9 @@ The key points are:
### Contributor License Agreement
In order for us to accept pull-requests, the contributor must first complete
-a Contributor License Agreement (CLA). This clarifies the intellectual
-property license granted with any contribution. It is for your protection as a
-Contributor as well as the protection of IBM and its customers; it does not
+a Contributor License Agreement (CLA). This clarifies the intellectual
+property license granted with any contribution. It is for your protection as a
+Contributor as well as the protection of IBM and its customers; it does not
change your rights to use your own Contributions for any other purpose.
Once you have created a pull-request, we'll provide a link to the appropriate
@@ -42,3 +42,64 @@ slightly different.
## Copyright and license
Copyright 2013 IBM Corp. under [the Apache 2.0 license](LICENSE).
+
+# Extra Node Information
+
+### Analysis
+
+**72-wordpos** - Analyses the payload and classifies the part-of-speech of each word. The resulting message has msg.pos added with the results. A word may appear in multiple categories (eg, 'great' is both a noun and an adjective).
+
+**74-swearfilter** - Analyses the payload and tries to filter out any messages containing bad swear words. This only operates on payloads of type string. Everything else is blocked.
+
+### Hardware
+
+**37-rpi-piface** - Adds support for the PiFace interface module for Raspberry Pi.
+
+**78-ledborg** - A simple driver for the LEDborg plug on module for Raspberry Pi.
+
+**60-wemo** - Basic node to drive a WeMo socket and switch. Does not use discovery.
+
+**76-blinkstick** - Provides support for the BlinkStick USB LED device.
+
+**77-blink1** - Provides support for the Blink1 USB LED from ThingM.
+
+**78-digiRGB** - Provides support for the DigiSpark RGB USB LED.
+
+**79-sensorTag** - Reads data from the Ti BLE SensorTag device.
+
+**101-scanBLE** - Scans for a particular Bluetooth Low Energy (BLE) device.
+
+### IO
+
+**26-rawserial** - Only really needed for Windows boxes without serialport npm module installed.
+Uses a simple read of the serial port as a file to input data. You **must** set the baud rate etc externally *before* starting Node-RED. This node does not implement pooling of connections so only one instance of each port may be used - so in **or** out but **not** both.
+
+**39-wol** - Sends a Wake-On-LAN magic packet to the mac address specified. You may instead set msg.mac to dynamically set the target device mac to wake up.
+
+**88-ping** - Pings a machine and returns the trip time in mS. Returns false if no response received within 3 seconds, or if the host is unresolveable. Default ping is every 20 seconds but can be configured.
+
+### Social
+
+**69-mpd** - MPD music control nodes. Output node expects payload to be a valid mpc command. Currently only simple commands that expect no reply are supported. Input node creates a payload object with Artist, Album, Title, Genre and Date.
+
+**57-notify** - Uses Growl to provide a desktop popup containing the payload. Only useful on the local machine.
+
+**57-prowl** - Uses Prowl to push the payload to an Apple device that has the Prowl app installed.
+
+**57-pushbullet** - Uses PushBullet to push the payload to an Android device that has the PushBullet app installed.
+
+**92-xmpp** - Connects to an XMPP server to send and receive messages.
+
+### Storage
+
+**67-leveldb** - Uses LevelDB for a simple key value pair database.
+
+**68-mysql** - Allows basic access to a MySQL database. This node uses the **query** operation against the configured database. This does allow both INSERTS and DELETES. By it's very nature it allows SQL injection... *so be careful out there...*
+
+### Time
+
+**79-suncalc** - Uses the suncalc module to generate an output at sunrise and sunset based on a specified location. Several choices of definition of sunrise and sunset are available,
+
+### Misc
+
+**99-sample** - A sample node with more comments than most to try to help you get started without any other docs...
diff --git a/analysis/swearfilter/74-swearfilter.html b/analysis/swearfilter/74-swearfilter.html
new file mode 100644
index 00000000..34379f9b
--- /dev/null
+++ b/analysis/swearfilter/74-swearfilter.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
diff --git a/analysis/swearfilter/74-swearfilter.js b/analysis/swearfilter/74-swearfilter.js
new file mode 100644
index 00000000..135c9455
--- /dev/null
+++ b/analysis/swearfilter/74-swearfilter.js
@@ -0,0 +1,29 @@
+/**
+ * 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 badwordsRegExp = require('badwords/regexp');
+
+function BadwordsNode(n) {
+ RED.nodes.createNode(this,n);
+ var node = this;
+ this.on("input", function(msg) {
+ if (typeof msg.payload === "string") {
+ if ( !badwordsRegExp.test(msg.payload) ) { node.send(msg); }
+ }
+ });
+}
+RED.nodes.registerType("badwords",BadwordsNode);
diff --git a/analysis/wordpos/72-wordpos.html b/analysis/wordpos/72-wordpos.html
new file mode 100644
index 00000000..6b098990
--- /dev/null
+++ b/analysis/wordpos/72-wordpos.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
diff --git a/analysis/wordpos/72-wordpos.js b/analysis/wordpos/72-wordpos.js
new file mode 100644
index 00000000..6f472781
--- /dev/null
+++ b/analysis/wordpos/72-wordpos.js
@@ -0,0 +1,31 @@
+/**
+ * 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 WordPos = require('wordpos');
+var wordpos = new WordPos();
+
+function WordPOSNode(n) {
+ RED.nodes.createNode(this,n);
+ this.on("input", function(msg) {
+ var node = this;
+ wordpos.getPOS(msg.payload, function (result) {
+ msg.pos = result;
+ node.send(msg);
+ });
+ });
+}
+RED.nodes.registerType("wordpos",WordPOSNode);
diff --git a/hardware/Pi/37-rpi-piface.html b/hardware/Pi/37-rpi-piface.html
index 3e3ac043..36e91117 100644
--- a/hardware/Pi/37-rpi-piface.html
+++ b/hardware/Pi/37-rpi-piface.html
@@ -52,10 +52,10 @@
+
+
+
+
diff --git a/hardware/blink/76-blinkstick.js b/hardware/blink/76-blinkstick.js
new file mode 100644
index 00000000..ebbdacc7
--- /dev/null
+++ b/hardware/blink/76-blinkstick.js
@@ -0,0 +1,62 @@
+/**
+ * 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 blinkstick = require("blinkstick");
+
+Object.size = function(obj) {
+ var size = 0, key;
+ for (key in obj) { if (obj.hasOwnProperty(key)) size++; }
+ return size;
+};
+
+function BlinkStick(n) {
+ RED.nodes.createNode(this,n);
+ var p1 = /^\#[A-Fa-f0-9]{6}$/
+ var p2 = /[0-9]+,[0-9]+,[0-9]+/
+ this.led = blinkstick.findFirst(); // maybe try findAll() (one day)
+ var node = this;
+
+ this.on("input", function(msg) {
+ if (msg != null) {
+ if (Object.size(node.led) !== 0) {
+ try {
+ if (p2.test(msg.payload)) {
+ var rgb = msg.payload.split(",");
+ node.led.setColor(parseInt(rgb[0])&255, parseInt(rgb[1])&255, parseInt(rgb[2])&255);
+ }
+ else {
+ node.led.setColor(msg.payload.toLowerCase().replace(/\s+/g,''));
+ }
+ }
+ catch (err) {
+ node.warn("BlinkStick missing ?");
+ node.led = blinkstick.findFirst();
+ }
+ }
+ else {
+ //node.warn("No BlinkStick found");
+ node.led = blinkstick.findFirst();
+ }
+ }
+ });
+ if (Object.size(node.led) === 0) {
+ node.error("No BlinkStick found");
+ }
+
+}
+
+RED.nodes.registerType("blinkstick",BlinkStick);
diff --git a/hardware/blink/77-blink1.html b/hardware/blink/77-blink1.html
new file mode 100644
index 00000000..25ebf6b9
--- /dev/null
+++ b/hardware/blink/77-blink1.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
diff --git a/hardware/blink/77-blink1.js b/hardware/blink/77-blink1.js
new file mode 100644
index 00000000..580e1060
--- /dev/null
+++ b/hardware/blink/77-blink1.js
@@ -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.
+ **/
+
+var RED = require(process.env.NODE_RED_HOME+"/red/red");
+var Blink1 = require("node-blink1");
+
+function Blink1Node(n) {
+ RED.nodes.createNode(this,n);
+ this.fade = n.fade||0;
+ var node = this;
+
+ try {
+ var p1 = /^\#[A-Fa-f0-9]{6}$/
+ var p2 = /[0-9]+,[0-9]+,[0-9]+/
+ this.on("input", function(msg) {
+ if (blink1) {
+ if (p1.test(msg.payload)) {
+ // if it is a hex colour string
+ var r = parseInt(msg.payload.slice(1,3),16);
+ var g = parseInt(msg.payload.slice(3,5),16);
+ var b = parseInt(msg.payload.slice(5),16);
+ if (node.fade == 0) { blink1.setRGB( r, g, b ); }
+ else { blink1.fadeToRGB(node.fade, r, g, b ); }
+ }
+ else if (p2.test(msg.payload)) {
+ // if it is a r,g,b triple
+ var rgb = msg.payload.split(',');
+ if (node.fade == 0) { blink1.setRGB(parseInt(rgb[0])&255, parseInt(rgb[1])&255, parseInt(rgb[2])&255); }
+ else { blink1.fadeToRGB(node.fade, parseInt(rgb[0])&255, parseInt(rgb[1])&255, parseInt(rgb[2])&255); }
+ }
+ else {
+ // you can add fancy colours by name here if you want...
+ node.warn("Blink1 : invalid msg : "+msg.payload);
+ }
+ }
+ else {
+ node.warn("No Blink1 found");
+ }
+ });
+ var blink1 = new Blink1.Blink1();
+ }
+ catch(e) {
+ node.error("No Blink1 found");
+ }
+}
+RED.nodes.registerType("blink1",Blink1Node);
diff --git a/hardware/digiRGB/78-digiRGB.html b/hardware/digiRGB/78-digiRGB.html
index a8f0b309..bbb2a128 100644
--- a/hardware/digiRGB/78-digiRGB.html
+++ b/hardware/digiRGB/78-digiRGB.html
@@ -14,55 +14,34 @@
limitations under the License.
-->
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/hardware/wemo/60-wemo.js b/hardware/wemo/60-wemo.js
new file mode 100644
index 00000000..34391dee
--- /dev/null
+++ b/hardware/wemo/60-wemo.js
@@ -0,0 +1,60 @@
+/**
+ * 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 WeMo = new require('wemo');
+
+function WeMoOut(n) {
+ RED.nodes.createNode(this,n);
+ this.ipaddr = n.ipaddr;
+ this.wemoSwitch = new WeMo(n.ipaddr);
+ var node = this;
+
+ this.on("input", function(msg) {
+ if (msg != null) {
+ var state = 0;
+ if ( msg.payload == 1 || msg.payload == true || msg.payload == "on" ) { var state = 1; }
+ node.wemoSwitch.setBinaryState(state, function(err, result) {
+ if (err) node.warn(err);
+ //else { node.log(result); }
+ });
+ }
+ });
+}
+RED.nodes.registerType("wemo out",WeMoOut);
+
+function WeMoIn(n) {
+ RED.nodes.createNode(this,n);
+ this.ipaddr = n.ipaddr;
+ this.wemoSwitch = new WeMo(n.ipaddr);
+ this.wemoSwitch.state = 0;
+ var node = this;
+
+ var tick = setInterval(function() {
+ wemoSwitch.getBinaryState(function(err, result) {
+ if (err) node.warn(err);
+ if (parseInt(result) != wemoSwitch.state) {
+ wemoSwitch.state = parseInt(result);
+ node.send({payload:wemoSwitch.state,topic:"wemo/"+node.ipaddr});
+ }
+ });
+ }, 2000);
+
+ this.on("close", function() {
+ clearInterval(tick);
+ });
+}
+RED.nodes.registerType("wemo in",WeMoOut);
diff --git a/io/ping/88-ping.html b/io/ping/88-ping.html
index 051a9ab8..f171c2c5 100644
--- a/io/ping/88-ping.html
+++ b/io/ping/88-ping.html
@@ -15,18 +15,18 @@
-->
diff --git a/io/ping/88-ping.js b/io/ping/88-ping.js
index be6740a6..301aea4c 100644
--- a/io/ping/88-ping.js
+++ b/io/ping/88-ping.js
@@ -13,45 +13,43 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
-var RED = require("../../red/red");
+
+var RED = require(process.env.NODE_RED_HOME+"/red/red");
var spawn = require('child_process').spawn;
var plat = require('os').platform();
function PingNode(n) {
- RED.nodes.createNode(this,n);
- this.host = n.host;
- this.timer = n.timer * 1000;
- var node = this;
+ RED.nodes.createNode(this,n);
+ this.host = n.host;
+ this.timer = n.timer * 1000;
+ var node = this;
- node.tout = setInterval(function() {
- var ex;
- if (plat == "linux") ex = spawn('ping', ['-n', '-w 5', '-c 1', node.host]);
- else if (plat.match(/^win/)) ex = spawn('ping', ['-n 1', '-w 5000', node.host]);
- else if (plat == "darwin") ex = spawn('ping', ['-n', '-t 5', '-c 1', node.host]);
- else node.error("Sorry - your platform - "+plat+" - is not recognised.");
- var res="";
+ node.tout = setInterval(function() {
+ var ex;
+ if (plat == "linux") ex = spawn('ping', ['-n', '-w 5', '-c 1', node.host]);
+ else if (plat.match(/^win/)) ex = spawn('ping', ['-n 1', '-w 5000', node.host]);
+ else if (plat == "darwin") ex = spawn('ping', ['-n', '-t 5', '-c 1', node.host]);
+ else node.error("Sorry - your platform - "+plat+" - is not recognised.");
+ var res="";
+ ex.stdout.on('data', function (data) {
+ //console.log('[ping] stdout: ' + data.toString());
+ var regex = /time=(.*)ms/;
+ var m = regex.exec(data.toString())||[""];
+ res = Number(m[1]);
+ });
+ ex.stderr.on('data', function (data) {
+ //console.log('[ping] stderr: ' + data);
+ });
+ ex.on('close', function (code) {
+ //console.log('[ping] result: ' + code);
+ var msg = { payload: false, topic:node.host };
+ if (code == 0) msg = { payload: res, topic:node.host };
+ node.send(msg);
+ });
+ }, node.timer);
- ex.stdout.on('data', function (data) {
- //console.log('[ping] stdout: ' + data.toString());
- var regex = /time=(.*)ms/;
- var m = regex.exec(data.toString())||[""];
- res = Number(m[1]);
- });
- ex.stderr.on('data', function (data) {
- //console.log('[ping] stderr: ' + data);
- });
- ex.on('close', function (code) {
- //console.log('[ping] result: ' + code);
- var msg = { payload: false, topic:node.host };
- if (code == 0) msg = { payload: res, topic:node.host };
- node.send(msg);
- });
-
- }, node.timer);
+ this.on("close", function() {
+ clearInterval(this.tout);
+ });
}
-
RED.nodes.registerType("ping",PingNode);
-
-PingNode.prototype.close = function() {
- clearInterval(this.tout);
-}
diff --git a/io/rawserial/26-rawserial.html b/io/rawserial/26-rawserial.html
new file mode 100644
index 00000000..c7b7c362
--- /dev/null
+++ b/io/rawserial/26-rawserial.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/io/rawserial/26-rawserial.js b/io/rawserial/26-rawserial.js
new file mode 100644
index 00000000..6fcefc2d
--- /dev/null
+++ b/io/rawserial/26-rawserial.js
@@ -0,0 +1,112 @@
+/**
+ * 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 util = require("util");
+var fs = require('fs');
+var plat = require('os').platform();
+var pre = "\\\\.\\";
+
+if (! plat.match(/^win/)) {
+ util.log("[26-rawserial.js] Advise: Only really needed for Windows boxes without serialport npm module installed.");
+ pre = "";
+}
+
+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";
+ var node = this;
+
+ var setupSerial = function() {
+ node.inp = fs.createReadStream(pre+node.port);
+ node.inp.setEncoding('utf8');
+ var line = "";
+ node.inp.on('data', function (data) {
+ if (node.split != null) {
+ if (data == node.split) {
+ node.send({payload:line});
+ line = "";
+ }
+ 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.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); }
+ node.tout = setTimeout(function() {
+ setupSerial();
+ },settings.serialReconnectTime);
+ });
+ }
+ setupSerial();
+
+ node.on('close', function() {
+ if (node.tout) { clearTimeout(node.tout); }
+ if (node.inp) { node.inp.pause(); }
+ });
+
+}
+RED.nodes.registerType("rawserial in",RawSerialInNode);
+
+
+function RawSerialOutNode(n) {
+ RED.nodes.createNode(this,n);
+ this.port = n.port;
+ var node = this;
+
+ var setupSerial = function() {
+ node.oup = fs.createWriteStream(pre+node.port,{ flags:'w', encoding:'utf8', mode:0666 });
+ node.on("input", function(msg) {
+ if (msg.payload != null) {
+ 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('close', function (error) {
+ util.log("[rawserial] "+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); }
+ node.tout = setTimeout(function() {
+ setupSerial();
+ },settings.serialReconnectTime);
+ });
+ }
+ setupSerial();
+
+ node.on('close', function() {
+ if (node.tout) { clearTimeout(node.tout); }
+ });
+}
+RED.nodes.registerType("rawserial out",RawSerialOutNode);
diff --git a/io/wol/39-wol.html b/io/wol/39-wol.html
new file mode 100644
index 00000000..c2d051d9
--- /dev/null
+++ b/io/wol/39-wol.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
diff --git a/io/wol/39-wol.js b/io/wol/39-wol.js
new file mode 100644
index 00000000..497474fc
--- /dev/null
+++ b/io/wol/39-wol.js
@@ -0,0 +1,41 @@
+/**
+ * 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 wol = require('wake_on_lan');
+var chk = /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/;
+
+function WOLnode(n) {
+ RED.nodes.createNode(this,n);
+ this.mac = n.mac
+ var node = this;
+
+ this.on("input", function(msg) {
+ if (msg != null) {
+ var mac = this.mac || msg.mac || null;
+ if (mac != null) {
+ if (chk.test(mac)) {
+ wol.wake(mac, function(error) {
+ if (error) { node.warn(error); }
+ });
+ }
+ else { node.warn("WOL: bad mac address "+mac); }
+ }
+ else { node.warn("WOL: no mac address specified"); }
+ }
+ });
+}
+RED.nodes.registerType("wake on lan",WOLnode);
diff --git a/io/wol/icons/onoff.png b/io/wol/icons/onoff.png
new file mode 100644
index 00000000..ba3d9cb9
Binary files /dev/null and b/io/wol/icons/onoff.png differ
diff --git a/social/music/69-mpd.html b/social/music/69-mpd.html
new file mode 100644
index 00000000..acfc07be
--- /dev/null
+++ b/social/music/69-mpd.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/social/music/69-mpd.js b/social/music/69-mpd.js
new file mode 100644
index 00000000..298d4cf4
--- /dev/null
+++ b/social/music/69-mpd.js
@@ -0,0 +1,84 @@
+/**
+ * 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 komponist = require('komponist');
+
+var mpc = "";
+komponist.createConnection(6600, 'localhost', function(err, client) {
+ if (err) node.error("MPD: Failed to connect to MPD server");
+ mpc = client;
+});
+
+function MPDOut(n) {
+ RED.nodes.createNode(this,n);
+ var node = this;
+ node.mpc = mpc;
+
+ this.on("input", function(msg) {
+ if (msg != null) {
+ console.log(msg);
+ try {
+ //node.mpc.command(msg.payload);
+ node.mpc.command(msg.payload, msg.param, function(err, results) {
+ if (err) { console.log("MPD: Error:",err); }
+ //else { console.log(results); }
+ });
+ } catch (err) { console.log("MPD: Error:",err); }
+ }
+ });
+
+ node.mpc.on('error', function(err) {
+ console.log("MPD: Error:",err);
+ });
+}
+RED.nodes.registerType("mpd out",MPDOut);
+
+function MPDIn(n) {
+ RED.nodes.createNode(this,n);
+ var node = this;
+ node.mpc = mpc;
+ var oldMsg = "";
+
+ getSong();
+
+ function getSong() {
+ node.mpc.currentsong(function(err, info) {
+ if (err) console.log(err);
+ else {
+ var msg = {payload:{},topic:"music"};
+ msg.payload.Artist = info.Artist;
+ msg.payload.Album = info.Album;
+ msg.payload.Title = info.Title;
+ msg.payload.Genre = info.Genre;
+ msg.payload.Date = info.Date;
+ if (JSON.stringify(msg) != oldMsg) {
+ node.send(msg);
+ oldMsg = JSON.stringify(msg);
+ }
+ }
+ });
+ }
+
+ node.mpc.on('changed', function(system) {
+ getSong();
+ });
+
+ this.on("close", function() {
+ // node.mpc.command("stop");
+ });
+}
+RED.nodes.registerType("mpd in",MPDIn);
diff --git a/social/music/icons/music.png b/social/music/icons/music.png
new file mode 100644
index 00000000..4e99a1bf
Binary files /dev/null and b/social/music/icons/music.png differ
diff --git a/social/notify/57-notify.html b/social/notify/57-notify.html
new file mode 100644
index 00000000..67c04cbf
--- /dev/null
+++ b/social/notify/57-notify.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
diff --git a/social/notify/57-notify.js b/social/notify/57-notify.js
new file mode 100644
index 00000000..db4b2e20
--- /dev/null
+++ b/social/notify/57-notify.js
@@ -0,0 +1,39 @@
+/**
+ * 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 growl = require('growl');
+var imagefile = process.env.NODE_RED_HOME+"/public/mqtt-node-red.png";
+
+function NotifyNode(n) {
+ RED.nodes.createNode(this,n);
+ this.title = n.title;
+ var node = this;
+ this.on("input",function(msg) {
+ var titl = this.title||msg.topic;
+ if (typeof(msg.payload) == 'object') {
+ msg.payload = JSON.stringify(msg.payload);
+ }
+ if (typeof(titl) != 'undefined') {
+ growl(msg.payload, { title: titl, image: imagefile });
+ }
+ else {
+ growl(msg.payload, { image: imagefile });
+ }
+ });
+}
+
+RED.nodes.registerType("notify",NotifyNode);
diff --git a/social/prowl/57-prowl.html b/social/prowl/57-prowl.html
new file mode 100644
index 00000000..6a897f79
--- /dev/null
+++ b/social/prowl/57-prowl.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
diff --git a/social/prowl/57-prowl.js b/social/prowl/57-prowl.js
new file mode 100644
index 00000000..df07759e
--- /dev/null
+++ b/social/prowl/57-prowl.js
@@ -0,0 +1,67 @@
+/**
+ * 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 Prowl = require('node-prowl');
+var util = require('util');
+
+// Either add a line like this to settings.js
+// prowl: {prowlkey:'My-API-KEY'},
+// or create pushkey.js in dir ABOVE node-red, it just needs to be like
+// module.exports = {prowlkey:'My-API-KEY'}
+
+try {
+ var pushkey = require(process.env.NODE_RED_HOME+"/settings").prowl || require(process.env.NODE_RED_HOME+"/../pushkey.js");
+}
+catch(err) {
+ util.log("[57-prowl.js] Error: Failed to load Prowl credentials");
+}
+
+if (pushkey) {
+ var prowl = new Prowl(pushkey.prowlkey);
+}
+
+function ProwlNode(n) {
+ RED.nodes.createNode(this,n);
+ this.title = n.title;
+ this.priority = parseInt(n.priority);
+ if (this.priority > 2) this.priority = 2;
+ if (this.priority < -2) this.priority = -2;
+ var node = this;
+ this.on("input",function(msg) {
+ var titl = this.title||msg.topic||"Node-RED";
+ var pri = msg.priority||this.priority;
+ if (typeof(msg.payload) == 'object') {
+ msg.payload = JSON.stringify(msg.payload);
+ }
+ if (pushkey) {
+ try {
+ prowl.push(msg.payload, titl, { priority: pri }, function(err, remaining) {
+ if (err) node.error(err);
+ node.log( remaining + ' calls to Prowl api during current hour.' );
+ });
+ }
+ catch (err) {
+ node.error(err);
+ }
+ }
+ else {
+ node.warn("Prowl credentials not set/found. See node info.");
+ }
+ });
+}
+
+RED.nodes.registerType("prowl",ProwlNode);
diff --git a/social/prowl/icons/prowl.png b/social/prowl/icons/prowl.png
new file mode 100644
index 00000000..43f32253
Binary files /dev/null and b/social/prowl/icons/prowl.png differ
diff --git a/social/pushbullet/57-pushbullet.html b/social/pushbullet/57-pushbullet.html
new file mode 100644
index 00000000..32020297
--- /dev/null
+++ b/social/pushbullet/57-pushbullet.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
diff --git a/social/pushbullet/57-pushbullet.js b/social/pushbullet/57-pushbullet.js
new file mode 100644
index 00000000..fa39d94b
--- /dev/null
+++ b/social/pushbullet/57-pushbullet.js
@@ -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 PushBullet = require('pushbullet');
+var util = require('util');
+
+// Either add a line like this to settings.js
+// pushbullet: {pushbullet:'My-API-KEY', deviceid:'12345'},
+// or create pushkey.js in dir ABOVE node-red, it just needs to be like
+// module.exports = {pushbullet:'My-API-KEY', deviceid:'12345'}
+
+try {
+ var pushkey = RED.settings.pushbullet || require(process.env.NODE_RED_HOME+"/../pushkey.js");
+}
+catch(err) {
+ util.log("[57-pushbullet.js] Error: Failed to load PushBullet credentials");
+}
+
+if (pushkey) {
+ var pusher = new PushBullet(pushkey.pushbullet);
+ var deviceId = pushkey.deviceid;
+}
+
+function PushbulletNode(n) {
+ RED.nodes.createNode(this,n);
+ this.title = n.title;
+ var node = this;
+ this.on("input",function(msg) {
+ var titl = this.title||msg.topic||"Node-RED";
+ if (typeof(msg.payload) == 'object') {
+ msg.payload = JSON.stringify(msg.payload);
+ }
+ if (pushkey) {
+ try {
+ pusher.note(deviceId, titl, msg.payload, function(err, response) {
+ if (err) node.error(err);
+ console.log(response);
+ });
+ }
+ catch (err) {
+ node.error(err);
+ }
+ }
+ else {
+ node.warn("Pushbullet credentials not set/found. See node info.");
+ }
+ });
+}
+
+RED.nodes.registerType("pushbullet",PushbulletNode);
diff --git a/social/pushbullet/icons/bullet.png b/social/pushbullet/icons/bullet.png
new file mode 100644
index 00000000..3cf11b3f
Binary files /dev/null and b/social/pushbullet/icons/bullet.png differ
diff --git a/social/twilio/56-twilio.html b/social/twilio/56-twilio.html
new file mode 100644
index 00000000..21badcb7
--- /dev/null
+++ b/social/twilio/56-twilio.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
diff --git a/social/twilio/56-twilio.js b/social/twilio/56-twilio.js
new file mode 100644
index 00000000..6f301f71
--- /dev/null
+++ b/social/twilio/56-twilio.js
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2013 Andrew D Lindsay @AndrewDLindsay
+ * http://blog.thiseldo.co.uk
+ *
+ * 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');
+
+// Either add a line like this to settings.js
+// twilio: { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN',from:'FROM-NUMBER' },
+// Or as a twiliokey.js file in the directory ABOVE node-red.
+// module.exports = { account:'My-ACCOUNT-SID', authtoken:'TWILIO-TOKEN',from:'FROM-NUMBER' }
+
+try {
+ var twiliokey = RED.settings.twilio || require(process.env.NODE_RED_HOME+"/../twiliokey.js");
+}
+catch(err) {
+ util.log("[56-twilio.js] Error: Failed to load Twilio credentials");
+}
+
+if (twiliokey) {
+ var twilioClient = require('twilio')(twiliokey.account, twiliokey.authtoken);
+ var fromNumber = twiliokey.from;
+}
+
+function TwilioOutNode(n) {
+ RED.nodes.createNode(this,n);
+ this.title = n.title;
+ var node = this;
+ this.on("input",function(msg) {
+ if (typeof(msg.payload) == 'object') {
+ msg.payload = JSON.stringify(msg.payload);
+ }
+ if (twiliokey) {
+ try {
+ // Send SMS
+ twilioClient.sendMessage( {to: msg.topic, from: fromNumber, body: msg.payload}, function(err, response) {
+ if (err) node.error(err);
+ //console.log(response);
+ });
+ }
+ catch (err) {
+ node.error(err);
+ }
+ }
+ else {
+ node.warn("Twilio credentials not set/found. See node info.");
+ }
+ });
+}
+
+RED.nodes.registerType("twilio out",TwilioOutNode);
diff --git a/social/twilio/icons/twilio.png b/social/twilio/icons/twilio.png
new file mode 100644
index 00000000..7404be1d
Binary files /dev/null and b/social/twilio/icons/twilio.png differ
diff --git a/social/xmpp/92-xmpp.html b/social/xmpp/92-xmpp.html
new file mode 100644
index 00000000..b16f4c5a
--- /dev/null
+++ b/social/xmpp/92-xmpp.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
diff --git a/social/xmpp/92-xmpp.js b/social/xmpp/92-xmpp.js
new file mode 100644
index 00000000..5c250b41
--- /dev/null
+++ b/social/xmpp/92-xmpp.js
@@ -0,0 +1,122 @@
+/**
+ * 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 orig=console.warn;
+console.warn=(function() { // suppress warning from stringprep when not needed)
+ var orig=console.warn;
+ return function() {
+ //orig.apply(console, arguments);
+ };
+})();
+
+var RED = require(process.env.NODE_RED_HOME+"/red/red");
+var xmpp = require('simple-xmpp');
+console.warn = orig;
+
+try {
+ var xmppkey = require(process.env.NODE_RED_HOME+"/settings").xmpp || require(process.env.NODE_RED_HOME+"/../xmppkeys.js");
+} catch(err) {
+ throw new Error("Failed to load XMPP credentials");
+}
+
+function XmppNode(n) {
+ RED.nodes.createNode(this,n);
+ this.server = n.server;
+ this.port = n.port;
+ this.join = n.join || false;
+ this.nick = n.nick || "Node-RED";
+ this.sendAll = n.sendObject;
+ this.to = n.to || "";
+ var node = this;
+
+ setTimeout(function() {
+ xmpp.connect({
+ jid : xmppkey.jid,
+ password : xmppkey.password,
+ host : this.server,
+ port : this.port,
+ skipPresence : true,
+ reconnect : false
+ });
+ }, 5000);
+
+ xmpp.on('online', function() {
+ node.log('connected to '+node.server);
+ xmpp.setPresence('online', node.nick+' online');
+ if (node.join) {
+ xmpp.join(node.to+'/'+node.nick);
+ }
+ });
+
+ xmpp.on('chat', function(from, message) {
+ var msg = { topic:from, payload:message };
+ node.send([msg,null]);
+ });
+
+ xmpp.on('groupchat', function(conference, from, message, stamp) {
+ var msg = { topic:from, payload:message, room:conference };
+ if (from != node.nick) { node.send([msg,null]); }
+ });
+
+ //xmpp.on('chatstate', function(from, state) {
+ //console.log('%s is currently %s', from, state);
+ //var msg = { topic:from, payload:state };
+ //node.send([null,msg]);
+ //});
+
+ xmpp.on('buddy', function(jid, state, statusText) {
+ node.log(jid+" is "+state+" : "+statusText);
+ var msg = { topic:jid, payload: { presence:state, status:statusText} };
+ node.send([null,msg]);
+ });
+
+ xmpp.on('error', function(err) {
+ console.error(err);
+ });
+
+ xmpp.on('close', function(err) {
+ node.log('connection closed');
+ });
+
+ xmpp.on('subscribe', function(from) {
+ xmpp.acceptSubscription(from);
+ });
+
+ this.on("input", function(msg) {
+ var to = msg.topic;
+ if (node.to != "") { to = node.to; }
+ if (node.sendAll) {
+ xmpp.send(to, JSON.stringify(msg), node.join);
+ }
+ else {
+ xmpp.send(to, msg.payload, node.join);
+ }
+ });
+
+ this.on("close", function() {
+ xmpp.setPresence('offline');
+ try {
+ xmpp.disconnect();
+ // TODO - DCJ NOTE... this is not good. It leaves the connection up over a restart - which will end up with bad things happening...
+ // (but requires the underlying xmpp lib to be fixed, which does have an open bug request on fixing the close method - and a work around.
+ // see - https://github.com/simple-xmpp/node-simple-xmpp/issues/12 for the fix
+ } catch(e) {
+ this.warn("Due to an underlying bug in the xmpp library this does not disconnect old sessions. This is bad... A restart would be better.");
+ }
+ });
+}
+
+RED.nodes.registerType("xmpp",XmppNode);
diff --git a/social/xmpp/icons/xmpp.png b/social/xmpp/icons/xmpp.png
new file mode 100644
index 00000000..57e43fc4
Binary files /dev/null and b/social/xmpp/icons/xmpp.png differ
diff --git a/storage/leveldb/67-leveldb.html b/storage/leveldb/67-leveldb.html
new file mode 100644
index 00000000..72ead707
--- /dev/null
+++ b/storage/leveldb/67-leveldb.html
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/storage/leveldb/67-leveldb.js b/storage/leveldb/67-leveldb.js
new file mode 100644
index 00000000..f4a91db6
--- /dev/null
+++ b/storage/leveldb/67-leveldb.js
@@ -0,0 +1,94 @@
+/**
+ * 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 lvldb = require('level');
+
+function LevelNode(n) {
+ RED.nodes.createNode(this,n);
+ this.dbname = n.db;
+ var node = this;
+ lvldb(this.dbname, function(err, db) {
+ if (err) node.error(err);
+ node.db = db;
+ });
+ this.on('close', function() {
+ if (node.db) { node.db.close(); }
+ });
+}
+RED.nodes.registerType("leveldbase",LevelNode);
+
+
+function LevelDBNodeIn(n) {
+ RED.nodes.createNode(this,n);
+ this.level = n.level;
+ this.levelConfig = RED.nodes.getNode(this.level);
+
+ if (this.levelConfig) {
+ var node = this;
+ node.on("input", function(msg) {
+ if (typeof msg.topic === 'string') {
+ node.levelConfig.db.get(msg.topic, function(err, value) {
+ if (err) {
+ //node.warn(err);
+ // for some reason they treat nothing found as an error...
+ msg.payload = null; // so we should return null
+ }
+ else { msg.payload = value; }
+ node.send(msg);
+ });
+ }
+ else {
+ if (typeof msg.topic !== 'string') node.error("msg.topic (the key is not defined");
+ }
+ });
+ }
+ else {
+ this.error("LevelDB database name not configured");
+ }
+}
+RED.nodes.registerType("leveldb in",LevelDBNodeIn);
+
+
+function LevelDBNodeOut(n) {
+ RED.nodes.createNode(this,n);
+ this.level = n.level;
+ this.operation = n.operation;
+ this.levelConfig = RED.nodes.getNode(this.level);
+
+ if (this.levelConfig) {
+ var node = this;
+ node.on("input", function(msg) {
+ if (typeof msg.topic === 'string') {
+ if (node.operation === "delete") {
+ node.levelConfig.db.del(msg.topic);
+ }
+ else {
+ node.levelConfig.db.put(msg.topic, msg.payload, function(err) {
+ if (err) node.error(err);
+ });
+ }
+ }
+ else {
+ if (typeof msg.topic !== 'string') node.error("msg.topic (the key is not defined");
+ }
+ });
+ }
+ else {
+ this.error("LevelDB database name not configured");
+ }
+}
+RED.nodes.registerType("leveldb out",LevelDBNodeOut);
diff --git a/storage/mysql/68-mysql.html b/storage/mysql/68-mysql.html
new file mode 100644
index 00000000..a68e642b
--- /dev/null
+++ b/storage/mysql/68-mysql.html
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/storage/mysql/68-mysql.js b/storage/mysql/68-mysql.js
new file mode 100644
index 00000000..d01d6f92
--- /dev/null
+++ b/storage/mysql/68-mysql.js
@@ -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 reconnect = RED.settings.mysqlReconnectTime || 30000;
+var mysqldb = require('mysql');
+var querystring = require('querystring');
+
+RED.app.get('/MySQLdatabase/: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.app.delete('/MySQLdatabase/:id',function(req,res) {
+ RED.nodes.deleteCredentials(req.params.id);
+ res.send(200);
+});
+
+RED.app.post('/MySQLdatabase/: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 MySQLNode(n) {
+ RED.nodes.createNode(this,n);
+ this.host = n.host;
+ this.port = n.port;
+
+ this.connected = false;
+ this.connecting = false;
+
+ if (n.user) {
+ var credentials = {};
+ credentials.user = n.user;
+ credentials.password = n.pass;
+ RED.nodes.addCredentials(n.id,credentials);
+ this.user = n.user;
+ this.password = n.pass;
+ } else {
+ var credentials = RED.nodes.getCredentials(n.id);
+ if (credentials) {
+ this.user = credentials.user;
+ this.password = credentials.password;
+ }
+ }
+
+ this.dbname = n.db;
+ var node = this;
+
+ function doConnect() {
+ node.connecting = true;
+ node.connection = mysqldb.createConnection({
+ host : node.host,
+ port : node.port,
+ user : node.user,
+ password : node.password,
+ database : node.dbname,
+ insecureAuth: true
+ });
+
+ node.connection.connect(function(err) {
+ node.connecting = false;
+ if (err) {
+ node.warn(err);
+ node.tick = setTimeout(doConnect, reconnect);
+ } else {
+ node.connected = true;
+ }
+ });
+
+ node.connection.on('error', function(err) {
+ node.connected = false;
+ if (err.code === 'PROTOCOL_CONNECTION_LOST') {
+ doConnect(); // silently reconnect...
+ } else {
+ node.error(err);
+ doConnect();
+ }
+ });
+ }
+
+ this.connect = function() {
+ if (!this.connected && !this.connecting) {
+ doConnect();
+ }
+ }
+
+ this.on('close', function () {
+ if (this.tick) { clearTimeout(this.tick); }
+ if (this.connection) {
+ node.connection.end(function(err) {
+ if (err) node.error(err);
+ });
+ }
+ });
+}
+RED.nodes.registerType("MySQLdatabase",MySQLNode);
+
+
+function MysqlDBNodeIn(n) {
+ RED.nodes.createNode(this,n);
+ this.mydb = n.mydb;
+ this.mydbConfig = RED.nodes.getNode(this.mydb);
+
+ if (this.mydbConfig) {
+ this.mydbConfig.connect();
+ var node = this;
+ node.on("input", function(msg) {
+ if (typeof msg.topic === 'string') {
+ //console.log("query:",msg.topic);
+ node.mydbConfig.connection.query(msg.topic, function(err, rows) {
+ if (err) { node.warn(err); }
+ else {
+ msg.payload = rows;
+ node.send(msg);
+ }
+ });
+ }
+ else {
+ if (typeof msg.topic !== 'string') node.error("msg.topic : the query is not defined as a string");
+ }
+ });
+ }
+ else {
+ this.error("MySQL database not configured");
+ }
+}
+RED.nodes.registerType("mysql",MysqlDBNodeIn);
+
+
+//function MysqlDBNodeOut(n) {
+ //RED.nodes.createNode(this,n);
+ //this.level = n.level;
+ //this.operation = n.operation;
+ //this.levelConfig = RED.nodes.getNode(this.level);
+
+ //if (this.levelConfig) {
+ //var node = this;
+ //node.on("input", function(msg) {
+ //if (typeof msg.topic === 'string') {
+ //if (node.operation === "delete") {
+ //node.levelConfig.db.del(msg.topic);
+ //}
+ //else {
+ //node.levelConfig.db.put(msg.topic, msg.payload, function(err) {
+ //if (err) node.error(err);
+ //});
+ //}
+ //}
+ //else {
+ //if (typeof msg.topic !== 'string') node.error("msg.topic : the key is not defined");
+ //}
+ //});
+ //}
+ //else {
+ //this.error("MySQL database not configured");
+ //}
+//}
+//RED.nodes.registerType("mysql out",MysqlDBNodeOut);
diff --git a/time/79-suncalc.js b/time/79-suncalc.js
index 383824a3..8004633d 100644
--- a/time/79-suncalc.js
+++ b/time/79-suncalc.js
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
-var RED = require("../../red/red");
+
+var RED = require(process.env.NODE_RED_HOME+"/red/red");
var SunCalc = require('suncalc');
function SunNode(n) {
diff --git a/time/icons/sun.png b/time/icons/sun.png
new file mode 100644
index 00000000..c4918e56
Binary files /dev/null and b/time/icons/sun.png differ