Added weather stuff and start of server tidyup
This commit is contained in:
parent
e0d8922c04
commit
378de8b4e4
55
.eslintrc.json
Normal file
55
.eslintrc.json
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 6,
|
||||||
|
"sourceType": "module",
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"node": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"arrow-spacing": "error",
|
||||||
|
"block-scoped-var": "error",
|
||||||
|
"block-spacing": "error",
|
||||||
|
"brace-style": ["error", "stroustrup", {}],
|
||||||
|
"camelcase": "error",
|
||||||
|
"comma-dangle": ["error", "never"],
|
||||||
|
"comma-spacing": ["error", { "before": false, "after": true }],
|
||||||
|
"comma-style": [1, "last"],
|
||||||
|
"consistent-this": [1, "_this"],
|
||||||
|
"curly": [1, "multi"],
|
||||||
|
"eol-last": 1,
|
||||||
|
"eqeqeq": 1,
|
||||||
|
"func-names": 1,
|
||||||
|
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||||
|
"lines-around-comment": ["error", { "beforeBlockComment": true, "allowArrayStart": true }],
|
||||||
|
"max-len": [1, 120, 2], // 2 spaces per tab, max 80 chars per line
|
||||||
|
"new-cap": 1,
|
||||||
|
"newline-before-return": "error",
|
||||||
|
"no-array-constructor": 1,
|
||||||
|
"no-inner-declarations": [1, "both"],
|
||||||
|
"no-mixed-spaces-and-tabs": 1,
|
||||||
|
"no-multi-spaces": 2,
|
||||||
|
"no-new-object": 1,
|
||||||
|
"no-shadow-restricted-names": 1,
|
||||||
|
"object-curly-spacing": ["error", "always"],
|
||||||
|
"padded-blocks": ["error", { "blocks": "never", "switches": "always" }],
|
||||||
|
"prefer-const": "error",
|
||||||
|
"prefer-template": "error",
|
||||||
|
"one-var": 0,
|
||||||
|
"quote-props": ["error", "always"],
|
||||||
|
"quotes": [1, "single"],
|
||||||
|
"radix": 1,
|
||||||
|
"semi": [1, "always"],
|
||||||
|
"space-before-blocks": [1, "always"],
|
||||||
|
"space-infix-ops": 1,
|
||||||
|
"vars-on-top": 1,
|
||||||
|
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }],
|
||||||
|
"spaced-comment": ["error", "always", { "markers": ["/"] }]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
152
.gitignore
vendored
Normal file
152
.gitignore
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Node template
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
### macOS template
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
# User-specific stuff:
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.xml
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-debug/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Elastic Beanstalk Files
|
||||||
|
.elasticbeanstalk/*
|
||||||
|
!.elasticbeanstalk/*.cfg.yml
|
||||||
|
!.elasticbeanstalk/*.global.yml
|
||||||
|
/src/bundle.js
|
||||||
|
/src/bundle.js.map
|
||||||
|
/src/react/bundle.js
|
||||||
|
/src/backbone/bundle.js
|
||||||
|
/src/react/bundle.js.map
|
||||||
|
/src/es2016/bundle.js
|
||||||
|
/src/es2016/bundle.js.map
|
||||||
|
/src/backbone/bundle.js.map
|
152
.ignore
Normal file
152
.ignore
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Node template
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
### macOS template
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
# User-specific stuff:
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
|
||||||
|
# Sensitive or high-churn files:
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.xml
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
|
||||||
|
# Gradle:
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-debug/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin:
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Elastic Beanstalk Files
|
||||||
|
.elasticbeanstalk/*
|
||||||
|
!.elasticbeanstalk/*.cfg.yml
|
||||||
|
!.elasticbeanstalk/*.global.yml
|
||||||
|
/src/bundle.js
|
||||||
|
/src/bundle.js.map
|
||||||
|
/src/react/bundle.js
|
||||||
|
/src/backbone/bundle.js
|
||||||
|
/src/react/bundle.js.map
|
||||||
|
/src/es2016/bundle.js
|
||||||
|
/src/es2016/bundle.js.map
|
||||||
|
/src/backbone/bundle.js.map
|
51
newapp.js
51
newapp.js
@ -1,31 +1,29 @@
|
|||||||
var express = require('express'), path = require('path'), http = require('http'),
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
const http = require('http');
|
||||||
|
const favicon = require('serve-favicon');
|
||||||
|
const logger = require('morgan');
|
||||||
|
const cookieParser = require('cookie-parser');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const routes = require('./routes/index');
|
||||||
|
const users = require('./routes/users');
|
||||||
|
const timeroute = require('./routes/time');
|
||||||
|
const btcroute = require('./routes/btc');
|
||||||
|
const temproute = require('./routes/temp');
|
||||||
|
const weightroute = require('./routes/weight');
|
||||||
|
const weatherRoute = require('./server/routes/weather');
|
||||||
|
|
||||||
favicon = require('serve-favicon'),
|
const app = express();
|
||||||
logger = require('morgan'),
|
GLOBAL.lastcheck = { 'btc': 0, 'fx': 0 };
|
||||||
cookieParser = require('cookie-parser'),
|
|
||||||
bodyParser = require('body-parser'),
|
|
||||||
|
|
||||||
routes = require('./routes/index'),
|
|
||||||
users = require('./routes/users'),
|
|
||||||
|
|
||||||
timeroute = require('./routes/time'),
|
|
||||||
btcroute = require('./routes/btc'),
|
|
||||||
temproute = require('./routes/temp'),
|
|
||||||
weightroute = require('./routes/weight')
|
|
||||||
//train = require('lib/train')
|
|
||||||
/* ,submit = require('./routes/mongo/submit') */
|
|
||||||
;
|
|
||||||
var app = express();
|
|
||||||
GLOBAL.lastcheck = {"btc": 0, "fx": 0};
|
|
||||||
|
|
||||||
|
|
||||||
app.set('port', process.env.PORT || 8030);
|
app.set('port', process.env.PORT || 8030);
|
||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
app.set('view engine', 'ejs');
|
app.set('view engine', 'ejs');
|
||||||
app.use(logger('dev'));
|
app.use(logger('dev'));
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ 'extended': true }));
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(express.static(path.join(__dirname, 'public')));
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
|
||||||
@ -36,12 +34,23 @@ GLOBAL.lastcheck = {"btc": 0, "fx": 0};
|
|||||||
app.use('/btc', btcroute);
|
app.use('/btc', btcroute);
|
||||||
app.use('/temp', temproute);
|
app.use('/temp', temproute);
|
||||||
app.use('/weight', weightroute);
|
app.use('/weight', weightroute);
|
||||||
|
app.use('/weather', weatherRoute);
|
||||||
|
|
||||||
|
// Handle 404
|
||||||
|
app.use((req, res) => {
|
||||||
|
res.status(404).send('404: Page not Found');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle 500
|
||||||
|
app.use((error, req, res, next) => {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send('500: Internal Server Error');
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create the server
|
* create the server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app.listen(app.get('port'), function() {
|
app.listen(app.get('port'), function() {
|
||||||
console.log('APIServer listening on ' + app.get('port'));
|
console.log(`APIServer listening on ${ app.get('port')}`);
|
||||||
});
|
});
|
30
package.json
30
package.json
@ -6,19 +6,27 @@
|
|||||||
"start": "node ./bin/www"
|
"start": "node ./bin/www"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "~1.13.2",
|
"body-parser": "^1.19.0",
|
||||||
"cookie-parser": "~1.3.5",
|
"cookie-parser": "^1.4.4",
|
||||||
"debug": "~2.2.0",
|
"debug": "^4.1.1",
|
||||||
"ejs": "~2.3.3",
|
"dotenv": "^8.2.0",
|
||||||
"events": "^1.1.0",
|
"ejs": "^2.7.1",
|
||||||
"express": "~4.13.1",
|
"eslint": "^6.8.0",
|
||||||
"morgan": "~1.6.1",
|
"events": "^3.0.0",
|
||||||
"serve-favicon": "~2.3.0",
|
"express": "^4.17.1",
|
||||||
|
"express-promise-router": "^3.0.3",
|
||||||
|
"fecha": "^4.0.0",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"morgan": "^1.9.1",
|
||||||
|
"node-geocoder": "^3.25.0",
|
||||||
|
"openweather-apis": "^4.1.0",
|
||||||
|
"request-json": "^0.6.4",
|
||||||
|
"serve-favicon": "^2.5.0",
|
||||||
"websocket": "^1.0.22",
|
"websocket": "^1.0.22",
|
||||||
"ws": "^1.0.1"
|
"ws": "^7.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"log4js": "^0.6.31",
|
"log4js": "^5.2.1",
|
||||||
"sqlite3": "~3.1.1"
|
"sqlite3": "^4.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
var express = require('express');
|
var express = require('express');
|
||||||
var router = express.Router();
|
var router = express.Router();
|
||||||
|
var debug = require('debug')('silvrapi:time');
|
||||||
|
|
||||||
/* GET users listing. */
|
/* GET users listing. */
|
||||||
router.get('/', function(req, res, next) {
|
router.get('/', function(req, res, next) {
|
||||||
@ -20,6 +21,8 @@ router.get('/', function(req, res, next) {
|
|||||||
|
|
||||||
var t = {"zulu":now, "utc":now.toUTCString(),"date":date, "time":time};
|
var t = {"zulu":now, "utc":now.toUTCString(),"date":date, "time":time};
|
||||||
|
|
||||||
|
debug(t);
|
||||||
|
|
||||||
res.writeHead(200, {"ContentType": "application/json"});
|
res.writeHead(200, {"ContentType": "application/json"});
|
||||||
//res.send(JSON.stringify(t));
|
//res.send(JSON.stringify(t));
|
||||||
res.end(JSON.stringify(t));
|
res.end(JSON.stringify(t));
|
||||||
|
0
routes/trains.js
Normal file
0
routes/trains.js
Normal file
96
server/lib/geocode.js
Normal file
96
server/lib/geocode.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
const NodeGeocoder = require('node-geocoder');
|
||||||
|
const logger = require('log4js').getLogger('GeoCode');
|
||||||
|
|
||||||
|
const { reduceOpencage } = require('../reducers/opencage');
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
'provider': 'opencage',
|
||||||
|
|
||||||
|
// Optional depending on the providers
|
||||||
|
'httpAdapter': 'https', // Default
|
||||||
|
'apiKey': '893ab539eca84b5ca7a54cb03ef23443', // for Mapquest, OpenCage, Google Premier
|
||||||
|
'formatter': null // 'gpx', 'string', ...
|
||||||
|
};
|
||||||
|
|
||||||
|
const geocoder = NodeGeocoder(options);
|
||||||
|
|
||||||
|
function doGetGeocode(ll) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const [lat, lon ] = ll.split(',');
|
||||||
|
|
||||||
|
const latlong = { lat, lon };
|
||||||
|
|
||||||
|
logger.debug(latlong);
|
||||||
|
|
||||||
|
geocoder.reverse(latlong)
|
||||||
|
.then(function(res) {
|
||||||
|
if (res.hasOwnProperty('raw')) {
|
||||||
|
const result = reduceOpencage(res.raw);
|
||||||
|
|
||||||
|
return resolve(result[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return resolve(res[0]);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
logger.error(err);
|
||||||
|
|
||||||
|
return reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { doGetGeocode };
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
opencage
|
||||||
|
|
||||||
|
{
|
||||||
|
"latitude": 51.508751,
|
||||||
|
"longitude": -0.067457,
|
||||||
|
"country": "United Kingdom",
|
||||||
|
"city": "London",
|
||||||
|
"state": "England",
|
||||||
|
"zipcode": "SE15",
|
||||||
|
"streetName": "Vaughan Way",
|
||||||
|
"countryCode": "gb",
|
||||||
|
"suburb": "St.George in the East",
|
||||||
|
"extra": {
|
||||||
|
"flag": "🇬🇧",
|
||||||
|
"confidence": 9,
|
||||||
|
"confidenceKM": 0.5,
|
||||||
|
"map": "https://www.openstreetmap.org/?mlat=51.50875&mlon=-0.06746#map=17/51.50875/-0.06746"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
google
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"administrativeLevels": {
|
||||||
|
"level1long": "England",
|
||||||
|
"level1short": "England",
|
||||||
|
"level2long": "Northamptonshire",
|
||||||
|
"level2short": "Northamptonshire"
|
||||||
|
},
|
||||||
|
"city": "Northampton",
|
||||||
|
"country": "United Kingdom",
|
||||||
|
"countryCode": "GB",
|
||||||
|
"extra": {
|
||||||
|
"confidence": 0.7,
|
||||||
|
"establishment": "Daventy depot",
|
||||||
|
"googlePlaceId": "ChIJI8H0WFUVd0gRIIFzNwDQAuM",
|
||||||
|
"neighborhood": "Kilsby",
|
||||||
|
"premise": null,
|
||||||
|
"subpremise": null
|
||||||
|
},
|
||||||
|
"formattedAddress": "Daventy depot, Kilsby, Northampton NN6 7GY, UK",
|
||||||
|
"latitude": 52.3546726,
|
||||||
|
"longitude": -1.1741823,
|
||||||
|
"provider": "google",
|
||||||
|
"zipcode": "NN6 7GY"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
*/
|
118
server/lib/weather.js
Normal file
118
server/lib/weather.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
const Client = require('request-json');
|
||||||
|
|
||||||
|
const logger = require('log4js').getLogger('Weather');
|
||||||
|
const weather = require('openweather-apis');
|
||||||
|
const { reduceWeather } = require('../reducers/weather');
|
||||||
|
const request = require('request');
|
||||||
|
|
||||||
|
logger.level = 'debug';
|
||||||
|
logger.label = 'Weather';
|
||||||
|
|
||||||
|
const openWeatherApiKey = process.env.openweatherAPI || '';
|
||||||
|
|
||||||
|
const darkskyApiKey = process.env.darkskyApiKey || '';
|
||||||
|
|
||||||
|
const dsURL = `https://api.darksky.net/forecast/${ darkskyApiKey }/`;
|
||||||
|
const DSclient = Client.createClient(`https://api.darksky.net/forecast/${ darkskyApiKey }/`);
|
||||||
|
|
||||||
|
weather.setAPPID(openWeatherApiKey);
|
||||||
|
weather.setLang('en');
|
||||||
|
// weather.setCity('Glasgow City');
|
||||||
|
|
||||||
|
function doGetOpenWeather(ll) {
|
||||||
|
const [lat, long ] = ll.split(',');
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
weather.setCoordinate(lat, long);
|
||||||
|
weather.getWeatherForecast( function(err, wData) {
|
||||||
|
if (err)
|
||||||
|
return reject(err);
|
||||||
|
else
|
||||||
|
return resolve(wData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function doGetOpenWeatherForecast(ll) {
|
||||||
|
const [lat, long ] = ll.split(',');
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
weather.setCoordinate(lat, long);
|
||||||
|
weather.getWeatherForecastForDays(5, function(err, wData) {
|
||||||
|
if (err)
|
||||||
|
return reject(err);
|
||||||
|
else
|
||||||
|
return resolve(wData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function doGetDarkSkyWeather(ll) {
|
||||||
|
const query = `${ll}?units=uk2&exclude=daily,flags,minutely,hourly`;
|
||||||
|
logger.debug(`https://api.darksky.net/forecast/${ darkskyApiKey }/${query}`);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DSclient.get(query, function(err, res, body) {
|
||||||
|
if (err || !body || !body.currently)
|
||||||
|
return reject(err);
|
||||||
|
|
||||||
|
return resolve(body);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function doGetFullForcast(ll) {
|
||||||
|
const query = `${ll}?units=uk2&exclude=flags,minutely`;
|
||||||
|
logger.debug('doGetFullForcast');
|
||||||
|
logger.debug(query);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DSclient.get(query, function(err, res, body) {
|
||||||
|
if (err || !body || !body.currently)
|
||||||
|
return reject(err);
|
||||||
|
|
||||||
|
const output = reduceWeather(body);
|
||||||
|
|
||||||
|
return resolve(output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function doGetFullForcastV2(ll) {
|
||||||
|
const query = `${ll}?units=uk2&exclude=flags,minutely`;
|
||||||
|
logger.debug('doGetFullForcastV2');
|
||||||
|
const url = `${dsURL}${query}`;
|
||||||
|
|
||||||
|
logger.debug(url);
|
||||||
|
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
request.get({ 'url':url }, function(err, resp, body) {
|
||||||
|
if (err) {
|
||||||
|
logger.error(err);
|
||||||
|
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
// Logger.error(err);
|
||||||
|
// return reject(err);
|
||||||
|
// Throw err;
|
||||||
|
|
||||||
|
console.log;
|
||||||
|
const output = reduceWeather(body);
|
||||||
|
output.fullBody = JSON.parse(body);
|
||||||
|
output.timestamp = new Date().getTime();
|
||||||
|
|
||||||
|
console.log(output);
|
||||||
|
|
||||||
|
return resolve(output);
|
||||||
|
}, function(error, response, body) {
|
||||||
|
console.log(response);
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
logger.error(response.statusCode);
|
||||||
|
logger.error(body);
|
||||||
|
|
||||||
|
return reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { doGetOpenWeather, doGetOpenWeatherForecast, doGetDarkSkyWeather, doGetFullForcast, doGetFullForcastV2 };
|
62
server/reducers/opencage.js
Normal file
62
server/reducers/opencage.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
const logger = require('log4js').getLogger('GeoCode 🔧');
|
||||||
|
|
||||||
|
const { get, isEmpty, has, uniq } = require('lodash');
|
||||||
|
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
var ConfidenceInKM = {
|
||||||
|
'10': 0.25,
|
||||||
|
'9': 0.5,
|
||||||
|
'8': 1,
|
||||||
|
'7': 5,
|
||||||
|
'6': 7.5,
|
||||||
|
'5': 10,
|
||||||
|
'4': 15,
|
||||||
|
'3': 20,
|
||||||
|
'2': 25,
|
||||||
|
'1': Number.POSITIVE_INFINITY,
|
||||||
|
'0': Number.NaN
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatResult (result) {
|
||||||
|
var confidence = result.confidence || 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
'latitude': result.geometry.lat,
|
||||||
|
'longitude': result.geometry.lng,
|
||||||
|
'country': result.components.country,
|
||||||
|
'city': result.components.city,
|
||||||
|
'town': result.components.town,
|
||||||
|
'state': result.components.state,
|
||||||
|
'zipcode': result.components.postcode,
|
||||||
|
'streetName': result.components.road,
|
||||||
|
'streetNumber': result.components.house_number,
|
||||||
|
'countryCode': result.components.country_code,
|
||||||
|
'county': result.components.county,
|
||||||
|
'suburb': result.components.suburb,
|
||||||
|
'neighbourhood' : result.components.neighbourhood,
|
||||||
|
'village' : result.components.village,
|
||||||
|
'formatted' : result.formatted,
|
||||||
|
'target' : result.components.village || result.components.town || result.components.city,
|
||||||
|
'extra': {
|
||||||
|
'flag' : result.annotations.flag,
|
||||||
|
'confidence': confidence,
|
||||||
|
'confidenceKM': ConfidenceInKM[result.confidence] || Number.NaN,
|
||||||
|
'map' : result.annotations.OSM.url
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function reduceOpencage(result) {
|
||||||
|
logger.debug(JSON.stringify(result));
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
if (result && result.results instanceof Array)
|
||||||
|
for (let i = 0; i < result.results.length; i++)
|
||||||
|
results.push(formatResult(result.results[i]));
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { reduceOpencage };
|
154
server/reducers/weather.js
Normal file
154
server/reducers/weather.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
const logger = require('log4js').getLogger('Weather 🔧');
|
||||||
|
const fecha = require('fecha');
|
||||||
|
|
||||||
|
const { get } = require('lodash');
|
||||||
|
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
function getTodaysForcast(hourlyData) {
|
||||||
|
const data = get(hourlyData, 'data', []);
|
||||||
|
|
||||||
|
const output = [];
|
||||||
|
const now = new Date().getTime();
|
||||||
|
const nowToHour = now - (now % 3600000);
|
||||||
|
const tomorrow = nowToHour + (60 * 1000 * 60 * 24);
|
||||||
|
|
||||||
|
for (const item of data) {
|
||||||
|
const time = item.time * 1000;
|
||||||
|
if (!(time < nowToHour || time > tomorrow)) {
|
||||||
|
// logger.debug(item);
|
||||||
|
const newItem = { 'time': fecha.format(time, 'h A'), 'icon': item.icon, 'temp': item.temperature, 'precip': item.precipProbability };
|
||||||
|
output.push(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDailyForcast(dailyData) {
|
||||||
|
const data = get(dailyData, 'data', []);
|
||||||
|
|
||||||
|
const output = [];
|
||||||
|
|
||||||
|
const h24 = (60 * 1000 * 60 * 24);
|
||||||
|
const now = new Date().getTime();
|
||||||
|
|
||||||
|
const startODBase = new Date();
|
||||||
|
startODBase.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const startOD = startODBase.getTime();
|
||||||
|
const endOD = startOD + h24 - 1;
|
||||||
|
|
||||||
|
logger.debug('startOD', fecha.format(new Date(startOD), 'default'));
|
||||||
|
logger.debug('endOD', fecha.format(new Date(endOD), 'default'));
|
||||||
|
|
||||||
|
for (const item of data) {
|
||||||
|
const time = item.time * 1000;
|
||||||
|
if (!(time < endOD)) {
|
||||||
|
// logger.debug(item);
|
||||||
|
const newItem = {
|
||||||
|
'time': fecha.format(time, 'dddd'),
|
||||||
|
'icon': item.icon,
|
||||||
|
'tempHigh': item.temperatureHigh,
|
||||||
|
'tempLow': item.temperatureLow,
|
||||||
|
'precip': item.precipProbability,
|
||||||
|
'precipType': item.precipType
|
||||||
|
};
|
||||||
|
output.push(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toCompass(degrees) {
|
||||||
|
return ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'][Math.round(degrees / 11.25 / 2)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function moonCalc(moonPhase) {
|
||||||
|
let output = '';
|
||||||
|
if (moonPhase === 0.0)
|
||||||
|
output = '🌕 New moon';
|
||||||
|
else if (moonPhase >= 0.1 && moonPhase < 0.25)
|
||||||
|
output = '🌔 waxing crescent';
|
||||||
|
else if (moonPhase === 0.25)
|
||||||
|
output = '🌓 First Quarter';
|
||||||
|
else if (moonPhase > 0.25 && moonPhase < 0.5)
|
||||||
|
output = '🌒 waxing gibbous';
|
||||||
|
else if (moonPhase === 0.5)
|
||||||
|
output = '🌑 Full moon';
|
||||||
|
else if (moonPhase > 0.5 && moonPhase < 0.75)
|
||||||
|
output = '🌘 Waning gibbous';
|
||||||
|
else if (moonPhase === 0.5)
|
||||||
|
output = '🌗 Third quarter';
|
||||||
|
else if (moonPhase > 0.75)
|
||||||
|
output = '🌖 Waning crescent';
|
||||||
|
|
||||||
|
return output;
|
||||||
|
// ['🌑', '🌘', '🌗', '🌖', '🌕', '🌔', '🌓', '🌒']
|
||||||
|
// a value of 0 corresponds to a new moon, 0.25 to a first quarter moon, 0.5 to a full moon, and 0.75 to a last quarter moon. (The ranges
|
||||||
|
// in between these represent waxing crescent, waxing gibbous, waning gibbous, and waning crescent moons, respectively.)
|
||||||
|
}
|
||||||
|
function getDetails(dailyData) {
|
||||||
|
const data = get(dailyData, 'data', []);
|
||||||
|
|
||||||
|
const today = data[0];
|
||||||
|
|
||||||
|
const output = {};
|
||||||
|
|
||||||
|
output.summary = dailyData.summary;
|
||||||
|
output.icon = dailyData.icon;
|
||||||
|
output.humidity = today.humidity;
|
||||||
|
output.visibility = today.visibility;
|
||||||
|
output.uvIndex = today.uvIndex;
|
||||||
|
output.sunriseTime = fecha.format(today.sunriseTime * 1000, 'shortTime');
|
||||||
|
output.sunsetTime = fecha.format(today.sunsetTime * 1000, 'shortTime');
|
||||||
|
output.moonphase = moonCalc(today.moonPhase);
|
||||||
|
output.moonPhaseVal = today.moonPhase;
|
||||||
|
output.windSpeed = today.windSpeed;
|
||||||
|
output.pressure = today.pressure;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reduceWeather(body = '') {
|
||||||
|
if (body === '') return {};
|
||||||
|
const obj = {};
|
||||||
|
const { currently, daily, hourly } = body;
|
||||||
|
const today = daily.data[0];
|
||||||
|
|
||||||
|
const outCurrent = {};
|
||||||
|
|
||||||
|
outCurrent.icon = get(currently, 'icon');
|
||||||
|
outCurrent.temperature = get(currently, 'temperature');
|
||||||
|
outCurrent.summary = get(currently, 'summary');
|
||||||
|
outCurrent.precip = get(currently, 'precipProbability');
|
||||||
|
outCurrent.precipType = get(currently, 'precipType');
|
||||||
|
outCurrent.tempMax = get(today, 'temperatureMax');
|
||||||
|
outCurrent.tempMin = get(today, 'temperatureMin');
|
||||||
|
outCurrent.windBearing = get(today, 'windBearing');
|
||||||
|
outCurrent.windBearingRead = toCompass(get(today, 'windBearing'));
|
||||||
|
|
||||||
|
const forcastToday = getTodaysForcast(hourly);
|
||||||
|
const dailyForecast = getDailyForcast(daily);
|
||||||
|
const details = getDetails(daily);
|
||||||
|
|
||||||
|
obj.currently = outCurrent;
|
||||||
|
obj.forcastToday = forcastToday;
|
||||||
|
obj.dailyForecast = dailyForecast;
|
||||||
|
obj.details = details;
|
||||||
|
obj.time = get(currently, 'time');
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { reduceWeather };
|
||||||
|
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
moonPhase optional, only on daily
|
||||||
|
The fractional part of the lunation number during the given day: a value of 0 corresponds to a new moon, 0.25 to a first quarter
|
||||||
|
moon, 0.5 to a full moon, and 0.75 to a last quarter moon. (The ranges in between these represent waxing crescent, waxing gibbous,
|
||||||
|
waning gibbous, and waning crescent moons, respectively.)
|
||||||
|
|
||||||
|
*/
|
97
server/routes/weather.js
Normal file
97
server/routes/weather.js
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
var router = require('express-promise-router')();
|
||||||
|
|
||||||
|
const weather = require('../lib/weather');
|
||||||
|
|
||||||
|
const logger = require('log4js').getLogger('simpleWeather');
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
OpenWeather:
|
||||||
|
/ow/forecast
|
||||||
|
/ow/fullforecast
|
||||||
|
|
||||||
|
DarkSkies
|
||||||
|
/ds/forecast
|
||||||
|
/ds/fullforecast
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
router.get('/ow/forecast', async (req, res, next) => {
|
||||||
|
if (req.query.hasOwnProperty('ll')) {
|
||||||
|
const ll = req.query.ll;
|
||||||
|
|
||||||
|
const weatherData = await weather.doGetOpenWeather(ll);
|
||||||
|
|
||||||
|
res.send(weatherData);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// throw new Error('Weather: LL missing');
|
||||||
|
logger.warn('FS: LL missing');
|
||||||
|
res.status(500).send('LL Missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/ow/fullforecast', async (req, res, next) => {
|
||||||
|
if (req.query.hasOwnProperty('ll')) {
|
||||||
|
const ll = req.query.ll;
|
||||||
|
|
||||||
|
const weatherData = await weather.doGetOpenWeatherForecast(ll);
|
||||||
|
|
||||||
|
res.send(weatherData);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// throw new Error('Weather: LL missing');
|
||||||
|
logger.warn('FS: LL missing');
|
||||||
|
res.status(500).send('LL Missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/ds/forecast', async (req, res, next) => {
|
||||||
|
if (req.query.hasOwnProperty('ll')) {
|
||||||
|
const ll = req.query.ll;
|
||||||
|
|
||||||
|
const weatherData = await weather.doGetDarkSkyWeather(ll);
|
||||||
|
|
||||||
|
res.send(weatherData);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// throw new Error('Weather: LL missing');
|
||||||
|
logger.warn('FS: LL missing');
|
||||||
|
res.status(500).send('LL Missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/ds/fullforecast', async (req, res, next) => {
|
||||||
|
if (req.query.hasOwnProperty('ll')) {
|
||||||
|
const ll = req.query.ll;
|
||||||
|
|
||||||
|
const weatherData = await weather.doGetFullForcast(ll);
|
||||||
|
|
||||||
|
res.send(weatherData);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// throw new Error('Weather: LL missing');
|
||||||
|
logger.warn('FS: LL missing');
|
||||||
|
res.status(500).send('LL Missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router;
|
Loading…
Reference in New Issue
Block a user