Added weather alerts
This commit is contained in:
parent
326ca1005b
commit
9f13a3e391
9
package-lock.json
generated
9
package-lock.json
generated
@ -9588,6 +9588,15 @@
|
||||
"error": "7.0.2"
|
||||
}
|
||||
},
|
||||
"request-json": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/request-json/-/request-json-0.6.3.tgz",
|
||||
"integrity": "sha512-5TVnMD3LaeK0GRCyFlsNgJf5Fjg8J8j7VEfsoJESSWZlWRgPIf7IojsBLbTHcg2798JrrRkJ6L3k1+wj4sglgw==",
|
||||
"requires": {
|
||||
"depd": "1.1.2",
|
||||
"request": "2.83.0"
|
||||
}
|
||||
},
|
||||
"request-promise": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
|
||||
|
@ -34,6 +34,7 @@
|
||||
"muicss": "^0.9.36",
|
||||
"node-foursquare-venues": "^1.1.0",
|
||||
"openweather-apis": "^3.3.5",
|
||||
"request-json": "^0.6.3",
|
||||
"twitter": "^1.7.1",
|
||||
"uglifyify": "^4.0.5",
|
||||
"underscore": "^1.8.3",
|
||||
|
20
server.js
20
server.js
@ -21,6 +21,7 @@ app.use(express.static(path.join(__dirname, sitePath)));
|
||||
|
||||
app.get('/weather', cache('45 minutes'), (req, res) => {
|
||||
if (req.query.hasOwnProperty('ll'))
|
||||
|
||||
weather.doGetOpenWeather(req.query.ll)
|
||||
.then((d) => {
|
||||
res.send(d);
|
||||
@ -36,6 +37,25 @@ app.get('/weather', cache('45 minutes'), (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/weatheralert', cache('45 minutes'), (req, res) => {
|
||||
if (req.query.hasOwnProperty('ll'))
|
||||
// weather.doGetOpenWeather(req.query.ll)
|
||||
// doGetDarkSkyWeather
|
||||
weather.doGetDarkSkyWeather(req.query.ll)
|
||||
.then((d) => {
|
||||
res.send(d);
|
||||
}).catch((e) => {
|
||||
logger.error(e);
|
||||
res.status(500).send('There was an error!');
|
||||
});
|
||||
|
||||
else {
|
||||
// throw new Error('Weather: LL missing');
|
||||
logger.warn('Weather: LL missing');
|
||||
res.status(500).send('LL Missing');
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/fsexplore', cache('30 minutes'), (req, res) => {
|
||||
if (req.query.hasOwnProperty('ll'))
|
||||
foursquare.doGetFourSquareExplore(req.query.ll)
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
const Client = require('request-json');
|
||||
const logger = require('log4js').getLogger('Weather');
|
||||
const weather = require('openweather-apis');
|
||||
|
||||
@ -6,6 +6,9 @@ logger.level = 'debug';
|
||||
|
||||
const openWeatherApiKey = process.env.openweatherAPI || '936a0ed9eb23b95cf08fc9f693c24264';
|
||||
|
||||
const darkskyApiKey = process.env.darkskyApiKey || '9ad2a41d420f3cf4960571bb886f710c';
|
||||
const DSclient = Client.createClient(`https://api.darksky.net/forecast/${ darkskyApiKey }/`);
|
||||
|
||||
weather.setAPPID(openWeatherApiKey);
|
||||
weather.setLang('en');
|
||||
// weather.setCity('Glasgow City');
|
||||
@ -38,5 +41,17 @@ function doGetOpenWeatherForecast(ll) {
|
||||
});
|
||||
}
|
||||
|
||||
function doGetDarkSkyWeather(ll) {
|
||||
const query = `${ll}?units=uk2&exclude=daily,flags,minutely,hourly`;
|
||||
logger.debug(query);
|
||||
return new Promise((resolve, reject) => {
|
||||
DSclient.get(query, function(err, res, body) {
|
||||
if (err || !body || !body.currently)
|
||||
return reject(err);
|
||||
|
||||
module.exports = { doGetOpenWeather, doGetOpenWeatherForecast };
|
||||
return resolve(body);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { doGetOpenWeather, doGetOpenWeatherForecast, doGetDarkSkyWeather };
|
||||
|
@ -25,10 +25,16 @@
|
||||
<div class="mui-container">
|
||||
<div id="greet"></div>
|
||||
|
||||
</div>
|
||||
<div class="mui-container" id="viewFrame">
|
||||
<div id="weatherAlertShell" class="mui-panel" style="display: none;">
|
||||
<div id="weatherAlertTitle" class="mui--text-title cardTitle">Weather Alert</div>
|
||||
<div id="weatherAlert"></div>
|
||||
</div>
|
||||
<div id="bymeShell" class="mui-panel" style="display: none;">
|
||||
<div id="byMeTitle" class="mui--text-title cardTitle">By me</div>
|
||||
<div id="byme"></div>
|
||||
</div>
|
||||
<div id="byMeTitle" class="mui--text-title cardTitle">By me</div>
|
||||
<div id="byme"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="nearbyShell" class="mui-panel" style="display: none;">
|
||||
@ -37,14 +43,14 @@
|
||||
</div>
|
||||
|
||||
<div id="newsShell" class="mui-panel" style="display: none;">
|
||||
<div class="mui--text-title cardTitle">Latest news</div>
|
||||
<div id="news" class="scrolling-wrapper-flexbox"></div>
|
||||
</div>
|
||||
<div class="mui--text-title cardTitle">Latest news</div>
|
||||
<div id="news" class="scrolling-wrapper-flexbox"></div>
|
||||
</div>
|
||||
|
||||
<div id="weatherShell" class="mui-panel" style="display: none;">
|
||||
<div class="mui--text-title cardTitle">Weather</div>
|
||||
<div id="weather"></div>
|
||||
</div>
|
||||
<div class="mui--text-title cardTitle">Weather</div>
|
||||
<div id="weather"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -113,7 +113,6 @@ const LocationModel = Backbone.Model.extend({
|
||||
console.error(err);
|
||||
this.set('location', newLocation);
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
newLocation.city = current.city;
|
||||
@ -126,16 +125,16 @@ const LocationModel = Backbone.Model.extend({
|
||||
// console.log('>> distanceFromLastGeocode', distanceFromLastGeocode, TimeFormat.fromMs(timestamp - lastGeocode.timestamp, 'hh:mm:ss'));
|
||||
console.log('>> distanceFromLastGeocode', distanceFromLastGeocode, TimeFormat.fromMs(currentTime - lastGeocode.timestamp, 'hh:mm:ss'));
|
||||
console.log(`(currentTime:${currentTime}, timestamp:${timestamp}, lastGeocode.timestamp:${lastGeocode.timestamp})`);
|
||||
console.log('(currentTime - current.timestamp > 900000) ' , (currentTime - current.timestamp > 900000));
|
||||
//if ((distanceFromLast > 0.5 && distanceFromLast < 2.0) || (timestamp - current.timestamp > 900000)) {
|
||||
if ((distanceFromLast > 0.5 && distanceFromLast < 2.0) || (currentTime - current.timestamp > 900000)) {
|
||||
console.log('(currentTime - current.timestamp > 900000) ', (currentTime - current.timestamp > 900000));
|
||||
// if ((distanceFromLast > 0.5 && distanceFromLast < 2.0) || (timestamp - current.timestamp > 900000)) {
|
||||
if ((distanceFromLast > 0.5 && distanceFromLast < 2.0) || ((currentTime - current.timestamp > 900000) && (currentTime - lastGeocode.timestamp < 1.8e+6))) {
|
||||
// dont bother re geocoding
|
||||
console.log('Slightly moved from previous');
|
||||
this.set('location', newLocation);
|
||||
this.set('moving', moving);
|
||||
}
|
||||
else if (distanceFromLastGeocode >= 2.0 || (timestamp - lastGeocode.timestamp > 1.8e+6) ) {
|
||||
console.log('Moved from previous', (timestamp - lastGeocode.timestamp > 1.8e+6));
|
||||
else if (distanceFromLastGeocode >= 2.0 || (currentTime - lastGeocode.timestamp >= 1.8e+6) ) {
|
||||
console.log('Moved from previous', (currentTime - lastGeocode.timestamp >= 1.8e+6));
|
||||
console.info('>> Location:geocoder request');
|
||||
geocoder.reverse(latlong)
|
||||
.then(function(res) {
|
||||
|
@ -92,7 +92,7 @@ const WeatherModel = Backbone.Model.extend({
|
||||
},
|
||||
'getWeather': function() {
|
||||
// const ll = this.get('llShort');
|
||||
console.info('>> Weather:request');
|
||||
console.log('>> Weather request');
|
||||
const llFixed = this.get('llFixed');
|
||||
request({
|
||||
'url': `${window.loc}/weather`,
|
||||
@ -175,7 +175,7 @@ const WeatherView = Backbone.View.extend({
|
||||
console.log('>> Weather No location yet');
|
||||
},
|
||||
'render': function() {
|
||||
console.info('>> Weather:Render');
|
||||
console.log('>> Weather:Render');
|
||||
|
||||
this.$el.empty();
|
||||
const item = this.wCollection.first();
|
||||
|
161
src/v1/js/WeatherAlert.js
Normal file
161
src/v1/js/WeatherAlert.js
Normal file
@ -0,0 +1,161 @@
|
||||
const $ = require('jquery');
|
||||
const _ = require('underscore');
|
||||
const Backbone = require('backbone');
|
||||
const request = require('request');
|
||||
const fecha = require('fecha');
|
||||
const { get } = require('lodash');
|
||||
const { reduceOpenWeather } = require('./reducers');
|
||||
const { distance, toHour } = require('./utils');
|
||||
|
||||
const WeatherAlertModel = Backbone.Model.extend({
|
||||
'defaults': function (obj) {
|
||||
// return a new object
|
||||
return {
|
||||
'update': new Date().getTime()
|
||||
};
|
||||
},
|
||||
'initialize': function () {
|
||||
this.run = false;
|
||||
this.listenTo(this, 'change:ll', this.onChange);
|
||||
this.listenTo(this, 'change:update', this.onChange);
|
||||
},
|
||||
'onChange': function () {
|
||||
console.log('Weather LL has changed');
|
||||
// if distance change > 10km
|
||||
// if its been an hour since last update
|
||||
|
||||
if (!this.has('log')) {
|
||||
console.info('First run');
|
||||
this.getWeatherAlert();
|
||||
}
|
||||
else {
|
||||
const log = this.get('log');
|
||||
const timeDiff = new Date().getTime() - log.time;
|
||||
const ll = this.get('ll').split(',');
|
||||
|
||||
const dist = distance(log.lat, log.long, ll[0], ll[1]);
|
||||
console.log('Weather distance:', dist);
|
||||
|
||||
if ((dist > 5.0) && (timeDiff > 1.8e+6))
|
||||
this.getWeatherAlert();
|
||||
else if (timeDiff > 3.6e+6) {
|
||||
console.log('WeatherAlert hourly update');
|
||||
this.getWeatherAlert();
|
||||
}
|
||||
}
|
||||
},
|
||||
'getWeatherAlert': function () {
|
||||
// const ll = this.get('llShort');
|
||||
console.log('>> WeatherAlert request');
|
||||
const llFixed = this.get('ll');
|
||||
request({
|
||||
'url': `${window.loc}/weatheralert`,
|
||||
'method': 'GET',
|
||||
'qs': {
|
||||
'll': llFixed
|
||||
}
|
||||
}, function (err, res, body) {
|
||||
if (err)
|
||||
console.error(err);
|
||||
else {
|
||||
// console.log(body);
|
||||
const fsJSON = JSON.parse(body);
|
||||
|
||||
const alerts = get(fsJSON, 'alerts', []);
|
||||
const item = alerts.slice(0, 1);
|
||||
|
||||
this.set('alert', item);
|
||||
|
||||
console.log(fsJSON);
|
||||
|
||||
this.logUpdate();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
'logUpdate': function () {
|
||||
console.log('WeatherAlert logging:');
|
||||
|
||||
const ll = this.get('ll').split(',');
|
||||
|
||||
const log = { 'lat': ll[0], 'long': ll[1], 'time': new Date().getTime() };
|
||||
|
||||
console.log('>>WeatherAlert log', log);
|
||||
this.set('log', log);
|
||||
|
||||
this.timerID = setTimeout(
|
||||
() => this.tick(),
|
||||
toHour
|
||||
);
|
||||
|
||||
// console.log(this);
|
||||
},
|
||||
'tick': function () {
|
||||
console.log('Set update');
|
||||
this.set('update', new Date().getTime());
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
const WeatherAlertView = Backbone.View.extend({
|
||||
'className': 'mui--align-middle',
|
||||
|
||||
'initialize': function(options) {
|
||||
this.eventBus = options.eventBus;
|
||||
this.location = options.location;
|
||||
|
||||
this.$parent = this.$el.parent();
|
||||
this.$title = $('#weatherAlertTitle');
|
||||
|
||||
// this.model.bind('change', this.render, this);
|
||||
this.location.bind('change', this.updateLocation, this);
|
||||
this.model.bind('change:alert', this.render, this);
|
||||
},
|
||||
'template': _.template(`
|
||||
<div>
|
||||
<div class="mui--text-body1 %>"><%=description%></div>
|
||||
|
||||
<div class="mui--text-dark-secondary mui--text-caption mui--text-right">
|
||||
Expires <%= readdate %>
|
||||
</div>
|
||||
`),
|
||||
'attributes': function() {
|
||||
return {
|
||||
'class': 'mui--align-middle'
|
||||
};
|
||||
},
|
||||
'events': {
|
||||
'click': 'doClick'
|
||||
},
|
||||
'updateLocation': function(l) {
|
||||
console.log('>> WeatherAlert Location has changed...');
|
||||
|
||||
if (l.has('location')) {
|
||||
const location = l.get('location');
|
||||
if (location.hasOwnProperty('atHome'))
|
||||
this.model.set('ll', location.llFixed);
|
||||
}
|
||||
else
|
||||
console.log('>> Weather No location yet');
|
||||
},
|
||||
'render': function() {
|
||||
console.log('>> WeatherAlert:Render');
|
||||
|
||||
this.$el.empty();
|
||||
|
||||
const alert = this.model.get('alert');
|
||||
|
||||
if (alert.length === 0)
|
||||
// nothing to see, hide the alert.
|
||||
this.$parent.hide();
|
||||
else {
|
||||
const fts = new Date(alert[0].expires * 1000);
|
||||
alert[0].readdate = fecha.format(fts, 'default');
|
||||
this.$title.html(alert[0].title);
|
||||
this.$el.html(this.template(alert[0]));
|
||||
this.$el.parent().show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = { WeatherAlertModel, WeatherAlertView };
|
@ -7,6 +7,7 @@ const { LocationModel } = require('./Location');
|
||||
const { GreetModel, GreetView } = require('./Greet');
|
||||
const { NearbyModel, NearbyView } = require('./Nearby');
|
||||
const { WeatherModel, WeatherView } = require('./Weather');
|
||||
const { WeatherAlertModel, WeatherAlertView } = require('./WeatherAlert');
|
||||
const { NewsModel, NewsView } = require('./News');
|
||||
const { ByMeModel, ByMeView } = require('./RightByMe');
|
||||
|
||||
@ -56,7 +57,9 @@ else
|
||||
|
||||
app.nearby = new NearbyView({ 'model': new NearbyModel(), 'eventBus': app.eventBus, 'location': app.locationModel, 'el':'#nearby' });
|
||||
|
||||
app.weather = new WeatherView({ 'model': new WeatherModel(), 'eventBus': app.eventBus, 'location': app.locationModel, 'el':'#weather' });
|
||||
app.weather = new WeatherView({ 'model': new WeatherModel(), 'eventBus': app.eventBus, 'location': app.locationModel, 'el':'#weather', 'viewFrame':'#viewFrame' });
|
||||
|
||||
app.weatherAlert = new WeatherAlertView({ 'model': new WeatherAlertModel(), 'eventBus': app.eventBus, 'location': app.locationModel, 'el':'#weatherAlert', 'viewFrame':'#viewFrame' });
|
||||
|
||||
app.news = new NewsView({ 'model': new NewsModel(), 'eventBus': app.eventBus, 'el':'#news' });
|
||||
|
||||
|
@ -1,6 +1,36 @@
|
||||
const fecha = require('fecha');
|
||||
const { get } = require('lodash');
|
||||
|
||||
function reduceDarksky(item, city) {
|
||||
// Openweather returns timestamps in seconds. Moment requires them in milliseconds.
|
||||
// Replaced Moment with Fecha.
|
||||
// Too many issues trying to get Moment packaged into the bundle.
|
||||
|
||||
if (!item || item === null) return {};
|
||||
const currently = get(item, 'currently');
|
||||
const alerts = get(item, 'alerts', []);
|
||||
const fts = new Date(currently.time * 1000);
|
||||
|
||||
const newItem = { 'timestamp': fts,
|
||||
'icon': `wi-wu-${currently.icon}`,
|
||||
'summary': currently.summary,
|
||||
'temp': parseInt(currently.temperature, 10),
|
||||
'feels': parseFloat(currently.apparentTemperature, 10),
|
||||
'datelong': fecha.format(fts, 'YYYY-MM-DDTHH:mm:ss.SSSZZ'),
|
||||
'readdate': fecha.format(fts, 'default'),
|
||||
'time': fts,
|
||||
'date': fecha.format(fts, 'D/M'),
|
||||
'day': fecha.format(fts, 'ddd'),
|
||||
'city': city
|
||||
};
|
||||
|
||||
return {
|
||||
'item' : newItem,
|
||||
'alerts': (alerts.length === 0) ? alerts : alerts.slice(0, 1)
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function reduceOpenWeather(item, city) {
|
||||
// Openweather returns timestamps in seconds. Moment requires them in milliseconds.
|
||||
// Replaced Moment with Fecha.
|
||||
@ -88,4 +118,4 @@ const pubdateSrc = fecha.parse(item.pubdate, 'ddd, DD MMM YYYY HH:mm:SS ZZ');
|
||||
</article>`;
|
||||
*/
|
||||
|
||||
module.exports = { reduceOpenWeather, reduceNearby, reduceEuronews };
|
||||
module.exports = { reduceOpenWeather, reduceNearby, reduceEuronews, reduceDarksky };
|
||||
|
Loading…
Reference in New Issue
Block a user