mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-27 03:39:55 +00:00
Merge pull request #9 from chmullig/master
Add weather icons to forecast. Use updated ical parser to convert UTC. Feed URL in config.
This commit is contained in:
commit
dd5bf51db9
@ -3,4 +3,6 @@ MagicMirror
|
|||||||
|
|
||||||
The super magic interface of my personal Magic Mirror. More information about this project can be found on my [blog](http://michaelteeuw.nl/tagged/magicmirror).
|
The super magic interface of my personal Magic Mirror. More information about this project can be found on my [blog](http://michaelteeuw.nl/tagged/magicmirror).
|
||||||
|
|
||||||
Modify js/config.js to change some general variables (language, wather location, compliments) and calendar.php to add your own ICS calendar
|
Runs as a php script on a web server with basically no external dependencies. Can use socket.io for XBEE integration, but isn't required for basic functionality.
|
||||||
|
|
||||||
|
Modify js/config.js to change some general variables (language, wather location, compliments, news feed RSS) and calendar.php to add your own ICS calendar
|
||||||
|
10
css/main.css
10
css/main.css
@ -134,6 +134,16 @@ body, html {
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-small
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 20px;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: -10px;
|
||||||
|
font-weight: 100;
|
||||||
|
}
|
||||||
|
|
||||||
.time .sec {
|
.time .sec {
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
@ -4,12 +4,18 @@ var lang = window.navigator.language;
|
|||||||
//var lang = 'en';
|
//var lang = 'en';
|
||||||
|
|
||||||
//change weather params here:
|
//change weather params here:
|
||||||
|
//units: metric or imperial
|
||||||
var weatherParams = {
|
var weatherParams = {
|
||||||
'q':'Baarn,Netherlands',
|
'q':'Baarn,Netherlands',
|
||||||
'units':'metric',
|
'units':'metric',
|
||||||
'lang':lang
|
'lang':lang
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var feed = 'http://feeds.nos.nl/nosjournaal?format=rss';
|
||||||
|
//var feed = 'http://www.nu.nl/feeds/rss/achterklap.rss';
|
||||||
|
//var feed = 'http://www.nu.nl/feeds/rss/opmerkelijk.rss';
|
||||||
|
//var feed = 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml';
|
||||||
|
|
||||||
// compliments:
|
// compliments:
|
||||||
var compliments = [
|
var compliments = [
|
||||||
'Hey, handsome!',
|
'Hey, handsome!',
|
||||||
|
64
js/ical_parser.js
Executable file → Normal file
64
js/ical_parser.js
Executable file → Normal file
@ -40,7 +40,7 @@ function ical_parser(feed_url, callback){
|
|||||||
*/
|
*/
|
||||||
this.makeDate = function(ical_date){
|
this.makeDate = function(ical_date){
|
||||||
//break date apart
|
//break date apart
|
||||||
var dt = {
|
var dtutc = {
|
||||||
year: ical_date.substr(0,4),
|
year: ical_date.substr(0,4),
|
||||||
month: ical_date.substr(4,2),
|
month: ical_date.substr(4,2),
|
||||||
day: ical_date.substr(6,2),
|
day: ical_date.substr(6,2),
|
||||||
@ -48,9 +48,19 @@ function ical_parser(feed_url, callback){
|
|||||||
minute: ical_date.substr(11,2)
|
minute: ical_date.substr(11,2)
|
||||||
}
|
}
|
||||||
//Create JS date (months start at 0 in JS - don't ask)
|
//Create JS date (months start at 0 in JS - don't ask)
|
||||||
dt.date = new Date(dt.year, (dt.month-1), dt.day, dt.hour, dt.minute);
|
var utcdatems = Date.UTC(dtutc.year, (dtutc.month-1), dtutc.day, dtutc.hour, dtutc.minute);
|
||||||
|
var dt = {};
|
||||||
|
dt.date = new Date(utcdatems);
|
||||||
|
|
||||||
|
dt.year = dt.date.getFullYear();
|
||||||
|
dt.month = ('0' + (dt.date.getMonth()+1)).slice(-2);
|
||||||
|
dt.day = ('0' + dt.date.getDate()).slice(-2);
|
||||||
|
dt.hour = ('0' + dt.date.getHours()).slice(-2);
|
||||||
|
dt.minute = ('0' + dt.date.getMinutes()).slice(-2);
|
||||||
|
|
||||||
//Get the full name of the given day
|
//Get the full name of the given day
|
||||||
dt.dayname =["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][dt.date.getDay()];
|
dt.dayname =["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][dt.date.getDay()];
|
||||||
|
dt.monthname = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ][dt.date.getMonth()] ;
|
||||||
|
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
@ -66,7 +76,7 @@ function ical_parser(feed_url, callback){
|
|||||||
this.events = [];
|
this.events = [];
|
||||||
|
|
||||||
//Clean string and split the file so we can handle it (line by line)
|
//Clean string and split the file so we can handle it (line by line)
|
||||||
cal_array = data.replace(new RegExp( "\\r", "g" ), "").split("\n");
|
cal_array = data.replace(new RegExp( "\\r", "g" ), "").replace(/\n /g,"").split("\n");
|
||||||
|
|
||||||
//Keep track of when we are activly parsing an event
|
//Keep track of when we are activly parsing an event
|
||||||
var in_event = false;
|
var in_event = false;
|
||||||
@ -80,18 +90,23 @@ function ical_parser(feed_url, callback){
|
|||||||
cur_event = {};
|
cur_event = {};
|
||||||
}
|
}
|
||||||
//If we encounter end event, complete the object and add it to our events array then clear it for reuse.
|
//If we encounter end event, complete the object and add it to our events array then clear it for reuse.
|
||||||
if(in_event && ln == 'END:VEVENT'){
|
if(in_event && ln == 'END:VEVENT'){
|
||||||
in_event = false;
|
in_event = false;
|
||||||
this.events.push(cur_event);
|
this.events.push(cur_event);
|
||||||
cur_event = null;
|
cur_event = null;
|
||||||
}
|
}
|
||||||
//If we are in an event
|
//If we are in an event
|
||||||
if(in_event){
|
else if(in_event){
|
||||||
|
//var lntrim = ln.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
|
||||||
|
//var lnsplit = lntrim.split(':');
|
||||||
|
//type = lnsplit[0];
|
||||||
|
//val = lnsplit[1];
|
||||||
|
|
||||||
//Split the item based on the first ":"
|
//Split the item based on the first ":"
|
||||||
idx = ln.indexOf(':');
|
idx = ln.indexOf(':');
|
||||||
//Apply trimming to values to reduce risks of badly formatted ical files.
|
//Apply trimming to values to reduce risks of badly formatted ical files.
|
||||||
type = ln.substr(0,idx).replace(/^\s\s*/, '').replace(/\s\s*$/, '');//Trim
|
type = ln.substr(0,idx).replace(/^\s\s*/, '').replace(/\s\s*$/, '');//Trim
|
||||||
val = ln.substr(idx+1,ln.length-(idx+1)).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
|
val = ln.substr(idx+1).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
|
||||||
|
|
||||||
//If the type is a start date, proccess it and store details
|
//If the type is a start date, proccess it and store details
|
||||||
if(type =='DTSTART'){
|
if(type =='DTSTART'){
|
||||||
@ -101,9 +116,10 @@ function ical_parser(feed_url, callback){
|
|||||||
cur_event.start_time = dt.hour+':'+dt.minute;
|
cur_event.start_time = dt.hour+':'+dt.minute;
|
||||||
cur_event.start_date = dt.day+'/'+dt.month+'/'+dt.year;
|
cur_event.start_date = dt.day+'/'+dt.month+'/'+dt.year;
|
||||||
cur_event.day = dt.dayname;
|
cur_event.day = dt.dayname;
|
||||||
|
cur_event.start_date_long = dt.day+'. '+dt.monthname+' '+dt.year ;
|
||||||
}
|
}
|
||||||
//If the type is an end date, do the same as above
|
//If the type is an end date, do the same as above
|
||||||
if(type =='DTEND'){
|
else if(type =='DTEND'){
|
||||||
dt = this.makeDate(val);
|
dt = this.makeDate(val);
|
||||||
val = dt.date;
|
val = dt.date;
|
||||||
//These are helpful for display
|
//These are helpful for display
|
||||||
@ -112,8 +128,16 @@ function ical_parser(feed_url, callback){
|
|||||||
cur_event.day = dt.dayname;
|
cur_event.day = dt.dayname;
|
||||||
}
|
}
|
||||||
//Convert timestamp
|
//Convert timestamp
|
||||||
if(type =='DTSTAMP') val = this.makeDate(val).date;
|
else if(type =='DTSTAMP'){
|
||||||
|
val = this.makeDate(val).date;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val = val
|
||||||
|
.replace(/\\r\\n/g,'<br />')
|
||||||
|
.replace(/\\n/g,'<br />')
|
||||||
|
.replace(/\\,/g,',');
|
||||||
|
}
|
||||||
|
|
||||||
//Add the value to our event object.
|
//Add the value to our event object.
|
||||||
cur_event[type] = val;
|
cur_event[type] = val;
|
||||||
}
|
}
|
||||||
@ -153,12 +177,28 @@ function ical_parser(feed_url, callback){
|
|||||||
var future_events = [], current_date = new Date();
|
var future_events = [], current_date = new Date();
|
||||||
|
|
||||||
this.events.forEach(function(itm){
|
this.events.forEach(function(itm){
|
||||||
//If the event starts after the current time, add it to the array to return.
|
//If the event ends after the current time, add it to the array to return.
|
||||||
if(itm.DTSTART > current_date) future_events.push(itm);
|
if(itm.DTEND > current_date) future_events.push(itm);
|
||||||
});
|
});
|
||||||
return future_events;
|
return future_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getPastEvents
|
||||||
|
* return all events sheduled to take place before the current date.
|
||||||
|
*
|
||||||
|
* @return list of events objects
|
||||||
|
*/
|
||||||
|
this.getPastEvents = function(){
|
||||||
|
var past_events = [], current_date = new Date();
|
||||||
|
|
||||||
|
this.events.forEach(function(itm){
|
||||||
|
//If the event ended before the current time, add it to the array to return.
|
||||||
|
if(itm.DTEND <= current_date) past_events.push(itm);
|
||||||
|
});
|
||||||
|
return past_events.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* load
|
* load
|
||||||
* load a new ICAL file.
|
* load a new ICAL file.
|
||||||
@ -181,4 +221,4 @@ function ical_parser(feed_url, callback){
|
|||||||
this.feed_url = feed_url;
|
this.feed_url = feed_url;
|
||||||
//Load the file
|
//Load the file
|
||||||
this.load(this.feed_url);
|
this.load(this.feed_url);
|
||||||
}
|
}
|
||||||
|
28
js/main.js
28
js/main.js
@ -249,6 +249,26 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
(function updateWeatherForecast()
|
(function updateWeatherForecast()
|
||||||
{
|
{
|
||||||
|
var iconTable = {
|
||||||
|
'01d':'wi-day-sunny',
|
||||||
|
'02d':'wi-day-cloudy',
|
||||||
|
'03d':'wi-cloudy',
|
||||||
|
'04d':'wi-cloudy-windy',
|
||||||
|
'09d':'wi-showers',
|
||||||
|
'10d':'wi-rain',
|
||||||
|
'11d':'wi-thunderstorm',
|
||||||
|
'13d':'wi-snow',
|
||||||
|
'50d':'wi-fog',
|
||||||
|
'01n':'wi-night-clear',
|
||||||
|
'02n':'wi-night-cloudy',
|
||||||
|
'03n':'wi-night-cloudy',
|
||||||
|
'04n':'wi-night-cloudy',
|
||||||
|
'09n':'wi-night-showers',
|
||||||
|
'10n':'wi-night-rain',
|
||||||
|
'11n':'wi-night-thunderstorm',
|
||||||
|
'13n':'wi-night-snow',
|
||||||
|
'50n':'wi-night-alt-cloudy-windy'
|
||||||
|
}
|
||||||
$.getJSON('http://api.openweathermap.org/data/2.5/forecast', weatherParams, function(json, textStatus) {
|
$.getJSON('http://api.openweathermap.org/data/2.5/forecast', weatherParams, function(json, textStatus) {
|
||||||
|
|
||||||
var forecastData = {};
|
var forecastData = {};
|
||||||
@ -260,10 +280,12 @@ jQuery(document).ready(function($) {
|
|||||||
if (forecastData[dateKey] == undefined) {
|
if (forecastData[dateKey] == undefined) {
|
||||||
forecastData[dateKey] = {
|
forecastData[dateKey] = {
|
||||||
'timestamp':forecast.dt * 1000,
|
'timestamp':forecast.dt * 1000,
|
||||||
|
'icon':forecast.weather[0].icon,
|
||||||
'temp_min':forecast.main.temp,
|
'temp_min':forecast.main.temp,
|
||||||
'temp_max':forecast.main.temp
|
'temp_max':forecast.main.temp
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
forecastData[dateKey]['icon'] = forecast.weather[0].icon;
|
||||||
forecastData[dateKey]['temp_min'] = (forecast.main.temp < forecastData[dateKey]['temp_min']) ? forecast.main.temp : forecastData[dateKey]['temp_min'];
|
forecastData[dateKey]['temp_min'] = (forecast.main.temp < forecastData[dateKey]['temp_min']) ? forecast.main.temp : forecastData[dateKey]['temp_min'];
|
||||||
forecastData[dateKey]['temp_max'] = (forecast.main.temp > forecastData[dateKey]['temp_max']) ? forecast.main.temp : forecastData[dateKey]['temp_max'];
|
forecastData[dateKey]['temp_max'] = (forecast.main.temp > forecastData[dateKey]['temp_max']) ? forecast.main.temp : forecastData[dateKey]['temp_max'];
|
||||||
}
|
}
|
||||||
@ -275,10 +297,12 @@ jQuery(document).ready(function($) {
|
|||||||
var opacity = 1;
|
var opacity = 1;
|
||||||
for (var i in forecastData) {
|
for (var i in forecastData) {
|
||||||
var forecast = forecastData[i];
|
var forecast = forecastData[i];
|
||||||
|
var iconClass = iconTable[forecast.icon];
|
||||||
var dt = new Date(forecast.timestamp);
|
var dt = new Date(forecast.timestamp);
|
||||||
var row = $('<tr />').css('opacity', opacity);
|
var row = $('<tr />').css('opacity', opacity);
|
||||||
|
|
||||||
row.append($('<td/>').addClass('day').html(moment.weekdaysShort(dt.getDay())));
|
row.append($('<td/>').addClass('day').html(moment.weekdaysShort(dt.getDay())));
|
||||||
|
row.append($('<td/>').addClass('icon-small').addClass(iconClass));
|
||||||
row.append($('<td/>').addClass('temp-max').html(roundVal(forecast.temp_max)));
|
row.append($('<td/>').addClass('temp-max').html(roundVal(forecast.temp_max)));
|
||||||
row.append($('<td/>').addClass('temp-min').html(roundVal(forecast.temp_min)));
|
row.append($('<td/>').addClass('temp-min').html(roundVal(forecast.temp_min)));
|
||||||
|
|
||||||
@ -297,9 +321,7 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
(function fetchNews() {
|
(function fetchNews() {
|
||||||
$.feedToJson({
|
$.feedToJson({
|
||||||
feed:'http://feeds.nos.nl/nosjournaal?format=rss',
|
feed: feed,
|
||||||
//feed:'http://www.nu.nl/feeds/rss/achterklap.rss',
|
|
||||||
//feed:'http://www.nu.nl/feeds/rss/opmerkelijk.rss',
|
|
||||||
success: function(data){
|
success: function(data){
|
||||||
news = [];
|
news = [];
|
||||||
for (var i in data.item) {
|
for (var i in data.item) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user