From 9baa1d0ba692d36caaea965e79eed8315aa106b1 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Thu, 5 Oct 2017 19:42:35 +0100 Subject: [PATCH 01/20] commit changes from past years - language bug fixes, style changes and latest bug fix regarding walking leg departure --- i18n/de.json | 10 +- localtransport.css | 8 ++ localtransport.js | 338 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 283 insertions(+), 73 deletions(-) diff --git a/i18n/de.json b/i18n/de.json index e041d2b..583999d 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -1,3 +1,11 @@ { - "LOADING_CONNECTIONS": "Lade Verbindungen ..." + "LOADING_CONNECTIONS": "Lade Verbindungen ...", + "ARRIVAL": "Ankunft", + "MINUTE_PL": "Minuten", + "MINUTE_SL": "Minute", + "SECOND_PL": "Sekunden", + "MINUTE_PS": "min", + "MINUTE_SS": "min", + "SECOND_PS": "sek", + "FROM": "von" } diff --git a/localtransport.css b/localtransport.css index a4beae0..c11f9ad 100644 --- a/localtransport.css +++ b/localtransport.css @@ -12,9 +12,17 @@ } .localtransport ul li img { margin: 0 .25em 0 .5em; + max-height: 15px; + max-width: 15px; + height: 15px; + width: 15px; } .localtransport ul li div { margin-left: .5em; } +.localtransport img.symbol.bw { + -webkit-filter: grayscale(100%); +} + /* This beautiful CSS-File has been crafted with LESS (lesscss.org) and compiled by simpLESS (wearekiss.com/simpless) */ diff --git a/localtransport.js b/localtransport.js index 1546413..1870929 100644 --- a/localtransport.js +++ b/localtransport.js @@ -3,122 +3,316 @@ * Module: localtransport * * By Christopher Fenner https://github.com/CFenner + * style options by Lasse Wollatz * MIT Licensed. */ Module.register('localtransport', { defaults: { + maximumEntries: 3, + displayStationLength: 0, + displayWalkType: 'short', + displayArrival: true, + maxWalkTime: 10, + fade: true, + fadePoint: 0.1, + maxModuleWidth: 0, animationSpeed: 1, updateInterval: 5, + language: config.language, + units: config.units, + timeFormat: config.timeFormat, mode: 'transit', traffic_model: 'best_guess', departure_time: 'now', - language: 'de', - units: 'metric', alternatives: true, - maxAlternatives: 3, + api_key: 'YOUR_API_KEY', apiBase: 'https://maps.googleapis.com/', - apiEndpoint: 'maps/api/directions/json' + apiEndpoint: 'maps/api/directions/json', + debug: false, + _laststop: '' }, start: function() { - Log.info('Starting module: ' + this.name); - this.loaded = false; - this.url = this.config.apiBase + this.config.apiEndpoint + this.getParams(); - this.update(); - // refresh every x minutes - setInterval( - this.update.bind(this), - this.config.updateInterval * 60 * 1000); + Log.info('Starting module: ' + this.name); + this.loaded = false; + if (this.config.api_key == 'YOUR_API_KEY'){ + this.config.api_key = config.apiKeys.google; + } + this.url = this.config.apiBase + this.config.apiEndpoint + this.getParams(); + var d = new Date(); + this.lastupdate = d.getTime() - 2 * this.config.updateInterval * 60 * 1000; + this.update(); + // refresh every 0.25 minutes + setInterval( + this.update.bind(this), + 15 * 1000); }, update: function() { - this.sendSocketNotification( - 'LOCAL_TRANSPORT_REQUEST', { - id: this.identifier, - url: this.config.apiBase + this.config.apiEndpoint + this.getParams() + //updateDOM + var dn = new Date(); + if (dn.getTime() - this.lastupdate >= this.config.updateInterval * 60 * 1000){ + //perform main update + //request routes from Google + this.sendSocketNotification( + 'LOCAL_TRANSPORT_REQUEST', { + id: this.identifier, + url: this.config.apiBase + this.config.apiEndpoint + this.getParams() + } + ); + if (this.config.debug){ + this.sendNotification("SHOW_ALERT", { timer: 3000, title: "LOCAL TRANSPORT", message: "special update"}); + } + this.lastupdate = dn.getTime(); + }else{ + //perform minor update + //only update time + if (this.config.debug){ + this.sendNotification("SHOW_ALERT", {timer: 3000, title: "LOCAL TRANSPORT", message: "normal update"}); } - ); + this.loaded = true; + this.updateDom(); //this.updateDom(this.config.animationSpeed * 1000) + } }, getParams: function() { - var params = '?'; - params += 'mode=' + this.config.mode; - params += '&origin=' + this.config.origin; - params += '&destination=' + this.config.destination; - params += '&key=' + this.config.api_key; - params += '&traffic_model=' + this.config.traffic_model; - params += '&departure_time=now'; - params += '&alternatives=true'; - return params; + var params = '?'; + params += 'mode=' + this.config.mode; + params += '&origin=' + this.config.origin; + params += '&destination=' + this.config.destination; + params += '&key=' + this.config.api_key; + params += '&traffic_model=' + this.config.traffic_model; + params += '&departure_time=now'; + params += '&alternatives=true'; + return params; }, renderLeg: function(wrapper, leg){ + /* renderLeg + * creates HTML element for one leg of a route + */ var depature = leg.departure_time.value * 1000; var arrival = leg.arrival_time.value * 1000; + //var depadd = leg.start_address; var span = document.createElement("div"); - span.innerHTML = - moment(depature).fromNow() - // + this.translate('TRAVEL_TIME') + ": " - // + moment.duration(moment(arrival).diff(depature, 'minutes'), 'minutes').humanize() - ; + span.className = "small bright"; + span.innerHTML = moment(depature).locale(this.config.language).fromNow(); + // span.innerHTML += "from " + depadd; + if (this.config.displayArrival && this.config.timeFormat == 24){ + span.innerHTML += " ("+this.translate("ARRIVAL")+": " + moment(arrival).format("H:mm") + ")"; + }else if(this.config.displayArrival){ + span.innerHTML += " ("+this.translate("ARRIVAL")+": " + moment(arrival).format("h:mm") + ")"; + } + // span.innerHTML += this.translate('TRAVEL_TIME') + ": "; + // span.innerHTML += moment.duration(moment(arrival).diff(depature, 'minutes'), 'minutes').humanize(); wrapper.appendChild(span); }, renderStep: function(wrapper, step){ + /* renderStep + * creates HTML element for one step of a leg + */ if(step.travel_mode === "WALKING"){ - return; // skip walking - } - var details = step.transit_details; - if(details) { - var img = document.createElement("img"); - img.src = details.line.vehicle.local_icon || ("http:" + details.line.vehicle.icon); - wrapper.appendChild(img); - var span = document.createElement("span"); - span.innerHTML = details.line.short_name || details.line.name; - span.className = "bright"; - wrapper.appendChild(span); + /*this step is not public transport but walking*/ + var duration = step.duration.value; + if (duration >= (this.config.maxWalkTime*60)){ + /*if time of walking is longer than + *specified, mark this route to be skipped*/ + wrapper.innerHTML = "too far"; + }else if(this.config.displayWalkType != 'none'){ + /*if walking and walking times should be + *specified, add symbol and time*/ + var img = document.createElement("img"); + if(this.config.showColor){ + img.className = "symbol"; + }else{ + img.className = "symbol bw"; + } + img.src = "http://maps.gstatic.com/mapfiles/transit/iw2/6/walk.png"; + //img.src = "/localtransport/walk.png"; //needs to be saved in localtransport/public/walk.png + wrapper.appendChild(img) + var span = document.createElement("span"); + span.innerHTML = moment.duration(duration, 'seconds').locale(this.config.language).humanize(); + if(this.config.displayWalkType == 'short'){ + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); + span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); + } + if (this.config._laststop !== ''){ + /* walking leg doesn't have a departure_stop set - maybe something else but can't find the documentation right now. + so in order to display the departure, we will just save the arrival of any transit leg into a global variable and + display the previous arrival instead of the current departure location. That means we need to reset the global variable + to not cause interference between different routes and we need to skip the display for the first leg if that is a walking + leg (alternatively one could display the departure location specified by the user, but I prefer this option) + */ + if (this.config.displayStationLength > 0){ + /* add departure stop (shortened)*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(this.config._laststop, this.config.displayStationLength) + ")"; + }else if (this.config.displayStationLength == 0){ + /* add departure stop*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; + } + } + span.className = "xsmall dimmed"; + wrapper.appendChild(span); + }else{ + /*skip walking*/ + return; + } + this.config._laststop = ''; + }else{ + /*if this is a transit step*/ + var details = step.transit_details; + if(details) { + /*add symbol of transport vehicle*/ + var img = document.createElement("img"); + if(this.config.showColor){ + img.className = "symbol"; + }else{ + img.className = "symbol bw"; + } + /* get symbol online*/ + img.src = details.line.vehicle.local_icon || ("http:" + details.line.vehicle.icon); + /* can provide own symbols under /localtransport/public/*.png */ + //img.src = "/localtransport/" + details.line.vehicle.name + ".png"; + img.alt = "[" + details.line.vehicle.name +"]"; + wrapper.appendChild(img); + /*add description*/ + var span = document.createElement("span"); + /* add line name*/ + span.innerHTML = details.line.short_name || details.line.name; + if (this.config.displayStationLength > 0){ + /* add departure stop (shortened)*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; + }else if (this.config.displayStationLength == 0){ + /* add departure stop*/ + span.innerHTML += " ("+this.translate("FROM")+" " + details.departure_stop.name + ")"; + } + if (this.config.debug){ + /* add vehicle type for debug*/ + span.innerHTML += " [" + details.line.vehicle.name +"]"; + } + this.config._laststop = details.arrival_stop.name; + span.className = "xsmall dimmed"; + wrapper.appendChild(span); + } } }, socketNotificationReceived: function(notification, payload) { - if (notification === 'LOCAL_TRANSPORT_RESPONSE' && payload.id === this.identifier) { - Log.info('received' + notification); - if(payload.data && payload.data.status === "OK"){ + if (notification === 'LOCAL_TRANSPORT_RESPONSE' && payload.id === this.identifier) { + Log.info('received' + notification); + if(payload.data && payload.data.status === "OK"){ this.data = payload.data; this.loaded = true; this.updateDom(this.config.animationSpeed * 1000); - } - } + } + } }, getStyles: function() { - return ["localtransport.css"]; + return ["localtransport.css"]; + }, + getScripts: function() { + return ["moment.js"]; }, - getScripts: function() { - return ["moment.js"]; - }, - getTranslations: function() { - return { - de: "i18n/de.json" + getTranslations: function() { + return { + de: "i18n/de.json", + en: "i18n/en.json" }; - }, + }, getDom: function() { + /* main function creating HTML code to display*/ var wrapper = document.createElement("div"); if (!this.loaded) { - wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); + /*if not loaded, display message*/ + wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); + wrapper.className = "small dimmed"; }else{ - var ul = document.createElement("ul"); - for(var routeKey in this.data.routes) { - if(Number(routeKey) >= this.config.maxAlternatives){ - break; + /*create an unsorted list with each + *route alternative being a new list item*/ + //var udt = document.createElement("div"); + //udt.innerHTML = moment().format("HH:mm:ss") + " (" + this.lastupdate + ")"; + //wrapper.appendChild(udt); + var ul = document.createElement("ul"); + var Nrs = 0; //number of routes + var routeArray = []; //array of all alternatives for later sorting + for(var routeKey in this.data.routes) { + /*each route describes a way to get from A to Z*/ + //if(Nrs >= this.config.maxAlternatives){ + // break; + //} + var route = this.data.routes[routeKey]; + var li = document.createElement("li"); + li.className = "small"; + var arrival = 0; + if (this.config.maxModuleWidth > 0){ + li.style.width = this.config.maxModuleWidth + "px"; + } + for(var legKey in route.legs) { + var leg = route.legs[legKey]; + arrival = leg.arrival_time.value; + var tmpwrapper = document.createElement("text"); + for(var stepKey in leg.steps) { + /*each leg consists of several steps + *e.g. (1) walk from A to B, then + (2) take the bus from B to C and then + (3) walk from C to Z*/ + var step = leg.steps[stepKey]; + this.renderStep(tmpwrapper, step); + if (tmpwrapper.innerHTML == "too far"){ + //walking distance was too long -> skip this option + break; + } + } + if (tmpwrapper.innerHTML == "too far"){ + //walking distance was too long -> skip this option + li.innerHTML = "too far"; + break; + } + this.renderLeg(li, leg); + li.appendChild(tmpwrapper); + } + if (li.innerHTML != "too far"){ + routeArray.push({"arrival":arrival,"html":li}); + Nrs += 1; + } } - var route = this.data.routes[routeKey]; - var li = document.createElement("li"); - for(var legKey in route.legs) { - var leg = route.legs[legKey]; - for(var stepKey in leg.steps) { - var step = leg.steps[stepKey]; - this.renderStep(li, step); - } - this.renderLeg(li, leg); + + /*sort the different alternative routes by arrival time*/ + routeArray.sort(function(a, b) { + return parseFloat(a.arrival) - parseFloat(b.arrival); + }); + /*only show the first few options as specified by "maximumEntries"*/ + routeArray = routeArray.slice(0, this.config.maximumEntries); + + /*create fade effect and append list items to the list*/ + var e = 0; + Nrs = routeArray.length; + for(var dataKey in routeArray) { + var routeData = routeArray[dataKey]; + var routeHtml = routeData.html; + // Create fade effect. + if (this.config.fade && this.config.fadePoint < 1) { + if (this.config.fadePoint < 0) { + this.config.fadePoint = 0; + } + var startingPoint = Nrs * this.config.fadePoint; + var steps = Nrs - startingPoint; + if (e >= startingPoint) { + var currentStep = e - startingPoint; + routeHtml.style.opacity = 1 - (1 / steps * currentStep); + } + } + ul.appendChild(routeHtml); + e += 1; } - ul.appendChild(li); - } - wrapper.appendChild(ul); + wrapper.appendChild(ul); } return wrapper; + }, + shorten: function(string, maxLength) { + /*shorten + *shortens a string to the number of characters specified*/ + if (string.length > maxLength) { + return string.slice(0,maxLength) + "…"; + } + return string; } + }); + From a9ddf39dc9a7f3e587bb3346b8cf71444fbd12a7 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Thu, 5 Oct 2017 19:58:49 +0100 Subject: [PATCH 02/20] added function to read API key from main config settings - this simplifies the code for multiple instances of the local transport module --- MMM-LocalTransport.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 53f83f7..9b9c272 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -26,6 +26,7 @@ Module.register('MMM-LocalTransport', { traffic_model: 'best_guess', departure_time: 'now', alternatives: true, + api_key: 'YOUR_API_KEY', apiBase: 'https://maps.googleapis.com/', apiEndpoint: 'maps/api/directions/json', debug: false @@ -33,6 +34,11 @@ Module.register('MMM-LocalTransport', { start: function() { Log.info('Starting module: ' + this.name); this.loaded = false; + if (this.config.api_key == 'YOUR_API_KEY'){ + /*if there is no api key specified in the options of the module, + look it up in the main config-file settings */ + this.config.api_key = config.apiKeys.google; + } this.url = this.config.apiBase + this.config.apiEndpoint + this.getParams(); var d = new Date(); this.lastupdate = d.getTime() - 2 * this.config.updateInterval * 60 * 1000; From 31128c52d6b299d36709fbc2cc71a0723a5213c7 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Thu, 5 Oct 2017 20:05:53 +0100 Subject: [PATCH 03/20] Added code to display departure location for walking steps --- MMM-LocalTransport.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 9b9c272..6e248c3 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -29,7 +29,8 @@ Module.register('MMM-LocalTransport', { api_key: 'YOUR_API_KEY', apiBase: 'https://maps.googleapis.com/', apiEndpoint: 'maps/api/directions/json', - debug: false + debug: false, + _laststop: '' }, start: function() { Log.info('Starting module: ' + this.name); @@ -135,12 +136,28 @@ Module.register('MMM-LocalTransport', { span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); } + if (this.config._laststop !== ''){ + /* walking step doesn't have a departure_stop set - maybe something else but can't find the documentation right now. + so in order to display the departure, we will just save the arrival of any transit step into a global variable and + display the previous arrival instead of the current departure location. That means we need to reset the global variable + to not cause interference between different routes and we need to skip the display for the first step if that is a walking + step (alternatively one could display the departure location specified by the user, but I prefer this option) + */ + if (this.config.displayStationLength > 0){ + /* add departure stop (shortened)*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(this.config._laststop, this.config.displayStationLength) + ")"; + }else if (this.config.displayStationLength == 0){ + /* add departure stop*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; + } + } span.className = "xsmall dimmed"; wrapper.appendChild(span); }else{ /*skip walking*/ return; } + this.config._laststop = ''; }else{ /*if this is a transit step*/ var details = step.transit_details; @@ -173,6 +190,7 @@ Module.register('MMM-LocalTransport', { /* add vehicle type for debug*/ span.innerHTML += " [" + details.line.vehicle.name +"]"; } + this.config._laststop = details.arrival_stop.name; span.className = "xsmall dimmed"; wrapper.appendChild(span); } From c47a9815eb75f5b9fb29ae9a5e7ebccd50b7fe81 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Thu, 5 Oct 2017 20:22:18 +0100 Subject: [PATCH 04/20] modified less and css to make symbols a bit smaller (to match text font-size) --- localtransport.css | 2 +- localtransport.less | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/localtransport.css b/localtransport.css index 3437976..9be3dd8 100644 --- a/localtransport.css +++ b/localtransport.css @@ -28,6 +28,6 @@ .MMM-LocalTransport ul li{margin-bottom:.25em} .MMM-LocalTransport ul li img.bw{-webkit-filter:grayscale(100%)} .MMM-LocalTransport ul li img:first-child{margin-left:0} -.MMM-LocalTransport ul li img{margin:0 .25em 0 .5em} +.MMM-LocalTransport ul li img{margin:0 .25em 0 .5em; max-height: 15px; max-width: 15px; height: 15px; width: 15px;} .MMM-LocalTransport ul li div{margin-left:.5em} /* This beautiful CSS-File has been crafted with LESS (lesscss.org) and compiled by simpLESS (wearekiss.com/simpless) */ diff --git a/localtransport.less b/localtransport.less index f738329..fdedef1 100644 --- a/localtransport.less +++ b/localtransport.less @@ -16,6 +16,10 @@ } img{ margin: 0 .25em 0 .5em; + max-height: 15px; + max-width: 15px; + height: 15px; + width: 15px; } div{ margin-left: .5em; From 3b60f6c5768029c6142f7be562895194db056c2f Mon Sep 17 00:00:00 2001 From: GHLasse Date: Thu, 5 Oct 2017 20:26:20 +0100 Subject: [PATCH 05/20] modified icons to load via https --- MMM-LocalTransport.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 6e248c3..5a93b66 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -126,7 +126,7 @@ Module.register('MMM-LocalTransport', { }else{ img.className = "symbol bw"; } - img.src = "http://maps.gstatic.com/mapfiles/transit/iw2/6/walk.png"; + img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/walk.png"; //img.src = "/localtransport/walk.png"; //needs to be saved in localtransport/public/walk.png wrapper.appendChild(img) var span = document.createElement("span"); @@ -170,7 +170,7 @@ Module.register('MMM-LocalTransport', { img.className = "symbol bw"; } /* get symbol online*/ - img.src = details.line.vehicle.local_icon || ("http:" + details.line.vehicle.icon); + img.src = details.line.vehicle.local_icon || ("https:" + details.line.vehicle.icon); /* can provide own symbols under /localtransport/public/*.png */ //img.src = "/localtransport/" + details.line.vehicle.name + ".png"; img.alt = "[" + details.line.vehicle.name +"]"; From 6ada2d801c06238619627e7162feccbdf77a1f4f Mon Sep 17 00:00:00 2001 From: GHLasse Date: Wed, 8 Nov 2017 17:50:33 +0000 Subject: [PATCH 06/20] added options to display alternative routes cleaned up code fixed bug where destination was displayed as origin for a leg if previous leg didn't end on a walking step --- MMM-LocalTransport.js | 774 ++++++++++++++++++++++++++++-------------- i18n/de.json | 3 +- i18n/en.json | 3 +- i18n/sv.json | 3 +- node_helper.js | 42 +++ 5 files changed, 562 insertions(+), 263 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 5a93b66..9cda5f0 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -3,57 +3,86 @@ * Module: MMM-LocalTransport * * By Christopher Fenner https://github.com/CFenner - * style options by Lasse Wollatz + * style options and calendar extension by Lasse Wollatz https://github.com/GHLasse * MIT Licensed. */ Module.register('MMM-LocalTransport', { - defaults: { - maximumEntries: 3, - displayStationLength: 0, - displayWalkType: 'short', - displayArrival: true, - maxWalkTime: 10, - fade: true, - fadePoint: 0.1, - showColor: true, - maxModuleWidth: 0, - animationSpeed: 1, - updateInterval: 5, - language: config.language, - units: config.units, - timeFormat: config.timeFormat, - mode: 'transit', - traffic_model: 'best_guess', - departure_time: 'now', - alternatives: true, - api_key: 'YOUR_API_KEY', - apiBase: 'https://maps.googleapis.com/', - apiEndpoint: 'maps/api/directions/json', - debug: false, - _laststop: '' - }, - start: function() { - Log.info('Starting module: ' + this.name); - this.loaded = false; - if (this.config.api_key == 'YOUR_API_KEY'){ - /*if there is no api key specified in the options of the module, - look it up in the main config-file settings */ - this.config.api_key = config.apiKeys.google; - } - this.url = this.config.apiBase + this.config.apiEndpoint + this.getParams(); - var d = new Date(); - this.lastupdate = d.getTime() - 2 * this.config.updateInterval * 60 * 1000; - this.update(); - // refresh every 0.25 minutes - setInterval( - this.update.bind(this), - 15 * 1000); - }, - update: function() { - //updateDOM - var dn = new Date(); - if (dn.getTime() - this.lastupdate >= this.config.updateInterval * 60 * 1000){ - //perform main update + defaults: { + maximumEntries: 3, //maximum number of Routes to display + displayStationLength: 0, + displayWalkType: 'short', + displayArrival: true, //display arrival time + displayAltWalk: false, //display info about how long walking would take + displayAltCycle: false, //display info about how long cycling would take + displayAltDrive: false, //display info about how long driving would take + maxWalkTime: 10, //maximum acceptable walking time between stations + fade: true, //apply fading effect + fadePoint: 0.1, + showColor: true, //display transport icons in colour + maxModuleWidth: 0, + animationSpeed: 1, + updateInterval: 5, //in min, how often to request new routes + language: config.language, + units: config.units, + timeFormat: config.timeFormat, + mode: 'transit', + traffic_model: 'best_guess', + departure_time: 'now', + alternatives: true, + getCalendarLocation: false, //read calendar notifications to display the route to the next event. + api_key: 'YOUR_API_KEY', + apiBase: 'https://maps.googleapis.com/', + apiEndpoint: 'maps/api/directions/json', + debug: false, + _laststop: '', //the variables with _ are for internal use only - should consider defining them elsewhere! + _headerDest: '', + _headerDestPlan: '', + _headerOrigPlan: '', + _destination: '', //actual destination requested from Google + _walktime: 'unknown', + _cycletime: 'unknown', + _drivetime: 'unknown', + test: "" + }, + start: function() { + Log.info('Starting module: ' + this.name); + this.loaded = false; + if (this.config.api_key === 'YOUR_API_KEY'){ + /*if there is no api key specified in the options of the module, + look it up in the main config-file settings */ + this.config.api_key = config.apiKeys.google; + } + this.config._destination = this.config.destination; + this.url = this.config.apiBase + this.config.apiEndpoint + this.getParams(); + var d = new Date(); + this.lastupdate = d.getTime() - 2 * this.config.updateInterval * 60 * 1000; + this.update(); + // refresh every 0.25 minutes so that the time left till departure is always correct without having to request an update from Google every time. + setInterval( + this.update.bind(this), + 15 * 1000); + }, + update: function() { + //updateDOM + var dn = new Date(); + if (dn.getTime() - this.lastupdate >= this.config.updateInterval * 60 * 1000){ + //perform main update + this.doMainUpdate(); + this.lastupdate = dn.getTime(); + }else{ + //perform minor update + //only update time + if (this.config.debug){ + this.sendNotification("SHOW_ALERT", {timer: 3000, title: "LOCAL TRANSPORT", message: "normal update"}); + } + this.loaded = true; + this.updateDom(); //this.updateDom(this.config.animationSpeed * 1000) + } + }, + doMainUpdate: function() { + /*doMainUpdate + *requests routes from Google for public transport and any alternatives if applicable. + */ //request routes from Google this.sendSocketNotification( 'LOCAL_TRANSPORT_REQUEST', { @@ -61,65 +90,179 @@ Module.register('MMM-LocalTransport', { url: this.config.apiBase + this.config.apiEndpoint + this.getParams() } ); - if (this.config.debug){ - this.sendNotification("SHOW_ALERT", { timer: 3000, title: "LOCAL TRANSPORT", message: "special update"}); + Log.info("requested public transport route"); + //request walking time + if (this.config.displayAltWalk){ + this.config.mode = 'walking'; + this.sendSocketNotification( + 'LOCAL_TRANSPORT_WALK_REQUEST', { + id: this.identifier, + url: this.config.apiBase + this.config.apiEndpoint + this.getParams() + } + ); + Log.info("requested walking route"); + this.config.mode = 'transit'; + } + //request cycling time + if (this.config.displayAltCycle){ + this.config.mode = 'bicycling'; + this.sendSocketNotification( + 'LOCAL_TRANSPORT_CYCLE_REQUEST', { + id: this.identifier, + url: this.config.apiBase + this.config.apiEndpoint + this.getParams() + } + ); + Log.info("requested cycling route"); + this.config.mode = 'transit'; + } + //request driving time + if (this.config.displayAltWalk){ + this.config.mode = 'driving'; + this.sendSocketNotification( + 'LOCAL_TRANSPORT_DRIVE_REQUEST', { + id: this.identifier, + url: this.config.apiBase + this.config.apiEndpoint + this.getParams() + } + ); + Log.info("requested driving route"); + this.config.mode = 'transit'; } - this.lastupdate = dn.getTime(); - }else{ - //perform minor update - //only update time if (this.config.debug){ - this.sendNotification("SHOW_ALERT", {timer: 3000, title: "LOCAL TRANSPORT", message: "normal update"}); + this.sendNotification("SHOW_ALERT", { timer: 3000, title: "LOCAL TRANSPORT", message: "special update"}); } - this.loaded = true; - this.updateDom(); //this.updateDom(this.config.animationSpeed * 1000) - } - }, - getParams: function() { - var params = '?'; - params += 'mode=' + this.config.mode; - params += '&origin=' + this.config.origin; - params += '&destination=' + this.config.destination; - params += '&key=' + this.config.api_key; - params += '&traffic_model=' + this.config.traffic_model; - params += '&departure_time=now'; - params += '&alternatives=true'; - return params; - }, - renderLeg: function(wrapper, leg){ - /* renderLeg - * creates HTML element for one leg of a route - */ - var depature = leg.departure_time.value * 1000; - var arrival = leg.arrival_time.value * 1000; - //var depadd = leg.start_address; - var span = document.createElement("div"); - span.className = "small bright"; - span.innerHTML = moment(depature).locale(this.config.language).fromNow(); - // span.innerHTML += "from " + depadd; - if (this.config.displayArrival && this.config.timeFormat === 24){ - span.innerHTML += " ("+this.translate("ARRIVAL")+": " + moment(arrival).format("H:mm") + ")"; - }else if(this.config.displayArrival){ - span.innerHTML += " ("+this.translate("ARRIVAL")+": " + moment(arrival).format("h:mm") + ")"; - } - // span.innerHTML += this.translate('TRAVEL_TIME') + ": "; - // span.innerHTML += moment.duration(moment(arrival).diff(depature, 'minutes'), 'minutes').humanize(); - wrapper.appendChild(span); - }, - renderStep: function(wrapper, step){ - /* renderStep - * creates HTML element for one step of a leg - */ - if(step.travel_mode === "WALKING"){ - /*this step is not public transport but walking*/ - var duration = step.duration.value; - if (duration >= (this.config.maxWalkTime*60)){ - /*if time of walking is longer than - *specified, mark this route to be skipped*/ - wrapper.innerHTML = "too far"; - }else if(this.config.displayWalkType != 'none'){ - /*if walking and walking times should be - *specified, add symbol and time*/ + }, + getParams: function() { + var params = '?'; + params += 'mode=' + this.config.mode; + params += '&origin=' + this.config.origin; + params += '&destination=' + this.config._destination; + params += '&key=' + this.config.api_key; + params += '&traffic_model=' + this.config.traffic_model; + params += '&departure_time=now'; + params += '&alternatives=true'; + return params; + }, + renderLeg: function(wrapper, leg){ + /* renderLeg + * creates HTML element for one leg of a route + */ + var depature = leg.departure_time.value * 1000; + var arrival = leg.arrival_time.value * 1000; + //var depadd = leg.start_address; + var span = document.createElement("div"); + span.className = "small bright"; + span.innerHTML = moment(depature).locale(this.config.language).fromNow(); + // span.innerHTML += "from " + depadd; + if (this.config.displayArrival && this.config.timeFormat === 24){ + span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": " + moment(arrival).format("H:mm") + ")"; + }else if(this.config.displayArrival){ + span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": " + moment(arrival).format("h:mm") + ")"; + } + // span.innerHTML += this.translate('TRAVEL_TIME') + ": "; + // span.innerHTML += moment.duration(moment(arrival).diff(depature, 'minutes'), 'minutes').humanize(); + wrapper.appendChild(span); + }, + renderStep: function(wrapper, step){ + /* renderStep + * creates HTML element for one step of a leg + */ + if(step.travel_mode === "WALKING"){ + /*this step is not public transport but walking*/ + var duration = step.duration.value; + if (duration >= (this.config.maxWalkTime*60)){ + /*if time of walking is longer than + *specified, mark this route to be skipped*/ + wrapper.innerHTML = "too far"; + }else if(this.config.displayWalkType != 'none'){ + /*if walking and walking times should be + *specified, add symbol and time*/ + var img = document.createElement("img"); + if(this.config.showColor){ + img.className = "symbol"; + }else{ + img.className = "symbol bw"; + } + img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/walk.png"; + //img.src = "/localtransport/walk.png"; //needs to be saved in localtransport/public/walk.png + wrapper.appendChild(img) + var span = document.createElement("span"); + span.innerHTML = moment.duration(duration, 'seconds').locale(this.config.language).humanize(); + if(this.config.displayWalkType === 'short'){ + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); + span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); + } + if (this.config._laststop !== ''){ + /* walking step doesn't have a departure_stop set - maybe something else but can't find the documentation right now. + so in order to display the departure, we will just save the arrival of any transit step into a global variable and + display the previous arrival instead of the current departure location. That means we need to reset the global variable + to not cause interference between different routes and we need to skip the display for the first step if that is a walking + step (alternatively one could display the departure location specified by the user, but I prefer this option) + */ + if (this.config.displayStationLength > 0){ + /* add departure stop (shortened)*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(this.config._laststop, this.config.displayStationLength) + ")"; + }else if (this.config.displayStationLength === 0){ + /* add departure stop*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; + } + } + span.className = "xsmall dimmed"; + wrapper.appendChild(span); + }else{ + /*skip walking*/ + return; + } + this.config._laststop = ''; + }else{ + /*if this is a transit step*/ + var details = step.transit_details; + if(details) { + /*add symbol of transport vehicle*/ + var img = document.createElement("img"); + if(this.config.showColor){ + img.className = "symbol"; + }else{ + img.className = "symbol bw"; + } + /* get symbol online*/ + img.src = details.line.vehicle.local_icon || ("https:" + details.line.vehicle.icon); + /* can provide own symbols under /localtransport/public/*.png */ + //img.src = "/localtransport/" + details.line.vehicle.name + ".png"; + img.alt = "[" + details.line.vehicle.name +"]"; + wrapper.appendChild(img); + /*add description*/ + var span = document.createElement("span"); + /* add line name*/ + span.innerHTML = details.line.short_name || details.line.name; + if (this.config.displayStationLength > 0){ + /* add departure stop (shortened)*/ + span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; + }else if (this.config.displayStationLength === 0){ + /* add departure stop*/ + span.innerHTML += " ("+this.translate("FROM")+" " + details.departure_stop.name + ")"; + } + if (this.config.debug){ + /* add vehicle type for debug*/ + span.innerHTML += " [" + details.line.vehicle.name +"]"; + } + this.config._laststop = details.arrival_stop.name; + span.className = "xsmall dimmed"; + wrapper.appendChild(span); + } + } + }, + renderAlternatives: function(){ + /*creates a
  • containing the duration for ALTERNATIVE transport methods*/ + var li = document.createElement("li"); + li.className = "small"; + //intro + var span = document.createElement("span"); + span.innerHTML = this.translate("ALT") + ": "; + li.appendChild(span); + /*add alternative walking time*/ + if (this.config.displayAltWalk){ + //symbol for walking var img = document.createElement("img"); if(this.config.showColor){ img.className = "symbol"; @@ -128,194 +271,305 @@ Module.register('MMM-LocalTransport', { } img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/walk.png"; //img.src = "/localtransport/walk.png"; //needs to be saved in localtransport/public/walk.png - wrapper.appendChild(img) + li.appendChild(img); + //actual walking time var span = document.createElement("span"); - span.innerHTML = moment.duration(duration, 'seconds').locale(this.config.language).humanize(); + span.innerHTML = moment.duration(this.config._walktime, 'seconds').locale(this.config.language).humanize(); if(this.config.displayWalkType === 'short'){ span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); } - if (this.config._laststop !== ''){ - /* walking step doesn't have a departure_stop set - maybe something else but can't find the documentation right now. - so in order to display the departure, we will just save the arrival of any transit step into a global variable and - display the previous arrival instead of the current departure location. That means we need to reset the global variable - to not cause interference between different routes and we need to skip the display for the first step if that is a walking - step (alternatively one could display the departure location specified by the user, but I prefer this option) - */ - if (this.config.displayStationLength > 0){ - /* add departure stop (shortened)*/ - span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(this.config._laststop, this.config.displayStationLength) + ")"; - }else if (this.config.displayStationLength == 0){ - /* add departure stop*/ - span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; - } + li.appendChild(span); + } + /*add alternative cycling time*/ + if (this.config.displayAltCycle){ + //symbol for bicycle + var img = document.createElement("img"); + if(this.config.showColor){ + img.className = "symbol"; + }else{ + img.className = "symbol bw"; } - span.className = "xsmall dimmed"; - wrapper.appendChild(span); - }else{ - /*skip walking*/ - return; + img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/cycle.png"; + //img.src = "/localtransport/cycle.png"; //needs to be saved in localtransport/public/walk.png + li.appendChild(img); + //actual cycling time + var span = document.createElement("span"); + span.innerHTML = moment.duration(this.config._cycletime, 'seconds').locale(this.config.language).humanize(); + if(this.config.displayWalkType === 'short'){ + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); + span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); + } + li.appendChild(span); } - this.config._laststop = ''; - }else{ - /*if this is a transit step*/ - var details = step.transit_details; - if(details) { - /*add symbol of transport vehicle*/ + /*add alternative driving time*/ + if (this.config.displayAltDrive){ + //symbol for car var img = document.createElement("img"); if(this.config.showColor){ img.className = "symbol"; }else{ img.className = "symbol bw"; } - /* get symbol online*/ - img.src = details.line.vehicle.local_icon || ("https:" + details.line.vehicle.icon); - /* can provide own symbols under /localtransport/public/*.png */ - //img.src = "/localtransport/" + details.line.vehicle.name + ".png"; - img.alt = "[" + details.line.vehicle.name +"]"; - wrapper.appendChild(img); - /*add description*/ + img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/drive.png"; + //img.src = "/localtransport/drive.png"; //needs to be saved in localtransport/public/walk.png + li.appendChild(img); + //actual driving time var span = document.createElement("span"); - /* add line name*/ - span.innerHTML = details.line.short_name || details.line.name; - if (this.config.displayStationLength > 0){ - /* add departure stop (shortened)*/ - span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; - }else if (this.config.displayStationLength === 0){ - /* add departure stop*/ - span.innerHTML += " ("+this.translate("FROM")+" " + details.departure_stop.name + ")"; + span.innerHTML = moment.duration(this.config._drivetime, 'seconds').locale(this.config.language).humanize(); + if(this.config.displayWalkType === 'short'){ + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); + span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); + span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); } - if (this.config.debug){ - /* add vehicle type for debug*/ - span.innerHTML += " [" + details.line.vehicle.name +"]"; + li.appendChild(span); + } + return li; + }, + socketNotificationReceived: function(notification, payload) { + /*socketNotificationReceived + *handles notifications send by this module + */ + if (notification === 'LOCAL_TRANSPORT_RESPONSE' && payload.id === this.identifier) { + //Received response on public transport routes (main one) + Log.info('received ' + notification); + if(payload.data && payload.data.status === "OK"){ + this.info = payload.data; + this.loaded = true; + this.updateDom(this.config.animationSpeed * 1000); + }else{ + Log.warning('received LOCAL_TRANSPORT_RESPONSE with status '+payload.data.status); } - this.config._laststop = details.arrival_stop.name; - span.className = "xsmall dimmed"; - wrapper.appendChild(span); } - } - }, - socketNotificationReceived: function(notification, payload) { - if (notification === 'LOCAL_TRANSPORT_RESPONSE' && payload.id === this.identifier) { - Log.info('received' + notification); - if(payload.data && payload.data.status === "OK"){ - this.info = payload.data; - this.loaded = true; - this.updateDom(this.config.animationSpeed * 1000); + if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE' && payload.id === this.identifier) { + //Received response on routes for walking + Log.info('received ' + notification); + if(payload.data && payload.data.status === "OK"){ + //only interested in duration, first option should be the shortest one + var route = payload.data.routes[0]; + var leg = route.legs[0]; + this.config._walktime = leg.duration.value; + this.updateDom(this.config.animationSpeed * 1000); + }else{ + this.config._walktime = "unknown"; + Log.warning('received LOCAL_TRANSPORT_WALK_RESPONSE with status '+payload.data.status); + } } - } - }, - getStyles: function() { - return ["localtransport.css"]; - }, - getScripts: function() { - return ["moment.js"]; - }, - getTranslations: function() { - return { - de: "i18n/de.json", - en: "i18n/en.json", - sv: "i18n/sv.json" - }; - }, - getDom: function() { - /* main function creating HTML code to display*/ - var wrapper = document.createElement("div"); - if (!this.loaded) { - /*if not loaded, display message*/ - wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); - wrapper.className = "small dimmed"; - }else{ - /*create an unsorted list with each - *route alternative being a new list item*/ - //var udt = document.createElement("div"); - //udt.innerHTML = moment().format("HH:mm:ss") + " (" + this.lastupdate + ")"; - //wrapper.appendChild(udt); - var ul = document.createElement("ul"); - var Nrs = 0; //number of routes - var routeArray = []; //array of all alternatives for later sorting - for(var routeKey in this.info.routes) { - /*each route describes a way to get from A to Z*/ - //if(Nrs >= this.config.maxAlternatives){ - // break; - //} - var route = this.info.routes[routeKey]; - var li = document.createElement("li"); - li.className = "small"; - var arrival = 0; - if (this.config.maxModuleWidth > 0){ - li.style.width = this.config.maxModuleWidth + "px"; + if (notification === 'LOCAL_TRANSPORT_CYCLE_RESPONSE' && payload.id === this.identifier) { + //Received response on routes for bicycle + Log.info('received ' + notification); + if(payload.data && payload.data.status === "OK"){ + //only interested in duration, first option should be the shortest one + var route = payload.data.routes[0]; + var leg = route.legs[0]; + this.config._cycletime = leg.duration.value; + this.updateDom(this.config.animationSpeed * 1000); + }else{ + this.config._cycletime = "unknown"; + Log.warning('received LOCAL_TRANSPORT_CYCLE_RESPONSE with status '+payload.data.status); + } + } + if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE' && payload.id === this.identifier) { + //Received response on routes for driving + Log.info('received ' + notification); + if(payload.data && payload.data.status === "OK"){ + //only interested in duration, first option should be the shortest one + var route = payload.data.routes[0]; + var leg = route.legs[0]; + this.config._drivetime = leg.duration.value; + this.updateDom(this.config.animationSpeed * 1000); + }else{ + this.config._drivetime = "unknown"; + Log.warning('received LOCAL_TRANSPORT_DRIVE_RESPONSE with status '+payload.data.status); + } + } + }, + notificationReceived: function(notification, payload, sender) { + /*notificationReceived + *handles notifications send by other modules + */ + if (notification === 'CALENDAR_EVENTS' && sender.name === 'calendar' && this.config.getCalendarLocation) { + //received calendar events AND user wants events to influence the travel destination. + Log.info('received ' + notification); + var dn = new Date(); + var oneSecond = 1000; // 1,000 milliseconds + var oneMinute = oneSecond * 60; + var oneHour = oneMinute * 60; + var oneDay = oneHour * 24; + + var value; + for (let x of payload) { + //go through the events, pick first one with a set location. + //also ignore running events + if(x.location !== '' && x.location !== false && x.startDate - dn >= 0){ + value = x; + break; + } + } + //check if event is less than one day away + if(value.startDate - dn - oneDay <= 0){ + //if so, then update the destination and request an update of the routes + this.config._destination = value.location; + this.doMainUpdate(); + this.lastupdate = dn.getTime(); + }else{ + //if not, then make sure the default destination is set again. + this.config._destination = this.config.destination; + } + + if (this.config.debug){ + this.sendNotification("SHOW_ALERT", { timer: 3000, title: "LOCAL TRANSPORT", message: "calendar update"}); } - for(var legKey in route.legs) { - var leg = route.legs[legKey]; - arrival = leg.arrival_time.value; - var tmpwrapper = document.createElement("text"); - for(var stepKey in leg.steps) { - /*each leg consists of several steps - *e.g. (1) walk from A to B, then - (2) take the bus from B to C and then - (3) walk from C to Z*/ - var step = leg.steps[stepKey]; - this.renderStep(tmpwrapper, step); + + } + }, + getHeader: function() { + var header = this.data.header; + //use %{destX} in the header definition for the module and it will be replaces with the destination as returned by Google + header = header.replace("%{destX}", this.config._headerDest); + //use %{dest} in the header definition for the module and it will be replaces with the destination as defined in the config/ calendar event + this.config._headerDestPlan = this.shortenAddress(this.config._destination); + header = header.replace("%{dest}", this.config._headerDestPlan); + //use %{orig} in the header definition for the module and it will be replaces with the origin as defined in the config + this.config._headerOrigPlan = this.shortenAddress(this.config.origin); + header = header.replace("%{orig}", this.config._headerOrigPlan); + + return header; + }, + getStyles: function() { + return ["localtransport.css"]; + }, + getScripts: function() { + return ["moment.js"]; + }, + getTranslations: function() { + return { + de: "i18n/de.json", + en: "i18n/en.json", + sv: "i18n/sv.json" + }; + }, + getDom: function() { + /* main function creating HTML code to display*/ + var wrapper = document.createElement("div"); + if (!this.loaded) { + /*if not loaded, display message*/ + wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); + wrapper.className = "small dimmed"; + }else{ + /*create an unsorted list with each + *route alternative being a new list item*/ + var ul = document.createElement("ul"); + var Nrs = 0; //number of routes + var routeArray = []; //array of all alternatives for later sorting + for(var routeKey in this.info.routes) { + /*each route describes a way to get from A to Z*/ + //if(Nrs >= this.config.maxAlternatives){ + // break; + //} + var route = this.info.routes[routeKey]; + var li = document.createElement("li"); + li.className = "small"; + var arrival = 0; + if (this.config.maxModuleWidth > 0){ + li.style.width = this.config.maxModuleWidth + "px"; + } + for(var legKey in route.legs) { + var leg = route.legs[legKey]; + //Log.info(leg); + var tmpwrapper = document.createElement("text"); + this.config._headerdest = this.shortenAddress(leg.end_address); + this.config._laststop = ''; //need to reset the _laststop in case the previous leg didn't end with a walking step. + try { + + arrival = leg.arrival_time.value; + for(var stepKey in leg.steps) { + /*each leg consists of several steps + *e.g. (1) walk from A to B, then + (2) take the bus from B to C and then + (3) walk from C to Z*/ + var step = leg.steps[stepKey]; + this.renderStep(tmpwrapper, step); + if (tmpwrapper.innerHTML === "too far"){ + //walking distance was too long -> skip this option + break; + } + } + } + catch(err) { + tmpwrapper.innerHTML = "too far"; + } if (tmpwrapper.innerHTML === "too far"){ //walking distance was too long -> skip this option + li.innerHTML = "too far"; break; } + this.renderLeg(li, leg); + li.appendChild(tmpwrapper); } - if (tmpwrapper.innerHTML === "too far"){ - //walking distance was too long -> skip this option - li.innerHTML = "too far"; - break; + if (li.innerHTML !== "too far"){ + routeArray.push({"arrival":arrival,"html":li}); + Nrs += 1; } - this.renderLeg(li, leg); - li.appendChild(tmpwrapper); - } - if (li.innerHTML !== "too far"){ - routeArray.push({"arrival":arrival,"html":li}); - Nrs += 1; } - } - /*sort the different alternative routes by arrival time*/ - routeArray.sort(function(a, b) { - return parseFloat(a.arrival) - parseFloat(b.arrival); - }); - /*only show the first few options as specified by "maximumEntries"*/ - routeArray = routeArray.slice(0, this.config.maximumEntries); + /*sort the different alternative routes by arrival time*/ + routeArray.sort(function(a, b) { + return parseFloat(a.arrival) - parseFloat(b.arrival); + }); + /*only show the first few options as specified by "maximumEntries"*/ + routeArray = routeArray.slice(0, this.config.maximumEntries); + + /*add ALTERNATIVE transport notes*/ + if (this.config.displayAltWalk || this.config.displayAltCycle || this.config.displayAltDrive){ + var li = this.renderAlternatives(); + routeArray.push({"arrival":'',"html":li}); + } - /*create fade effect and append list items to the list*/ - var e = 0; - Nrs = routeArray.length; - for(var dataKey in routeArray) { - var routeData = routeArray[dataKey]; - var routeHtml = routeData.html; - // Create fade effect. - if (this.config.fade && this.config.fadePoint < 1) { - if (this.config.fadePoint < 0) { - this.config.fadePoint = 0; - } - var startingPoint = Nrs * this.config.fadePoint; - var steps = Nrs - startingPoint; - if (e >= startingPoint) { - var currentStep = e - startingPoint; - routeHtml.style.opacity = 1 - (1 / steps * currentStep); + /*create fade effect and append list items to the list*/ + var e = 0; + Nrs = routeArray.length; + for(var dataKey in routeArray) { + var routeData = routeArray[dataKey]; + var routeHtml = routeData.html; + // Create fade effect. + if (this.config.fade && this.config.fadePoint < 1) { + if (this.config.fadePoint < 0) { + this.config.fadePoint = 0; + } + var startingPoint = Nrs * this.config.fadePoint; + var steps = Nrs - startingPoint; + if (e >= startingPoint) { + var currentStep = e - startingPoint; + routeHtml.style.opacity = 1 - (1 / steps * currentStep); + } } + ul.appendChild(routeHtml); + e += 1; } - ul.appendChild(routeHtml); - e += 1; + wrapper.appendChild(ul); } - wrapper.appendChild(ul); - } - return wrapper; - }, - shorten: function(string, maxLength) { - /*shorten - *shortens a string to the number of characters specified*/ - if (string.length > maxLength) { - return string.slice(0,maxLength) + "…"; + return wrapper; + }, + shorten: function(string, maxLength) { + /*shorten + *shortens a string to the number of characters specified*/ + if (string.length > maxLength) { + return string.slice(0,maxLength) + "…"; + } + return string; + }, + shortenAddress: function(address) { + /*shortenAddress + *shortens a string to the first part of an address + *this assumes that the address string is split by ',' + *useful since Google will require a very precise + *definition of an address while the user would usually + *know which city and country they are looking at*/ + var temp = address.split(","); + return temp[0]; } - return string; - } }); diff --git a/i18n/de.json b/i18n/de.json index 583999d..4beeb6c 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -7,5 +7,6 @@ "MINUTE_PS": "min", "MINUTE_SS": "min", "SECOND_PS": "sek", - "FROM": "von" + "FROM": "von", + "ALT": "Alternativen" } diff --git a/i18n/en.json b/i18n/en.json index 7bbdbcb..29de385 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -7,5 +7,6 @@ "MINUTE_PS": "min", "MINUTE_SS": "min", "SECOND_PS": "sec", - "FROM": "from" + "FROM": "from", + "ALT": "alternatives" } diff --git a/i18n/sv.json b/i18n/sv.json index 77b6227..a95482b 100644 --- a/i18n/sv.json +++ b/i18n/sv.json @@ -7,5 +7,6 @@ "MINUTE_PS": "min", "MINUTE_SS": "min", "SECOND_PS": "s", - "FROM": "frÃ¥n" + "FROM": "frÃ¥n", + "ALT": "alternativ" } diff --git a/node_helper.js b/node_helper.js index fa48ee8..0be8471 100644 --- a/node_helper.js +++ b/node_helper.js @@ -27,5 +27,47 @@ module.exports = NodeHelper.create({ } }); } + if (notification === 'LOCAL_TRANSPORT_WALK_REQUEST') { + var that = this; + request({ + url: payload.url, + method: 'GET' + }, function(error, response, body) { + if (!error && response.statusCode == 200) { + that.sendSocketNotification('LOCAL_TRANSPORT_WALK_RESPONSE', { + id: payload.id, + data: JSON.parse(body) + }); + } + }); + } + if (notification === 'LOCAL_TRANSPORT_CYCLE_REQUEST') { + var that = this; + request({ + url: payload.url, + method: 'GET' + }, function(error, response, body) { + if (!error && response.statusCode == 200) { + that.sendSocketNotification('LOCAL_TRANSPORT_CYCLE_RESPONSE', { + id: payload.id, + data: JSON.parse(body) + }); + } + }); + } + if (notification === 'LOCAL_TRANSPORT_DRIVE_REQUEST') { + var that = this; + request({ + url: payload.url, + method: 'GET' + }, function(error, response, body) { + if (!error && response.statusCode == 200) { + that.sendSocketNotification('LOCAL_TRANSPORT_DRIVE_RESPONSE', { + id: payload.id, + data: JSON.parse(body) + }); + } + }); + } } }); From 96366ee38fcec42f99dc070a2e3c9997ea54a5be Mon Sep 17 00:00:00 2001 From: GHLasse Date: Wed, 8 Nov 2017 18:13:13 +0000 Subject: [PATCH 07/20] simplified some code by adding new functions --- MMM-LocalTransport.js | 88 ++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 60 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 9cda5f0..328325d 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -142,6 +142,26 @@ Module.register('MMM-LocalTransport', { params += '&alternatives=true'; return params; }, + getSymbol: function(symName){ + var img = document.createElement("img"); + if(this.config.showColor){ + img.className = "symbol"; + }else{ + img.className = "symbol bw"; + } + img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/"+symName+".png"; + //img.src = "/localtransport/"+symName+".png"; //needs to be saved in localtransport/public/walk.png + return img; + }, + convertTime: function(seconds){ + var ans = moment.duration(seconds, 'seconds').locale(this.config.language).humanize(); + if(this.config.displayWalkType === 'short'){ + ans = ans.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); + ans = ans.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); + ans = ans.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); + } + return ans; + }, renderLeg: function(wrapper, leg){ /* renderLeg * creates HTML element for one leg of a route @@ -176,22 +196,9 @@ Module.register('MMM-LocalTransport', { }else if(this.config.displayWalkType != 'none'){ /*if walking and walking times should be *specified, add symbol and time*/ - var img = document.createElement("img"); - if(this.config.showColor){ - img.className = "symbol"; - }else{ - img.className = "symbol bw"; - } - img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/walk.png"; - //img.src = "/localtransport/walk.png"; //needs to be saved in localtransport/public/walk.png - wrapper.appendChild(img) + wrapper.appendChild(this.getSymbol("walk")); var span = document.createElement("span"); - span.innerHTML = moment.duration(duration, 'seconds').locale(this.config.language).humanize(); - if(this.config.displayWalkType === 'short'){ - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); - span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); - } + span.innerHTML = this.convertTime(duration); if (this.config._laststop !== ''){ /* walking step doesn't have a departure_stop set - maybe something else but can't find the documentation right now. so in order to display the departure, we will just save the arrival of any transit step into a global variable and @@ -263,67 +270,28 @@ Module.register('MMM-LocalTransport', { /*add alternative walking time*/ if (this.config.displayAltWalk){ //symbol for walking - var img = document.createElement("img"); - if(this.config.showColor){ - img.className = "symbol"; - }else{ - img.className = "symbol bw"; - } - img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/walk.png"; - //img.src = "/localtransport/walk.png"; //needs to be saved in localtransport/public/walk.png - li.appendChild(img); + li.appendChild(this.getSymbol("walk")); //actual walking time var span = document.createElement("span"); - span.innerHTML = moment.duration(this.config._walktime, 'seconds').locale(this.config.language).humanize(); - if(this.config.displayWalkType === 'short'){ - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); - span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); - } + span.innerHTML = this.convertTime(this.config._walktime); li.appendChild(span); } /*add alternative cycling time*/ if (this.config.displayAltCycle){ //symbol for bicycle - var img = document.createElement("img"); - if(this.config.showColor){ - img.className = "symbol"; - }else{ - img.className = "symbol bw"; - } - img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/cycle.png"; - //img.src = "/localtransport/cycle.png"; //needs to be saved in localtransport/public/walk.png - li.appendChild(img); + li.appendChild(this.getSymbol("cycle")); //actual cycling time var span = document.createElement("span"); - span.innerHTML = moment.duration(this.config._cycletime, 'seconds').locale(this.config.language).humanize(); - if(this.config.displayWalkType === 'short'){ - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); - span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); - } + span.innerHTML = this.convertTime(this.config._cycletime); li.appendChild(span); } /*add alternative driving time*/ if (this.config.displayAltDrive){ //symbol for car - var img = document.createElement("img"); - if(this.config.showColor){ - img.className = "symbol"; - }else{ - img.className = "symbol bw"; - } - img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/drive.png"; - //img.src = "/localtransport/drive.png"; //needs to be saved in localtransport/public/walk.png - li.appendChild(img); + li.appendChild(this.getSymbol("drive")); //actual driving time var span = document.createElement("span"); - span.innerHTML = moment.duration(this.config._drivetime, 'seconds').locale(this.config.language).humanize(); - if(this.config.displayWalkType === 'short'){ - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_PL"),this.translate("MINUTE_PS")); - span.innerHTML = span.innerHTML.replace(this.translate("MINUTE_SL"),this.translate("MINUTE_SS")); - span.innerHTML = span.innerHTML.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); - } + span.innerHTML = this.convertTime(this.config._drivetime); li.appendChild(span); } return li; From 5dec81043a42c504d38dac623c16b9123dfa4cfd Mon Sep 17 00:00:00 2001 From: GHLasse Date: Wed, 8 Nov 2017 18:55:14 +0000 Subject: [PATCH 08/20] simplified code by adding some functions --- MMM-LocalTransport.js | 34 ++++++++++++----------------- node_helper.js | 51 ++++++++++--------------------------------- 2 files changed, 25 insertions(+), 60 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 328325d..aa840c5 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -79,51 +79,45 @@ Module.register('MMM-LocalTransport', { this.updateDom(); //this.updateDom(this.config.animationSpeed * 1000) } }, + sendRequest: function(requestName) { + this.sendSocketNotification( + requestName, { + id: this.identifier, + url: this.config.apiBase + this.config.apiEndpoint + this.getParams() + } + ); + }, doMainUpdate: function() { /*doMainUpdate *requests routes from Google for public transport and any alternatives if applicable. */ //request routes from Google - this.sendSocketNotification( + this.sendRequest('LOCAL_TRANSPORT_REQUEST'); + /*this.sendSocketNotification( 'LOCAL_TRANSPORT_REQUEST', { id: this.identifier, url: this.config.apiBase + this.config.apiEndpoint + this.getParams() } - ); + );*/ Log.info("requested public transport route"); //request walking time if (this.config.displayAltWalk){ this.config.mode = 'walking'; - this.sendSocketNotification( - 'LOCAL_TRANSPORT_WALK_REQUEST', { - id: this.identifier, - url: this.config.apiBase + this.config.apiEndpoint + this.getParams() - } - ); + this.sendRequest('LOCAL_TRANSPORT_WALK_REQUEST'); Log.info("requested walking route"); this.config.mode = 'transit'; } //request cycling time if (this.config.displayAltCycle){ this.config.mode = 'bicycling'; - this.sendSocketNotification( - 'LOCAL_TRANSPORT_CYCLE_REQUEST', { - id: this.identifier, - url: this.config.apiBase + this.config.apiEndpoint + this.getParams() - } - ); + this.sendRequest('LOCAL_TRANSPORT_CYCLE_REQUEST'); Log.info("requested cycling route"); this.config.mode = 'transit'; } //request driving time if (this.config.displayAltWalk){ this.config.mode = 'driving'; - this.sendSocketNotification( - 'LOCAL_TRANSPORT_DRIVE_REQUEST', { - id: this.identifier, - url: this.config.apiBase + this.config.apiEndpoint + this.getParams() - } - ); + this.sendRequest('LOCAL_TRANSPORT_DRIVE_REQUEST'); Log.info("requested driving route"); this.config.mode = 'transit'; } diff --git a/node_helper.js b/node_helper.js index 0be8471..712150d 100644 --- a/node_helper.js +++ b/node_helper.js @@ -11,63 +11,34 @@ module.exports = NodeHelper.create({ start: function () { console.log(this.name + ' helper started ...'); }, - socketNotificationReceived: function(notification, payload) { - //console.log(notification); - if (notification === 'LOCAL_TRANSPORT_REQUEST') { + makeAPIrequest: function(payload,responseName){ var that = this; request({ url: payload.url, method: 'GET' }, function(error, response, body) { if (!error && response.statusCode == 200) { - that.sendSocketNotification('LOCAL_TRANSPORT_RESPONSE', { + that.sendSocketNotification(responseName, { id: payload.id, data: JSON.parse(body) }); } }); + }, + socketNotificationReceived: function(notification, payload) { + //console.log(notification); + + if (notification === 'LOCAL_TRANSPORT_REQUEST') { + this.makeAPIrequest(payload,'LOCAL_TRANSPORT_RESPONSE'); } if (notification === 'LOCAL_TRANSPORT_WALK_REQUEST') { - var that = this; - request({ - url: payload.url, - method: 'GET' - }, function(error, response, body) { - if (!error && response.statusCode == 200) { - that.sendSocketNotification('LOCAL_TRANSPORT_WALK_RESPONSE', { - id: payload.id, - data: JSON.parse(body) - }); - } - }); + this.makeAPIrequest(payload,'LOCAL_TRANSPORT_WALK_RESPONSE'); } if (notification === 'LOCAL_TRANSPORT_CYCLE_REQUEST') { - var that = this; - request({ - url: payload.url, - method: 'GET' - }, function(error, response, body) { - if (!error && response.statusCode == 200) { - that.sendSocketNotification('LOCAL_TRANSPORT_CYCLE_RESPONSE', { - id: payload.id, - data: JSON.parse(body) - }); - } - }); + this.makeAPIrequest(payload,'LOCAL_TRANSPORT_CYCLE_RESPONSE'); } if (notification === 'LOCAL_TRANSPORT_DRIVE_REQUEST') { - var that = this; - request({ - url: payload.url, - method: 'GET' - }, function(error, response, body) { - if (!error && response.statusCode == 200) { - that.sendSocketNotification('LOCAL_TRANSPORT_DRIVE_RESPONSE', { - id: payload.id, - data: JSON.parse(body) - }); - } - }); + this.makeAPIrequest(payload,'LOCAL_TRANSPORT_DRIVE_RESPONSE'); } } }); From 52c33894b5cf8f1cd4eb072b39452e08ff7beb82 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Wed, 8 Nov 2017 19:07:53 +0000 Subject: [PATCH 09/20] simplified code by adding new function --- MMM-LocalTransport.js | 68 +++++++++++++------------------------------ 1 file changed, 21 insertions(+), 47 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index aa840c5..4f41f10 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -86,6 +86,8 @@ Module.register('MMM-LocalTransport', { url: this.config.apiBase + this.config.apiEndpoint + this.getParams() } ); + Log.info("requested "+requestName); + this.config.mode = 'transit'; }, doMainUpdate: function() { /*doMainUpdate @@ -93,33 +95,20 @@ Module.register('MMM-LocalTransport', { */ //request routes from Google this.sendRequest('LOCAL_TRANSPORT_REQUEST'); - /*this.sendSocketNotification( - 'LOCAL_TRANSPORT_REQUEST', { - id: this.identifier, - url: this.config.apiBase + this.config.apiEndpoint + this.getParams() - } - );*/ - Log.info("requested public transport route"); //request walking time if (this.config.displayAltWalk){ this.config.mode = 'walking'; this.sendRequest('LOCAL_TRANSPORT_WALK_REQUEST'); - Log.info("requested walking route"); - this.config.mode = 'transit'; } //request cycling time if (this.config.displayAltCycle){ this.config.mode = 'bicycling'; this.sendRequest('LOCAL_TRANSPORT_CYCLE_REQUEST'); - Log.info("requested cycling route"); - this.config.mode = 'transit'; } //request driving time - if (this.config.displayAltWalk){ + if (this.config.displayAltDrive){ this.config.mode = 'driving'; this.sendRequest('LOCAL_TRANSPORT_DRIVE_REQUEST'); - Log.info("requested driving route"); - this.config.mode = 'transit'; } if (this.config.debug){ this.sendNotification("SHOW_ALERT", { timer: 3000, title: "LOCAL TRANSPORT", message: "special update"}); @@ -290,6 +279,21 @@ Module.register('MMM-LocalTransport', { } return li; }, + receiveAlternative: function(notification, payload){ + Log.info('received ' + notification); + var ans = "" + if(payload.data && payload.data.status === "OK"){ + //only interested in duration, first option should be the shortest one + var route = payload.data.routes[0]; + var leg = route.legs[0]; + ans = leg.duration.value; + }else{ + ans = "unknown"; + Log.warning('received '+notification+' with status '+payload.data.status); + } + this.updateDom(this.config.animationSpeed * 1000); + return ans; + }, socketNotificationReceived: function(notification, payload) { /*socketNotificationReceived *handles notifications send by this module @@ -307,45 +311,15 @@ Module.register('MMM-LocalTransport', { } if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE' && payload.id === this.identifier) { //Received response on routes for walking - Log.info('received ' + notification); - if(payload.data && payload.data.status === "OK"){ - //only interested in duration, first option should be the shortest one - var route = payload.data.routes[0]; - var leg = route.legs[0]; - this.config._walktime = leg.duration.value; - this.updateDom(this.config.animationSpeed * 1000); - }else{ - this.config._walktime = "unknown"; - Log.warning('received LOCAL_TRANSPORT_WALK_RESPONSE with status '+payload.data.status); - } + this.config._walktime = this.receiveAlternative(notification, payload); } if (notification === 'LOCAL_TRANSPORT_CYCLE_RESPONSE' && payload.id === this.identifier) { //Received response on routes for bicycle - Log.info('received ' + notification); - if(payload.data && payload.data.status === "OK"){ - //only interested in duration, first option should be the shortest one - var route = payload.data.routes[0]; - var leg = route.legs[0]; - this.config._cycletime = leg.duration.value; - this.updateDom(this.config.animationSpeed * 1000); - }else{ - this.config._cycletime = "unknown"; - Log.warning('received LOCAL_TRANSPORT_CYCLE_RESPONSE with status '+payload.data.status); - } + this.config._cycletime = this.receiveAlternative(notification, payload); } if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE' && payload.id === this.identifier) { //Received response on routes for driving - Log.info('received ' + notification); - if(payload.data && payload.data.status === "OK"){ - //only interested in duration, first option should be the shortest one - var route = payload.data.routes[0]; - var leg = route.legs[0]; - this.config._drivetime = leg.duration.value; - this.updateDom(this.config.animationSpeed * 1000); - }else{ - this.config._drivetime = "unknown"; - Log.warning('received LOCAL_TRANSPORT_DRIVE_RESPONSE with status '+payload.data.status); - } + this.config._drivetime = this.receiveAlternative(notification, payload); } }, notificationReceived: function(notification, payload, sender) { From 2c5ca0665b4cf5bde902f7bfb607187a275bd564 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Wed, 8 Nov 2017 19:27:05 +0000 Subject: [PATCH 10/20] updated readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 5580ce4..6e414da 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,12 @@ Add module configuration to config.js. }, ``` +For the header, the following keys can be specified and will be replaced with the according values at runtime: +use `%{orig}` in the header definition for the module and it will be replaces with the origin as defined in the config +use `%{dest}` in the header definition for the module and it will be replaces with the destination as defined in the config/ calendar event +use `%{destX}` in the header definition for the module and it will be replaces with the destination as returned by Google +These options are particularly useful if the destination is changed according to the calendar. The `%{orig}` option may become useful in the future. + |Option|Description| |---|---| |`apiKey`|The API key, which can be obtained [here](https://developers.google.com/maps/documentation/directions/).

    This value is **REQUIRED**| @@ -49,8 +55,12 @@ Add module configuration to config.js. |`maximumEntries`|Maximum number of routes to display. Less routes will be shown if less are returned by Google. Routes will be sorted by arrival time. This option should take an integer value between `1` and `5`.

    **Default value:** `3`| |`updateInterval`|How often does the content need to be fetched? (Minutes) Note that the module refreshes every 15 seconds to always display an accurate estimate when you need to leave.

    **Default value:** `5`| |`animationSpeed`|Speed of the update animation. (Seconds)

    **Default value:** `1`| +|`getCalendarLocation`|Boolean to specify whether to read calendar notifications send by the default calendar module to display the route to the next event. The event must be less than one day away and contain a location to be considered for this functionality.

    **Default value:** `false`| |`displayStationLength`|Number of characters of the departure station for each transport mode to display.
    `0` means display all,
    `-1` means don't show the departure station

    **Default value:** `0`| |`displayArrival`|Boolean if the arrival time should be shown in the header for each option.

    **Default value:** `true`| +|`displayAltWalk`|Boolean if a note should be shown with the time it would take to walk instead of using public transport.

    **Default value:** `false`| +|`displayAltCycle`|Boolean if a note should be shown with the time it would take to take a bicycle instead of using public transport.

    **Default value:** `false`| +|`displayAltDrive`|Boolean if a note should be shown with the time it would take to drive instead of using public transport.

    **Default value:** `false`| |`displayWalkType`|String how detailed the walking segments should be shown.
    `'none'` means to not display anything,
    `'short'` means to display the symbol, the time and the short version of the unit or
    `'long'` means that a symbol, the time and the long string for the unit is displayed. This options is default if an invalid string is supplied.

    **Default value:** `'short'`| |`maxWalkTime`|Maximum time you are willing to walk between stations in minutes

    **Default value:** `10`| |`maxModuleWidth`|Maximum width of the module in pixel. Unlimited when set to `0`. This option can be used to make the module shorter in case of very long lines for directions.

    **Default value:** `0`| From 8bd9ba4f17078cebb09e4ce5b2f3ed72fb74c942 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sat, 20 Jan 2018 12:35:00 +0000 Subject: [PATCH 11/20] display error messages and bug fixes --- MMM-LocalTransport.js | 96 ++++++++++++++++++++++++++++++++----------- i18n/de.json | 7 ++++ i18n/en.json | 7 ++++ 3 files changed, 85 insertions(+), 25 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 4f41f10..548a889 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -15,6 +15,7 @@ Module.register('MMM-LocalTransport', { displayAltWalk: false, //display info about how long walking would take displayAltCycle: false, //display info about how long cycling would take displayAltDrive: false, //display info about how long driving would take + displayAltTransit: false, //display info about how long public transport does take maxWalkTime: 10, //maximum acceptable walking time between stations fade: true, //apply fading effect fadePoint: 0.1, @@ -34,6 +35,7 @@ Module.register('MMM-LocalTransport', { apiBase: 'https://maps.googleapis.com/', apiEndpoint: 'maps/api/directions/json', debug: false, + ignoreErrors: ["OK","OVER_QUERY_LIMIT","UNKNOWN_ERROR"], //any of: OK, NOT_FOUND, ZERO_RESULTS, MAX_WAYPOINTS_EXCEEDED, INVALID_REQUEST, OVER_QUERY_LIMIT, REQUEST_DENIED, UNKNOWN_ERROR _laststop: '', //the variables with _ are for internal use only - should consider defining them elsewhere! _headerDest: '', _headerDestPlan: '', @@ -46,7 +48,11 @@ Module.register('MMM-LocalTransport', { }, start: function() { Log.info('Starting module: ' + this.name); + //default certain global variables this.loaded = false; + this.ignoredError = false; + this.transittime = 'unknown'; + if (this.config.api_key === 'YOUR_API_KEY'){ /*if there is no api key specified in the options of the module, look it up in the main config-file settings */ @@ -75,7 +81,7 @@ Module.register('MMM-LocalTransport', { if (this.config.debug){ this.sendNotification("SHOW_ALERT", {timer: 3000, title: "LOCAL TRANSPORT", message: "normal update"}); } - this.loaded = true; + //this.loaded = false; this.updateDom(); //this.updateDom(this.config.animationSpeed * 1000) } }, @@ -86,7 +92,7 @@ Module.register('MMM-LocalTransport', { url: this.config.apiBase + this.config.apiEndpoint + this.getParams() } ); - Log.info("requested "+requestName); + Log.log("requested "+requestName); this.config.mode = 'transit'; }, doMainUpdate: function() { @@ -94,6 +100,7 @@ Module.register('MMM-LocalTransport', { *requests routes from Google for public transport and any alternatives if applicable. */ //request routes from Google + this.loaded = false; this.sendRequest('LOCAL_TRANSPORT_REQUEST'); //request walking time if (this.config.displayAltWalk){ @@ -242,6 +249,17 @@ Module.register('MMM-LocalTransport', { } } }, + + renderAlternativeTime: function(time){ + var span = document.createElement("span"); + if(time != "unknown"){ + span.innerHTML = this.convertTime(time); + }else{ + span.innerHTML = "n/a"; + } + return span; + }, + renderAlternatives: function(){ /*creates a
  • containing the duration for ALTERNATIVE transport methods*/ var li = document.createElement("li"); @@ -252,46 +270,48 @@ Module.register('MMM-LocalTransport', { li.appendChild(span); /*add alternative walking time*/ if (this.config.displayAltWalk){ - //symbol for walking li.appendChild(this.getSymbol("walk")); - //actual walking time - var span = document.createElement("span"); - span.innerHTML = this.convertTime(this.config._walktime); + var span = this.renderAlternativeTime(this.config._walktime) li.appendChild(span); } /*add alternative cycling time*/ if (this.config.displayAltCycle){ - //symbol for bicycle li.appendChild(this.getSymbol("cycle")); - //actual cycling time - var span = document.createElement("span"); - span.innerHTML = this.convertTime(this.config._cycletime); + var span = this.renderAlternativeTime(this.config._cycletime); + li.appendChild(span); + } + /*add alternative driving time*/ + if (this.config.displayAltTransit){ + li.appendChild(this.getSymbol("rail")); + var span = this.renderAlternativeTime(this.transittime); li.appendChild(span); } /*add alternative driving time*/ if (this.config.displayAltDrive){ - //symbol for car li.appendChild(this.getSymbol("drive")); - //actual driving time - var span = document.createElement("span"); - span.innerHTML = this.convertTime(this.config._drivetime); + var span = this.renderAlternativeTime(this.config._drivetime); li.appendChild(span); } return li; }, receiveAlternative: function(notification, payload){ - Log.info('received ' + notification); var ans = "" if(payload.data && payload.data.status === "OK"){ + Log.log('received ' + notification); //only interested in duration, first option should be the shortest one var route = payload.data.routes[0]; var leg = route.legs[0]; ans = leg.duration.value; }else{ ans = "unknown"; - Log.warning('received '+notification+' with status '+payload.data.status); + var errlst = this.config.ignoreErrors + if (errlst.indexOf(payload.data.status) < 0){ + Log.warn('received '+notification+' with status '+payload.data.status); + }else{ + Log.info('received '+notification+' with status '+payload.data.status); + } } - this.updateDom(this.config.animationSpeed * 1000); + this.updateDom(); return ans; }, socketNotificationReceived: function(notification, payload) { @@ -300,13 +320,32 @@ Module.register('MMM-LocalTransport', { */ if (notification === 'LOCAL_TRANSPORT_RESPONSE' && payload.id === this.identifier) { //Received response on public transport routes (main one) - Log.info('received ' + notification); + if(payload.data && payload.data.status === "OK"){ + Log.log('received ' + notification); this.info = payload.data; this.loaded = true; + this.ignoredError = false; + this.config._headerDestPlan = this.shortenAddress(this.config._destination); + this.transittime = this.receiveAlternative(notification, payload); this.updateDom(this.config.animationSpeed * 1000); + }else if(!payload.data){ + this.loaded = false; + this.ignoredError = false; }else{ - Log.warning('received LOCAL_TRANSPORT_RESPONSE with status '+payload.data.status); + var errlst = this.config.ignoreErrors + if (this.info && errlst.indexOf(payload.data.status) >= 0){ + Log.info('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = true; + this.loaded = true; + this.updateDom(this.config.animationSpeed * 1000); + }else{ + Log.warn('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = false; + this.info = payload.data; + this.loaded = false; + this.updateDom(this.config.animationSpeed * 1000); + } } } if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE' && payload.id === this.identifier) { @@ -366,8 +405,11 @@ Module.register('MMM-LocalTransport', { //use %{destX} in the header definition for the module and it will be replaces with the destination as returned by Google header = header.replace("%{destX}", this.config._headerDest); //use %{dest} in the header definition for the module and it will be replaces with the destination as defined in the config/ calendar event - this.config._headerDestPlan = this.shortenAddress(this.config._destination); - header = header.replace("%{dest}", this.config._headerDestPlan); + if(!this.ignoredError){ + header = header.replace("%{dest}", this.config._headerDestPlan); + }else{ //in case the last request returned an error an we use the previous data, then better use the destination of the last request as well. + header = header.replace("%{dest}", this.config._headerDest); + } //use %{orig} in the header definition for the module and it will be replaces with the origin as defined in the config this.config._headerOrigPlan = this.shortenAddress(this.config.origin); header = header.replace("%{orig}", this.config._headerOrigPlan); @@ -389,10 +431,15 @@ Module.register('MMM-LocalTransport', { }, getDom: function() { /* main function creating HTML code to display*/ + this.config._headerDest = this.config._headerDestPlan; //resetting _headerDest in case there was an error loading... var wrapper = document.createElement("div"); - if (!this.loaded) { + if (!this.loaded || !this.info) { /*if not loaded, display message*/ - wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); + if(!this.info){ + wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); + }else{ + wrapper.innerHTML = this.translate(this.info.status); + } wrapper.className = "small dimmed"; }else{ /*create an unsorted list with each @@ -414,9 +461,8 @@ Module.register('MMM-LocalTransport', { } for(var legKey in route.legs) { var leg = route.legs[legKey]; - //Log.info(leg); var tmpwrapper = document.createElement("text"); - this.config._headerdest = this.shortenAddress(leg.end_address); + this.config._headerDest = this.shortenAddress(leg.end_address); this.config._laststop = ''; //need to reset the _laststop in case the previous leg didn't end with a walking step. try { diff --git a/i18n/de.json b/i18n/de.json index 4beeb6c..c6dcb94 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -1,5 +1,12 @@ { "LOADING_CONNECTIONS": "Lade Verbindungen ...", + "OK": "Ich kenne die Antwort aber ich sage sie dir nicht :-P Dies ist höchstwahrscheinlich ein bug.", + "NOT_FOUND": "Start- oder Endpunkt konntent nicht gefunden werden.", + "ZERO_RESULTS": "Keine Verbindung gefunden.", + "INVALID_REQUEST": "Es wurde eine ungültige Anfrage gemacht.", + "OVER_QUERY_LIMIT": "Sie haben zu viele Anfragen gestellt.", + "REQUEST_DENIED": "Google hat ihre Anfrage abgewiesen.", + "UNKNOWN_ERROR": "Irgendetwas ist falsch gelaufen.", "ARRIVAL": "Ankunft", "MINUTE_PL": "Minuten", "MINUTE_SL": "Minute", diff --git a/i18n/en.json b/i18n/en.json index 29de385..d17b7a5 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,5 +1,12 @@ { "LOADING_CONNECTIONS": "Loading ...", + "OK": "I have a valid answer, but I don't want to show it to you :-P This is most likely a bug.", + "NOT_FOUND": "Either origin or destination couldn't be found.", + "ZERO_RESULTS": "No route found.", + "INVALID_REQUEST": "An invalid request was send.", + "OVER_QUERY_LIMIT": "You send too many requests.", + "REQUEST_DENIED": "Google denied your request.", + "UNKNOWN_ERROR": "Something went wrong. No one knows what.", "ARRIVAL": "arriving", "MINUTE_PL": "minutes", "MINUTE_SL": "minute", From 9665935723577fe12c39d0bc1de7a0867534a5df Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sat, 20 Jan 2018 13:32:21 +0000 Subject: [PATCH 12/20] refactored some varibles and tried to simplify code according to codeclimate --- MMM-LocalTransport.js | 155 +++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 86 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index ec99035..b19b035 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -41,9 +41,6 @@ Module.register('MMM-LocalTransport', { _headerDestPlan: '', _headerOrigPlan: '', _destination: '', //actual destination requested from Google - _walktime: 'unknown', - _cycletime: 'unknown', - _drivetime: 'unknown', test: "" }, start: function() { @@ -51,7 +48,13 @@ Module.register('MMM-LocalTransport', { //default certain global variables this.loaded = false; this.ignoredError = false; - this.transittime = 'unknown'; + this.altTimeWalk = 'unknown'; + this.altTimeCycle = 'unknown'; + this.altTimeTransit = 'unknown'; + this.altTimeDrive = 'unknown'; + this.altSymbols = ['walk','cycle','rail','drive']; + this.altModes = ['walking','bicycling','transit','driving']; + if (this.config.api_key === 'YOUR_API_KEY'){ /*if there is no api key specified in the options of the module, @@ -158,18 +161,18 @@ Module.register('MMM-LocalTransport', { */ var depature = leg.departure_time.value * 1000; var arrival = leg.arrival_time.value * 1000; - //var depadd = leg.start_address; var span = document.createElement("div"); span.className = "small bright"; span.innerHTML = moment(depature).locale(this.config.language).fromNow(); - // span.innerHTML += "from " + depadd; - if (this.config.displayArrival && this.config.timeFormat === 24){ - span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": " + moment(arrival).format("H:mm") + ")"; - }else if(this.config.displayArrival){ - span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": " + moment(arrival).format("h:mm") + ")"; - } - // span.innerHTML += this.translate('TRAVEL_TIME') + ": "; - // span.innerHTML += moment.duration(moment(arrival).diff(depature, 'minutes'), 'minutes').humanize(); + if (this.config.displayArrival){ + span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": "; + if (this.config.timeFormat === 24){ + span.innerHTML += moment(arrival).format("H:mm"); + }else{ + span.innerHTML += moment(arrival).format("h:mm"); + } + span.innerHTML += ")"; + } wrapper.appendChild(span); }, renderStep: function(wrapper, step){ @@ -268,29 +271,16 @@ Module.register('MMM-LocalTransport', { var span = document.createElement("span"); span.innerHTML = this.translate("ALT") + ": "; li.appendChild(span); - /*add alternative walking time*/ - if (this.config.displayAltWalk){ - li.appendChild(this.getSymbol("walk")); - var span = this.renderAlternativeTime(this.config._walktime) - li.appendChild(span); - } - /*add alternative cycling time*/ - if (this.config.displayAltCycle){ - li.appendChild(this.getSymbol("cycle")); - var span = this.renderAlternativeTime(this.config._cycletime); - li.appendChild(span); - } - /*add alternative driving time*/ - if (this.config.displayAltTransit){ - li.appendChild(this.getSymbol("rail")); - var span = this.renderAlternativeTime(this.transittime); - li.appendChild(span); - } - /*add alternative driving time*/ - if (this.config.displayAltDrive){ - li.appendChild(this.getSymbol("drive")); - var span = this.renderAlternativeTime(this.config._drivetime); - li.appendChild(span); + + /*add alternative times*/ + var displayAlt = [this.config.displayAltWalk,this.config.displayAltCycle,this.config.displayAltTransit,this.config.displayAltDrive]; + var timeAlt = [this.altTimeWalk,this.altTimeCycle,this.altTimeTransit,this.altTimeDrive]; + for (i = 0; i < displayAlt.length; i++) { + if (displayAlt[i]){ + li.appendChild(this.getSymbol(this.altSymbols[i])); + var span = this.renderAlternativeTime(timeAlt[i]); + li.appendChild(span); + } } return li; }, @@ -318,47 +308,46 @@ Module.register('MMM-LocalTransport', { /*socketNotificationReceived *handles notifications send by this module */ - if (notification === 'LOCAL_TRANSPORT_RESPONSE' && payload.id === this.identifier) { - //Received response on public transport routes (main one) - - if(payload.data && payload.data.status === "OK"){ - Log.log('received ' + notification); - this.info = payload.data; - this.loaded = true; - this.ignoredError = false; - this.config._headerDestPlan = this.shortenAddress(this.config._destination); - this.transittime = this.receiveAlternative(notification, payload); - this.updateDom(this.config.animationSpeed * 1000); - }else if(!payload.data){ - this.loaded = false; - this.ignoredError = false; - }else{ - var errlst = this.config.ignoreErrors - if (this.info && errlst.indexOf(payload.data.status) >= 0){ - Log.info('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = true; - this.loaded = true; - this.updateDom(this.config.animationSpeed * 1000); - }else{ - Log.warn('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = false; - this.info = payload.data; - this.loaded = false; - this.updateDom(this.config.animationSpeed * 1000); - } - } - } - if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE' && payload.id === this.identifier) { - //Received response on routes for walking - this.config._walktime = this.receiveAlternative(notification, payload); - } - if (notification === 'LOCAL_TRANSPORT_CYCLE_RESPONSE' && payload.id === this.identifier) { - //Received response on routes for bicycle - this.config._cycletime = this.receiveAlternative(notification, payload); - } - if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE' && payload.id === this.identifier) { - //Received response on routes for driving - this.config._drivetime = this.receiveAlternative(notification, payload); + if (payload.id === this.identifier){ + //Received response on public transport routes (main one) + if (notification === 'LOCAL_TRANSPORT_RESPONSE') { + if(payload.data && payload.data.status === "OK"){ + Log.log('received ' + notification); + this.info = payload.data; + this.loaded = true; + this.ignoredError = false; + this.config._headerDestPlan = this.shortenAddress(this.config._destination); + this.altTimeTransit = this.receiveAlternative(notification, payload); + this.updateDom(this.config.animationSpeed * 1000); + }else if(!payload.data){ + this.loaded = false; + this.ignoredError = false; + }else{ + var errlst = this.config.ignoreErrors + if (this.info && errlst.indexOf(payload.data.status) >= 0){ + Log.info('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = true; + this.loaded = true; + this.updateDom(this.config.animationSpeed * 1000); + }else{ + Log.warn('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = false; + this.info = payload.data; + this.loaded = false; + this.updateDom(this.config.animationSpeed * 1000); + } + } + } + //Received response on alternative routes + if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE') { + this.altTimeWalk = this.receiveAlternative(notification, payload); + } + if (notification === 'LOCAL_TRANSPORT_CYCLE_RESPONSE') { + this.altTimeCycle = this.receiveAlternative(notification, payload); + } + if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE') { + this.altTimeDrive = this.receiveAlternative(notification, payload); + } } }, notificationReceived: function(notification, payload, sender) { @@ -446,13 +435,9 @@ Module.register('MMM-LocalTransport', { /*create an unsorted list with each *route alternative being a new list item*/ var ul = document.createElement("ul"); - var Nrs = 0; //number of routes var routeArray = []; //array of all alternatives for later sorting for(var routeKey in this.info.routes) { /*each route describes a way to get from A to Z*/ - //if(Nrs >= this.config.maxAlternatives){ - // break; - //} var route = this.info.routes[routeKey]; var li = document.createElement("li"); li.className = "small"; @@ -466,14 +451,13 @@ Module.register('MMM-LocalTransport', { this.config._headerDest = this.shortenAddress(leg.end_address); this.config._laststop = ''; //need to reset the _laststop in case the previous leg didn't end with a walking step. try { - arrival = leg.arrival_time.value; for(var stepKey in leg.steps) { /*each leg consists of several steps *e.g. (1) walk from A to B, then (2) take the bus from B to C and then (3) walk from C to Z*/ - var step = leg.steps[stepKey]; + var step = leg.steps[stepKey]; this.renderStep(tmpwrapper, step); if (tmpwrapper.innerHTML === "too far"){ //walking distance was too long -> skip this option @@ -494,7 +478,6 @@ Module.register('MMM-LocalTransport', { } if (li.innerHTML !== "too far"){ routeArray.push({"arrival":arrival,"html":li}); - Nrs += 1; } } @@ -513,7 +496,7 @@ Module.register('MMM-LocalTransport', { /*create fade effect and append list items to the list*/ var e = 0; - Nrs = routeArray.length; + var Nrs = routeArray.length; for(var dataKey in routeArray) { var routeData = routeArray[dataKey]; var routeHtml = routeData.html; @@ -555,4 +538,4 @@ Module.register('MMM-LocalTransport', { return temp[0]; } -}); +}); \ No newline at end of file From d272007903f5d0b26c0d64c8533ca586ee36ed63 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sat, 20 Jan 2018 13:56:04 +0000 Subject: [PATCH 13/20] code simplification in the spirit of codeclimate --- MMM-LocalTransport.js | 121 ++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 58 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index b19b035..e1569fb 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -284,6 +284,38 @@ Module.register('MMM-LocalTransport', { } return li; }, + receiveMain: function(notification, payload){ + if(payload.data && payload.data.status === "OK"){ + //API request returned a result -> we are happy + Log.log('received ' + notification); + this.info = payload.data; + this.loaded = true; + this.ignoredError = false; + this.config._headerDestPlan = this.shortenAddress(this.config._destination); + this.altTimeTransit = this.receiveAlternative(notification, payload); + this.updateDom(this.config.animationSpeed * 1000); + }else if(!payload.data){ + //API request returned nothing + this.loaded = false; + this.ignoredError = false; + }else{ + //API request returned an error + var errlst = this.config.ignoreErrors + if (this.info && errlst.indexOf(payload.data.status) >= 0){ + //API request returned an error but we have previous results + Log.info('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = true; + this.loaded = true; + }else{ + //API request returned an error so we don't have any routes to display -> show error + Log.warn('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = false; + this.info = payload.data; + this.loaded = false; + } + this.updateDom(this.config.animationSpeed * 1000); + } + }, receiveAlternative: function(notification, payload){ var ans = "" if(payload.data && payload.data.status === "OK"){ @@ -311,32 +343,7 @@ Module.register('MMM-LocalTransport', { if (payload.id === this.identifier){ //Received response on public transport routes (main one) if (notification === 'LOCAL_TRANSPORT_RESPONSE') { - if(payload.data && payload.data.status === "OK"){ - Log.log('received ' + notification); - this.info = payload.data; - this.loaded = true; - this.ignoredError = false; - this.config._headerDestPlan = this.shortenAddress(this.config._destination); - this.altTimeTransit = this.receiveAlternative(notification, payload); - this.updateDom(this.config.animationSpeed * 1000); - }else if(!payload.data){ - this.loaded = false; - this.ignoredError = false; - }else{ - var errlst = this.config.ignoreErrors - if (this.info && errlst.indexOf(payload.data.status) >= 0){ - Log.info('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = true; - this.loaded = true; - this.updateDom(this.config.animationSpeed * 1000); - }else{ - Log.warn('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = false; - this.info = payload.data; - this.loaded = false; - this.updateDom(this.config.animationSpeed * 1000); - } - } + this.receiveMain(notification, payload); } //Received response on alternative routes if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE') { @@ -350,43 +357,41 @@ Module.register('MMM-LocalTransport', { } } }, + calendarReceived: function(notification, payload, sender) { + //received calendar events AND user wants events to influence the travel destination. + Log.info('received ' + notification); + var dn = new Date(); + var oneSecond = 1000; // 1,000 milliseconds + var oneMinute = oneSecond * 60; + var oneHour = oneMinute * 60; + var oneDay = oneHour * 24; + + var value; + for (let x of payload) { + //go through the events, pick first one with a set location. + //also ignore running events + if(x.location !== '' && x.location !== false && x.startDate - dn >= 0){ + value = x; + break; + } + } + //check if event is less than one day away + if(value.startDate - dn - oneDay <= 0){ + //if so, then update the destination and request an update of the routes + this.config._destination = value.location; + this.doMainUpdate(); + this.lastupdate = dn.getTime(); + }else{ + //if not, then make sure the default destination is set again. + this.config._destination = this.config.destination; + } + }, notificationReceived: function(notification, payload, sender) { /*notificationReceived *handles notifications send by other modules */ if (notification === 'CALENDAR_EVENTS' && sender.name === 'calendar' && this.config.getCalendarLocation) { - //received calendar events AND user wants events to influence the travel destination. - Log.info('received ' + notification); - var dn = new Date(); - var oneSecond = 1000; // 1,000 milliseconds - var oneMinute = oneSecond * 60; - var oneHour = oneMinute * 60; - var oneDay = oneHour * 24; - - var value; - for (let x of payload) { - //go through the events, pick first one with a set location. - //also ignore running events - if(x.location !== '' && x.location !== false && x.startDate - dn >= 0){ - value = x; - break; - } - } - //check if event is less than one day away - if(value.startDate - dn - oneDay <= 0){ - //if so, then update the destination and request an update of the routes - this.config._destination = value.location; - this.doMainUpdate(); - this.lastupdate = dn.getTime(); - }else{ - //if not, then make sure the default destination is set again. - this.config._destination = this.config.destination; - } - - if (this.config.debug){ - this.sendNotification("SHOW_ALERT", { timer: 3000, title: "LOCAL TRANSPORT", message: "calendar update"}); - } - + this.calendarReceived(notification, payload, sender); } }, getHeader: function() { From 5b3872c61b8b03fa19b0cc311cb7e05dfea1aa52 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sat, 20 Jan 2018 14:04:18 +0000 Subject: [PATCH 14/20] code simplification in the spirit of codeclimate --- MMM-LocalTransport.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index e1569fb..a417c06 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -341,6 +341,24 @@ Module.register('MMM-LocalTransport', { *handles notifications send by this module */ if (payload.id === this.identifier){ + switch(notification){ + case 'LOCAL_TRANSPORT_RESPONSE': + //Received response on public transport routes (main one) + this.receiveMain(notification, payload); + break; + case 'LOCAL_TRANSPORT_WALK_RESPONSE': + //Received response on walking alternative + this.altTimeWalk = this.receiveAlternative(notification, payload); + break; + case 'LOCAL_TRANSPORT_CYCLE_RESPONSE': + //Received response on cycling alternative + this.altTimeCycle = this.receiveAlternative(notification, payload); + break; + case 'LOCAL_TRANSPORT_DRIVE_RESPONSE': + //Received response on driving alternative + this.altTimeDrive = this.receiveAlternative(notification, payload); + } + /* //Received response on public transport routes (main one) if (notification === 'LOCAL_TRANSPORT_RESPONSE') { this.receiveMain(notification, payload); @@ -354,7 +372,7 @@ Module.register('MMM-LocalTransport', { } if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE') { this.altTimeDrive = this.receiveAlternative(notification, payload); - } + }*/ } }, calendarReceived: function(notification, payload, sender) { From 11a5f0667fe48937976a02393f786f854aad410a Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sat, 20 Jan 2018 15:02:56 +0000 Subject: [PATCH 15/20] added helper.js to outsource small functions to reduce number of functions and length of main file --- MMM-LocalTransport.js | 273 +++++++++++++++++++----------------------- helper.js | 36 ++++++ 2 files changed, 157 insertions(+), 152 deletions(-) create mode 100644 helper.js diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index a417c06..d56a1ed 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -48,13 +48,13 @@ Module.register('MMM-LocalTransport', { //default certain global variables this.loaded = false; this.ignoredError = false; - this.altTimeWalk = 'unknown'; - this.altTimeCycle = 'unknown'; + this.altTimeWalk = 'unknown'; + this.altTimeCycle = 'unknown'; this.altTimeTransit = 'unknown'; - this.altTimeDrive = 'unknown'; + this.altTimeDrive = 'unknown'; this.altSymbols = ['walk','cycle','rail','drive']; - this.altModes = ['walking','bicycling','transit','driving']; - + this.altModes = ['walking','bicycling','transit','driving']; + if (this.config.api_key === 'YOUR_API_KEY'){ /*if there is no api key specified in the options of the module, @@ -88,7 +88,8 @@ Module.register('MMM-LocalTransport', { this.updateDom(); //this.updateDom(this.config.animationSpeed * 1000) } }, - sendRequest: function(requestName) { + sendRequest: function(requestName, mode) { + this.config.mode = mode; this.sendSocketNotification( requestName, { id: this.identifier, @@ -104,21 +105,18 @@ Module.register('MMM-LocalTransport', { */ //request routes from Google this.loaded = false; - this.sendRequest('LOCAL_TRANSPORT_REQUEST'); + this.sendRequest('LOCAL_TRANSPORT_REQUEST',this.config.mode); //request walking time if (this.config.displayAltWalk){ - this.config.mode = 'walking'; - this.sendRequest('LOCAL_TRANSPORT_WALK_REQUEST'); + this.sendRequest('LOCAL_TRANSPORT_WALK_REQUEST','walking'); } //request cycling time if (this.config.displayAltCycle){ - this.config.mode = 'bicycling'; - this.sendRequest('LOCAL_TRANSPORT_CYCLE_REQUEST'); + this.sendRequest('LOCAL_TRANSPORT_CYCLE_REQUEST','bicycling'); } //request driving time if (this.config.displayAltDrive){ - this.config.mode = 'driving'; - this.sendRequest('LOCAL_TRANSPORT_DRIVE_REQUEST'); + this.sendRequest('LOCAL_TRANSPORT_DRIVE_REQUEST','driving'); } if (this.config.debug){ this.sendNotification("SHOW_ALERT", { timer: 3000, title: "LOCAL TRANSPORT", message: "special update"}); @@ -135,17 +133,6 @@ Module.register('MMM-LocalTransport', { params += '&alternatives=true'; return params; }, - getSymbol: function(symName){ - var img = document.createElement("img"); - if(this.config.showColor){ - img.className = "symbol"; - }else{ - img.className = "symbol bw"; - } - img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/"+symName+".png"; - //img.src = "/localtransport/"+symName+".png"; //needs to be saved in localtransport/public/walk.png - return img; - }, convertTime: function(seconds){ var ans = moment.duration(seconds, 'seconds').locale(this.config.language).humanize(); if(this.config.displayWalkType === 'short'){ @@ -164,15 +151,15 @@ Module.register('MMM-LocalTransport', { var span = document.createElement("div"); span.className = "small bright"; span.innerHTML = moment(depature).locale(this.config.language).fromNow(); - if (this.config.displayArrival){ - span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": "; - if (this.config.timeFormat === 24){ - span.innerHTML += moment(arrival).format("H:mm"); - }else{ - span.innerHTML += moment(arrival).format("h:mm"); - } - span.innerHTML += ")"; - } + if (this.config.displayArrival){ + span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": "; + if (this.config.timeFormat === 24){ + span.innerHTML += moment(arrival).format("H:mm"); + }else{ + span.innerHTML += moment(arrival).format("h:mm"); + } + span.innerHTML += ")"; + } wrapper.appendChild(span); }, renderStep: function(wrapper, step){ @@ -189,7 +176,7 @@ Module.register('MMM-LocalTransport', { }else if(this.config.displayWalkType != 'none'){ /*if walking and walking times should be *specified, add symbol and time*/ - wrapper.appendChild(this.getSymbol("walk")); + wrapper.appendChild(getSymbol("walk",this.config.showColor)); var span = document.createElement("span"); span.innerHTML = this.convertTime(duration); if (this.config._laststop !== ''){ @@ -201,7 +188,7 @@ Module.register('MMM-LocalTransport', { */ if (this.config.displayStationLength > 0){ /* add departure stop (shortened)*/ - span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(this.config._laststop, this.config.displayStationLength) + ")"; + span.innerHTML += " ("+this.translate("FROM")+" " + shorten(this.config._laststop, this.config.displayStationLength) + ")"; }else if (this.config.displayStationLength === 0){ /* add departure stop*/ span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; @@ -237,7 +224,7 @@ Module.register('MMM-LocalTransport', { span.innerHTML = details.line.short_name || details.line.name; if (this.config.displayStationLength > 0){ /* add departure stop (shortened)*/ - span.innerHTML += " ("+this.translate("FROM")+" " + this.shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; + span.innerHTML += " ("+this.translate("FROM")+" " + shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; }else if (this.config.displayStationLength === 0){ /* add departure stop*/ span.innerHTML += " ("+this.translate("FROM")+" " + details.departure_stop.name + ")"; @@ -277,45 +264,45 @@ Module.register('MMM-LocalTransport', { var timeAlt = [this.altTimeWalk,this.altTimeCycle,this.altTimeTransit,this.altTimeDrive]; for (i = 0; i < displayAlt.length; i++) { if (displayAlt[i]){ - li.appendChild(this.getSymbol(this.altSymbols[i])); + li.appendChild(getSymbol(this.altSymbols[i],this.config.showColor)); var span = this.renderAlternativeTime(timeAlt[i]); li.appendChild(span); } } return li; }, - receiveMain: function(notification, payload){ - if(payload.data && payload.data.status === "OK"){ - //API request returned a result -> we are happy - Log.log('received ' + notification); - this.info = payload.data; - this.loaded = true; - this.ignoredError = false; - this.config._headerDestPlan = this.shortenAddress(this.config._destination); - this.altTimeTransit = this.receiveAlternative(notification, payload); - this.updateDom(this.config.animationSpeed * 1000); - }else if(!payload.data){ - //API request returned nothing - this.loaded = false; - this.ignoredError = false; - }else{ - //API request returned an error - var errlst = this.config.ignoreErrors - if (this.info && errlst.indexOf(payload.data.status) >= 0){ - //API request returned an error but we have previous results - Log.info('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = true; - this.loaded = true; - }else{ - //API request returned an error so we don't have any routes to display -> show error - Log.warn('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = false; - this.info = payload.data; - this.loaded = false; - } - this.updateDom(this.config.animationSpeed * 1000); - } - }, + receiveMain: function(notification, payload){ + if(payload.data && payload.data.status === "OK"){ + //API request returned a result -> we are happy + Log.log('received ' + notification); + this.info = payload.data; + this.loaded = true; + this.ignoredError = false; + this.config._headerDestPlan = shortenAddress(this.config._destination); + this.altTimeTransit = this.receiveAlternative(notification, payload); + this.updateDom(this.config.animationSpeed * 1000); + }else if(!payload.data){ + //API request returned nothing + this.loaded = false; + this.ignoredError = false; + }else{ + //API request returned an error + var errlst = this.config.ignoreErrors + if (this.info && errlst.indexOf(payload.data.status) >= 0){ + //API request returned an error but we have previous results and permission to ignore it + Log.info('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = true; + this.loaded = true; + }else{ + //API request returned an error so we don't have any routes to display -> show error + Log.warn('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = false; + this.info = payload.data; + this.loaded = false; + } + this.updateDom(this.config.animationSpeed * 1000); + } + }, receiveAlternative: function(notification, payload){ var ans = "" if(payload.data && payload.data.status === "OK"){ @@ -341,69 +328,69 @@ Module.register('MMM-LocalTransport', { *handles notifications send by this module */ if (payload.id === this.identifier){ - switch(notification){ - case 'LOCAL_TRANSPORT_RESPONSE': - //Received response on public transport routes (main one) - this.receiveMain(notification, payload); - break; - case 'LOCAL_TRANSPORT_WALK_RESPONSE': - //Received response on walking alternative - this.altTimeWalk = this.receiveAlternative(notification, payload); - break; - case 'LOCAL_TRANSPORT_CYCLE_RESPONSE': - //Received response on cycling alternative - this.altTimeCycle = this.receiveAlternative(notification, payload); - break; - case 'LOCAL_TRANSPORT_DRIVE_RESPONSE': - //Received response on driving alternative - this.altTimeDrive = this.receiveAlternative(notification, payload); - } - /* - //Received response on public transport routes (main one) - if (notification === 'LOCAL_TRANSPORT_RESPONSE') { - this.receiveMain(notification, payload); - } - //Received response on alternative routes - if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE') { - this.altTimeWalk = this.receiveAlternative(notification, payload); - } - if (notification === 'LOCAL_TRANSPORT_CYCLE_RESPONSE') { - this.altTimeCycle = this.receiveAlternative(notification, payload); - } - if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE') { - this.altTimeDrive = this.receiveAlternative(notification, payload); - }*/ + switch(notification){ + case 'LOCAL_TRANSPORT_RESPONSE': + //Received response on public transport routes (main one) + this.receiveMain(notification, payload); + break; + case 'LOCAL_TRANSPORT_WALK_RESPONSE': + //Received response on walking alternative + this.altTimeWalk = this.receiveAlternative(notification, payload); + break; + case 'LOCAL_TRANSPORT_CYCLE_RESPONSE': + //Received response on cycling alternative + this.altTimeCycle = this.receiveAlternative(notification, payload); + break; + case 'LOCAL_TRANSPORT_DRIVE_RESPONSE': + //Received response on driving alternative + this.altTimeDrive = this.receiveAlternative(notification, payload); + } + /* + //Received response on public transport routes (main one) + if (notification === 'LOCAL_TRANSPORT_RESPONSE') { + this.receiveMain(notification, payload); + } + //Received response on alternative routes + if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE') { + this.altTimeWalk = this.receiveAlternative(notification, payload); + } + if (notification === 'LOCAL_TRANSPORT_CYCLE_RESPONSE') { + this.altTimeCycle = this.receiveAlternative(notification, payload); + } + if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE') { + this.altTimeDrive = this.receiveAlternative(notification, payload); + }*/ + } + }, + calendarReceived: function(notification, payload, sender) { + //received calendar events AND user wants events to influence the travel destination. + Log.info('received ' + notification); + var dn = new Date(); + var oneSecond = 1000; // 1,000 milliseconds + var oneMinute = oneSecond * 60; + var oneHour = oneMinute * 60; + var oneDay = oneHour * 24; + + var value; + for (let x of payload) { + //go through the events, pick first one with a set location. + //also ignore running events + if(x.location !== '' && x.location !== false && x.startDate - dn >= 0){ + value = x; + break; + } + } + //check if event is less than one day away + if(value.startDate - dn - oneDay <= 0){ + //if so, then update the destination and request an update of the routes + this.config._destination = value.location; + this.doMainUpdate(); + this.lastupdate = dn.getTime(); + }else{ + //if not, then make sure the default destination is set again. + this.config._destination = this.config.destination; } }, - calendarReceived: function(notification, payload, sender) { - //received calendar events AND user wants events to influence the travel destination. - Log.info('received ' + notification); - var dn = new Date(); - var oneSecond = 1000; // 1,000 milliseconds - var oneMinute = oneSecond * 60; - var oneHour = oneMinute * 60; - var oneDay = oneHour * 24; - - var value; - for (let x of payload) { - //go through the events, pick first one with a set location. - //also ignore running events - if(x.location !== '' && x.location !== false && x.startDate - dn >= 0){ - value = x; - break; - } - } - //check if event is less than one day away - if(value.startDate - dn - oneDay <= 0){ - //if so, then update the destination and request an update of the routes - this.config._destination = value.location; - this.doMainUpdate(); - this.lastupdate = dn.getTime(); - }else{ - //if not, then make sure the default destination is set again. - this.config._destination = this.config.destination; - } - }, notificationReceived: function(notification, payload, sender) { /*notificationReceived *handles notifications send by other modules @@ -423,7 +410,7 @@ Module.register('MMM-LocalTransport', { header = header.replace("%{dest}", this.config._headerDest); } //use %{orig} in the header definition for the module and it will be replaces with the origin as defined in the config - this.config._headerOrigPlan = this.shortenAddress(this.config.origin); + this.config._headerOrigPlan = shortenAddress(this.config.origin); header = header.replace("%{orig}", this.config._headerOrigPlan); return header; @@ -432,7 +419,7 @@ Module.register('MMM-LocalTransport', { return ["localtransport.css"]; }, getScripts: function() { - return ["moment.js"]; + return ["moment.js","helper.js"]; }, getTranslations: function() { return { @@ -452,7 +439,7 @@ Module.register('MMM-LocalTransport', { wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); }else{ wrapper.innerHTML = this.translate(this.info.status); - } + } wrapper.className = "small dimmed"; }else{ /*create an unsorted list with each @@ -471,7 +458,7 @@ Module.register('MMM-LocalTransport', { for(var legKey in route.legs) { var leg = route.legs[legKey]; var tmpwrapper = document.createElement("text"); - this.config._headerDest = this.shortenAddress(leg.end_address); + this.config._headerDest = shortenAddress(leg.end_address); this.config._laststop = ''; //need to reset the _laststop in case the previous leg didn't end with a walking step. try { arrival = leg.arrival_time.value; @@ -541,24 +528,6 @@ Module.register('MMM-LocalTransport', { wrapper.appendChild(ul); } return wrapper; - }, - shorten: function(string, maxLength) { - /*shorten - *shortens a string to the number of characters specified*/ - if (string.length > maxLength) { - return string.slice(0,maxLength) + "…"; - } - return string; - }, - shortenAddress: function(address) { - /*shortenAddress - *shortens a string to the first part of an address - *this assumes that the address string is split by ',' - *useful since Google will require a very precise - *definition of an address while the user would usually - *know which city and country they are looking at*/ - var temp = address.split(","); - return temp[0]; } }); \ No newline at end of file diff --git a/helper.js b/helper.js new file mode 100644 index 0000000..e981ec5 --- /dev/null +++ b/helper.js @@ -0,0 +1,36 @@ +/* small collection of functions that do basic things + * main purpose is to reduce the number of functions per file + */ + +function getSymbol(symName,showColor){ + var img = document.createElement("img"); + if(showColor){ + img.className = "symbol"; + }else{ + img.className = "symbol bw"; + } + img.src = "https://maps.gstatic.com/mapfiles/transit/iw2/6/"+symName+".png"; + //img.src = "/localtransport/"+symName+".png"; //needs to be saved in localtransport/public/walk.png + return img; +} + + +function shorten(string, maxLength) { + /*shorten + *shortens a string to the number of characters specified*/ + if (string.length > maxLength) { + return string.slice(0,maxLength) + "…"; + } + return string; +} + +function shortenAddress(address) { + /*shortenAddress + *shortens a string to the first part of an address + *this assumes that the address string is split by ',' + *useful since Google will require a very precise + *definition of an address while the user would usually + *know which city and country they are looking at*/ + var temp = address.split(","); + return temp[0]; +} \ No newline at end of file From cca9b78d3d9095717c655232f42ee90ed6c489a6 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sat, 10 Feb 2018 19:32:37 +0000 Subject: [PATCH 16/20] moved renderLef into helper.js and started to look into moving parts of other functions --- MMM-LocalTransport.js | 42 ++++++++-------- helper.js | 111 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 20 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index d56a1ed..edbb441 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -141,12 +141,12 @@ Module.register('MMM-LocalTransport', { ans = ans.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); } return ans; - }, + },/* renderLeg: function(wrapper, leg){ /* renderLeg * creates HTML element for one leg of a route */ - var depature = leg.departure_time.value * 1000; +/* var depature = leg.departure_time.value * 1000; var arrival = leg.arrival_time.value * 1000; var span = document.createElement("div"); span.className = "small bright"; @@ -161,7 +161,7 @@ Module.register('MMM-LocalTransport', { span.innerHTML += ")"; } wrapper.appendChild(span); - }, + },*/ renderStep: function(wrapper, step){ /* renderStep * creates HTML element for one step of a leg @@ -186,13 +186,14 @@ Module.register('MMM-LocalTransport', { to not cause interference between different routes and we need to skip the display for the first step if that is a walking step (alternatively one could display the departure location specified by the user, but I prefer this option) */ - if (this.config.displayStationLength > 0){ - /* add departure stop (shortened)*/ - span.innerHTML += " ("+this.translate("FROM")+" " + shorten(this.config._laststop, this.config.displayStationLength) + ")"; - }else if (this.config.displayStationLength === 0){ - /* add departure stop*/ - span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; - } + renderDeparture(span, this.config._laststop, this.translate("FROM"), this.config); + //if (this.config.displayStationLength > 0){ + // /* add departure stop (shortened)*/ + // span.innerHTML += " ("+this.translate("FROM")+" " + shorten(this.config._laststop, this.config.displayStationLength) + ")"; + //}else if (this.config.displayStationLength === 0){ + // /* add departure stop*/ + // span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; + //} } span.className = "xsmall dimmed"; wrapper.appendChild(span); @@ -222,13 +223,14 @@ Module.register('MMM-LocalTransport', { var span = document.createElement("span"); /* add line name*/ span.innerHTML = details.line.short_name || details.line.name; - if (this.config.displayStationLength > 0){ - /* add departure stop (shortened)*/ - span.innerHTML += " ("+this.translate("FROM")+" " + shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; - }else if (this.config.displayStationLength === 0){ - /* add departure stop*/ - span.innerHTML += " ("+this.translate("FROM")+" " + details.departure_stop.name + ")"; - } + renderDeparture(span, details.departure_stop.name, this.translate("FROM"), this.config); + //if (this.config.displayStationLength > 0){ + // /* add departure stop (shortened)*/ + // span.innerHTML += " ("+this.translate("FROM")+" " + shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; + //}else if (this.config.displayStationLength === 0){ + // /* add departure stop*/ + // span.innerHTML += " ("+this.translate("FROM")+" " + details.departure_stop.name + ")"; + //} if (this.config.debug){ /* add vehicle type for debug*/ span.innerHTML += " [" + details.line.vehicle.name +"]"; @@ -423,8 +425,8 @@ Module.register('MMM-LocalTransport', { }, getTranslations: function() { return { - de: "i18n/de.json", en: "i18n/en.json", + de: "i18n/de.json", sv: "i18n/sv.json", fr: "i18n/fr.json" }; @@ -469,6 +471,7 @@ Module.register('MMM-LocalTransport', { (3) walk from C to Z*/ var step = leg.steps[stepKey]; this.renderStep(tmpwrapper, step); + //renderStep(tmpwrapper, step, this.translate("FROM"), config); if (tmpwrapper.innerHTML === "too far"){ //walking distance was too long -> skip this option break; @@ -483,7 +486,8 @@ Module.register('MMM-LocalTransport', { li.innerHTML = "too far"; break; } - this.renderLeg(li, leg); + //this.renderLeg(li, leg); + renderLeg(li, leg, this.translate("ARRIVAL"), this.config, ); li.appendChild(tmpwrapper); } if (li.innerHTML !== "too far"){ diff --git a/helper.js b/helper.js index e981ec5..54276b8 100644 --- a/helper.js +++ b/helper.js @@ -33,4 +33,113 @@ function shortenAddress(address) { *know which city and country they are looking at*/ var temp = address.split(","); return temp[0]; -} \ No newline at end of file +} + +function renderLeg(wrapper, leg, arrivalWord, config){ + /* renderLeg + * creates HTML element for one leg of a route + */ + var depature = leg.departure_time.value * 1000; + var arrival = leg.arrival_time.value * 1000; + var span = document.createElement("div"); + span.className = "small bright"; + span.innerHTML = moment(depature).locale(config.language).fromNow(); + if (config.displayArrival){ + span.innerHTML += " ("+config.test+arrivalWord+": "; + if (config.timeFormat === 24){ + span.innerHTML += moment(arrival).format("H:mm"); + }else{ + span.innerHTML += moment(arrival).format("h:mm"); + } + span.innerHTML += ")"; + } + wrapper.appendChild(span); +} + +function renderDeparture(span, departureStop, fromWord, config){ + if (config.displayStationLength > 0){ + /* add departure stop (shortened)*/ + span.innerHTML += " ("+fromWord+" " + shorten(departureStop, config.displayStationLength) + ")"; + }else if (config.displayStationLength === 0){ + /* add departure stop*/ + span.innerHTML += " ("+fromWord+" " + config._laststop + ")"; + } +} + +//function renderStep(wrapper, step, fromWord, config){ + // /* renderStep + // * creates HTML element for one step of a leg + // */ + // if(step.travel_mode === "WALKING"){ + // /*this step is not public transport but walking*/ + // var duration = step.duration.value; + // if (duration >= (config.maxWalkTime*60)){ + // /*if time of walking is longer than + // *specified, mark this route to be skipped*/ + // wrapper.innerHTML = "too far"; + // }else if(config.displayWalkType != 'none'){ + // /*if walking and walking times should be + // *specified, add symbol and time*/ + // wrapper.appendChild(getSymbol("walk",config.showColor)); + // var span = document.createElement("span"); + // span.innerHTML = this.convertTime(duration); + // if (config._laststop !== ''){ + // /* walking step doesn't have a departure_stop set - maybe something else but can't find the documentation right now. + // so in order to display the departure, we will just save the arrival of any transit step into a global variable and + // display the previous arrival instead of the current departure location. That means we need to reset the global variable + // to not cause interference between different routes and we need to skip the display for the first step if that is a walking + // step (alternatively one could display the departure location specified by the user, but I prefer this option) + // */ + // if (config.displayStationLength > 0){ + // /* add departure stop (shortened)*/ + // span.innerHTML += " ("+fromWord+" " + shorten(config._laststop, config.displayStationLength) + ")"; + // }else if (config.displayStationLength === 0){ + // /* add departure stop*/ + // span.innerHTML += " ("+fromWord+" " + config._laststop + ")"; + // } + // } + // span.className = "xsmall dimmed"; + // wrapper.appendChild(span); + // }else{ + // /*skip walking*/ + // return; + // } + // config._laststop = ''; + // }else{ + // /*if this is a transit step*/ + // var details = step.transit_details; + // if(details) { + // /*add symbol of transport vehicle*/ + // var img = document.createElement("img"); + // if(config.showColor){ + // img.className = "symbol"; + // }else{ + // img.className = "symbol bw"; + // } + // /* get symbol online*/ + // img.src = details.line.vehicle.local_icon || ("https:" + details.line.vehicle.icon); + // /* can provide own symbols under /localtransport/public/*.png */ + // //img.src = "/localtransport/" + details.line.vehicle.name + ".png"; + // img.alt = "[" + details.line.vehicle.name +"]"; + // wrapper.appendChild(img); + // /*add description*/ + // var span = document.createElement("span"); + // /* add line name*/ + // span.innerHTML = details.line.short_name || details.line.name; + // if (config.displayStationLength > 0){ + // /* add departure stop (shortened)*/ + // span.innerHTML += " ("+fromWord+" " + shorten(details.departure_stop.name, config.displayStationLength) + ")"; + // }else if (config.displayStationLength === 0){ + // /* add departure stop*/ + // span.innerHTML += " ("+fromWord+" " + details.departure_stop.name + ")"; + // } + // if (config.debug){ + // /* add vehicle type for debug*/ + // span.innerHTML += " [" + details.line.vehicle.name +"]"; + // } + // config._laststop = details.arrival_stop.name; + // span.className = "xsmall dimmed"; + // wrapper.appendChild(span); + // } + // } +// } \ No newline at end of file From abdbbbacf3f1f5a647e8ed72612f39a559cdfc06 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sat, 10 Feb 2018 19:35:16 +0000 Subject: [PATCH 17/20] removed old comments --- MMM-LocalTransport.js | 51 +------------------------------------------ 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index edbb441..1621f65 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -141,27 +141,7 @@ Module.register('MMM-LocalTransport', { ans = ans.replace(this.translate("SECOND_PL"),this.translate("SECOND_PS")); } return ans; - },/* - renderLeg: function(wrapper, leg){ - /* renderLeg - * creates HTML element for one leg of a route - */ -/* var depature = leg.departure_time.value * 1000; - var arrival = leg.arrival_time.value * 1000; - var span = document.createElement("div"); - span.className = "small bright"; - span.innerHTML = moment(depature).locale(this.config.language).fromNow(); - if (this.config.displayArrival){ - span.innerHTML += " ("+this.config.test+this.translate("ARRIVAL")+": "; - if (this.config.timeFormat === 24){ - span.innerHTML += moment(arrival).format("H:mm"); - }else{ - span.innerHTML += moment(arrival).format("h:mm"); - } - span.innerHTML += ")"; - } - wrapper.appendChild(span); - },*/ + }, renderStep: function(wrapper, step){ /* renderStep * creates HTML element for one step of a leg @@ -187,13 +167,6 @@ Module.register('MMM-LocalTransport', { step (alternatively one could display the departure location specified by the user, but I prefer this option) */ renderDeparture(span, this.config._laststop, this.translate("FROM"), this.config); - //if (this.config.displayStationLength > 0){ - // /* add departure stop (shortened)*/ - // span.innerHTML += " ("+this.translate("FROM")+" " + shorten(this.config._laststop, this.config.displayStationLength) + ")"; - //}else if (this.config.displayStationLength === 0){ - // /* add departure stop*/ - // span.innerHTML += " ("+this.translate("FROM")+" " + this.config._laststop + ")"; - //} } span.className = "xsmall dimmed"; wrapper.appendChild(span); @@ -224,13 +197,6 @@ Module.register('MMM-LocalTransport', { /* add line name*/ span.innerHTML = details.line.short_name || details.line.name; renderDeparture(span, details.departure_stop.name, this.translate("FROM"), this.config); - //if (this.config.displayStationLength > 0){ - // /* add departure stop (shortened)*/ - // span.innerHTML += " ("+this.translate("FROM")+" " + shorten(details.departure_stop.name, this.config.displayStationLength) + ")"; - //}else if (this.config.displayStationLength === 0){ - // /* add departure stop*/ - // span.innerHTML += " ("+this.translate("FROM")+" " + details.departure_stop.name + ")"; - //} if (this.config.debug){ /* add vehicle type for debug*/ span.innerHTML += " [" + details.line.vehicle.name +"]"; @@ -347,21 +313,6 @@ Module.register('MMM-LocalTransport', { //Received response on driving alternative this.altTimeDrive = this.receiveAlternative(notification, payload); } - /* - //Received response on public transport routes (main one) - if (notification === 'LOCAL_TRANSPORT_RESPONSE') { - this.receiveMain(notification, payload); - } - //Received response on alternative routes - if (notification === 'LOCAL_TRANSPORT_WALK_RESPONSE') { - this.altTimeWalk = this.receiveAlternative(notification, payload); - } - if (notification === 'LOCAL_TRANSPORT_CYCLE_RESPONSE') { - this.altTimeCycle = this.receiveAlternative(notification, payload); - } - if (notification === 'LOCAL_TRANSPORT_DRIVE_RESPONSE') { - this.altTimeDrive = this.receiveAlternative(notification, payload); - }*/ } }, calendarReceived: function(notification, payload, sender) { From 1971ed4fe8f21417041fa8e2af38514a347bdb92 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sun, 11 Feb 2018 17:45:15 +0000 Subject: [PATCH 18/20] simplified receiveMain and moved receiveAlternative --- MMM-LocalTransport.js | 61 ++++++++++++++++--------------------------- helper.js | 20 ++++++++++++++ 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index 1621f65..f48e316 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -240,6 +240,7 @@ Module.register('MMM-LocalTransport', { return li; }, receiveMain: function(notification, payload){ + var errlst = this.config.ignoreErrors; if(payload.data && payload.data.status === "OK"){ //API request returned a result -> we are happy Log.log('received ' + notification); @@ -247,49 +248,27 @@ Module.register('MMM-LocalTransport', { this.loaded = true; this.ignoredError = false; this.config._headerDestPlan = shortenAddress(this.config._destination); - this.altTimeTransit = this.receiveAlternative(notification, payload); + //this.altTimeTransit = this.receiveAlternative(notification, payload); + this.altTimeTransit = receiveAlternative(notification, payload, this.config.ignoreErrors); this.updateDom(this.config.animationSpeed * 1000); }else if(!payload.data){ //API request returned nothing this.loaded = false; this.ignoredError = false; - }else{ - //API request returned an error - var errlst = this.config.ignoreErrors - if (this.info && errlst.indexOf(payload.data.status) >= 0){ - //API request returned an error but we have previous results and permission to ignore it - Log.info('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = true; - this.loaded = true; - }else{ - //API request returned an error so we don't have any routes to display -> show error - Log.warn('received ' + notification + ' with status '+payload.data.status); - this.ignoredError = false; - this.info = payload.data; - this.loaded = false; - } + }else if(this.info && errlst.indexOf(payload.data.status) >= 0){ + //API request returned an error but we have previous results and permission to ignore it + Log.info('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = true; + this.loaded = true; this.updateDom(this.config.animationSpeed * 1000); - } - }, - receiveAlternative: function(notification, payload){ - var ans = "" - if(payload.data && payload.data.status === "OK"){ - Log.log('received ' + notification); - //only interested in duration, first option should be the shortest one - var route = payload.data.routes[0]; - var leg = route.legs[0]; - ans = leg.duration.value; }else{ - ans = "unknown"; - var errlst = this.config.ignoreErrors - if (errlst.indexOf(payload.data.status) < 0){ - Log.warn('received '+notification+' with status '+payload.data.status); - }else{ - Log.info('received '+notification+' with status '+payload.data.status); - } + //API request returned an error so we don't have any routes to display -> show error + Log.warn('received ' + notification + ' with status '+payload.data.status); + this.ignoredError = false; + this.info = payload.data; + this.loaded = false; + this.updateDom(this.config.animationSpeed * 1000); } - this.updateDom(); - return ans; }, socketNotificationReceived: function(notification, payload) { /*socketNotificationReceived @@ -303,15 +282,21 @@ Module.register('MMM-LocalTransport', { break; case 'LOCAL_TRANSPORT_WALK_RESPONSE': //Received response on walking alternative - this.altTimeWalk = this.receiveAlternative(notification, payload); + //this.altTimeWalk = this.receiveAlternative(notification, payload); + this.altTimeWalk = receiveAlternative(notification, payload, this.config.ignoreErrors); + this.updateDom(); break; case 'LOCAL_TRANSPORT_CYCLE_RESPONSE': //Received response on cycling alternative - this.altTimeCycle = this.receiveAlternative(notification, payload); + //this.altTimeCycle = this.receiveAlternative(notification, payload); + this.altTimeCycle = receiveAlternative(notification, payload, this.config.ignoreErrors); + this.updateDom(); break; case 'LOCAL_TRANSPORT_DRIVE_RESPONSE': //Received response on driving alternative - this.altTimeDrive = this.receiveAlternative(notification, payload); + //this.altTimeDrive = this.receiveAlternative(notification, payload); + this.altTimeDrive = receiveAlternative(notification, payload, this.config.ignoreErrors); + this.updateDom(); } } }, diff --git a/helper.js b/helper.js index 54276b8..0d7b0ed 100644 --- a/helper.js +++ b/helper.js @@ -35,6 +35,26 @@ function shortenAddress(address) { return temp[0]; } +function receiveAlternative(notification, payload, ignoreErrors){ + var ans = "" + if(payload.data && payload.data.status === "OK"){ + Log.log('received ' + notification); + //only interested in duration, first option should be the shortest one + var route = payload.data.routes[0]; + var leg = route.legs[0]; + ans = leg.duration.value; + }else{ + ans = "unknown"; + var errlst = ignoreErrors; + if (errlst.indexOf(payload.data.status) < 0){ + Log.warn('received '+notification+' with status '+payload.data.status); + }else{ + Log.info('received '+notification+' with status '+payload.data.status); + } + } + return ans; +} + function renderLeg(wrapper, leg, arrivalWord, config){ /* renderLeg * creates HTML element for one leg of a route From 32f1a62729826362166046ccf0a1cddd18c203c3 Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sun, 11 Feb 2018 18:07:49 +0000 Subject: [PATCH 19/20] placed rendering of fade effect in its own function and simplified getDom --- MMM-LocalTransport.js | 50 +++++++++++++++++-------------------------- helper.js | 39 ++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 38 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index f48e316..b21a698 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -301,13 +301,12 @@ Module.register('MMM-LocalTransport', { } }, calendarReceived: function(notification, payload, sender) { - //received calendar events AND user wants events to influence the travel destination. Log.info('received ' + notification); var dn = new Date(); - var oneSecond = 1000; // 1,000 milliseconds - var oneMinute = oneSecond * 60; - var oneHour = oneMinute * 60; - var oneDay = oneHour * 24; + //var oneSecond = 1000; // 1,000 milliseconds + //var oneMinute = oneSecond * 60; + //var oneHour = oneMinute * 60; + var oneDay = 1000 * 60 * 60 * 24; var value; for (let x of payload) { @@ -334,6 +333,7 @@ Module.register('MMM-LocalTransport', { *handles notifications send by other modules */ if (notification === 'CALENDAR_EVENTS' && sender.name === 'calendar' && this.config.getCalendarLocation) { + //received calendar events AND user wants events to influence the travel destination. this.calendarReceived(notification, payload, sender); } }, @@ -371,18 +371,23 @@ Module.register('MMM-LocalTransport', { /* main function creating HTML code to display*/ this.config._headerDest = this.config._headerDestPlan; //resetting _headerDest in case there was an error loading... var wrapper = document.createElement("div"); - if (!this.loaded || !this.info) { - /*if not loaded, display message*/ + /*if (!this.loaded || !this.info) { if(!this.info){ wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); }else{ wrapper.innerHTML = this.translate(this.info.status); } + wrapper.className = "small dimmed";*/ + if (!this.loaded && !this.info) { + /*if not loaded, display message*/ + wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); + wrapper.className = "small dimmed"; + }else if (!this.loaded){ + /*if not loaded, display message*/ + wrapper.innerHTML = this.translate(this.info.status); wrapper.className = "small dimmed"; }else{ - /*create an unsorted list with each - *route alternative being a new list item*/ - var ul = document.createElement("ul"); + /*we have routes -> render them*/ var routeArray = []; //array of all alternatives for later sorting for(var routeKey in this.info.routes) { /*each route describes a way to get from A to Z*/ @@ -443,28 +448,13 @@ Module.register('MMM-LocalTransport', { var li = this.renderAlternatives(); routeArray.push({"arrival":'',"html":li}); } + + /*create an unsorted list with each + *route alternative being a new list item*/ + //var ul = document.createElement("ul"); /*create fade effect and append list items to the list*/ - var e = 0; - var Nrs = routeArray.length; - for(var dataKey in routeArray) { - var routeData = routeArray[dataKey]; - var routeHtml = routeData.html; - // Create fade effect. - if (this.config.fade && this.config.fadePoint < 1) { - if (this.config.fadePoint < 0) { - this.config.fadePoint = 0; - } - var startingPoint = Nrs * this.config.fadePoint; - var steps = Nrs - startingPoint; - if (e >= startingPoint) { - var currentStep = e - startingPoint; - routeHtml.style.opacity = 1 - (1 / steps * currentStep); - } - } - ul.appendChild(routeHtml); - e += 1; - } + var ul = renderFade(routeArray,this.config); wrapper.appendChild(ul); } return wrapper; diff --git a/helper.js b/helper.js index 0d7b0ed..218d139 100644 --- a/helper.js +++ b/helper.js @@ -36,21 +36,18 @@ function shortenAddress(address) { } function receiveAlternative(notification, payload, ignoreErrors){ - var ans = "" + var ans = "unknown"; + var errlst = ignoreErrors; if(payload.data && payload.data.status === "OK"){ Log.log('received ' + notification); //only interested in duration, first option should be the shortest one var route = payload.data.routes[0]; var leg = route.legs[0]; ans = leg.duration.value; + }else if (errlst.indexOf(payload.data.status) < 0){ + Log.warn('received '+notification+' with status '+payload.data.status); }else{ - ans = "unknown"; - var errlst = ignoreErrors; - if (errlst.indexOf(payload.data.status) < 0){ - Log.warn('received '+notification+' with status '+payload.data.status); - }else{ - Log.info('received '+notification+' with status '+payload.data.status); - } + Log.info('received '+notification+' with status '+payload.data.status); } return ans; } @@ -86,6 +83,32 @@ function renderDeparture(span, departureStop, fromWord, config){ } } +function renderFade(routeArray,config){ + /*create fade effect and append list items to the list*/ + var ul = document.createElement("ul"); + var e = 0; + var Nrs = routeArray.length; + for(var dataKey in routeArray) { + var routeData = routeArray[dataKey]; + var routeHtml = routeData.html; + // Create fade effect. + if (config.fade && config.fadePoint < 1) { + if (config.fadePoint < 0) { + config.fadePoint = 0; + } + var startingPoint = Nrs * config.fadePoint; + var steps = Nrs - startingPoint; + if (e >= startingPoint) { + var currentStep = e - startingPoint; + routeHtml.style.opacity = 1 - (1 / steps * currentStep); + } + } + ul.appendChild(routeHtml); + e += 1; + } + return ul +} + //function renderStep(wrapper, step, fromWord, config){ // /* renderStep // * creates HTML element for one step of a leg From ea2ee38f8aa41cb18b7fb2d36888699a65bf791e Mon Sep 17 00:00:00 2001 From: GHLasse Date: Sun, 11 Feb 2018 18:17:35 +0000 Subject: [PATCH 20/20] simplified renderFade --- MMM-LocalTransport.js | 7 ------- helper.js | 28 +++++++++++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/MMM-LocalTransport.js b/MMM-LocalTransport.js index b21a698..930e0b5 100644 --- a/MMM-LocalTransport.js +++ b/MMM-LocalTransport.js @@ -371,13 +371,6 @@ Module.register('MMM-LocalTransport', { /* main function creating HTML code to display*/ this.config._headerDest = this.config._headerDestPlan; //resetting _headerDest in case there was an error loading... var wrapper = document.createElement("div"); - /*if (!this.loaded || !this.info) { - if(!this.info){ - wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); - }else{ - wrapper.innerHTML = this.translate(this.info.status); - } - wrapper.className = "small dimmed";*/ if (!this.loaded && !this.info) { /*if not loaded, display message*/ wrapper.innerHTML = this.translate("LOADING_CONNECTIONS"); diff --git a/helper.js b/helper.js index 218d139..cee44be 100644 --- a/helper.js +++ b/helper.js @@ -83,6 +83,22 @@ function renderDeparture(span, departureStop, fromWord, config){ } } +function calcOpacity(Nrs,e,config){ + if (config.fadePoint < 0) { + config.fadePoint = 0; + } + if (config.fade && config.fadePoint < 1) { + var startingPoint = Nrs * config.fadePoint; + var steps = Nrs - startingPoint; + if (e >= startingPoint) { + var currentStep = e - startingPoint; + return = 1 - (1 / steps * currentStep); + } + }else{ + return 1; + } +} + function renderFade(routeArray,config){ /*create fade effect and append list items to the list*/ var ul = document.createElement("ul"); @@ -92,17 +108,7 @@ function renderFade(routeArray,config){ var routeData = routeArray[dataKey]; var routeHtml = routeData.html; // Create fade effect. - if (config.fade && config.fadePoint < 1) { - if (config.fadePoint < 0) { - config.fadePoint = 0; - } - var startingPoint = Nrs * config.fadePoint; - var steps = Nrs - startingPoint; - if (e >= startingPoint) { - var currentStep = e - startingPoint; - routeHtml.style.opacity = 1 - (1 / steps * currentStep); - } - } + routeHtml.style.opacity = calcOpacity(Nrs,e,config); ul.appendChild(routeHtml); e += 1; }