diff --git a/.ebextensions/mongodb.config b/.ebextensions/mongodb.config new file mode 100644 index 0000000..9d0ff8b --- /dev/null +++ b/.ebextensions/mongodb.config @@ -0,0 +1,27 @@ +files: + "/home/ec2-user/install_mongo.sh" : + mode: "0007555" + owner: root + group: root + content: | + #!/bin/bash + echo "[MongoDB] + name=MongoDB Repository + baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64 + gpgcheck=0 + enabled=1" | tee -a /etc/yum.repos.d/mongodb.repo + yum -y update + yum -y install mongodb-org-server mongodb-org-shell mongodb-org-tools + +commands: + 01install_mongo: + command: ./install_mongo.sh + cwd: /home/ec2-user + test: '[ ! -f /usr/bin/mongo ] && echo "MongoDB not installed"' + +services: + sysvinit: + mongod: + enabled: true + ensureRunning: true + commands: ['01install_mongo'] diff --git a/Gruntfile.js b/Gruntfile.js index bce0537..bdc3b44 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2,7 +2,6 @@ module.exports = function( grunt ) { // Load node-modules; grunt.loadNpmTasks( "grunt-contrib-jshint" ); - grunt.loadNpmTasks( "grunt-contrib-compress" ); grunt.loadNpmTasks( "grunt-jscs" ); // Project configuration. @@ -10,36 +9,22 @@ module.exports = function( grunt ) { pkg: grunt.file.readJSON( "package.json" ), jshint: { - main: [ "server.js", "routes/**" ], + main: [ "Gruntfile.js", "server.js", "routes/**", "models/**" ], options: { jshintrc: true } }, jscs: { - main: [ "server.js", "routes/**" ], + main: [ "Gruntfile.js", "server.js", "routes/**", "models/**" ], options: { config: true, fix: true } - }, - - compress: { - build: { - options: { - archive: "WeatherService.zip" - }, - files: [ { - src: [ ".ebextensions/*", "routes/*", "server.js", "package.json" ], - expand: true - } ] - } } - } ); // Default task(s). grunt.registerTask( "default", [ "jshint", "jscs" ] ); - grunt.registerTask( "build", [ "jshint", "jscs", "compress:build" ] ); }; diff --git a/models/Cache.js b/models/Cache.js new file mode 100644 index 0000000..ef5e107 --- /dev/null +++ b/models/Cache.js @@ -0,0 +1,14 @@ +var mongoose = require( "mongoose" ); + +var cacheSchema = new mongoose.Schema( { + + // Stores the current GPS location as unique for weather data cache + location: { type: String, unique: true }, + + // This is the end of day value for the humidity yesterday + yesterdayHumidity: Number, + currentHumidityTotal: Number, + currentHumidityCount: Number +} ); + +module.exports = mongoose.model( "Cache", cacheSchema ); diff --git a/package.json b/package.json index be73cc4..5ad1ce4 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,13 @@ "version": "0.0.1", "repository": "https://github.com/OpenSprinkler/Weather-Adjustments/", "dependencies": { + "cron": "^1.0.9", "dotenv": "^1.2.0", "express": "^4.13.0", "grunt": "^0.4.5", - "grunt-contrib-compress": "^0.13.0", "grunt-contrib-jshint": "^0.11.2", "grunt-jscs": "^1.8.0", + "mongoose": "^4.0.6", "xml2js": "^0.4.9" } } diff --git a/routes/weather.js b/routes/weather.js index 4f64e07..ecfabd2 100644 --- a/routes/weather.js +++ b/routes/weather.js @@ -2,6 +2,7 @@ var http = require( "http" ), parseXML = require( "xml2js" ).parseString, + Cache = require( "../models/Cache" ), // Define regex filters to match against location filters = { @@ -126,9 +127,20 @@ httpRequest( url, function( data ) { try { + var weather = JSON.parse( data ); - // Return the data to the callback function if successful - callback( JSON.parse( data ) ); + location = location.join( "," ); + + Cache.findOne( { location: location }, function( err, record ) { + if ( record && record.hasOwnProperty( "yesterdayHumidity" ) ) { + weather.yesterdayHumidity = record.yesterdayHumidity; + } + + // Return the data to the callback function if successful + callback( weather ); + } ); + + updateCache( location, weather ); } catch (err) { // Otherwise indicate the request failed @@ -163,6 +175,28 @@ } ); } + // Update weather cache record in the local database + function updateCache( location, weather ) { + + // Search for a cache record for the provided location + Cache.findOne( { location: location }, function( err, record ) { + + // If a record is found update the data and save it + if ( record ) { + record.currentHumidityTotal += weather.observation.imperial.rh; + record.currentHumidityCount++; + record.save(); + } else { + + // If no cache record is found, generate a new one and save it + new Cache( { + currentHumidityTotal: weather.observation.imperial.rh, + currentHumidityCount: 1 + } ).save(); + } + } ); + } + // Calculates the resulting water scale using the provided weather data, adjustment method and options function calculateWeatherScale( adjustmentMethod, adjustmentOptions, weather ) { diff --git a/server.js b/server.js index 4a47ad0..e96b010 100644 --- a/server.js +++ b/server.js @@ -1,12 +1,23 @@ -var express = require( "express" ), - weather = require( "./routes/weather.js" ), - port = process.env.PORT || 3000; - app = express(); +var express = require( "express" ), + weather = require( "./routes/weather.js" ), + mongoose = require( "mongoose" ), + Cache = require( "./models/Cache" ), + CronJob = require( "cron" ).CronJob, + port = process.env.PORT || 3000; + app = express(); if ( !process.env.PORT ) { require( "dotenv" ).load(); } +// Connect to local MongoDB instance +mongoose.connect( "localhost" ); + +// If the database connection cannot be established, throw an error +mongoose.connection.on( "error", function() { + console.error( "MongoDB Connection Error. Please make sure that MongoDB is running." ); +} ); + // Handle requests matching /weatherID.py where ID corresponds to the // weather adjustment method selector. // This endpoint is considered deprecated and supported for prior firmware @@ -23,3 +34,29 @@ var server = app.listen( port, "127.0.0.1", function() { console.log( "OpenSprinkler Weather Service now listening on port %s", port ); } ); + +// Schedule a cronjob daily to consildate the weather cache data, runs daily +new CronJob( "0 * * * * *", function() { + + // Find all records in the weather cache + Cache.find( {}, function( err, records ) { + + // Cycle through each record + records.forEach( function( record ){ + + // If the record contains any unaveraged data, then process the record + if ( record.currentHumidityCount > 0 ) { + + // Average the humidity by dividing the total over the total data points collected + record.yesterdayHumidity = record.currentHumidityTotal / record.currentHumidityCount; + + // Reset the current humidity data for the new day + record.currentHumidityTotal = 0; + record.currentHumidityCount = 0; + + // Save the record in the database + record.save(); + } + } ); + } ); +}, null, true, "UTC" );