From 8a8b9bf7d82c0c4c375f0125922b6e9ab5b7ca3f Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Mon, 9 Dec 2013 21:45:15 +1100 Subject: [PATCH 01/24] Implementation for Amazon DynamoDB --- README.md | 2 ++ storage/ddb/69-ddbout.html | 72 ++++++++++++++++++++++++++++++++++++++ storage/ddb/69-ddbout.js | 45 ++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 storage/ddb/69-ddbout.html create mode 100644 storage/ddb/69-ddbout.js diff --git a/README.md b/README.md index 5c150f4c..fa93915e 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,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/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html new file mode 100644 index 00000000..70235393 --- /dev/null +++ b/storage/ddb/69-ddbout.html @@ -0,0 +1,72 @@ + + + + + + + diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js new file mode 100644 index 00000000..8f51576b --- /dev/null +++ b/storage/ddb/69-ddbout.js @@ -0,0 +1,45 @@ +/** + * 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.accessKey = n.accessKey; + this.secretAccessKey = n.secretAccessKey; + this.region = n.region || "us-east-1"; + this.table = n.table; + + aws.config.update({ accessKeyId: this.accessKey, + secretAccessKey: this.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); From 17a040adfe3103200da5b2336584683401a35a57 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Thu, 19 Dec 2013 13:07:40 +1100 Subject: [PATCH 02/24] Support external credentials Add base node with credentials --- storage/ddb/69-ddbout.html | 65 +++++++++++++++++++++++++++++++++----- storage/ddb/69-ddbout.js | 55 +++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 12 deletions(-) diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index 70235393..33b5463e 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -16,12 +16,8 @@ + + + + diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js index 8f51576b..8cf0d753 100644 --- a/storage/ddb/69-ddbout.js +++ b/storage/ddb/69-ddbout.js @@ -16,18 +16,65 @@ var RED = require(process.env.NODE_RED_HOME+"/red/red"); var util = require("util"); +var querystring = require('querystring'); var aws = require("aws-sdk"); var attrWrapper = require("dynamodb-data-types").AttributeValue; +function DDBNode(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("awscredentials", DDBNode); + +RED.app.get('/awscredentials/: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.app.delete('/awscredentials/:id', function(req, res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.app.post('/awscredentials/: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); + }); +}); + function DDBOutNode(n) { RED.nodes.createNode(this, n); - this.accessKey = n.accessKey; - this.secretAccessKey = n.secretAccessKey; + this.credentials = RED.nodes.getNode(n.credentials); this.region = n.region || "us-east-1"; this.table = n.table; - aws.config.update({ accessKeyId: this.accessKey, - secretAccessKey: this.secretAccessKey, + aws.config.update({ accessKeyId: this.credentials.accessKey, + secretAccessKey: this.credentials.secretAccessKey, region: this.region }); var ddb = new aws.DynamoDB(); From fe109f15d84f3627b3c9867afdedc6de9351941a Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Fri, 20 Dec 2013 10:00:35 +0100 Subject: [PATCH 03/24] added postgres node --- storage/postgres/110-postgresout.html | 148 ++++++++++++++++++++++++++ storage/postgres/110-postgresout.js | 83 +++++++++++++++ storage/postgres/icons/postgres.png | Bin 0 -> 625 bytes 3 files changed, 231 insertions(+) create mode 100644 storage/postgres/110-postgresout.html create mode 100644 storage/postgres/110-postgresout.js create mode 100644 storage/postgres/icons/postgres.png diff --git a/storage/postgres/110-postgresout.html b/storage/postgres/110-postgresout.html new file mode 100644 index 00000000..ab3291cc --- /dev/null +++ b/storage/postgres/110-postgresout.html @@ -0,0 +1,148 @@ + + + + + + + + + + + diff --git a/storage/postgres/110-postgresout.js b/storage/postgres/110-postgresout.js new file mode 100644 index 00000000..bf882b6a --- /dev/null +++ b/storage/postgres/110-postgresout.js @@ -0,0 +1,83 @@ +/** + * 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"); +var pg=require('pg'); +var named=require('node-postgres-named'); + +function PostgresDatabaseNode(n) { + RED.nodes.createNode(this,n); + this.hostname = n.hostname; + this.port = n.port; + this.db = n.db; + this.username = n.username; + this.password = n.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.outputs = n.outputs; + + var node = this; + if(this.postgresConfig) + { + + var conString = 'postgres://'+this.postgresConfig.username +':' + 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){ + node.clientdb.query(node.sqlquery, + msg.payload, + function (err, results) { + if(err) { node.error(err); } + else { + if(node.outputs>0) + { + 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 Date: Fri, 20 Dec 2013 10:18:22 +0100 Subject: [PATCH 04/24] added examples to node documentation --- storage/postgres/110-postgresout.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/storage/postgres/110-postgresout.html b/storage/postgres/110-postgresout.html index ab3291cc..4e984f5a 100644 --- a/storage/postgres/110-postgresout.html +++ b/storage/postgres/110-postgresout.html @@ -78,6 +78,16 @@

This node can be used to write and read from a Postgres database

To receive the results from a query, simply set the outputs to 1 and connect a node

The msg.payload on the output will be a json array of the returned records

+

+

Insert exampleb>

+

msg.payload = { 'sensorid': 1, 'value': 2 }

+

insert into table (field1, field2) values ($sensorid, $value)

+ +

+

Select exampleb>

+

msg.payload = { 'sensorid': 1, 'value': 2 }

+

select * from table where field1=$sensorid order by time desc limit 1

+ diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js index bf882b6a..36e02b05 100644 --- a/storage/postgres/110-postgres.js +++ b/storage/postgres/110-postgres.js @@ -1,5 +1,5 @@ /** - * Copyright 2013 IBM Corp. + * 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. @@ -14,11 +14,6 @@ * 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"); var pg=require('pg'); var named=require('node-postgres-named'); From 43c6bdb95ad71b9f7e691de467e8634e053c4f97 Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Sat, 21 Dec 2013 09:23:46 +0100 Subject: [PATCH 07/24] removed script editor from node config added support for script in msg.payload added support for query parameters in msg.queryParameters --- storage/postgres/110-postgres.html | 83 +++++------------------------- storage/postgres/110-postgres.js | 9 ++-- 2 files changed, 17 insertions(+), 75 deletions(-) diff --git a/storage/postgres/110-postgres.html b/storage/postgres/110-postgres.html index 09a887a8..033cc990 100644 --- a/storage/postgres/110-postgres.html +++ b/storage/postgres/110-postgres.html @@ -60,43 +60,18 @@
- - -
-
-
- - + + +
@@ -107,8 +82,7 @@ limit 1

defaults: { postgresdb: { type:"postgresdb",required:true}, name: {value:""}, - sqlquery: {value:"",required:true}, - outputs: {value:0} + output: {value:false} }, inputs:1, outputs:0, @@ -121,47 +95,14 @@ limit 1

return this.name?"node_label_italic":""; }, oneditprepare: function() { - $( "#node-input-outputs" ).spinner({ - min:0, - max:1 - }); - $( "#node-input-outputs" ).spinner( "value", this.outputs ); + $( "#node-input-output" ).prop( "checked", this.output ); + $("#node-input-name").focus(); - function functionDialogResize(ev,ui) { - $("#node-input-sqlquery-editor").css("height",(ui.size.height-235)+"px"); - }; - - $( "#dialog" ).on("dialogresize", functionDialogResize); - $( "#dialog" ).one("dialogopen", function(ev) { - var size = $( "#dialog" ).dialog('option','sizeCache-function'); - if (size) { - functionDialogResize(null,{size:size}); - } - }); - $( "#dialog" ).one("dialogclose", function(ev,ui) { - var height = $( "#dialog" ).dialog('option','height'); - $( "#dialog" ).off("dialogresize",functionDialogResize); - }); - var that = this; - require(["orion/editor/edit"], function(edit) { - that.editor = edit({ - parent:document.getElementById('node-input-sqlquery-editor'), - lang:"sql", - contents: $("#node-input-sqlquery").val() - }); - RED.library.create({ - url:"storage", // where to get the data from - type:"postgres", // the type of object the library is for - editor:that.editor, // the field name the main text body goes to - fields:['name','outputs'] - }); - $("#node-input-name").focus(); - - }); }, oneditsave: function() { - $("#node-input-sqlquery").val(this.editor.getText()) + var hasOutput = $( "#node-input-output" ).prop( "checked" ); + this.outputs = hasOutput ? 1: 0; delete this.editor; } }); diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js index 36e02b05..edd42c88 100644 --- a/storage/postgres/110-postgres.js +++ b/storage/postgres/110-postgres.js @@ -36,7 +36,7 @@ function PostgresNode(n) { this.postgresdb = n.postgresdb; this.postgresConfig = RED.nodes.getNode(this.postgresdb); this.sqlquery = n.sqlquery; - this.outputs = n.outputs; + this.output = n.output; var node = this; if(this.postgresConfig) @@ -51,12 +51,13 @@ function PostgresNode(n) { else { node.on('input', function(msg){ - node.clientdb.query(node.sqlquery, - msg.payload, + if(!msg.queryParameters) msg.queryParameters={}; + node.clientdb.query(msg.payload, + msg.queryParameters, function (err, results) { if(err) { node.error(err); } else { - if(node.outputs>0) + if(node.output) { msg.payload = results.rows; node.send(msg); From 497f08bba93a001872ffa01907fac99d3adbccfb Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Sat, 21 Dec 2013 11:01:19 +0100 Subject: [PATCH 08/24] moved credtials from config to credential store --- storage/postgres/110-postgres.html | 47 ++++++++++++++++++++++++---- storage/postgres/110-postgres.js | 50 ++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/storage/postgres/110-postgres.html b/storage/postgres/110-postgres.html index 033cc990..a4ea5e57 100644 --- a/storage/postgres/110-postgres.html +++ b/storage/postgres/110-postgres.html @@ -27,7 +27,7 @@
- +
@@ -40,12 +40,46 @@ defaults: { hostname: { value:"localhost",required:true}, port: { value: 5432,required:true}, - db: { value:"postgres",required:true}, - username: { value:"postgres", required:true }, - password: { value:"postgres", required:true } + db: { value:"postgres",required:true} }, label: function() { return this.name||this.hostname+":"+this.port+"/"+this.db; + }, + oneditprepare: function() { + + $.getJSON('postgresdb/'+this.id,function(data) { + if (data.user) { + $('#node-config-input-user').val(data.user); + } + if (data.hasPassword) { + $('#node-config-input-password').val('__PWRD__'); + } else { + $('#node-config-input-password').val(''); + } + }); + }, + oneditsave: function() { + + var newUser = $('#node-config-input-user').val(); + var newPass = $('#node-config-input-password').val(); + var credentials = {}; + credentials.user = newUser; + if (newPass != '__PWRD__') { + credentials.password = newPass; + } + $.ajax({ + url: 'postgresdb/'+this.id, + type: 'POST', + data: credentials, + success:function(result){} + }); + }, + ondelete: function() { + $.ajax({ + url: 'postgresdb/'+this.id, + type: 'DELETE', + success: function(result) {} + }); } }); @@ -98,12 +132,13 @@ $( "#node-input-output" ).prop( "checked", this.output ); $("#node-input-name").focus(); - + }, oneditsave: function() { + var hasOutput = $( "#node-input-output" ).prop( "checked" ); this.outputs = hasOutput ? 1: 0; - delete this.editor; + } }); diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js index edd42c88..4e2d41ee 100644 --- a/storage/postgres/110-postgres.js +++ b/storage/postgres/110-postgres.js @@ -17,14 +17,57 @@ 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.app.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.app.delete('/postgresdb/:id',function(req,res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.app.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; - this.username = n.username; - this.password = n.password; + + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.user = credentials.user; + this.password = credentials.password; + } } RED.nodes.registerType("postgresdb",PostgresDatabaseNode); @@ -39,10 +82,11 @@ function PostgresNode(n) { this.output = n.output; var node = this; + if(this.postgresConfig) { - var conString = 'postgres://'+this.postgresConfig.username +':' + this.postgresConfig.password + '@' + this.postgresConfig.hostname + ':' + this.postgresConfig.port + '/' + this.postgresConfig.db; + 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); From e72ced85e6f5ec18b8e6c3489a9d565ccba7a934 Mon Sep 17 00:00:00 2001 From: Kris Daniels Date: Sat, 21 Dec 2013 16:55:44 +0100 Subject: [PATCH 09/24] fixed bug with outputs not being set correctly after initial load --- storage/postgres/110-postgres.html | 60 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/storage/postgres/110-postgres.html b/storage/postgres/110-postgres.html index a4ea5e57..6fae6ac1 100644 --- a/storage/postgres/110-postgres.html +++ b/storage/postgres/110-postgres.html @@ -111,34 +111,36 @@ From 243fc9ffd4da4de5e73d2252aba892abb18581e5 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Sat, 21 Dec 2013 18:44:50 +0100 Subject: [PATCH 10/24] Setting defaults with credentials fields persists them in the flows file. Fixed. --- storage/ddb/69-ddbout.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index 33b5463e..dfe8dac0 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -80,10 +80,6 @@ + + diff --git a/lib/aws.js b/lib/aws.js new file mode 100644 index 00000000..9997b676 --- /dev/null +++ b/lib/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.app.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.app.delete('/aws-credentials/:id', function(req, res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.app.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/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index dfe8dac0..4262ea5a 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -51,7 +51,7 @@ category: "storage-output", color: "#ffaaaa", defaults: { - credentials: { type: "awscredentials", required: true }, + credentials: { type: "aws credentials", required: true }, region: { value: "us-east-1" }, table: { value: "", required: true }, name: { value: "" } @@ -65,53 +65,3 @@ } }); - - - - diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js index 8cf0d753..3a9120d5 100644 --- a/storage/ddb/69-ddbout.js +++ b/storage/ddb/69-ddbout.js @@ -15,58 +15,11 @@ **/ var RED = require(process.env.NODE_RED_HOME+"/red/red"); +require("../../lib/aws"); var util = require("util"); -var querystring = require('querystring'); var aws = require("aws-sdk"); var attrWrapper = require("dynamodb-data-types").AttributeValue; -function DDBNode(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("awscredentials", DDBNode); - -RED.app.get('/awscredentials/: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.app.delete('/awscredentials/:id', function(req, res) { - RED.nodes.deleteCredentials(req.params.id); - res.send(200); -}); - -RED.app.post('/awscredentials/: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); - }); -}); - function DDBOutNode(n) { RED.nodes.createNode(this, n); this.credentials = RED.nodes.getNode(n.credentials); From 4e20f70bfde35b31427f36ca1231322252f69985 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Sun, 22 Dec 2013 08:48:02 +0100 Subject: [PATCH 12/24] Leave region selection open so new regions are quicker to use. --- storage/ddb/69-ddbout.html | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index 4262ea5a..3f0859bd 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -21,16 +21,7 @@
- +
@@ -52,7 +43,7 @@ color: "#ffaaaa", defaults: { credentials: { type: "aws credentials", required: true }, - region: { value: "us-east-1" }, + region: { value: "us-east-1", required: true }, table: { value: "", required: true }, name: { value: "" } }, From 5342637132108a6914f99c2960088d72edadc0ee Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Tue, 24 Dec 2013 17:21:22 +0100 Subject: [PATCH 13/24] Need to retain the accessKey defaults to be able to show them in the UI --- lib/aws.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/aws.html b/lib/aws.html index da463c52..5c26c904 100644 --- a/lib/aws.html +++ b/lib/aws.html @@ -31,6 +31,9 @@ label: function() { return this.accessKey; }, + defaults: { + accessKey: { value: "", required: true } + }, oneditprepare: function() { $.getJSON("aws-credentials/" + this.id, function(data) { if (data.accessKey) { From efb9fbb92b10dee2d8c93b0f9a29745db8970f46 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Sun, 2 Feb 2014 21:52:08 +1100 Subject: [PATCH 14/24] Move AWS credentials to DDB node --- storage/ddb/69-ddbout.js | 1 - {lib => storage/ddb}/aws.html | 0 {lib => storage/ddb}/aws.js | 0 3 files changed, 1 deletion(-) rename {lib => storage/ddb}/aws.html (100%) rename {lib => storage/ddb}/aws.js (100%) diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js index 3a9120d5..939d7d23 100644 --- a/storage/ddb/69-ddbout.js +++ b/storage/ddb/69-ddbout.js @@ -15,7 +15,6 @@ **/ var RED = require(process.env.NODE_RED_HOME+"/red/red"); -require("../../lib/aws"); var util = require("util"); var aws = require("aws-sdk"); var attrWrapper = require("dynamodb-data-types").AttributeValue; diff --git a/lib/aws.html b/storage/ddb/aws.html similarity index 100% rename from lib/aws.html rename to storage/ddb/aws.html diff --git a/lib/aws.js b/storage/ddb/aws.js similarity index 100% rename from lib/aws.js rename to storage/ddb/aws.js From 2723210922fc84e93905bdf33730a44320ca0d8c Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Wed, 5 Feb 2014 11:15:37 +0000 Subject: [PATCH 15/24] fixed typo in Temperature topic (sensorTag/Tempature to sensorTag/Temperature) This will break existing flows that are filtering on topic --- hardware/sensorTag/79-sensorTag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardware/sensorTag/79-sensorTag.js b/hardware/sensorTag/79-sensorTag.js index 61dbc24b..91d40b07 100644 --- a/hardware/sensorTag/79-sensorTag.js +++ b/hardware/sensorTag/79-sensorTag.js @@ -51,7 +51,7 @@ function sensorTagNode(n) { 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) }; From 2f07bb7d135931d3c5d57c440d6906f0fa5ffec5 Mon Sep 17 00:00:00 2001 From: Dave C-J Date: Wed, 5 Feb 2014 18:36:29 +0000 Subject: [PATCH 16/24] Fix ping error response on Pi - Fixes Issue #23 --- io/ping/88-ping.html | 2 -- io/ping/88-ping.js | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/io/ping/88-ping.html b/io/ping/88-ping.html index f171c2c5..06e3028f 100644 --- a/io/ping/88-ping.html +++ b/io/ping/88-ping.html @@ -29,14 +29,12 @@
- - + + + + + + + + diff --git a/io/emoncms/88-emoncms.js b/io/emoncms/88-emoncms.js new file mode 100644 index 00000000..a40ee9a5 --- /dev/null +++ b/io/emoncms/88-emoncms.js @@ -0,0 +1,71 @@ +/** + * 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.apikey = n.apikey; + this.name = n.name; +} +RED.nodes.registerType("emoncms-server",EmoncmsServerNode); + +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; + this.url = this.baseurl + '/input/post.json?json={' + topic + ':' + msg.payload+'}&apikey='+this.apikey; + if(this.nodegroup != ""){ + this.url += '&node='+this.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 From b1b230eb37759bae0e05b07624c2f76557b1b5e5 Mon Sep 17 00:00:00 2001 From: Dave C-J Date: Sat, 8 Feb 2014 13:31:00 +0000 Subject: [PATCH 19/24] Forced payload to be strings for Prowl node Fixes #26 --- social/prowl/57-prowl.js | 61 ++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/social/prowl/57-prowl.js b/social/prowl/57-prowl.js index 15be6f2a..9d8801bc 100644 --- a/social/prowl/57-prowl.js +++ b/social/prowl/57-prowl.js @@ -24,44 +24,45 @@ var util = require('util'); // module.exports = {prowlkey:'My-API-KEY'} try { - var pushkey = RED.settings.prowl || require(process.env.NODE_RED_HOME+"/../pushkey.js"); + var pushkey = RED.settings.prowl || require(process.env.NODE_RED_HOME+"/../pushkey.js"); } catch(err) { - util.log("[57-prowl.js] Error: Failed to load Prowl credentials"); + util.log("[57-prowl.js] Error: Failed to load Prowl credentials"); } if (pushkey) { - var prowl = new Prowl(pushkey.prowlkey); + 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.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); + } + else { msg.payload = msg.payload.toString(); } + 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); From dc13290f97e227076fdcd4517b67ee2c5665e62b Mon Sep 17 00:00:00 2001 From: henols Date: Sun, 9 Feb 2014 00:21:17 +0100 Subject: [PATCH 20/24] Some usage clarifications --- io/emoncms/88-emoncms.html | 15 ++++++++------- io/emoncms/88-emoncms.js | 5 +++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/io/emoncms/88-emoncms.html b/io/emoncms/88-emoncms.html index ff71828b..b179b7af 100644 --- a/io/emoncms/88-emoncms.html +++ b/io/emoncms/88-emoncms.html @@ -23,21 +23,22 @@ +
+ + +
-
- - -
-
If Topic is left blank the output Topic is the same as the input Topic.
+
Topic is not mandatory, if Topic is left blank msg.topic will used. Topic overrides msg.topic
+ Node Group (numeric) is not mandatory, if Node Group is left blank msg.nodegrpup will used. Node Group overrides msg.nodegroup
diff --git a/io/emoncms/88-emoncms.js b/io/emoncms/88-emoncms.js index a007d3d5..74ad43a4 100644 --- a/io/emoncms/88-emoncms.js +++ b/io/emoncms/88-emoncms.js @@ -19,11 +19,50 @@ var RED = require(process.env.NODE_RED_HOME+"/red/red"); function EmoncmsServerNode(n) { RED.nodes.createNode(this,n); this.server = n.server; - this.apikey = n.apikey; 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.app.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.app.delete('/emoncms-server/:id',function(req,res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.app.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; From 4a53c20792ebb4220fcbf534cfe804f7f849d292 Mon Sep 17 00:00:00 2001 From: Dave C-J Date: Fri, 14 Feb 2014 20:38:39 +0000 Subject: [PATCH 23/24] Update pushbullet to use latest 0.4 npm and allow iden as well as id --- social/pushbullet/57-pushbullet.html | 13 ++++--- social/pushbullet/57-pushbullet.js | 55 ++++++++++++++-------------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/social/pushbullet/57-pushbullet.html b/social/pushbullet/57-pushbullet.html index 32020297..dda75be5 100644 --- a/social/pushbullet/57-pushbullet.html +++ b/social/pushbullet/57-pushbullet.html @@ -26,12 +26,13 @@