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/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) }; diff --git a/io/emoncms/88-emoncms.html b/io/emoncms/88-emoncms.html new file mode 100644 index 00000000..8f20f07e --- /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 00000000..c1dde58b --- /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.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; + 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 00000000..8cde7871 Binary files /dev/null and b/io/emoncms/icons/emoncms-logo.png differ diff --git a/io/emoncms/icons/emoncms.png b/io/emoncms/icons/emoncms.png new file mode 100644 index 00000000..a3abe7d2 Binary files /dev/null and b/io/emoncms/icons/emoncms.png differ 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/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js new file mode 100644 index 00000000..939d7d23 --- /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 00000000..5c26c904 --- /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 00000000..9997b676 --- /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.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/postgres/110-postgres.html b/storage/postgres/110-postgres.html new file mode 100644 index 00000000..6fae6ac1 --- /dev/null +++ b/storage/postgres/110-postgres.html @@ -0,0 +1,146 @@ + + + + + + + + + + + diff --git a/storage/postgres/110-postgres.js b/storage/postgres/110-postgres.js new file mode 100644 index 00000000..4e2d41ee --- /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.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; + + 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 00000000..e46c3169 Binary files /dev/null and b/storage/postgres/icons/postgres.png differ