Uh, interesting topic. I like API calls. :D Back when I started, my main issue was understanding the node_helper.js – and that it was neccessary.
I’m still struggling to make sense of your token complexity. Apart from that, your files would be something like this:
MMM-OutOfMilk.js:
Module.register("MMM-OutOfMilk",{
defaults: {
// your defaults
},
start: function() {
var payload = "start"; // example
this.sendSocketNotification("GetMyShoppingList", payload);
},
socketNotificationReceived: function(notification, shoppingList) {
if (notification === "ShoppingListRecieved") {
this.handeShoppingList(shoppingList);
}
},
handleShoppingList: function(shoppingList) {
// do something with your shopping list
}
}
node_helper.js:
var NodeHelper = require("node_helper");
var request = require("request"); // needed? see below
var fs = require("fs"); // needed? see below
var timer = 0; // needed? see below "I added a timer"
var token;
module.exports = NodeHelper.create({
start: function() {
},
socketNotificationReceived: function(notification, payload) {
if (notification === "GetMyShoppingList") {
// start the logic to recieve the shopping list
// get token?
// make call
this.getShoppingList(payload);
}
},
getToken: function(payload) {
// however you get your token
getShoppingList(payload);
},
getShoppingList: function(payload) {
var self = this;
var source = ; // your source URL
if (token) {
request({
url: source,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
self.sendSocketNotification("ShoppingListRecieved", body);
}
else {
// check error if it's a token issue
// if so, get new token
self.getToken(payload);
}
})
}
}
}
From another project I know that sometimes a token can be used for a while. In that case I’d directly call the getShoppingList and only on an error that read “wrong token” or something like that, I’d call getToken which saves the token to a global variable and calls back getShoppingList to try again. That way you don’t have to get a new token for every call.
Alternatively?
getShoppingList: function(token) {
var self = this;
var source = ; // your source URL
var rawdata = fs.readFileSync(source);
var history = JSON.parse(rawdata);
self.sendSocketNotification("ShoppingListRecieved", history);
}
I’d also use a timer to request data on the first call and after that automatically only every full hour:
So, in the node_helper.js, in the socketNotificationReceived I don’t forward the payload to this.updateTimer(payload) instead of getToken or getShoppingList to do this:
updateTimer: function(payload) {
var self = this;
var d = new Date();
var h = d.getHours();
var min = d.getMinutes();
var sec = d.getSeconds();
if (timer === 0) {
timer ++; // prevent unnecessary timer by double calls
this.getShoppingList(payload);
if((min == '00') && (sec == '00')){
// console.log(h + ":" + min + ":" + sec + " - update and wait 1 hour");
// console.log("restart timer");
setTimeout(() => {
this.clearTimer(payload);
}, 60*1000*60); // 60 sec * 1000 ms = 1 min * 60 = 1 hour
} else {
// console.log(h + ":" + min + ":" + sec + " - update waits for " + (59-min) + " min and " + (60-sec) + "sec");
// console.log("restart timer");
setTimeout(() => {
this.clearTimer(payload);
}, ((60-sec)*1000)+(60*1000*(59-min)));
}
}
else {
// console.log("timer already running, data displayed outside of timer run");
this.getShoppingList(payload);
}
},
clearTimer: function(payload) {
timer --;
this.updateTimer(payload);
}
For one of my modules I couldn’t use fs.readFile... or request because of CORS issues. In that case I had to use a php proxy.
I’d strongly suggest trying to solve this with fs.readFile... or request but just for the sake of completeness and maybe to help you understand:
In order to use PHP within nodeJS via Child Process Dependency you have to have PHP installed and in your PATH!
You can read how I used it, here: https://forum.magicmirror.builders/topic/5830/call-api-no-cors-used-to-do-it-with-php-proxy/9