/* global Module */
/* Magic Mirror
- Module: MMM-Traffic
- By Sam Lewis https://github.com/SamLewis0602
- MIT Licensed.
*/
Module.register(‘MMM-Traffic’, {
defaults: {
api_key: '',
mode: 'driving',
interval: 300000, //all modules use milliseconds
origin: '',
destination: '',
mon_destination: '',
tues_destination: '',
wed_destination: '',
thurs_destination: '',
fri_destination: '',
traffic_model: 'best_guess',
departure_time: 'now',
arrival_time: '',
loadingText: 'Loading commute...',
prependText: 'Current commute is',
changeColor: false,
limitYellow: 10,
limitRed: 30,
showGreen: true,
language: config.language,
show_summary: true,
showWeekend: true,
allTime: true,
startHr: 7,
endHr: 22,
avoid:'',
summaryText:'via',
leaveByText:'Leave by',
arriveByText:'to arrive by',
hideOffHours: false,
},
setLocalParams: function(){
// These parameters are populated mostly
// by node_helper
this.loaded = false;
this.mapLoaded= false;
this.leaveBy = '';
this.symbols = {
'driving': 'fa fa-car',
'walking': 'fa fa-odnoklassniki',
'bicycling': 'fa fa-bicycle',
'transit': 'fa fa-train'
};
this.commute = '';
this.summary = '';
},
start: function() {
Log.info('Starting module: ' + this.name);
if (this.data.classes === 'MMM-Traffic') {
this.data.classes = 'bright medium';
}
this.loaded = false;
this.mapLoaded= false;
this.leaveBy = '';
var myURL = 'https://maps.googleapis.com/maps/api/directions/json' + this.getParams();
console.log("Querying with loc = " + myURL);
this.url = encodeURI('https://maps.googleapis.com/maps/api/directions/json' + this.getParams());
this.symbols = {
'driving': 'fa fa-car',
'walking': 'fa fa-odnoklassniki',
'bicycling': 'fa fa-bicycle',
'transit': 'fa fa-train'
};
this.commute = '';
this.summary = '';
this.updateCommute(this);
},
// Handler for notifications from any other module asking for
// TRAFFFIC update.
// This will invoke updateCommute with new source and destination
// TODO: The new source and destination will continue to get displayed untill
// it is reset. Will try to revert that
notificationReceived: function(notification, payload, sender){
Log.log(notification+" received from "+sender);
var myURL = "";
if(notification === "TRAFFIC_ACTION_NEEDED"){
console.log("Received new traffic update request for start: "+payload.start_location+" end:"+payload.end_location);
myURL = 'https://maps.googleapis.com/maps/api/directions/json' +
this.getParam_specific(payload.start_location, payload.end_location);
console.log("Querying with "+myURL);
this.url = encodeURI(myURL);
this.updateCommute(this);
}
},
updateCommute: function(self) {
console.log("updateCommute called");
timeConfig = {
showWeekend: self.config.showWeekend,
allTime: self.config.allTime,
startHr: self.config.startHr,
endHr: self.config.endHr
};
if (self.config.arrival_time.length == 4) {
self.sendSocketNotification('LEAVE_BY', {'url':self.url, 'arrival':self.config.arrival_time, 'timeConfig':timeConfig});
} else {
self.sendSocketNotification('TRAFFIC_URL', {'url':self.url, 'timeConfig':timeConfig});
}
setTimeout(self.updateCommute, self.config.interval, self);
},
getStyles: function() {
return ['traffic.css', 'font-awesome.css'];
},
createMap_area: function(start_location, end_location){
console.log("createMap_area invoked");
if(document.getElementById('map'))
{
console.log("Map Div available "+start_location.lat);
var map_options = {
center: new google.maps.LatLng(start_location.lat, start_location.lng),
zoom: 20,
size: '300x300',
panControl: true,
mapTypeControl: false,
panControlOptions: {
position: google.maps.ControlPosition.RIGHT_CENTER
},
zoomControl: true,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.LARGE,
position: google.maps.ControlPosition.RIGHT_CENTER
},
scaleControl: false,
streetViewControl: false,
streetViewControlOptions: {
position: google.maps.ControlPosition.RIGHT_CENTER
}
};
// map div is added to document.body
var map = new google.maps.Map(document.getElementById("map"), map_options);
var start_bound = new google.maps.LatLng(start_location.lat, start_location.lng);
var end_bound = new google.maps.LatLng(end_location.lat, end_location.lng);
var marker = new google.maps.Marker({
position: start_bound,
map: map
});
var marker = new google.maps.Marker({
position: end_bound,
map: map
})
var bounds = new google.maps.LatLngBounds();
bounds.extend(start_bound);
bounds.extend(end_bound);
map.fitBounds(bounds);
// the preserveViewport is almost mandatory to prevent zoom/pan out of the screen
var directionsDisplay = new google.maps.DirectionsRenderer({
map: map,
zoom: 20,
preserveViewport: true
});
directionsDisplay.setMap(map);
// Set destination, origin and travel mode.
var request = {
destination: end_location,
origin: start_location,
travelMode: 'DRIVING'
};
// Pass the directions request to the directions service.
var directionsService = new google.maps.DirectionsService();
directionsService.route(request, function(response, status) {
if (status == 'OK') {
// Display the route on the map.
directionsDisplay.setDirections(response);
}
});
// Pass the directions request to the directions service.
this.mapLoaded = true;
}
return document.getElementById('map');
},
createMap: function(){
var wrapper = document.createElement('div');
wrapper.style.height = this.config.height;
wrapper.style.width = this.config.width;
wrapper.setAttribute("id", "map");
// This script is appended to the main body
var outer_script = document.createElement("script");
outer_script.type = "text/javascript";
outer_script.src = "https://maps.googleapis.com/maps/api/js?key=" + this.config.api_key;
outer_script.setAttribute("async","");
outer_script.setAttribute("defer","");
document.body.appendChild(outer_script);
outer_script.onload = function(){
console.log("Added the map script to document body");
}
return wrapper;
},
getDom: function() {
var wrapper = document.createElement("div");
var commuteInfo = document.createElement('div');
var routeName = document.createElement('div');
// Map display
if (!this.loaded) {
console.log("[MMM-Traffic]Pre-loading invoked");
//wrapper.innerHTML = this.config.loadingText;
// Invoke adding the Google Maps base script to the dcoument.body
// It needs to be invoked only once.
wrapper.appendChild(this.createMap());
return wrapper;
}
if ((this.commute == '' || this.commute == '--') && this.config.hideOffHours && !this.config.allTime) {
wrapper.innerHTML = '';
return wrapper;
}
// Obtain start/end co-ordinates
var start_loc = this.start_location;
var end_loc = this.end_location;
console.log("Start lat "+start_loc.lat+" long "+start_loc.lng);
wrapper.appendChild(this.createMap_area(this.start_location, this.end_location));
//symbol
var symbol = document.createElement('span');
symbol.className = this.symbols[this.config.mode] + ' symbol';
commuteInfo.appendChild(symbol);
if (this.config.arrival_time == '') {
//commute time
var trafficInfo = document.createElement('span');
trafficInfo.innerHTML = this.config.prependText + ' ' + this.commute;
commuteInfo.appendChild(trafficInfo);
//routeName
if (this.config.route_name) {
routeName.className = 'dimmed small';
if (this.summary.length > 0 && this.config.show_summary){
routeName.innerHTML = this.config.route_name + ' ' + this.config.summaryText + ' ' + this.summary;
} else {
routeName.innerHTML = this.config.route_name;
}
}
} else {
//leave-by time
var trafficInfo = document.createElement('span');
trafficInfo.innerHTML = this.config.leaveByText + ' ' + this.leaveBy;
commuteInfo.appendChild(trafficInfo);
//routeName
if (this.config.route_name) {
routeName.className = 'dimmed small';
if (this.summary.length > 0 && this.config.show_summary){
routeName.innerHTML = this.config.route_name + ' ' + this.config.summaryText + ' ' + this.summary + ' ' + this.config.arriveByText + ' ' + this.config.arrival_time.substring(0,2) + ":" + this.config.arrival_time.substring(2,4);
} else {
console.log(typeof this.config.arrival_time );
routeName.innerHTML = this.config.route_name + ' ' + this.config.arriveByText + ' ' + this.config.arrival_time.substring(0,2) + ":" + this.config.arrival_time.substring(2,4);
}
}
}
//change color if desired
if (this.config.changeColor) {
if (this.trafficComparison >= 1 + (this.config.limitRed / 100)) {
commuteInfo.className += ' red';
} else if (this.trafficComparison >= 1 + (this.config.limitYellow / 100)) {
commuteInfo.className += ' yellow';
} else if (this.config.showGreen) {
commuteInfo.className += ' green';
}
}
wrapper.appendChild(commuteInfo);
wrapper.appendChild(routeName);
return wrapper;
},
getParam_specific: function(origin, destination){
var params = '?';
params += 'mode=' + this.config.mode;
params += '&origin=' + origin;
params += '&destination=' + destination;
params += '&key=' + this.config.api_key;
params += '&traffic_model=' + this.config.traffic_model;
params += '&language=' + this.config.language;
if (this.config.avoid.length > 0) {
params += '&avoid=' + this.config.avoid;
}
return params;
},
getParams: function() {
var params = '?';
params += 'mode=' + this.config.mode;
params += '&origin=' + this.config.origin;
params += '&destination=' + this.getTodaysDestination();
params += '&key=' + this.config.api_key;
params += '&traffic_model=' + this.config.traffic_model;
params += '&language=' + this.config.language;
if (this.config.avoid.length > 0) {
params += '&avoid=' + this.config.avoid;
}
return params;
},
getTodaysDestination: function() {
var todays_destination = "";
switch (new Date().getDay()) {
case 1:
todays_destination = this.config.mon_destination;
break;
case 2:
todays_destination = this.config.tues_destination;
break;
case 3:
todays_destination = this.config.wed_destination;
break;
case 4:
todays_destination = this.config.thurs_destination;
break;
case 5:
todays_destination = this.config.fri_destination;
break;
default:
//to handle Sat and Sun (GoogleAPI may raise error if no destination set)
todays_destination = this.config.destination;
}
if(todays_destination === ""){ //if no weekday destinations defined in config.js, set to default
todays_destination = this.config.destination;
}
return todays_destination;
},
socketNotificationReceived: function(notification, payload) {
this.leaveBy = '';
this.start_location = payload.start_location;
this.end_location = payload.end_location;
if (notification === 'TRAFFIC_COMMUTE' && payload.url === this.url) {
Log.info('received TRAFFIC_COMMUTE');
this.commute = payload.commute;
this.summary = payload.summary;
this.trafficComparison = payload.trafficComparison;
this.loaded = true;
this.updateDom(1000);
} else if (notification === 'TRAFFIC_TIMING' && payload.url === this.url) {
Log.info('received TRAFFIC_TIMING');
this.leaveBy = payload.commute;
this.commute = payload.commute; //support for hideOffHours
this.summary = payload.summary;
this.loaded = true;
this.updateDom(1000);
}
}
});