From ac7a5599bb2b3e2d1ce60bc9fcf5073951c2528f Mon Sep 17 00:00:00 2001 From: hdoukas Date: Fri, 14 Feb 2014 13:30:19 +0100 Subject: [PATCH 1/9] Update 104-hue_manage.js fixed issue with 'payload undefined' error --- hardware/hue/104-hue_manage.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hardware/hue/104-hue_manage.js b/hardware/hue/104-hue_manage.js index 954a8f167..4808f344c 100644 --- a/hardware/hue/104-hue_manage.js +++ b/hardware/hue/104-hue_manage.js @@ -65,6 +65,7 @@ function HueNode(n) { msg.topic = this.topic; this.on("input", function(msg){ + global.msg = msg; //set the lamp status //first locate the Hue gateway: hue.locateBridges(function(err, result) { @@ -84,11 +85,11 @@ function HueNode(n) { var state = lightState.create(); var status; - if(msg.payload=="ALERT"){ + if(global.msg.payload=="ALERT"){ status = "ALERT"; } - else if(node.lamp_status=="ON" || msg.payload=="ON") status = "ON"; - else if(node.lamp_status=="OFF" || msg.payload=="OFF") status = "OFF"; + else if(node.lamp_status=="ON" || global.msg.payload=="ON") status = "ON"; + else if(node.lamp_status=="OFF" || global.msg.payload=="OFF") status = "OFF"; if(status=="ALERT") { @@ -142,4 +143,4 @@ var displayError = function(err) { // Register the node by name. This must be called before overriding any of the // Node functions. -RED.nodes.registerType("HueNode",HueNode); \ No newline at end of file +RED.nodes.registerType("HueNode",HueNode); From 4363b7f642ff36b5fa2847469b5843aa07d56b85 Mon Sep 17 00:00:00 2001 From: hdoukas Date: Fri, 14 Feb 2014 16:29:58 +0100 Subject: [PATCH 2/9] Update 104-hue_manage.js used local variable instead of global msg --- hardware/hue/104-hue_manage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hardware/hue/104-hue_manage.js b/hardware/hue/104-hue_manage.js index 4808f344c..6fb530273 100644 --- a/hardware/hue/104-hue_manage.js +++ b/hardware/hue/104-hue_manage.js @@ -65,7 +65,7 @@ function HueNode(n) { msg.topic = this.topic; this.on("input", function(msg){ - global.msg = msg; + var myMsg = msg; //set the lamp status //first locate the Hue gateway: hue.locateBridges(function(err, result) { @@ -85,11 +85,11 @@ function HueNode(n) { var state = lightState.create(); var status; - if(global.msg.payload=="ALERT"){ + if(myMsg.payload=="ALERT"){ status = "ALERT"; } - else if(node.lamp_status=="ON" || global.msg.payload=="ON") status = "ON"; - else if(node.lamp_status=="OFF" || global.msg.payload=="OFF") status = "OFF"; + else if(node.lamp_status=="ON" || myMsg.payload=="ON") status = "ON"; + else if(node.lamp_status=="OFF" || myMsg.payload=="OFF") status = "OFF"; if(status=="ALERT") { From d3512b2ef52735696d570bfd171f771006592e4e Mon Sep 17 00:00:00 2001 From: hdoukas Date: Fri, 14 Feb 2014 20:08:44 +0100 Subject: [PATCH 3/9] Update 104-hue_manage.js --- hardware/hue/104-hue_manage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hardware/hue/104-hue_manage.js b/hardware/hue/104-hue_manage.js index 6fb530273..2ebf7db6e 100644 --- a/hardware/hue/104-hue_manage.js +++ b/hardware/hue/104-hue_manage.js @@ -96,8 +96,8 @@ function HueNode(n) { api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done(); } else if(status=="ON") { - if(node.color==null) { - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(msg.topic).r,hexToRgb(msg.topic).g,hexToRgb(msg.topic).b)).then(displayResult).fail(displayError).done(); + if(node.color==null || node.color=="") { + api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); } else { api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b)).then(displayResult).fail(displayError).done(); From 4fc6b4137ca655bb0a5a8c09fc34c991d7f6fc56 Mon Sep 17 00:00:00 2001 From: hdoukas Date: Tue, 18 Mar 2014 12:12:23 +0100 Subject: [PATCH 4/9] Update 104-hue_manage.js --- hardware/hue_manage/104-hue_manage.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hardware/hue_manage/104-hue_manage.js b/hardware/hue_manage/104-hue_manage.js index 954a8f167..2ebf7db6e 100644 --- a/hardware/hue_manage/104-hue_manage.js +++ b/hardware/hue_manage/104-hue_manage.js @@ -65,6 +65,7 @@ function HueNode(n) { msg.topic = this.topic; this.on("input", function(msg){ + var myMsg = msg; //set the lamp status //first locate the Hue gateway: hue.locateBridges(function(err, result) { @@ -84,19 +85,19 @@ function HueNode(n) { var state = lightState.create(); var status; - if(msg.payload=="ALERT"){ + if(myMsg.payload=="ALERT"){ status = "ALERT"; } - else if(node.lamp_status=="ON" || msg.payload=="ON") status = "ON"; - else if(node.lamp_status=="OFF" || msg.payload=="OFF") status = "OFF"; + else if(node.lamp_status=="ON" || myMsg.payload=="ON") status = "ON"; + else if(node.lamp_status=="OFF" || myMsg.payload=="OFF") status = "OFF"; if(status=="ALERT") { api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done(); } else if(status=="ON") { - if(node.color==null) { - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(msg.topic).r,hexToRgb(msg.topic).g,hexToRgb(msg.topic).b)).then(displayResult).fail(displayError).done(); + if(node.color==null || node.color=="") { + api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); } else { api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b)).then(displayResult).fail(displayError).done(); @@ -142,4 +143,4 @@ var displayError = function(err) { // Register the node by name. This must be called before overriding any of the // Node functions. -RED.nodes.registerType("HueNode",HueNode); \ No newline at end of file +RED.nodes.registerType("HueNode",HueNode); From abe062c96927b6b5998b242af929da30e66b1436 Mon Sep 17 00:00:00 2001 From: hdoukas Date: Sat, 22 Mar 2014 17:56:28 +0100 Subject: [PATCH 5/9] added icon folder to hue removed hue_manage, hue_discover --- hardware/{hue_manage => hue}/icons/hue.png | Bin hardware/hue_discover/103-hue_discover.html | 54 -------- hardware/hue_discover/103-hue_discover.js | 105 -------------- hardware/hue_discover/icons/philipshue.png | Bin 9372 -> 0 bytes hardware/hue_manage/104-hue_manage.html | 80 ----------- hardware/hue_manage/104-hue_manage.js | 146 -------------------- 6 files changed, 385 deletions(-) rename hardware/{hue_manage => hue}/icons/hue.png (100%) delete mode 100644 hardware/hue_discover/103-hue_discover.html delete mode 100644 hardware/hue_discover/103-hue_discover.js delete mode 100644 hardware/hue_discover/icons/philipshue.png delete mode 100644 hardware/hue_manage/104-hue_manage.html delete mode 100644 hardware/hue_manage/104-hue_manage.js diff --git a/hardware/hue_manage/icons/hue.png b/hardware/hue/icons/hue.png similarity index 100% rename from hardware/hue_manage/icons/hue.png rename to hardware/hue/icons/hue.png diff --git a/hardware/hue_discover/103-hue_discover.html b/hardware/hue_discover/103-hue_discover.html deleted file mode 100644 index 14f7fa0a5..000000000 --- a/hardware/hue_discover/103-hue_discover.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - diff --git a/hardware/hue_discover/103-hue_discover.js b/hardware/hue_discover/103-hue_discover.js deleted file mode 100644 index 4106aeffd..000000000 --- a/hardware/hue_discover/103-hue_discover.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * philips_hue.js - * Basic functionality for accessing a Philips Hue wireless Lamp - * Allows for bridge/gateway detection and light scanning. - * Requires node-hue-api https://github.com/peter-murray/node-hue-api - * Copyright 2013 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. - **/ - - -//Require node-hue-api -var hue = require("node-hue-api"); -var HueApi = require("node-hue-api").HueApi; - -// Require main module -var RED = require(process.env.NODE_RED_HOME+"/red/red"); - -//store the IP address of the Hue Gateway -var gw_ipaddress = ""; - -var username; - -// The main node definition - most things happen in here -function HueNodeDiscovery(n) { - // Create a RED node - RED.nodes.createNode(this,n); - - var node = this; - - //get username from user input - this.username = n.username; - - - // Store local copies of the node configuration (as defined in the .html) - this.topic = n.topic; - - this.on("input", function(msg){ - - //start with detecting the IP address of the Hue gateway in the local network: - hue.locateBridges(function(err, result) { - var msg = {}; - if (err) throw err; - //check for found bridges - if(result[0]!=null) { - //save the IP address of the 1st bridge found - this.gw_ipaddress = result[0].ipaddress; - msg.payload = this.gw_ipaddress; - - //get light info: - var api = new HueApi(this.gw_ipaddress, node.username); - api.lights(function(err, lights) { - var msg2 = {}; - if (err) throw err; - var lights_discovered = JSON.stringify(lights, null, 2); - msg2.topic = "Lights"; - msg2.payload = lights_discovered; - node.send([msg, msg2]); - - }); - } - else { - //bridge not found: - var msg = {}; - msg.payload = "Bridge not found!"; - node.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(); - }); - - } - - //hue debugging on the output: - var displayResult = function(result) { - console.log(result); -}; - -var displayError = function(err) { - console.error(err); -}; - - - -// Register the node by name. This must be called before overriding any of the -// Node functions. -RED.nodes.registerType("Discover",HueNodeDiscovery); \ No newline at end of file diff --git a/hardware/hue_discover/icons/philipshue.png b/hardware/hue_discover/icons/philipshue.png deleted file mode 100644 index 261b38d195b32744852cf19e7ed994535dedf376..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9372 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 m;*>y8gD%+pbFA3HD}c - - - - - - - - diff --git a/hardware/hue_manage/104-hue_manage.js b/hardware/hue_manage/104-hue_manage.js deleted file mode 100644 index 2ebf7db6e..000000000 --- a/hardware/hue_manage/104-hue_manage.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * philips_hue.js - * Basic functionality for accessing and contolling a Philips Hue wireless Lamp - * Allows for bridge/gateway and light scanning, as well as Light ON/OFF/ALERT status update - * Requires node-hue-api https://github.com/peter-murray/node-hue-api - * Copyright 2013 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. - **/ - - -//Require node-hue-api -var hue = require("node-hue-api"); -var HueApi = require("node-hue-api").HueApi; - -// Require main module -var RED = require(process.env.NODE_RED_HOME+"/red/red"); - -//store the IP address of the Hue Gateway -var gw_ipaddress = ""; - - -var username, lamp_status, lamp_id, color; - -function hexToRgb(hex) { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; -} - - -// The main node definition - most things happen in here -function HueNode(n) { - // Create a RED node - RED.nodes.createNode(this,n); - - var node = this; - - //get parameters from user - this.username = n.username; - this.lamp_status = n.lamp_status; - this.lamp_id = n.lamp_id; - this.color = n.color; - - - // Store local copies of the node configuration (as defined in the .html) - this.topic = n.topic; - - - var msg = {}; - - msg.topic = this.topic; - - this.on("input", function(msg){ - var myMsg = msg; - //set the lamp status - //first locate the Hue gateway: - hue.locateBridges(function(err, result) { - - var msg2 = {}; - msg2.topic = this.topic; - if (err) throw err; - //check for found bridges - if(result[0]!=null) { - //save the IP address of the 1st bridge found - this.gw_ipaddress = result[0].ipaddress; - - - //set light status - var api = new HueApi(this.gw_ipaddress, node.username); - var lightState = hue.lightState; - var state = lightState.create(); - - var status; - if(myMsg.payload=="ALERT"){ - status = "ALERT"; - } - else if(node.lamp_status=="ON" || myMsg.payload=="ON") status = "ON"; - else if(node.lamp_status=="OFF" || myMsg.payload=="OFF") status = "OFF"; - - - if(status=="ALERT") { - api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done(); - } - else if(status=="ON") { - if(node.color==null || node.color=="") { - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); - } - else { - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b)).then(displayResult).fail(displayError).done(); - } - } - else { - api.setLightState(node.lamp_id, state.off()).then(displayResult).fail(displayError).done(); - } - - msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+status; - node.send(msg2); - } - else { - //bridge not found: - var msg = {}; - msg.payload = "Bridge not found!"; - node.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(); - }); - - } - - //hue debugging on the output: - var displayResult = function(result) { - console.log(result); -}; - -var displayError = function(err) { - console.error(err); -}; - - - - -// Register the node by name. This must be called before overriding any of the -// Node functions. -RED.nodes.registerType("HueNode",HueNode); From 3badce651cd8cd185aa18ec1b4a996227f55648b Mon Sep 17 00:00:00 2001 From: hdoukas Date: Sat, 22 Mar 2014 19:10:16 +0100 Subject: [PATCH 6/9] Added option to set brightness Added option to set Lamp ID from message payload --- hardware/hue/104-hue_manage.html | 8 ++++++- hardware/hue/104-hue_manage.js | 38 +++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/hardware/hue/104-hue_manage.html b/hardware/hue/104-hue_manage.html index 7aa408e20..f506ac756 100644 --- a/hardware/hue/104-hue_manage.html +++ b/hardware/hue/104-hue_manage.html @@ -36,6 +36,11 @@ +
+ + +
+
@@ -51,7 +56,7 @@ @@ -65,6 +70,7 @@ discovery_mode: {value: "", required:false}, lamp_id: {value:"", required:false}, color: {value:"EBF5FF"}, + brightness: {value:"100"}, lamp_status:{} }, inputs:1, // set the number of inputs - only 0 or 1 diff --git a/hardware/hue/104-hue_manage.js b/hardware/hue/104-hue_manage.js index 2ebf7db6e..28d0b1cdc 100644 --- a/hardware/hue/104-hue_manage.js +++ b/hardware/hue/104-hue_manage.js @@ -30,7 +30,7 @@ var RED = require(process.env.NODE_RED_HOME+"/red/red"); var gw_ipaddress = ""; -var username, lamp_status, lamp_id, color; +var username, lamp_status, lamp_id, color, brightness; function hexToRgb(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); @@ -54,6 +54,7 @@ function HueNode(n) { this.lamp_status = n.lamp_status; this.lamp_id = n.lamp_id; this.color = n.color; + this.brightness = n.brightness; // Store local copies of the node configuration (as defined in the .html) @@ -85,6 +86,16 @@ function HueNode(n) { var state = lightState.create(); var status; + var lamp = -1; + + //check for lamp ID in the payload + if(myMsg.payload.length>1) { + var tmp_status = myMsg.payload.split(":"); + myMsg.payload = tmp_status[1]; + lamp = tmp_status[0]; + + } + if(myMsg.payload=="ALERT"){ status = "ALERT"; } @@ -93,21 +104,36 @@ function HueNode(n) { if(status=="ALERT") { - api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done(); + if(lamp!=-1) + api.setLightState(lamp, state.alert()).then(displayResult).fail(displayError).done(); + else + api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done(); } else if(status=="ON") { if(node.color==null || node.color=="") { - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); + if(lamp!=-1) + api.setLightState(lamp, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); + else + api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); } else { - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b)).then(displayResult).fail(displayError).done(); + if(lamp!=-1) + api.setLightState(lamp, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b).brightness(node.brightness)).then(displayResult).fail(displayError).done(); + else + api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b).brightness(node.brightness)).then(displayResult).fail(displayError).done(); } } else { - api.setLightState(node.lamp_id, state.off()).then(displayResult).fail(displayError).done(); + if(lamp!=-1) + api.setLightState(lamp, state.off()).then(displayResult).fail(displayError).done(); + else + api.setLightState(node.lamp_id, state.off()).then(displayResult).fail(displayError).done(); } - msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+status; + if(lamp!=-1) + msg2.payload = 'Light with ID: '+lamp+ ' was set to '+status; + else + msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+status; node.send(msg2); } else { From 98ce26bb89dc03eb49f9b5bcd88ce6f40900bb92 Mon Sep 17 00:00:00 2001 From: hdoukas Date: Sun, 23 Mar 2014 12:03:13 +0100 Subject: [PATCH 7/9] re-wrote code in a more structured way, added brightness setting through msg.topic --- hardware/hue/104-hue_manage.html | 2 +- hardware/hue/104-hue_manage.js | 62 ++++++++++++++++---------------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/hardware/hue/104-hue_manage.html b/hardware/hue/104-hue_manage.html index f506ac756..c77d4ed0e 100644 --- a/hardware/hue/104-hue_manage.html +++ b/hardware/hue/104-hue_manage.html @@ -56,7 +56,7 @@ diff --git a/hardware/hue/104-hue_manage.js b/hardware/hue/104-hue_manage.js index 28d0b1cdc..95aed98cf 100644 --- a/hardware/hue/104-hue_manage.js +++ b/hardware/hue/104-hue_manage.js @@ -88,52 +88,50 @@ function HueNode(n) { var status; var lamp = -1; - //check for lamp ID in the payload - if(myMsg.payload.length>1) { - var tmp_status = myMsg.payload.split(":"); - myMsg.payload = tmp_status[1]; - lamp = tmp_status[0]; - - } - - if(myMsg.payload=="ALERT"){ - status = "ALERT"; - } - else if(node.lamp_status=="ON" || myMsg.payload=="ON") status = "ON"; - else if(node.lamp_status=="OFF" || myMsg.payload=="OFF") status = "OFF"; + //check for AUTO status (lamp settings set through node input) + if(node.lamp_status=="AUTO") { + var color; + var brightness; + //check for lamp ID in the payload + if(myMsg.payload.length>1) { + var tmp_status = myMsg.payload.split(":"); + myMsg.payload = tmp_status[1]; + lamp = tmp_status[0]; + } + //check for brightness & color: + if(myMsg.topic.length>1) { + var tmp_topic = myMsg.topic.split(":"); + color = tmp_topic[0]; + brightness = tmp_topic[1]; + } - if(status=="ALERT") { - if(lamp!=-1) + //case of ALERT: + if(myMsg.payload=="ALERT"){ api.setLightState(lamp, state.alert()).then(displayResult).fail(displayError).done(); - else - api.setLightState(node.lamp_id, state.alert()).then(displayResult).fail(displayError).done(); - } - else if(status=="ON") { - if(node.color==null || node.color=="") { - if(lamp!=-1) - api.setLightState(lamp, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); - else - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(myMsg.topic).r,hexToRgb(myMsg.topic).g,hexToRgb(myMsg.topic).b)).then(displayResult).fail(displayError).done(); + } + + //case of ON: + if(myMsg.payload=="ON") { + api.setLightState(lamp, state.on().rgb(hexToRgb(color).r,hexToRgb(color).g,hexToRgb(color).b).brightness(brightness)).then(displayResult).fail(displayError).done(); } else { - if(lamp!=-1) - api.setLightState(lamp, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b).brightness(node.brightness)).then(displayResult).fail(displayError).done(); - else - api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b).brightness(node.brightness)).then(displayResult).fail(displayError).done(); + api.setLightState(lamp, state.off()).then(displayResult).fail(displayError).done(); } + } else { - if(lamp!=-1) - api.setLightState(lamp, state.off()).then(displayResult).fail(displayError).done(); + //set lamp according to node settings + if(node.lamp_status=="ON") + api.setLightState(node.lamp_id, state.on().rgb(hexToRgb(node.color).r,hexToRgb(node.color).g,hexToRgb(node.color).b).brightness(node.brightness)).then(displayResult).fail(displayError).done(); else api.setLightState(node.lamp_id, state.off()).then(displayResult).fail(displayError).done(); } if(lamp!=-1) - msg2.payload = 'Light with ID: '+lamp+ ' was set to '+status; + msg2.payload = 'Light with ID: '+lamp+ ' was set to '+myMsg.payload; else - msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+status; + msg2.payload = 'Light with ID: '+node.lamp_id+ ' was set to '+node.lamp_status; node.send(msg2); } else { From fa78489b228007718671f2dd180a70feea087282 Mon Sep 17 00:00:00 2001 From: hdoukas Date: Sun, 23 Mar 2014 15:04:23 +0100 Subject: [PATCH 8/9] changed the msg.topic to contain the lamp id and status and the msg.payload to carry the color/brightnes --- hardware/hue/104-hue_manage.html | 2 +- hardware/hue/104-hue_manage.js | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hardware/hue/104-hue_manage.html b/hardware/hue/104-hue_manage.html index c77d4ed0e..a506c6ed7 100644 --- a/hardware/hue/104-hue_manage.html +++ b/hardware/hue/104-hue_manage.html @@ -56,7 +56,7 @@ diff --git a/hardware/hue/104-hue_manage.js b/hardware/hue/104-hue_manage.js index 95aed98cf..e01f4be57 100644 --- a/hardware/hue/104-hue_manage.js +++ b/hardware/hue/104-hue_manage.js @@ -92,27 +92,27 @@ function HueNode(n) { if(node.lamp_status=="AUTO") { var color; var brightness; - //check for lamp ID in the payload - if(myMsg.payload.length>1) { - var tmp_status = myMsg.payload.split(":"); - myMsg.payload = tmp_status[1]; + //check for lamp ID in the topic + if(myMsg.topic.length>1) { + var tmp_status = myMsg.topic.split(":"); + myMsg.topic = tmp_status[1]; lamp = tmp_status[0]; } //check for brightness & color: - if(myMsg.topic.length>1) { - var tmp_topic = myMsg.topic.split(":"); + if(myMsg.payload.length>1) { + var tmp_topic = myMsg.payload.split(":"); color = tmp_topic[0]; brightness = tmp_topic[1]; } //case of ALERT: - if(myMsg.payload=="ALERT"){ + if(myMsg.topic=="ALERT"){ api.setLightState(lamp, state.alert()).then(displayResult).fail(displayError).done(); } //case of ON: - if(myMsg.payload=="ON") { + if(myMsg.topic=="ON") { api.setLightState(lamp, state.on().rgb(hexToRgb(color).r,hexToRgb(color).g,hexToRgb(color).b).brightness(brightness)).then(displayResult).fail(displayError).done(); } else { From 91104067035df844486bf1d8711433d517f74f5f Mon Sep 17 00:00:00 2001 From: hdoukas Date: Sun, 23 Mar 2014 23:44:40 +0100 Subject: [PATCH 9/9] rebasing to master --- README.md | 4 + analysis/swearfilter/74-swearfilter.js | 6 +- hardware/BBB/145-BBB-hardware.html | 638 +++++++++++++++++++++++++ hardware/BBB/145-BBB-hardware.js | 508 ++++++++++++++++++++ hardware/BBB/icons/BBB.png | Bin 0 -> 719 bytes hardware/Pi/78-ledborg.js | 18 +- hardware/blink/77-blink1.html | 4 +- hardware/blink/77-blink1.js | 34 +- hardware/sensorTag/79-sensorTag.html | 26 +- hardware/sensorTag/79-sensorTag.js | 95 ++-- hardware/sensorTag/README | 4 +- io/emoncms/88-emoncms.html | 120 +++++ io/emoncms/88-emoncms.js | 111 +++++ io/emoncms/icons/emoncms-logo.png | Bin 0 -> 1418 bytes io/emoncms/icons/emoncms.png | Bin 0 -> 933 bytes io/ping/88-ping.html | 2 - io/ping/88-ping.js | 18 +- io/rawserial/26-rawserial.js | 1 + io/wol/39-wol.html | 2 +- io/wol/39-wol.js | 4 +- social/music/69-mpd.js | 105 ++-- social/prowl/57-prowl.js | 62 +-- social/pushbullet/57-pushbullet.html | 14 +- social/pushbullet/57-pushbullet.js | 56 +-- social/snapchat/79-snapchat.html | 53 ++ social/snapchat/79-snapchat.js | 68 +++ social/twilio/56-twilio.html | 59 +++ social/twilio/56-twilio.js | 64 +++ social/twilio/icons/twilio.png | Bin 0 -> 553 bytes social/xmpp/92-xmpp.html | 16 +- social/xmpp/92-xmpp.js | 176 +++---- storage/ddb/69-ddbout.html | 58 +++ storage/ddb/69-ddbout.js | 44 ++ storage/ddb/aws.html | 68 +++ storage/ddb/aws.js | 65 +++ storage/mysql/68-mysql.html | 44 +- storage/mysql/68-mysql.js | 117 ++++- storage/postgres/110-postgres.html | 146 ++++++ storage/postgres/110-postgres.js | 123 +++++ storage/postgres/icons/postgres.png | Bin 0 -> 625 bytes time/79-suncalc.js | 14 +- 41 files changed, 2650 insertions(+), 297 deletions(-) create mode 100644 hardware/BBB/145-BBB-hardware.html create mode 100644 hardware/BBB/145-BBB-hardware.js create mode 100644 hardware/BBB/icons/BBB.png create mode 100644 io/emoncms/88-emoncms.html create mode 100644 io/emoncms/88-emoncms.js create mode 100644 io/emoncms/icons/emoncms-logo.png create mode 100644 io/emoncms/icons/emoncms.png create mode 100644 social/snapchat/79-snapchat.html create mode 100644 social/snapchat/79-snapchat.js create mode 100644 social/twilio/56-twilio.html create mode 100644 social/twilio/56-twilio.js create mode 100644 social/twilio/icons/twilio.png create mode 100644 storage/ddb/69-ddbout.html create mode 100644 storage/ddb/69-ddbout.js create mode 100644 storage/ddb/aws.html create mode 100644 storage/ddb/aws.js create mode 100644 storage/postgres/110-postgres.html create mode 100644 storage/postgres/110-postgres.js create mode 100644 storage/postgres/icons/postgres.png diff --git a/README.md b/README.md index 5c150f4c0..c695027d0 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,8 @@ Copyright 2013 IBM Corp. under [the Apache 2.0 license](LICENSE). **101-scanBLE** - Scans for a particular Bluetooth Low Energy (BLE) device. +**145-BBB-hardware** - A collection of analogue & digital input & output nodes for the Beaglebone Black + ### IO **26-rawserial** - Only really needed for Windows boxes without serialport npm module installed. @@ -96,6 +98,8 @@ Uses a simple read of the serial port as a file to input data. You **must** set **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...* +**69-ddbout** - Support output to Amazon DynamoDB. + ### 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, diff --git a/analysis/swearfilter/74-swearfilter.js b/analysis/swearfilter/74-swearfilter.js index 765e497b4..394bca40a 100644 --- a/analysis/swearfilter/74-swearfilter.js +++ b/analysis/swearfilter/74-swearfilter.js @@ -16,13 +16,15 @@ var RED = require(process.env.NODE_RED_HOME+"/red/red"); var badwords = require('badwords'); +if (badwords.length == 0 ) { return; } +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 (badwords.ok(msg.payload)) { node.send(msg); } + if (typeof msg.payload === "string") { + if ( !badwordsRegExp.test(msg.payload) ) { node.send(msg); } } }); } diff --git a/hardware/BBB/145-BBB-hardware.html b/hardware/BBB/145-BBB-hardware.html new file mode 100644 index 000000000..2af864490 --- /dev/null +++ b/hardware/BBB/145-BBB-hardware.html @@ -0,0 +1,638 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hardware/BBB/145-BBB-hardware.js b/hardware/BBB/145-BBB-hardware.js new file mode 100644 index 000000000..70205a48e --- /dev/null +++ b/hardware/BBB/145-BBB-hardware.js @@ -0,0 +1,508 @@ +/** + * Copyright 2014 Maxwell R Hadley + * + * 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. + **/ + +// Require main module +var RED = require(process.env.NODE_RED_HOME + "/red/red"); + +// Require bonescript +try { + var bonescript = require("bonescript"); +} catch (err) { + require("util").log("[145-BBB-hardware] Error: cannot find module 'bonescript'"); +} + +// Node constructor for bbb-analogue-in +function AnalogueInputNode(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; + this.pin = n.pin; + this.breakpoints = n.breakpoints; + this.averaging = n.averaging; + if (this.averaging) { + this.averages = 10; + } else { + this.averages = 1; + } + + // Define 'node' to allow us to access 'this' from within callbacks + var node = this; + + // Variables used for input averaging + var sum; // accumulates the input readings to be averaged + var count; // keep track of the number of measurements made + + // The callback function for analogRead. Accumulates the required number of + // measurements, then divides the total number, applies output scaling and + // sends the result + var analogReadCallback = function (x) { + sum = sum + x.value; + count = count - 1; + if (count > 0) { + bonescript.analogRead(node.pin, analogReadCallback); + } else { + var msg = {}; + msg.topic = node.topic; + sum = sum/node.averages; + // i is the index of the first breakpoint where the 'input' value is strictly + // greater than the measurement (note: a measurement can never be == 1) + var i = node.breakpoints.map(function (breakpoint) { return sum >= breakpoint.input; }).indexOf(false); + msg.payload = node.breakpoints[i-1].output + (node.breakpoints[i].output - node.breakpoints[i-1].output) * + (sum - node.breakpoints[i-1].input)/(node.breakpoints[i].input - node.breakpoints[i-1].input); + node.send(msg); + } + }; + + // If we have a valid pin, set the input event handler to Bonescript's analogRead + if (["P9_39", "P9_40", "P9_37", "P9_38", "P9_33", "P9_36", "P9_35"].indexOf(node.pin) >= 0) { + node.on("input", function (msg) { + sum = 0; + count = node.averages; + bonescript.analogRead(node.pin, analogReadCallback); + }); + } else { + node.error("Unconfigured input pin"); + } +} + +// Node constructor for bbb-discrete-in +function DiscreteInputNode(n) { + RED.nodes.createNode(this, n); + + // Store local copies of the node configuration (as defined in the .html) + this.topic = n.topic; // the topic is not currently used + this.pin = n.pin; // The Beaglebone Black pin identifying string + if (n.activeLow) // Set the 'active' state 0 or 1 as appropriate + this.activeState = 0; + else + this.activeState = 1; + this.updateInterval = n.updateInterval * 1000; // How often to send totalActiveTime messages + this.debounce = n.debounce; // Enable switch contact debouncing algorithm + if (n.outputOn === "rising") { + this.activeEdges = [false, true]; + } else if (n.outputOn === "falling") { + this.activeEdges = [true, false]; + } else if (n.outputOn === "both") { + this.activeEdges = [true, true]; + } else { + node.error("Invalid edge type: " + n.outputOn); + } + + // Working variables + this.interruptAttached = false; // Flag: should we detach interrupt when we are closed? + this.intervalId = null; // Remember the timer ID so we can delete it when we are closed + this.currentState = 0; // The pin input state "1" or "0" + this.lastActiveTime = NaN; // The date (in ms since epoch) when the pin last went high + // switch to process.hrtime() + this.totalActiveTime = 0; // The total time in ms that the pin has been high (since reset) + this.starting = true; + this.debouncing = false; // True after a change of state while waiting for the 7ms debounce time to elapse + this.debounceTimer = null; + + // Define 'node' to allow us to access 'this' from within callbacks + var node = this; + + // This function is called by the input pin change-of-state interrupt. If + // debounce is disabled, send the output message. Otherwise, if we are + // currently debouncing, ignore this interrupt. If we are not debouncing, + // schedule a re-read of the input pin in 7ms time, and set the debouncing flag + // Note: this function gets called spuriously when the interrupt is first enabled: + // in this case x.value is undefined - we must test for this + var interruptCallback = function (x) { + if (x.value !== undefined && node.currentState !== Number(x.value)) { + if (node.debounce) { + if (node.debouncing === false) { + node.debouncing = true; + node.debounceTimer = setTimeout(function () { bonescript.digitalRead(node.pin, debounceCallback); }, 7); + } + } else { + sendStateMessage(x); + } + } + }; + + // This function is called approx 7ms after a potential change-of-state which is + // being debounced. Terminate the debounce, and send a message if the state has + // actually changed + var debounceCallback = function (x) { + node.debounceTimer = null; + node.debouncing = false; + if (x.value !== undefined && node.currentState !== Number(x.value)) { + sendStateMessage(x); + } + }; + + // This function is called when either the interruptCallback or the debounceCallback + // have determined we have a 'genuine' change of state. Update the currentState and + // ActiveTime variables, and send a message on the first output with the new state + var sendStateMessage = function (x) { + node.currentState = Number(x.value); + var now = Date.now(); + if (node.currentState === node.activeState) { + node.lastActiveTime = now; + } else if (!isNaN(node.lastActiveTime)) { + node.totalActiveTime += now - node.lastActiveTime; + } + if (node.activeEdges[node.currentState]) { + var msg = {}; + msg.topic = node.topic; + msg.payload = node.currentState; + node.send([msg, null]); + } + }; + + // This function is called by the timer. It updates the ActiveTime variables, and sends a + // message on the second output with the latest value of the total active time, in seconds + var timerCallback = function () { + if (node.currentState === node.activeState) { + var now = Date.now(); + node.totalActiveTime += now - node.lastActiveTime; + node.lastActiveTime = now; + } + var msg = {}; + msg.topic = node.topic; + msg.payload = node.totalActiveTime / 1000; + node.send([null, msg]); + // Re-synchronise the pin state if we have missed a state change interrupt for some + // reason, and we are not in the process of debouncing one + if (node.debouncing === false) { + bonescript.digitalRead(node.pin, interruptCallback); + } + }; + + // This function is called when we receive an input message. If the topic contains + // 'load' (case insensitive) set the totalActiveTime to the numeric value of the + // payload, if possible. Otherwise clear the totalActiveTime (so we start counting + // from zero again) + var inputCallback = function (ipMsg) { + if (String(ipMsg.topic).search(/load/i) < 0 || isFinite(ipMsg.payload) == false) { + node.totalActiveTime = 0; + } else { + node.totalActiveTime = Number(ipMsg.payload); + } + if (node.currentState === node.activeState) { + node.lastActiveTime = Date.now(); + } + // On startup, send an initial activeTime message, but only send an + // initial currentState message if we are in both edges active mode + if (node.starting) { + node.starting = false; + var msg; + if (node.activeEdges[0] && node.activeEdges[1]) { + msg = [{topic:node.topic}, {topic:node.topic}]; + msg[0].payload = node.currentState; + } else { + msg = [null, {topic:node.topic}]; + } + msg[1].payload = node.totalActiveTime; + node.send(msg); + } + }; + + // If we have a valid pin, set it as an input and read the (digital) state + if (["P8_7", "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15", + "P8_16", "P8_17", "P8_18", "P8_19", "P8_26", "P9_11", "P9_12", "P9_13", "P9_14", + "P9_15", "P9_16", "P9_17", "P9_18", "P9_21", "P9_22", "P9_23", "P9_24", "P9_26", + "P9_27", "P9_30", "P9_41", "P9_42"].indexOf(node.pin) >= 0) { + // Don't set up interrupts & intervals until after the close event handler has been installed + bonescript.detachInterrupt(node.pin); + process.nextTick(function () { + bonescript.pinMode(node.pin, bonescript.INPUT); + bonescript.digitalRead(node.pin, function (x) { + // Initialise the currentState and lastActveTime variables based on the value read + node.currentState = Number(x.value); + if (node.currentState === node.activeState) { + node.lastActiveTime = Date.now(); + // switch to process.hrtime() + } + // Attempt to attach a change-of-state interrupt handler to the pin. If we succeed, + // set the input event and interval handlers, then send an initial message with the + // pin state on the first output + if (bonescript.attachInterrupt(node.pin, true, bonescript.CHANGE, interruptCallback)) { + node.interruptAttached = true; + node.on("input", inputCallback); + node.intervalId = setInterval(timerCallback, node.updateInterval); + } else { + node.error("Failed to attach interrupt"); + } + setTimeout(function () { node.emit("input", {}); }, 50); + }); + }); + } else { + node.error("Unconfigured input pin"); + } +} + +// Node constructor for bbb-pulse-in +function PulseInputNode(n) { + RED.nodes.createNode(this, n); + + // Store local copies of the node configuration (as defined in the .html) + this.topic = n.topic; // the topic is not currently used + this.pin = n.pin; // The Beaglebone Black pin identifying string + this.updateInterval = n.updateInterval * 1000; // How often to send output messages + this.countType = n.countType; // Sets either 'edge' or 'pulse' counting + this.countUnit = n.countUnit; // Scaling appling to count output + this.countRate = n.countRate; // Scaling applied to rate output + + // Working variables + this.interruptAttached = false; // Flag: should we detach interrupt when we are closed? + this.intervalId = null; // Remember the timer ID so we can delete it when we are closed + this.pulseCount = 0; // (Unscaled) total pulse count + // Hold the hrtime of the last two pulses (with ns resolution) + this.pulseTime = [[NaN, NaN], [NaN, NaN]]; + + // Define 'node' to allow us to access 'this' from within callbacks + var node = this; + + // Called by the edge or pulse interrupt. If this is a valid interrupt, record the + // pulse time and count the pulse + var interruptCallback = function (x) { + if (x.value !== undefined) { + node.pulseTime = [node.pulseTime[1], process.hrtime()]; + node.pulseCount = node.pulseCount + 1; + } + }; + + // Called when an input message arrives. If the topic contains 'load' (case + // insensitive) and the payload is a valid number, set the count to that + // number, otherwise set it to zero + var inputCallback = function (msg) { + if (String(msg.topic).search(/load/i) < 0 || isFinite(msg.payload) == false) { + node.pulseCount = 0; + } else { + node.pulseCount = Number(msg.payload); + } + }; + + // Called by the message timer. Send two messages: the scaled pulse count on + // the first output and the scaled instantaneous pulse rate on the second. + // The instantaneous pulse rate is the reciprocal of the larger of either the + // time interval between the last two pulses, or the time interval since the last pulse. + var timerCallback = function () { + var now = process.hrtime(); + var lastTime = node.pulseTime[1][0] - node.pulseTime[0][0] + (node.pulseTime[1][1] - node.pulseTime[0][1]) / 1e9; + var thisTime = now[0] - node.pulseTime[1][0] + (now[1] - node.pulseTime[1][1]) / 1e9; + var msg = [{ topic:node.topic }, { topic:node.topic }]; + msg[0].payload = node.countUnit * node.pulseCount; + // At startup, pulseTime contains NaN's: force the rate output to 0 + msg[1].payload = node.countRate / Math.max(thisTime, lastTime) || 0; + node.send(msg); + }; + + // If we have a valid pin, set it as an input and read the (digital) state + if (["P8_7", "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15", + "P8_16", "P8_17", "P8_18", "P8_19", "P8_26", "P9_11", "P9_12", "P9_13", "P9_14", + "P9_15", "P9_16", "P9_17", "P9_18", "P9_21", "P9_22", "P9_23", "P9_24", "P9_26", + "P9_27", "P9_30", "P9_41", "P9_42"].indexOf(node.pin) >= 0) { + // Don't set up interrupts & intervals until after the close event handler has been installed + bonescript.detachInterrupt(node.pin); + process.nextTick(function () { + bonescript.pinMode(node.pin, bonescript.INPUT); + bonescript.digitalRead(node.pin, function (x) { + // Initialise the currentState based on the value read + node.currentState = Number(x.value); + // Attempt to attach an interrupt handler to the pin. If we succeed, + // set the input event and interval handlers + var interruptType; + if (node.countType === "pulse") { + // interruptType = bonescript.FALLING; <- doesn't work in v0.2.4 + interruptType = bonescript.RISING; + } else { + interruptType = bonescript.CHANGE; + } + if (bonescript.attachInterrupt(node.pin, true, interruptType, interruptCallback)) { + node.interruptAttached = true; + node.on("input", inputCallback); + node.intervalId = setInterval(timerCallback, node.updateInterval); + } else { + node.error("Failed to attach interrupt"); + } + }); + }); + } else { + node.error("Unconfigured input pin"); + } +} + +// Node constructor for bbb-discrete-out +function DiscreteOutputNode(n) { + RED.nodes.createNode(this, n); + + // Store local copies of the node configuration (as defined in the .html) + this.topic = n.topic; // the topic is not currently used + this.pin = n.pin; // The Beaglebone Black pin identifying string + this.defaultState = Number(n.defaultState); // What state to set up as + this.inverting = n.inverting; + this.toggle = n.toggle; + + // Working variables + this.currentState = this.defaultState; + + var node = this; + + // If the input message paylod is numeric, values > 0.5 are 'true', otherwise use + // the truthiness of the payload. Apply the inversion flag before setting the output + var inputCallback = function (msg) { + var newState; + if (node.toggle) { + newState = node.currentState === 0 ? 1 : 0; + } else { + if (isFinite(Number(msg.payload))) { + newState = Number(msg.payload) > 0.5 ? true : false; + } else if (msg.payload) { + newState = true; + } else { + newState = false; + } + if (node.inverting) { + newState = !newState; + } + } + bonescript.digitalWrite(node.pin, newState ? 1 : 0); + node.send({ topic:node.topic, payload:newState }); + node.currentState = newState; + }; + + // If we have a valid pin, set it as an output and set the default state + if (["P8_7", "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15", + "P8_16", "P8_17", "P8_18", "P8_19", "P8_26", "P9_11", "P9_12", "P9_13", "P9_14", + "P9_15", "P9_16", "P9_17", "P9_18", "P9_21", "P9_22", "P9_23", "P9_24", "P9_26", + "P9_27", "P9_30", "P9_41", "P9_42", "USR0", "USR1", "USR2", "USR3"].indexOf(node.pin) >= 0) { + // Don't set up interrupts & intervals until after the close event handler has been installed + bonescript.detachInterrupt(node.pin); + process.nextTick(function () { + bonescript.pinMode(node.pin, bonescript.OUTPUT); + node.on("input", inputCallback); + setTimeout(function () { bonescript.digitalWrite(node.pin, node.defaultState); }, 50); + }); + } else { + node.error("Unconfigured output pin"); + } +} + +// Node constructor for bbb-pulse-out +function PulseOutputNode(n) { + RED.nodes.createNode(this, n); + + // Store local copies of the node configuration (as defined in the .html) + this.topic = n.topic; // the topic is not currently used + this.pin = n.pin; // The Beaglebone Black pin identifying string + this.pulseState = Number(n.pulseState); // What state the pulse will be.. + this.defaultState = this.pulseState === 1 ? 0 : 1; + this.retriggerable = n.retriggerable; + this.pulseTime = n.pulseTime * 1000; // Pulse width in milliseconds + + // Working variables + this.pulseTimer = null; // Non-null while a pulse is being generated + + var node = this; + + // Generate a pulse in response to an input message. If the topic includes the text + // 'time' (case insensitive) and the payload is numeric, use this value as the + // pulse time. Otherwise use the value from the properties dialog. + // If the resulting pulse time is < 1ms, do nothing. + // If the pulse mode is not retriggerable, then if no pulseTimer is active, generate + // a pulse. If the pulse mode is retriggerable, and a pulseTimer is active, cancel it. + // If no timer is active, set the pulse output. In both cases schedule a new pulse + // timer. + var inputCallback = function (msg) { + var time = node.pulseTime; + if (String(msg.topic).search(/time/i) >= 0 && isFinite(msg.payload)) { + time = msg.payload * 1000; + } + if (time >= 1) { + if (node.retriggerable === false) { + if (node.pulseTimer === null) { + node.pulseTimer = setTimeout(endPulseCallback, time); + bonescript.digitalWrite(node.pin, node.pulseState); + node.send({ topic:node.topic, payload:node.pulseState }); + } + } else { + if (node.pulseTimer !== null) { + clearTimeout(node.pulseTimer); + } else { + bonescript.digitalWrite(node.pin, node.pulseState); + node.send({ topic:node.topic, payload:node.pulseState }); + } + node.pulseTimer = setTimeout(endPulseCallback, time); + } + } + }; + + // At the end of the pulse, restore the default state and set the timer to null + var endPulseCallback = function () { + node.pulseTimer = null; + bonescript.digitalWrite(node.pin, node.defaultState); + node.send({ topic:node.topic, payload:node.defaultState }); + }; + + // If we have a valid pin, set it as an output and set the default state + if (["P8_7", "P8_8", "P8_9", "P8_10", "P8_11", "P8_12", "P8_13", "P8_14", "P8_15", + "P8_16", "P8_17", "P8_18", "P8_19", "P8_26", "P9_11", "P9_12", "P9_13", "P9_14", + "P9_15", "P9_16", "P9_17", "P9_18", "P9_21", "P9_22", "P9_23", "P9_24", "P9_26", + "P9_27", "P9_30", "P9_41", "P9_42", "USR0", "USR1", "USR2", "USR3"].indexOf(node.pin) >= 0) { + // Don't set up interrupts & intervals until after the close event handler has been installed + bonescript.detachInterrupt(node.pin); + process.nextTick(function () { + bonescript.pinMode(node.pin, bonescript.OUTPUT); + node.on("input", inputCallback); + // Set the pin to the default stte once the dust settles + setTimeout(endPulseCallback, 50); + }); + } else { + node.error("Unconfigured output pin"); + } +} + +// Register the nodes by name. This must be called before overriding any of the Node functions. +RED.nodes.registerType("bbb-analogue-in", AnalogueInputNode); +RED.nodes.registerType("bbb-discrete-in", DiscreteInputNode); +RED.nodes.registerType("bbb-pulse-in", PulseInputNode); +RED.nodes.registerType("bbb-discrete-out", DiscreteOutputNode); +RED.nodes.registerType("bbb-pulse-out", PulseOutputNode); + +// On close, detach the interrupt (if we attached one) and clear any active timers +DiscreteInputNode.prototype.close = function () { + if (this.interruptAttached) { + bonescript.detachInterrupt(this.pin); + } + if (this.intervalId !== null) { + clearInterval(this.intervalId); + } + if (this.debounceTimer !== null) { + clearTimeout(this.debounceTimer); + } +}; + +// On close, detach the interrupt (if we attached one) and clear the interval (if we set one) +PulseInputNode.prototype.close = function () { + if (this.interruptAttached) { + bonescript.detachInterrupt(this.pin); + } + if (this.intervalId !== null) { + clearInterval(this.intervalId); + } +}; + +// On close, clear an active pulse timer +PulseOutputNode.prototype.close = function () { + if (this.pulseTimer !== null) { + clearTimeout(this.pulseTimer); + } +}; diff --git a/hardware/BBB/icons/BBB.png b/hardware/BBB/icons/BBB.png new file mode 100644 index 0000000000000000000000000000000000000000..0f2287741bb9458d83a489a139bde0d549fa2fd8 GIT binary patch literal 719 zcmV;=0xpHaY;l$R9HvNm@Q8nQ51#;0@+mH5#TUw zn$YUqAjsBK)m2nfU}`Y@g82dc0ho#v2pkH-20<3xuA!-^X$8KDkTiXF-pk=|KhC`~ zyQDms%$~WKnP<JF+ZbOYv% zbeS<5v*a^2z?Z1&8Ufv~;&3<|mLzTUv6rp@0Xmyjin%{Ke6KUMJG;AB3d<44q&56D zDSc9$vJ$%8K|?4eDg9i1ETpV}Vx-}9{EGXW1H%d+rn`ynQ;(P0t}|h^vsM?~A>uBj z{(AM>MLDz>)67K;t;OY5(o}lJU@&k^4ei996*J03CeB>fdTh54i}m%34F&*u@>+QE}6s&oSy$ms0spPt$N8g)I$1aKuC|c|3sm|D1xqzn+l|+k))=RqD9WS*^ zcASR|K5kH!SiuAF^wdR)NXD?vdgg8{*mIgzbSDqT<1qt4ZXz*hw{k_31Dq-tX#I6I z%sNGDbWDB>2^sO@5f@9f z$+MUHF3KVE3fR@QGS=>elN5(DZ?RYzdj%)Dm?Uf=-WuZZ#0D4XJc&z4is!d>8P$u* z)o?GkkMWo)ob>shFuaj|N7N5_; Name
-
Expects a msg.payload with three part csv string of r,g,b.
@@ -85,6 +97,7 @@ defaults: { // defines the editable properties of the node name: {value:"sensorTag"}, // along with default values. topic: {value:"sensorTag"}, + uuid: {value:undefined}, temperature: {value:true}, humidity: {value:true}, pressure: {value:true}, @@ -101,6 +114,17 @@ }, labelStyle: function() { // sets the class to apply to the label return this.name?"node_label_italic":""; + }, + oneditsave: function() { + var mac = $("#node-input-uuid").val(); + mac = mac.toLowerCase(); + //nasty hack as I can't get global replace to work + mac = mac.replace(/:/gi,''); + mac = mac.replace(/:/gi,''); + mac = mac.replace(/:/gi,''); + mac = mac.replace(/:/gi,''); + mac = mac.toLowerCase(); + $("#node-input-uuid").val(mac); } }); diff --git a/hardware/sensorTag/79-sensorTag.js b/hardware/sensorTag/79-sensorTag.js index c12529831..b63a6eba0 100644 --- a/hardware/sensorTag/79-sensorTag.js +++ b/hardware/sensorTag/79-sensorTag.js @@ -17,14 +17,13 @@ // Require main module var RED = require(process.env.NODE_RED_HOME+"/red/red"); var SensorTag = require('sensortag'); -var stag; -var node; // The main node definition - most things happen in here function sensorTagNode(n) { RED.nodes.createNode(this,n); this.name = n.name; this.topic = n.topic; + this.uuid = n.uuid; this.temperature = n.temperature; this.pressure = n.pressure; this.humidity = n.humidity; @@ -32,19 +31,25 @@ function sensorTagNode(n) { this.magnetometer = n.magnetometer; this.gyroscope = n.gyroscope; this.keys = n.keys; - node=this; - if ( typeof stag == "undefined") { + if (this.uuid === "") { + this.uuid = undefined; + } + //console.log(this.uuid); + + var node=this; + + if ( typeof node.stag == "undefined") { //console.log("starting"); SensorTag.discover(function(sensorTag){ - stag = sensorTag; + node.stag = sensorTag; sensorTag.connect(function(){ //console.log("connected"); sensorTag.discoverServicesAndCharacteristics(function(){ sensorTag.enableIrTemperature(function(){}); sensorTag.on('irTemperatureChange', function(objectTemperature, ambientTemperature){ - var msg = {'topic': node.topic + '/tempature'}; + var msg = {'topic': node.topic + '/temperature'}; msg.payload = {'object': objectTemperature.toFixed(1), 'ambient':ambientTemperature.toFixed(1) }; @@ -87,51 +92,51 @@ function sensorTagNode(n) { msg.payload = {'left': left, 'right': right}; node.send(msg); }); - enable(); + enable(node); }); }); - }); + },node.uuid); } else { //console.log("reconfig"); - enable(); + enable(node); } } -function enable() { - if (node.temperature) { - stag.notifyIrTemperature(function(){}); - } else { - stag.unnotifyIrTemperature(function(){}); - } - if (node.pressure) { - stag.notifyBarometricPressure(function(){}); - } else { - stag.unnotifyBarometricPressure(function(){}); - } - if (node.humidity) { - stag.notifyHumidity(function() {}); - } else { - stag.unnotifyHumidity(function() {}); - } - if (node.accelometer){ - stag.notifyAccelerometer(function() {}); - } else { - stag.unnotifyAccelerometer(function() {}); - } - if (node.magnetometer) { - stag.notifyMagnetometer(function() {}); - } else { - stag.unnotifyMagnetometer(function() {}); - } - if (node.gyroscope) { - stag.notifyGyroscope(function() {}); - } else { - stag.unnotifyGyroscope(function() {}); - } - if (node.keys) { - stag.notifySimpleKey(function() {}); - } else { - stag.unnotifySimpleKey(function() {}); - } +function enable(node) { + if (node.temperature) { + node.stag.notifyIrTemperature(function(){}); + } else { + node.stag.unnotifyIrTemperature(function(){}); + } + if (node.pressure) { + node.stag.notifyBarometricPressure(function(){}); + } else { + node.stag.unnotifyBarometricPressure(function(){}); + } + if (node.humidity) { + node.stag.notifyHumidity(function() {}); + } else { + node.stag.unnotifyHumidity(function() {}); + } + if (node.accelometer){ + node.stag.notifyAccelerometer(function() {}); + } else { + node.stag.unnotifyAccelerometer(function() {}); + } + if (node.magnetometer) { + node.stag.notifyMagnetometer(function() {}); + } else { + node.stag.unnotifyMagnetometer(function() {}); + } + if (node.gyroscope) { + node.stag.notifyGyroscope(function() {}); + } else { + node.stag.unnotifyGyroscope(function() {}); + } + if (node.keys) { + node.stag.notifySimpleKey(function() {}); + } else { + node.stag.unnotifySimpleKey(function() {}); + } } RED.nodes.registerType("sensorTag",sensorTagNode); diff --git a/hardware/sensorTag/README b/hardware/sensorTag/README index b524fc690..2d6657ab4 100644 --- a/hardware/sensorTag/README +++ b/hardware/sensorTag/README @@ -1,5 +1,5 @@ -This currently requires a slightly modified sensortag library +This currently requires the sensortag library To install use the following command in the Node-Red directory -npm install sensortag@https://api.github.com/repos/hardillb/node-sensortag/tarball +npm install sensortag diff --git a/io/emoncms/88-emoncms.html b/io/emoncms/88-emoncms.html new file mode 100644 index 000000000..8f20f07eb --- /dev/null +++ b/io/emoncms/88-emoncms.html @@ -0,0 +1,120 @@ + + + + + + + + + + + diff --git a/io/emoncms/88-emoncms.js b/io/emoncms/88-emoncms.js new file mode 100644 index 000000000..4138b0bc2 --- /dev/null +++ b/io/emoncms/88-emoncms.js @@ -0,0 +1,111 @@ +/** + * Copyright 2013 Henrik Olsson henols@gmail.com + * + * 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"); +//The Server Definition - this opens (and closes) the connection +function EmoncmsServerNode(n) { + RED.nodes.createNode(this,n); + this.server = n.server; + this.name = n.name; + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.apikey = credentials.apikey; + } + +} +RED.nodes.registerType("emoncms-server",EmoncmsServerNode); + +var querystring = require('querystring'); + +RED.httpAdmin.get('/emoncms-server/:id',function(req,res) { + var credentials = RED.nodes.getCredentials(req.params.id); + if (credentials) { + res.send(JSON.stringify({apikey:credentials.apikey})); + } else { + res.send(JSON.stringify({})); + } +}); + +RED.httpAdmin.delete('/emoncms-server/:id',function(req,res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.httpAdmin.post('/emoncms-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.apikey == null || newCreds.apikey == "") { + delete credentials.apikey; + } else { + credentials.apikey = newCreds.apikey; + } + RED.nodes.addCredentials(req.params.id,credentials); + res.send(200); + }); +}); + +function Emoncms(n) { + RED.nodes.createNode(this,n); + this.emonServer = n.emonServer; + var sc = RED.nodes.getNode(this.emonServer); + + this.baseurl = sc.server; + this.apikey = sc.apikey; + + this.topic = n.topic ||""; + this.nodegroup = n.nodegroup || ""; + var node = this; + if (this.baseurl.substring(0,5) === "https") { var http = require("https"); } + else { var http = require("http"); } + this.on("input", function(msg) { + + var topic = this.topic || msg.topic; + var nodegroup = this.nodegroup || msg.nodegroup; + this.url = this.baseurl + '/input/post.json?json={' + topic + ':' + msg.payload+'}&apikey='+this.apikey; + if(nodegroup != ""){ + this.url += '&node='+nodegroup; + } + node.log("[emoncms] "+this.url); + http.get(this.url, 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("emoncms",Emoncms); diff --git a/io/emoncms/icons/emoncms-logo.png b/io/emoncms/icons/emoncms-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8cde78715855be139d55b070f2f3bd97fb28b410 GIT binary patch literal 1418 zcmV;51$Fv~P)(^b8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H11qVq)K~zYIwU$e4RM#DczjN+$#$(SbeheOi85@%{kPzA;<4`M2 zLVyTxB1KLXRg>-#q;9fFltr3dqApr>m#S)|c2iYiL#%cMrFEJ(AvPG8$k>R7J=haG zhVi@~_i?(gu^^&Rk;0LFyL-M*_kSM$Ba~7+%po5t{XqpIBO|S&qobh*nIpcdL`RMs z=@vq~0X%CM=C(*AY%8V6=kqn!^)4&r|5FI@=drP|#RnD~K7908TU+b<0|VPT13??7 z=}@g!5mM3;45H~em2z3l&dx4ZtCbJN#>PJWzXT&ABb$8RKb}gZcE;oJ(Cpl0BH=LI z$s~zH0;S;QH(72hE>bKM8Q4BRHk&Oi%wJDyn)b?x6DOAbr(kq+)T}oeGf(V%GF2!R zP`+aDg`-^cqTKXas0)j~U4gjXU{|QZv(ekk{p%A<)4&b{RXTlPu3ReZIDPuGdxv?? zB9}^~-}I&Wx)+xg+5UsaNId^@PC0#Kv@YC06eG}ruv@q#Bb+RE@$S`rZa(!oTlxmL zefyT!vZZ&kZQCE-&D;#$p6)I}mJX`NhG52cNv(AN--St1F&cS)p(5K~_W*!?Mv$8_l$khKV#R zl)e^WSV+S{nl{tb2+eKJkj-XECVS#asgLgw2qA=F7@hTco#CJC!)lH4;#Qqq?GmXQ z2+aV^0IA~&9Zwqg(g4lm3F{W!xv%*9`6Y&)9>R4TG+pn$N3ehY{(fCIbkB9^O!hMM z=}Ep>%Fq+Gc_}664-1r#ctX-t5*JCzEb`du8Pe%AOT{J&MHefYz;#_r!!!>ZIItB! z2XGu`k71Z$$7v!$F#;{E{PoxG&>DS&y)TZk>!*i#Jg)KCP3Y2UY$>KWcQuQKLJA2& zB7|h7AgI-9n5Gpj6jt{D*K`0W<)eThghT?54?Ra}=MOplyI-;V^#o(*|APp$k=oqD z&=;R`#R;Rw_MoiR_07H(UkRiX0Jad?_Kgy`t~*hwlq5J%?0@@7+UDv5Msud~aJCt zc^;akF+Dwa%FE7tktJRmY+3e5y`}^aXrlFK# zCAYks&1T=e!xc&?gb*5F?%uuo)kq}z+qSkgb7duWZGL|KtxP791GM#s_4A_u5Ac%7 zWM^-0@9#T0I(qV}g?eE%f9&kpv!4J>rIdHiZ7PH?1_y`!t<807*qoM6N<$f*O9OkpKVy literal 0 HcmV?d00001 diff --git a/io/emoncms/icons/emoncms.png b/io/emoncms/icons/emoncms.png new file mode 100644 index 0000000000000000000000000000000000000000..a3abe7d2b528b5066a0e04c333a75b05e1b587de GIT binary patch literal 933 zcmV;W16urvP)Px#0%A)?L;(MXkIcUS000SaNLh0L019CM019CN{LD%v00007bV*G`2i^h*78DT& zA%qnG00SvWL_t(Y$L-b4Yn??D2Jqj!H(%EzCb>3^8XMCOgVb6}KLkY)v|U()wun1d zf-VXbL3HE7MgM@V+_(`GL=bB2rdZUCLe+v+V{NFmX+uA3yvJ{>QIqO%e~@4?FHgWIlog*TS{Md#=K>KGJ2s9f(VA)+@j>IO~L}N9)RS%a3HrxO<1Z zE*A>{LNtSp_7$gnINTSL&<)p35<{K*gQE`88yZgiY}mLK{f69hRnBHxb4g(_`;R%@ zP>xOEO#H-?9?^`OzW0?=O4<}`cink8Py5s33Ya(S(=Z&H!a^X15M!Uc-qmZuNk`0T z(j*`gupra!O?%w!hIf1!iZO(^REA=&Bl3>a=)@&CX-R - - diff --git a/social/pushbullet/57-pushbullet.js b/social/pushbullet/57-pushbullet.js index 75f774afd..a172490dd 100644 --- a/social/pushbullet/57-pushbullet.js +++ b/social/pushbullet/57-pushbullet.js @@ -24,41 +24,43 @@ var util = require('util'); // module.exports = {pushbullet:'My-API-KEY', deviceid:'12345'} try { - var pushkey = require(process.env.NODE_RED_HOME+"/settings").pushbullet || require(process.env.NODE_RED_HOME+"/../pushkey.js"); + 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"); + util.log("[57-pushbullet.js] Error: Failed to load PushBullet credentials"); } if (pushkey) { - var pusher = new PushBullet(pushkey.pushbullet); - var deviceId = pushkey.deviceid; + if (pushkey.pushbullet) { var pusher = new PushBullet(pushkey.pushbullet); } + if (pushkey.deviceid) { 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.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); + } + else { msg.payload = msg.payload.toString(); } + if (pushkey.pushbullet && pushkey.deviceid) { + try { + if (!isNaN(deviceId)) { deviceId = Number(deviceId); } + pusher.note(deviceId, titl, msg.payload, function(err, response) { + if (err) node.error("Pushbullet 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/snapchat/79-snapchat.html b/social/snapchat/79-snapchat.html new file mode 100644 index 000000000..f1fb9a746 --- /dev/null +++ b/social/snapchat/79-snapchat.html @@ -0,0 +1,53 @@ + + + diff --git a/social/snapchat/79-snapchat.js b/social/snapchat/79-snapchat.js new file mode 100644 index 000000000..f58295da8 --- /dev/null +++ b/social/snapchat/79-snapchat.js @@ -0,0 +1,68 @@ +// Require main module +var RED = require(process.env.NODE_RED_HOME+"/red/red"); +var snapchat = require('snapchat'), +client = new snapchat.Client(), +fs = require('fs'); + + + +function SnapChatAccountNode(n) { +RED.nodes.createNode(this,n); +this.username = n.username; +this.password = n.password; +} + + + +function SnapChatNode(n) { + // Create a RED node +RED.nodes.createNode(this,n); +var node = this; + +this.account = n.account; +this.path = n.path; +this.accountConfig = RED.nodes.getNode(this.account); +this.username = this.accountConfig.username; +this.password = this.accountConfig.password; + + +this.on("input",function(){ + +// Make sure the images folder exists +if(!fs.existsSync(this.path)) { + fs.mkdirSync(this.path); +} + +var path = this.path; +var msg ={}; +msg.snaps =[]; +client.login(this.username, this.password).then(function(data){ +msg.payload = data.snaps.length; +data.snaps.forEach(function(snap){ + if (snap.st == 1 && typeof snap.t !== 'undefined') + { + var full_path = path + snap.id + '.jpg'; + var snapObject = {Sender:snap.sn,Path:full_path,SnapId:snap.id}; + msg.snaps.push(snapObject); + + var stream = fs.createWriteStream(full_path, { flags: 'w', encoding: null, mode: 0666}); + client.getBlob(snap.id).then(function(blob){ + blob.pipe(stream); + blob.resume(); + }); + } + +}); +client.clear(); +node.send(msg); + +}); + +}); + +} + +// Register the node by name. This must be called before overriding any of the +// Node functions. +RED.nodes.registerType("Snap Chat",SnapChatNode); +RED.nodes.registerType("snapchat-account",SnapChatAccountNode); diff --git a/social/twilio/56-twilio.html b/social/twilio/56-twilio.html new file mode 100644 index 000000000..c73769bfa --- /dev/null +++ b/social/twilio/56-twilio.html @@ -0,0 +1,59 @@ + + + + + + + diff --git a/social/twilio/56-twilio.js b/social/twilio/56-twilio.js new file mode 100644 index 000000000..8aca55ffd --- /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.number = n.number; + var node = this; + this.on("input",function(msg) { + if (typeof(msg.payload) == 'object') { + msg.payload = JSON.stringify(msg.payload); + } + if (twiliokey) { + try { + // Send SMS + var tonum = node.number || msg.topic; + twilioClient.sendMessage( {to: tonum, 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 0000000000000000000000000000000000000000..ada41a2c82da6070a988e017f6cf691349ccd0cb GIT binary patch literal 553 zcmV+^0@nSBP)Px#kWfriMgRT%|NsB|{QUm@{{8*^{pIHV`uhFq>;Cxo{paZa{QUg={r&6g{pRQY z{{H{`{r>v*1WyH{psrd^7Hxm z`Q_&3!^Fn$@bUie@zd1R&tO_1oOt+}z#%@9+Qr|KWAa zKL7v#0d!JMQvg8b*k%9#00Cl4M??UK1szBL000SaNLh0L01FcU01FcV0GgZ_00007 zbV*G`2i^h*79%PqEzJc0009L_L_t(I%k7lg3c@f9K-;wH+!PT-6eEZzBKrT|XV+`m zr4HYhmp18HnoBbwCb1%ui~==G$}vdtQbCkfii4sFoYAZ$<~%%f)od1WdcGN zH!IRFkyq74-yTv069dfq!Qv&<-yvz#z*F{~1v{6TAD+;PkXmI3r3QemGV+yq|Gc)( rvH!;HjHjQTjB$6pKmPoWO~T0+XuAl}juI<800000NkvXXu0mjfHXbCq literal 0 HcmV?d00001 diff --git a/social/xmpp/92-xmpp.html b/social/xmpp/92-xmpp.html index daaa27155..b16f4c5a5 100644 --- a/social/xmpp/92-xmpp.html +++ b/social/xmpp/92-xmpp.html @@ -47,11 +47,17 @@ + + + + diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js new file mode 100644 index 000000000..939d7d23d --- /dev/null +++ b/storage/ddb/69-ddbout.js @@ -0,0 +1,44 @@ +/** + * Copyright 2013 Wolfgang Nagele + * + * 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 aws = require("aws-sdk"); +var attrWrapper = require("dynamodb-data-types").AttributeValue; + +function DDBOutNode(n) { + RED.nodes.createNode(this, n); + this.credentials = RED.nodes.getNode(n.credentials); + this.region = n.region || "us-east-1"; + this.table = n.table; + + aws.config.update({ accessKeyId: this.credentials.accessKey, + secretAccessKey: this.credentials.secretAccessKey, + region: this.region }); + + var ddb = new aws.DynamoDB(); + + this.on("input", function(msg) { + if (msg != null) { + ddb.putItem({ "TableName": this.table, + "Item": attrWrapper.wrap(msg.payload) }, + function(err, data) { + err && util.log(err); + }); + } + }); +} +RED.nodes.registerType("ddb out", DDBOutNode); diff --git a/storage/ddb/aws.html b/storage/ddb/aws.html new file mode 100644 index 000000000..5c26c9041 --- /dev/null +++ b/storage/ddb/aws.html @@ -0,0 +1,68 @@ + + + + + diff --git a/storage/ddb/aws.js b/storage/ddb/aws.js new file mode 100644 index 000000000..58eecc925 --- /dev/null +++ b/storage/ddb/aws.js @@ -0,0 +1,65 @@ +/** + * Copyright 2013 Wolfgang Nagele + * + * 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 querystring = require('querystring'); + +function AWSCredentialsNode(n) { + RED.nodes.createNode(this, n); + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.accessKey = credentials.accessKey; + this.secretAccessKey = credentials.secretAccessKey; + } +} +RED.nodes.registerType("aws credentials", AWSCredentialsNode); + +RED.httpAdmin.get('/aws-credentials/:id', function(req, res) { + var credentials = RED.nodes.getCredentials(req.params.id); + if (credentials) { + res.send(JSON.stringify({ accessKey: credentials.accessKey, secretAccessKey: credentials.secretAccessKey })); + } else { + res.send(JSON.stringify({})); + } +}); + +RED.httpAdmin.delete('/aws-credentials/:id', function(req, res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.httpAdmin.post('/aws-credentials/: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.accessKey == null || newCreds.accessKey == "") { + delete credentials.accessKey; + } else { + credentials.accessKey = newCreds.accessKey || credentials.accessKey; + } + if (newCreds.secretAccessKey == null || newCreds.secretAccessKey == "") { + delete credentials.secretAccessKey; + } else { + credentials.secretAccessKey = newCreds.secretAccessKey || credentials.secretAccessKey; + } + RED.nodes.addCredentials(req.params.id, credentials); + res.send(200); + }); +}); diff --git a/storage/mysql/68-mysql.html b/storage/mysql/68-mysql.html index 11c6fd80d..a68e642b7 100644 --- a/storage/mysql/68-mysql.html +++ b/storage/mysql/68-mysql.html @@ -29,7 +29,7 @@
- +
@@ -43,13 +43,49 @@ defaults: { host: {value:"127.0.0.1",required:true}, port: {value:"3306",required:true}, - user: {value:"",required:true}, - pass: {value:"",required:true}, + //user: {value:"",required:true}, + //pass: {value:"",required:true}, db: {value:"",required:true} }, label: function() { return this.db; + }, + oneditprepare: function() { + $.getJSON('MySQLdatabase/'+this.id,function(data) { + if (data.user) { + $('#node-config-input-user').val(data.user); + } + if (data.hasPassword) { + $('#node-config-input-pass').val('__PWRD__'); + } else { + $('#node-config-input-pass').val(''); + } + + }); + }, + oneditsave: function() { + var newUser = $('#node-config-input-user').val(); + var newPass = $('#node-config-input-pass').val(); + var credentials = {}; + credentials.user = newUser; + if (newPass != '__PWRD__') { + credentials.password = newPass; + } + $.ajax({ + url: 'MySQLdatabase/'+this.id, + type: 'POST', + data: credentials, + success:function(result){} + }); + }, + ondelete: function() { + $.ajax({ + url: 'MySQLdatabase/'+this.id, + type: 'DELETE', + success: function(result) {} + }); } + }); @@ -72,6 +108,8 @@

msg.topic must hold the query for the database, and the result is returned in msg.payload.

Typically the returned payload will be an array of the result rows.

If nothing is found for the key then null is returned,

+

The reconnect timeout in milliseconds can be changed by adding a line to settings.js +

mysqlReconnectTime: 30000,

+ + + + + + + + diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js new file mode 100644 index 000000000..6e6cdc9c7 --- /dev/null +++ b/storage/postgres/110-postgres.js @@ -0,0 +1,123 @@ +/** + * Copyright 2013 Kris Daniels. + * + * 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 pg=require('pg'); +var named=require('node-postgres-named'); +var querystring = require('querystring'); + +RED.httpAdmin.get('/postgresdb/: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('/postgresdb/:id',function(req,res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.httpAdmin.post('/postgresdb/: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 PostgresDatabaseNode(n) { + RED.nodes.createNode(this,n); + this.hostname = n.hostname; + this.port = n.port; + this.db = n.db; + + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.user = credentials.user; + this.password = credentials.password; + } +} + +RED.nodes.registerType("postgresdb",PostgresDatabaseNode); + +function PostgresNode(n) { + RED.nodes.createNode(this,n); + + this.topic = n.topic; + this.postgresdb = n.postgresdb; + this.postgresConfig = RED.nodes.getNode(this.postgresdb); + this.sqlquery = n.sqlquery; + this.output = n.output; + + var node = this; + + if(this.postgresConfig) + { + + var conString = 'postgres://'+this.postgresConfig.user +':' + this.postgresConfig.password + '@' + this.postgresConfig.hostname + ':' + this.postgresConfig.port + '/' + this.postgresConfig.db; + node.clientdb = new pg.Client(conString); + named.patch(node.clientdb); + + node.clientdb.connect(function(err){ + if(err) { node.error(err); } + else { + node.on('input', + function(msg){ + if(!msg.queryParameters) msg.queryParameters={}; + node.clientdb.query(msg.payload, + msg.queryParameters, + function (err, results) { + if(err) { node.error(err); } + else { + if(node.output) + { + msg.payload = results.rows; + node.send(msg); + } + } + }); + }); + } + }); + } else { + this.error("missing postgres configuration"); + } + + this.on("close", function() { + if(node.clientdb) node.clientdb.end(); + }); +} + +RED.nodes.registerType("postgres",PostgresNode); diff --git a/storage/postgres/icons/postgres.png b/storage/postgres/icons/postgres.png new file mode 100644 index 0000000000000000000000000000000000000000..e46c31696bc4e2240ffe3450323e74c6ae0bbe33 GIT binary patch literal 625 zcmV-%0*?KOP)HWn7*8>A2= zPoR*(#?ID4Ng-Z2`D|v#*^}9G_Q^$X!NAO#%Ubi#|Ib1tYvF+7Tk2bNTU{%hi%RaO z+0u;pmE@e8iN6ygs6-Pu4SWN3*>3`iz|YLz01Lo(U>VqnYtwxb;8(jiL}viLR)SqD z1S78h0gQn!z`a63fA^_p)z^KPtEWoPRNA)M6#TZ38nckHwYMK?4KOY25eQ8(I4au( z9s{?_>Cc9%ou8YeFVsS8^B56MPbce|0o0Y21)zP49ZV{twXZ5lU%F6 zJHXY#;uYZ09EXQYVxc4p3Xj~jvHH0{@5uleslHJ!m#W36qDQlmG~}C8-7M_g)8Q0& z3as_KWBZ|>2c8dv_gehW?Sr&0d(}_s{jC1=-ELH=nfn4h$;NjxSWG^E8l+1-g}qaN z`?N%Xbv4~C#$ue>0`QxNagEwd@_w%dR+aT6nOr8t8`f+T2{!M~)G3zp*z~Z)vf&@w ze-m)ypaJJ4O^qDmNd0h}kP55 0) & (e2 < 0)) { msg.payload = 1; } if (oldval == null) { oldval = msg.payload; }