MagicMirror Forum
    • Recent
    • Tags
    • Unsolved
    • Solved
    • MagicMirror² Repository
    • Documentation
    • 3rd-Party-Modules
    • Donate
    • Discord
    • Register
    • Login
    1. Home
    2. doubleT
    3. Posts
    A New Chapter for MagicMirror: The Community Takes the Lead
    Read the statement by Michael Teeuw here.
    D
    Offline
    • Profile
    • Following 0
    • Followers 4
    • Topics 4
    • Posts 176
    • Groups 1

    Posts

    Recent Best Controversial
    • RE: Currated Art

      I’m sure there’s an API for Arts&Culture. Everything on Google has an API. And it’s in the Cloud. There’s API documentation for the previous version, Google’s “Project Art” / “OpenGallery”.

      Edit: https://developers.google.com/opengallery/ => 404 :(
      https://opengallery.culturalspot.org/home
      Everything seems reachable … :/

      posted in Requests
      D
      doubleT
    • RE: Currated Art

      First thing that came to my mind:
      “Every piece of art you’ve ever wanted to see – up close and searchable” by Amit Sood at TED, https://www.youtube.com/watch?v=CjB6DQGalU0
      (if you don’t watch the full 15 min, check 4:00 min)

      https://artsandculture.google.com/

      In a quick search, I couldn’t find any current information on whether there is an API, but I’d guess so.

      posted in Requests
      D
      doubleT
    • RE: MMM-CountEvents

      More is always good! Nice module, I like that you can count the time since past events.

      posted in Utilities
      D
      doubleT
    • RE: Help with converting this HTML file to MM2 module format...

      I’d put them in a different structure, perhaps, depending on what you want to achieve.

      If it’s just this list that you want: Remove all line breaks and tabs, lead all quotation marks with a backslash (\") and put that complete one line of code in:

      targetElement.innerHTML = "your Code here";
      

      More flexible:


      var newsSources = [
      {
      “id”:“washington_post”,
      “name”:“Washington Post”,
      “alt”:“Washington Post”,
      “link”:“https://www.washingtonpost.com/?reload=true”
      },
      {
      “id”:“usa_today”,
      “name”:“USA Today”,
      “alt”:“USA Today”,
      “link”:“http://rssfeeds.usatoday.com/UsatodaycomNation-TopStories”
      },
      {
      “id”:“irish_news”,
      “name”:“Irish News”,
      “alt”:“Irish News”,
      “link”:“http://www.irishnews.com/news/worldnews/”
      },
      {
      “id”:“wall_street_journal”,
      “name”:“Wall St. Journal”,
      “alt”:“Wall St. Journal”,
      “link”:“https://www.wsj.com/news/us”
      },
      {
      “id”:“kansas_city_star”,
      “name”:“The Kansas City Star”,
      “alt”:“Kansas City, MO News”,
      “link”:“https://www.kansascity.com/news/”
      },
      {
      “id”:“bbc_news”,
      “name”:“BBC World News”,
      “alt”:“BBC World News”,
      “link”:“https://www.bbc.com/news/world”
      }
      ];
      newMainElement = document.createElement(“div”);
      newMainHeadline = document.createElement(“h2”);
      newMainHeadline.innerHTML = “< img src="pix/break_news.png" alt="Breaking News" />”;
      newMainElement.apply(newMainHeadline);
      frstWrapper = document.createElement(“div”);
      scndWrapper = document.createElement(“div”); // really neccessary?
      thrdWrapper = document.createElement(“div”); // really neccessary?
      newsList = document.createElement(“ul”);
      for (i=0; i< =newsSources.length; i++) {
      newsItem = document.createElement(“li”);
      newsLogo = document.createElement(“div”);
      newsLogo.innerHTML = “< img src="pix"+newsSources[i].id+”.png" alt="“+newsSources[i].alt+”" />"
      newsLink = document.createElement(“h3”);
      newsLink.innerHTML = “< a href="”+newsSources[i].link+“" target="myIframe">”+newsSources[i].name+“”;
      newsItem.apply(newsLogo);
      newsItem.apply(newsLink);
      newsList.apply(newsItem);
      }
      thrdWrapper.apply(newsList); // really neccessary? see above
      scndWrapper.apply(thrdWrapper); // really neccessary? see above
      frstWrapper.apply(scndWrapper);
      newMainElement.apply(frstWrapper);


      I didn’t use the code block because it can’t handle \".
      In < img and < a you have to remove the space.
      id = image name, you’ll have to adapt a little, I wrote them in a more uniform style.
      alt = could be the same as the name, but I put it in as you varied a little with your alt titles.


      Oh, by the way:
      Seems like this could also be a good case for a template system.
      https://forum.magicmirror.builders/topic/2443/html-templating-system
      https://forum.magicmirror.builders/topic/5053/better-way-to-use-html-in-module-development

      posted in Development
      D
      doubleT
    • RE: Real Time ECG

      For anything involving a graph drawn from JS(ON) data, I can only recommend highcharts.

      It’s possible to display dynamic graphs from live data. Example: https://www.highcharts.com/stock/demo/dynamic-update/
      https://www.highcharts.com/docs/working-with-data/live-data

      Your python code could provide a JSON and the MM-module calls the JSON and prints the graph.

      I’ve used highcharts before but never dynamically like in the example above.
      Here’s an example where I used it in a module: https://github.com/TTigges/MMM-Oiltank/blob/master/MMM-Oiltank.js

      posted in Development
      D
      doubleT
    • RE: Multiples of same module?

      If you want a quick and dirty solution, copy the module folder, rename the copy and then change the module’s name to match the new module/folder name in all occurances (file names and within the code).

      posted in Troubleshooting
      D
      doubleT
    • RE: countdown module for repeating aniversary

      As you said, MMM-doomsDay isn’t really the module you’re looking for. I wrote a possible solution as an answer to your question in the other thread. But the downside is, it’d only be possible for one event as that module can’t even list several events (at least that’s what I saw from a short look at the code).

      So in your case I’d take MMM-doomsDay and built your own module from that with the code changes I posted in the other thread.

      posted in Productivity
      D
      doubleT
    • RE: MMM-doomsDay - The countdown module,

      @zdenek Even though I think it’s possible with a few changes to the code, I don’t think this would fit the scope of this module, which is to manually set a countdown to one specific event (noteven a few, right?) but not for a whole list of calendar dates.

      Even if the code ignores the year and just always shows the next event, does it make sense to have it display “364 days left” right the next day?

      Anyway, if you want to do that, I’d suggest adding:

          doomsDay: "2018-12-24 24:00:00",
          yearlyEvent: true,
          toWhat: "X-Mass"
      

      The most simple simple change to the code would be to add this at line 48:

      if (this.config.yearlyEvent && daysLeft < = 0) {
          var diff = now.getFullYear() - doomsday.getFullYear();
          // update doomsday:
          doomsDay.setFullYear(d.getFullYear() + diff);
          // calculate again:
          timeparser = Date.parse(doomsDay) - Date.parse(now);
          daysLeft = Math.floor(timeparser/(1000*60*60*24));
      }
      

      (remove the space between “< =” … )
      I didn’t test this, though, (and I don’t recommend it).

      posted in Utilities
      D
      doubleT
    • RE: help developing an outofmilk.com module

      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

      posted in Development
      D
      doubleT
    • RE: How to develop modules

      I’d second that.

      For a quick overview:

      The DOM (all visible elements) is based on HTML, styled with CSS and usually filled with content and function by Java Script. That’s all you need for basic modules.

      If you go further, you’ll need Python in case you have something connected to the Pi andnodeJS for advanced modules with some backend code, like API calls, though some nodeJS knowledge will help you a lot to understand the whole structure in the first place.

      jQuery can be a helpful Java Script library.
      API calls usually deliver JSON or – rarely – XML, but both should be familiar if you know JS objects and arrays and HTML.

      As Sean said, playing around and manipulating existing modules should help you a lot. Go through the code, see if you understand the connections and find out what happens if you manipulate it.

      Your most important tool when working in js-files is the browser console where you can print to with the js code console.log("show me the content of var x: " + x); MM code Log.info("show me the content of var x: " + x);

      posted in General Discussion
      D
      doubleT
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 17
    • 18
    • 4 / 18