Its been two decades since I took a coding class (and I did not use it after I graduated).
I am setting up a MagicMirror dashboard and found a travel times website (www.traveltime.com) that has an API that should work without having to put a credit card down (like many of the others). There are modules on MagicMirror but none using this site.
Is this possible to do??
The API results are:
{"results":[{"search_id":"Matrix","locations":[{"id":"41.87690559224833,-87.63761648086727","properties":[{"travel_time":917}]}],"unreachable":[]}]}
The code I am trying to use is the following:
Module.register('MMM-Traffic', {
defaults: {
interval: 300000,
showSymbol: true,
firstLine: 'Current duration is {travel_time} mins',
loadingText: 'Loading...',
language: config.language,
mode: 'driving',
days: [0, 1, 2, 3, 4, 5, 6],
hoursStart: '00:00',
hoursEnd: '23:59'
},
start: function () {
console.log('Starting module: ' + this.name);
this.loading = true;
this.internalHidden = false;
this.firstResume = true;
this.errorMessage = undefined;
this.errorDescription = undefined;
this.updateCommute = this.updateCommute.bind(this);
this.getCommute = this.getCommute.bind(this);
this.getDom = this.getDom.bind(this);
if ([this.config.originCoordsLAT, this.config.originCoordsLNG, this.config.destinationCoords, this.config.accessToken].includes(undefined)) {
this.errorMessage = 'Config error';
this.errorDescription = 'You must set originCoordsLAT, originCoordsLNG, destinationCoords, and accessToken in your config';
this.updateDom();
} else {
this.updateCommute();
}
},
updateCommute: function () {
var today = new Date()
var date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = date+'T'+time+'-06:00';
let mode = this.config.mode == 'driving' ? 'driving' : this.config.mode;
this.url = encodeURI(`https://api.traveltimeapp.com/v4/time-filter?type=${mode}&departure_time=${dateTime}&search_lat=${this.config.originCoordsLAT}&search_lng=${this.config.originCoordsLNG}&locations=${this.config.destinationCoords}&app_id=TEXT&api_key=TEXT`);
// only run getDom once at the start of a hidden period to remove the module from the screen, then just wait until time to unhide to run again
if (this.shouldHide() && !this.internalHidden) {
console.log('Hiding MMM-Traffic due to config options: days, hoursStart, hoursEnd');
this.internalHidden = true;
this.updateDom();
} else if (!this.shouldHide()) {
this.internalHidden = false;
this.getCommute(this.url);
}
// no network requests are made when the module is hidden, so check every 30 seconds during hidden
// period to see if it's time to unhide yet
setTimeout(this.updateCommute, this.internalHidden ? 3000 : this.config.interval);
},
getCommute: function (api_url) {
var self = this;
fetch(api_url)
.then(self.checkStatus)
.then(json => {
self.travel_time = ; //this is where whatever I put here, it won't pull the travel_time information. I get undefined, etc. If I put a text or number, it does show that
self.errorMessage = self.errorDescription = undefined;
self.loading = false;
self.updateDom();
})
.catch(e => {
self.errorMessage = payload.error.message;
self.errorDescription = payload.error.description;
self.loading = false;
self.updateDom();
});
},
checkStatus: function (res) {
if (res.ok) {
return res.json();
} else {
return res.json().then(json => {
throw new MMMTrafficError(`API Error - ${json.code}`, json.message);
});
}
},
getStyles: function () {
return ['traffic.css', 'font-awesome.css'];
},
getScripts: function () {
return ['moment.js'];
},
getDom: function () {
var wrapper = document.createElement("div");
// hide when desired (called once on first update during hidden period)
if (this.internalHidden) return wrapper;
// base divs
var firstLineDiv = document.createElement('div');
firstLineDiv.className = 'bright medium mmmtraffic-firstline';
var secondLineDiv = document.createElement('div');
secondLineDiv.className = 'normal small mmmtraffic-secondline';
// display any errors
if (this.errorMessage) {
firstLineDiv.innerHTML = this.errorMessage;
secondLineDiv.innerHTML = this.errorDescription;
wrapper.append(firstLineDiv);
wrapper.append(secondLineDiv);
return wrapper;
}
let symbolString = 'car';
if (this.config.mode == 'cycling') symbolString = 'bicycle';
if (this.config.mode == 'walking') symbolString = 'walking';
// symbol
if (this.config.showSymbol) {
var symbol = document.createElement('span');
symbol.className = `fa fa-${symbolString} symbol`;
firstLineDiv.appendChild(symbol);
}
// first line
var firstLineText = document.createElement('span');
firstLineText.innerHTML = this.loading ? this.config.loadingText : this.replaceTokens(this.config.firstLine)
firstLineDiv.appendChild(firstLineText);
wrapper.appendChild(firstLineDiv);
if (this.loading) return wrapper;
// second line
if (this.config.secondLine) {
secondLineDiv.innerHTML = this.replaceTokens(this.config.secondLine);
wrapper.appendChild(secondLineDiv);
}
return wrapper;
},
replaceTokens: function (text) {
return text.replace(/{travel_time}/g, this.travel_time);
},
shouldHide: function () {
let hide = true;
let now = moment();
if (this.config.days.includes(now.day()) &&
moment(this.config.hoursStart, 'HH:mm').isBefore(now) &&
moment(this.config.hoursEnd, 'HH:mm').isAfter(now)
) {
hide = false;
}
return hide;
},
});
Text from config file:
{
module: "MMM-Traffic",
position: "top_left",
config: {
accessToken: "12345",
originCoordsLAT: "41.95581649395376",
originCoordsLNG: "-87.87083898397289",
destinationCoords: "41.876602828388485_-87.63840104746535",
firstLine: "{travel_time} mins",
}
},
I really just need to get the "travel_time" data point out and then divide it by 60 to get travel time in minutes.
Any help or guidance would be greatly appreciated!
Thank you, Jim
Considering that the API returns exacly as you showed, you can access the key you want by doing this (the question marks are optional chaining)
self.travel_time = json.results?.[0]?.locations?.[0]?.properties?.[0]?.travel_time;