<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[help developing an outofmilk.com module]]></title><description><![CDATA[<p dir="auto">Hi,<br />
I´m planning on migrating a windows based home-control-screen to magicmirror and so far i have found all the modules i need, except for a module for the website out of milk.</p>
<p dir="auto">Since my old solution already has the info on how to get the data from the website, i dont think i would be a big problem.</p>
<p dir="auto">The procedure right now is to call the mainsite <a href="https://outofmilk.com/" target="_blank" rel="noopener noreferrer nofollow ugc">https://outofmilk.com/</a> to get a session, and then call the /loginsite with post data containing credentials.<br />
This request returns a logincookie that you can use to get a shoppinglist from the api.</p>
<p dir="auto">im mostly a devops guy using powershell and other basic scripting languages, which makes the whole framework a big bite to take in at once.</p>
<p dir="auto">Do you have any good pointers of modules i can look into that uses the same way of getting data?</p>
<p dir="auto">i can code i already have in powershell if anyone is interrested.</p>
]]></description><link>https://forum.magicmirror.builders/topic/8462/help-developing-an-outofmilk-com-module</link><generator>RSS for Node</generator><lastBuildDate>Fri, 12 Jun 2026 20:31:17 GMT</lastBuildDate><atom:link href="https://forum.magicmirror.builders/topic/8462.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 25 Jul 2018 11:54:45 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to help developing an outofmilk.com module on Tue, 07 Aug 2018 15:35:06 GMT]]></title><description><![CDATA[<p dir="auto">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.<br />
I’m still struggling to make sense of your token complexity. Apart from that, your files would be something like this:</p>
<p dir="auto"><strong>MMM-OutOfMilk.js:</strong></p>
<pre><code>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
    }
}
</code></pre>
<p dir="auto"><strong>node_helper.js:</strong></p>
<pre><code>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 &amp;&amp; response.statusCode === 200) {
	                self.sendSocketNotification("ShoppingListRecieved", body);
	            }
	            else {
	            	// check error if it's a token issue
	            	// if so, get new token
	            	self.getToken(payload);
	            }
	        })
        }    
    }
}
</code></pre>
<p dir="auto">From another project I know that sometimes a token can be used for a while. In that case I’d directly call the <code>getShoppingList</code> and only on an error that read “wrong token” or something like that, I’d call <code>getToken</code> which saves the token to a global variable and calls back <code>getShoppingList</code> to try again. That way you don’t have to get a new token for every call.</p>
<p dir="auto"><strong>Alternatively?</strong></p>
<pre><code>    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);
    }
</code></pre>
<p dir="auto">I’d also use a timer to request data on the first call and after that automatically only every full hour:<br />
So, in the <code>node_helper.js</code>, in the <code>socketNotificationReceived</code> I don’t forward the payload to <code>this.updateTimer(payload)</code> instead of getToken or getShoppingList to do this:</p>
<pre><code>    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') &amp;&amp; (sec == '00')){
//              console.log(h + ":" + min + ":" + sec + " - update and wait 1 hour");
//              console.log("restart timer");
                setTimeout(() =&gt; {
                    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(() =&gt; {
                    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);
    }
</code></pre>
<p dir="auto">For one of my modules I couldn’t use <code>fs.readFile...</code> or <code>request</code> because of CORS issues. In that case I had to use a php proxy.<br />
I’d strongly suggest trying to solve this with <code>fs.readFile...</code> or <code>request</code> but just for the sake of completeness and maybe to help you understand:</p>
<p dir="auto">In order to use PHP within nodeJS via Child Process Dependency you have to have PHP installed and in your PATH!<br />
You can read how I used it, here: <a href="https://forum.magicmirror.builders/topic/5830/call-api-no-cors-used-to-do-it-with-php-proxy/9">https://forum.magicmirror.builders/topic/5830/call-api-no-cors-used-to-do-it-with-php-proxy/9</a></p>
]]></description><link>https://forum.magicmirror.builders/post/43191</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/43191</guid><dc:creator><![CDATA[doubleT]]></dc:creator><pubDate>Tue, 07 Aug 2018 15:35:06 GMT</pubDate></item><item><title><![CDATA[Reply to help developing an outofmilk.com module on Thu, 26 Jul 2018 21:12:29 GMT]]></title><description><![CDATA[<p dir="auto">okay, i see - i have been reading up on the http and request modules now.</p>
<p dir="auto">it should be possible for me to figure out how to get it to output the data directly in the console, and then i can tackle the presentation part of the module later.</p>
<p dir="auto">i have been looking at a lot of sourcecode for other mm modules and i cant seem to find any other projects that handle multiple requests like this directly, am i mistaken?</p>
]]></description><link>https://forum.magicmirror.builders/post/42691</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/42691</guid><dc:creator><![CDATA[mchrdk]]></dc:creator><pubDate>Thu, 26 Jul 2018 21:12:29 GMT</pubDate></item><item><title><![CDATA[Reply to help developing an outofmilk.com module on Thu, 26 Jul 2018 20:30:59 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/mchrdk" aria-label="Profile: mchrdk">@<bdi>mchrdk</bdi></a> or you can handle request and response with ’express’ and ’http’ or ’request’ node modules.</p>
]]></description><link>https://forum.magicmirror.builders/post/42689</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/42689</guid><dc:creator><![CDATA[[[global:former-user]]]]></dc:creator><pubDate>Thu, 26 Jul 2018 20:30:59 GMT</pubDate></item><item><title><![CDATA[Reply to help developing an outofmilk.com module on Thu, 26 Jul 2018 20:24:04 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/mchrdk" aria-label="Profile: mchrdk">@<bdi>mchrdk</bdi></a> I didn’t look inside deeply, but how about using ”curl”?</p>
]]></description><link>https://forum.magicmirror.builders/post/42688</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/42688</guid><dc:creator><![CDATA[[[global:former-user]]]]></dc:creator><pubDate>Thu, 26 Jul 2018 20:24:04 GMT</pubDate></item><item><title><![CDATA[Reply to help developing an outofmilk.com module on Thu, 26 Jul 2018 19:02:21 GMT]]></title><description><![CDATA[<p dir="auto">#quick mockup in the entirely wrong language :)</p>
<p dir="auto">$csrftoken = (($firstrequest.InputFields|where {$_.name -eq “csrfmiddlewaretoken”}).value)[0]<br />
$username = “insertemailhere”<br />
$password = “insertpasswordhere”<br />
$listid = “find listhere”<br />
$body = “csrfmiddlewaretoken=$csrftoken&amp;login-email=$username&amp;login-password=$password&amp;btnLogin=Submit”<br />
$headers = @{“Cookie”=“csrftoken=$csrftoken”; “Origin”=“<a href="https://www.outofmilk.com" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.outofmilk.com</a>”; “Accept”=“application/json, text/javascript, <em>/</em>; q=0.01”; “Referer”=“<a href="https://www.outofmilk.com/ShoppingList.aspx?signin=1" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.outofmilk.com/ShoppingList.aspx?signin=1</a>”; “X-CSRFToken”=“$csrftoken”; “X-Requested-With”=“XMLHttpRequest”; “DNT”=“1”}<br />
$secondrequest = Invoke-WebRequest -WebSession $Session -Uri “<a href="https://www.outofmilk.com/Login" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.outofmilk.com/Login</a>” -Method “POST” -Headers $headers -ContentType “application/x-www-form-urlencoded” -Body $Body<br />
$body = “{<code>"listID</code>”:$listid,<code>"listType</code>":<code>"shopping</code>"}"<br />
$thirdrequest = Invoke-WebRequest -WebSession $Session -Uri “<a href="https://www.outofmilk.com/Services/GenericService.asmx/GetItems" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.outofmilk.com/Services/GenericService.asmx/GetItems</a>” -Method “POST” -Headers $headers -ContentType “application/json; charset=UTF-8” -Body $body</p>
]]></description><link>https://forum.magicmirror.builders/post/42685</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/42685</guid><dc:creator><![CDATA[mchrdk]]></dc:creator><pubDate>Thu, 26 Jul 2018 19:02:21 GMT</pubDate></item><item><title><![CDATA[Reply to help developing an outofmilk.com module on Thu, 26 Jul 2018 18:58:43 GMT]]></title><description><![CDATA[<p dir="auto">I have all of that done already, im using the data in another application, done in powershell, i just need a bit of beginners guidance on how to get a magic mirror module to access the data, as i have never done anything in js before.</p>
]]></description><link>https://forum.magicmirror.builders/post/42684</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/42684</guid><dc:creator><![CDATA[mchrdk]]></dc:creator><pubDate>Thu, 26 Jul 2018 18:58:43 GMT</pubDate></item><item><title><![CDATA[Reply to help developing an outofmilk.com module on Thu, 26 Jul 2018 14:32:17 GMT]]></title><description><![CDATA[<p dir="auto">Reverse engineer ;)<br />
Looks like they have data exposed via APIs. See screenshot from chrome-&gt;devtools-&gt;network log<br />
You just need to login and set the cookie and make the API calls.<br />
<img src="/assets/uploads/files/1532615531128-screen-shot-2018-07-26-at-10.28.39-am-resized.png" alt="0_1532615531053_Screen Shot 2018-07-26 at 10.28.39 AM.png" class=" img-fluid img-markdown" /></p>
]]></description><link>https://forum.magicmirror.builders/post/42671</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/42671</guid><dc:creator><![CDATA[gauravsacc]]></dc:creator><pubDate>Thu, 26 Jul 2018 14:32:17 GMT</pubDate></item></channel></rss>