Rebase on latest master
Revert refactor versioning Tidy revert of versioning Bump version
This commit is contained in:
8
package-lock.json
generated
8
package-lock.json
generated
@@ -397,6 +397,14 @@
|
|||||||
"vary": "^1"
|
"vary": "^1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cron": {
|
||||||
|
"version": "1.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cron/-/cron-1.7.1.tgz",
|
||||||
|
"integrity": "sha512-gmMB/pJcqUVs/NklR1sCGlNYM7TizEw+1gebz20BMc/8bTm/r7QUp3ZPSPlG8Z5XRlvb7qhjEjq/+bdIfUCL2A==",
|
||||||
|
"requires": {
|
||||||
|
"moment-timezone": "^0.5.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"currently-unhandled": {
|
"currently-unhandled": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"cron": "^1.3.0",
|
||||||
"dotenv": "^6.2.0",
|
"dotenv": "^6.2.0",
|
||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
"geo-tz": "^4.0.2",
|
"geo-tz": "^4.0.2",
|
||||||
|
|||||||
62
routes/local.js
Executable file
62
routes/local.js
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
var CronJob = require( "cron" ).CronJob;
|
||||||
|
var server = require( "../server.js" );
|
||||||
|
var today = {}, yesterday = {};
|
||||||
|
var count = { temp: 0, humidity: 0 };
|
||||||
|
var current_date = new Date();
|
||||||
|
var last_rain = new Date().setTime(0);
|
||||||
|
|
||||||
|
function sameDay(d1, d2) {
|
||||||
|
return d1.getFullYear() === d2.getFullYear() &&
|
||||||
|
d1.getMonth() === d2.getMonth() &&
|
||||||
|
d1.getDate() === d2.getDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.captureWUStream = function( req, res ) {
|
||||||
|
var prev, curr;
|
||||||
|
|
||||||
|
if ( !( "dateutc" in req.query ) || !sameDay( current_date, new Date( req.query.dateutc + "Z") )) {
|
||||||
|
res.send( "Error: Bad date range\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ( "tempf" in req.query ) && !isNaN( curr = parseFloat( req.query.tempf ) ) && curr !== -9999.0 ) {
|
||||||
|
prev = ( "temp" in today ) ? today.temp : 0;
|
||||||
|
today.temp = ( prev * count.temp + curr ) / ( ++count.temp );
|
||||||
|
}
|
||||||
|
if ( ( "humidity" in req.query ) && !isNaN( curr = parseFloat( req.query.humidity ) ) && curr !== -9999.0 ) {
|
||||||
|
prev = ( "humidity" in today ) ? today.humidity : 0;
|
||||||
|
today.humidity = ( prev * count.humidity + curr ) / ( ++count.humidity );
|
||||||
|
}
|
||||||
|
if ( ( "dailyrainin" in req.query ) && !isNaN( curr = parseFloat( req.query.dailyrainin ) ) && curr !== -9999.0 ) {
|
||||||
|
today.precip = curr;
|
||||||
|
}
|
||||||
|
if ( ( "rainin" in req.query ) && !isNaN( curr = parseFloat( req.query.rainin ) ) && curr > 0 ) {
|
||||||
|
last_rain = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send( "success\n" );
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.hasLocalWeather = function() {
|
||||||
|
return ( server.pws !== "false" ? true : false );
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getLocalWeather = function() {
|
||||||
|
var result = {};
|
||||||
|
|
||||||
|
// Use today's weather if we dont have information for yesterday yet (i.e. on startup)
|
||||||
|
Object.assign( result, today, yesterday);
|
||||||
|
Object.assign( result, ( yesterday.precip && today.precip ) ? { precip: yesterday.precip + today.precip } : {} );
|
||||||
|
|
||||||
|
result.raining = ( ( Date.now() - last_rain ) / 1000 / 60 / 60 < 1 );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
new CronJob( "0 0 0 * * *", function() {
|
||||||
|
|
||||||
|
yesterday = Object.assign( {}, today );
|
||||||
|
today = Object.assign( {} );
|
||||||
|
count.temp = 0; count.humidity = 0;
|
||||||
|
current_date = new Date();
|
||||||
|
}, null, true );
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
var http = require( "http" ),
|
var http = require( "http" ),
|
||||||
|
local = require( "../routes/local.js" ),
|
||||||
SunCalc = require( "suncalc" ),
|
SunCalc = require( "suncalc" ),
|
||||||
moment = require( "moment-timezone" ),
|
moment = require( "moment-timezone" ),
|
||||||
geoTZ = require( "geo-tz" ),
|
geoTZ = require( "geo-tz" ),
|
||||||
@@ -134,6 +135,17 @@ function getOWMWeatherData( location, callback ) {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve weather data from Local record
|
||||||
|
function getLocalWateringData( location, callback ) {
|
||||||
|
|
||||||
|
getTimeData( location, function( weather ) {
|
||||||
|
Object.assign( weather, local.getLocalWeather() );
|
||||||
|
location = location.join( "," );
|
||||||
|
|
||||||
|
callback( weather );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate timezone and sun rise/set information
|
// Calculate timezone and sun rise/set information
|
||||||
function getTimeData( location, callback ) {
|
function getTimeData( location, callback ) {
|
||||||
var timezone = moment().tz( geoTZ( location[ 0 ], location[ 1 ] ) ).utcOffset();
|
var timezone = moment().tz( geoTZ( location[ 0 ], location[ 1 ] ) ).utcOffset();
|
||||||
@@ -234,7 +246,6 @@ exports.getWeatherData = function( req, res ) {
|
|||||||
res.json( data );
|
res.json( data );
|
||||||
} );
|
} );
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Attempt to resolve provided location to GPS coordinates when it does not match
|
// Attempt to resolve provided location to GPS coordinates when it does not match
|
||||||
// a GPS coordinate or Weather Underground location using Weather Underground autocomplete
|
// a GPS coordinate or Weather Underground location using Weather Underground autocomplete
|
||||||
resolveCoordinates( location, function( result ) {
|
resolveCoordinates( location, function( result ) {
|
||||||
@@ -249,7 +260,7 @@ exports.getWeatherData = function( req, res ) {
|
|||||||
res.json( data );
|
res.json( data );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// API Handler when using the weatherX.py where X represents the
|
// API Handler when using the weatherX.py where X represents the
|
||||||
@@ -310,13 +321,15 @@ exports.getWateringData = function( req, res ) {
|
|||||||
sunset: weather.sunset,
|
sunset: weather.sunset,
|
||||||
eip: ipToInt( remoteAddress ),
|
eip: ipToInt( remoteAddress ),
|
||||||
rawData: {
|
rawData: {
|
||||||
h: weather.humidity,
|
h: Math.round( weather.humidity ),
|
||||||
p: Math.round( weather.precip * 100 ) / 100,
|
p: Math.round( weather.precip * 100 ) / 100,
|
||||||
t: Math.round( weather.temp * 10 ) / 10,
|
t: Math.round( weather.temp * 10 ) / 10,
|
||||||
raining: weather.raining ? 1 : 0
|
raining: weather.raining ? 1 : 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log( "OpenSprinkler Weather Response: %s", JSON.stringify( data ) );
|
||||||
|
|
||||||
// Return the response to the client in the requested format
|
// Return the response to the client in the requested format
|
||||||
if ( outputFormat === "json" ) {
|
if ( outputFormat === "json" ) {
|
||||||
res.json( data );
|
res.json( data );
|
||||||
@@ -332,6 +345,8 @@ exports.getWateringData = function( req, res ) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log( "OpenSprinkler Weather Query: %s", JSON.stringify( req.query ) );
|
||||||
|
|
||||||
// Exit if no location is provided
|
// Exit if no location is provided
|
||||||
if ( !location ) {
|
if ( !location ) {
|
||||||
res.send( "Error: No location provided." );
|
res.send( "Error: No location provided." );
|
||||||
@@ -371,7 +386,6 @@ exports.getWateringData = function( req, res ) {
|
|||||||
// Continue with the weather request
|
// Continue with the weather request
|
||||||
getOWMWateringData( location, finishRequest );
|
getOWMWateringData( location, finishRequest );
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Attempt to resolve provided location to GPS coordinates when it does not match
|
// Attempt to resolve provided location to GPS coordinates when it does not match
|
||||||
// a GPS coordinate or Weather Underground location using Weather Underground autocomplete
|
// a GPS coordinate or Weather Underground location using Weather Underground autocomplete
|
||||||
resolveCoordinates( location, function( result ) {
|
resolveCoordinates( location, function( result ) {
|
||||||
@@ -383,7 +397,7 @@ exports.getWateringData = function( req, res ) {
|
|||||||
location = result;
|
location = result;
|
||||||
getOWMWateringData( location, finishRequest );
|
getOWMWateringData( location, finishRequest );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generic HTTP request handler that parses the URL and uses the
|
// Generic HTTP request handler that parses the URL and uses the
|
||||||
|
|||||||
15
server.js
15
server.js
@@ -1,14 +1,17 @@
|
|||||||
var express = require( "express" ),
|
var express = require( "express" ),
|
||||||
weather = require( "./routes/weather.js" ),
|
weather = require( "./routes/weather.js" ),
|
||||||
|
local = require( "./routes/local.js" ),
|
||||||
cors = require( "cors" ),
|
cors = require( "cors" ),
|
||||||
host = process.env.HOST || "127.0.0.1",
|
host = process.env.HOST || "127.0.0.1",
|
||||||
port = process.env.PORT || 3000,
|
port = process.env.PORT || 3000,
|
||||||
|
pws = process.env.PWS || "none",
|
||||||
app = express();
|
app = express();
|
||||||
|
|
||||||
if ( !process.env.HOST || !process.env.PORT ) {
|
if ( !process.env.HOST || !process.env.PORT || !process.env.LOCAL_PWS ) {
|
||||||
require( "dotenv" ).load();
|
require( "dotenv" ).load();
|
||||||
host = process.env.HOST || host;
|
host = process.env.HOST || host;
|
||||||
port = process.env.PORT || port;
|
port = process.env.PORT || port;
|
||||||
|
pws = process.env.PWS || pws;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle requests matching /weatherID.py where ID corresponds to the
|
// Handle requests matching /weatherID.py where ID corresponds to the
|
||||||
@@ -21,6 +24,11 @@ app.get( /(\d+)/, weather.getWateringData );
|
|||||||
app.options( /weatherData/, cors() );
|
app.options( /weatherData/, cors() );
|
||||||
app.get( /weatherData/, cors(), weather.getWeatherData );
|
app.get( /weatherData/, cors(), weather.getWeatherData );
|
||||||
|
|
||||||
|
// Endpoint to stream Weather Underground data from local PWS
|
||||||
|
if ( pws === "WU" ) {
|
||||||
|
app.get( "/weatherstation/updateweatherstation.php", local.captureWUStream );
|
||||||
|
}
|
||||||
|
|
||||||
app.get( "/", function( req, res ) {
|
app.get( "/", function( req, res ) {
|
||||||
res.send( "OpenSprinkler Weather Service" );
|
res.send( "OpenSprinkler Weather Service" );
|
||||||
} );
|
} );
|
||||||
@@ -34,6 +42,11 @@ app.use( function( req, res ) {
|
|||||||
// Start listening on the service port
|
// Start listening on the service port
|
||||||
app.listen( port, host, function() {
|
app.listen( port, host, function() {
|
||||||
console.log( "OpenSprinkler Weather Service now listening on %s:%s", host, port );
|
console.log( "OpenSprinkler Weather Service now listening on %s:%s", host, port );
|
||||||
|
|
||||||
|
if (pws !== "none" ) {
|
||||||
|
console.log( "OpenSprinkler Weather Service now listening for local weather stream" );
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
exports.app = app;
|
exports.app = app;
|
||||||
|
exports.pws = pws;
|
||||||
|
|||||||
Reference in New Issue
Block a user