• Recent
  • Tags
  • Unsolved
  • Solved
  • MagicMirror² Repository
  • Documentation
  • 3rd-Party-Modules
  • Donate
  • Discord
  • Register
  • Login
MagicMirror Forum
  • Recent
  • Tags
  • Unsolved
  • Solved
  • MagicMirror² Repository
  • Documentation
  • 3rd-Party-Modules
  • Donate
  • Discord
  • Register
  • Login
A New Chapter for MagicMirror: The Community Takes the Lead
Read the statement by Michael Teeuw here.

Head first developing MM module for extreme beginners

Scheduled Pinned Locked Moved Development
27 Posts 9 Posters 19.2k Views 12 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ? Offline
    A Former User
    last edited by Aug 7, 2018, 12:01 PM

    Head first developing MM module for extreme beginners

    Today morning, I’ve got two messages from two members of this forum at the same time. Both of two asked me the same thing - “How can I show my contents on MM with my module?”
    So, here is a simple guide for developing MM module. This is not a royal road or perfect answer, but I hope this could be a help

    This article is not about using git or any other deeper knowledge. I assume you are familiar with javascript(nodeJS) at least.

    Make a workspace

    cd ~/MagicMirror/modules
    mkdir MMM-Test
    cd MMM-Test
    touch MMM-Test.js  
    

    MMM-Test.js is your main module script. It will be called by MM core at running.

    Let’s make something.

    configuration

    First, add your module into MM framework. open ~/MagicMirror/config/config.js and add your module.

    modules: [
     {
      module: "MMM-Test",
      position: "top_left",
      config: {}
     },
    ]
    

    For simple things, remove all other modules except your MMM-Test.

    MMM-Test.js

    open MMM-Test.js and edit.

    nano MMM-Test.js
    

    In that, copy this and paste into MMM-Test.js.

    Module.register("MMM-Timetable", {
      defaults: {},
      start: function () {},
      getDom: function() {},
      notificationReceived: function() {},
      socketNotificationReceived: function() {},
    })
    
    

    There are many other things to study but currently, we will focus on these 5 things.

    getDom()

    This function will render your content on MM screen.
    Let’s do something.

    getDom: function() {
      var element = document.createElement("div")
      element.className = "myContent"
      element.innerHTML = "Hello, World!"
      return element
    },
    

    <div> element is created and returned to MM for rendering.
    When MM needs your module’s output being refreshed, this function will be called by MM core.
    See how it works.

    cd ~/MagicMirror
    npm start dev
    

    0_1533642942933_guide_1.png

    defaults:{}

    You can use default configuration values. Let’s do it

    defaults: {
      foo: "I'm alive!"
    },
    getDom: function() {
      var element = document.createElement("div")
      element.className = "myContent"
      element.innerHTML = "Hello, World! " + this.config.foo
      return element
    },
    

    your configuration value foo could be used like this.config.foo.
    this in this module, it directs module itself. you can access various module values with it.
    See how it works.

    0_1533642980707_guide_2.png

    And you can customize configuration values with config.js
    set your config.js like this;

    {
      module: "MMM-Test",
      position: "top_left",
      config: {
        foo: "I'm the King of the world!"
      }
    },
    

    The result will be like this;
    0_1533643071611_guide_3.png

    start() & updateDom()

    This function will be executed when your module is loaded successfully.
    Let’s change something.

    start: function (){
      this.count = 0
      var timer = setInterval(()=>{
        this.updateDom()
        this.count++
      }, 1000)
    },
    
    getDom: function() {
      var element = document.createElement("div")
      element.className = "myContent"
      element.innerHTML = "Hello, World! " + this.config.foo
      var subElement = document.createElement("p")
      subElement.innerHTML = "Count:" + this.count
      subElement.id = "COUNT"
      element.appendChild(subElement)
      return element
    },
    

    0_1533643168301_guide_4.png

    After your module is loaded, your module’s output will be updated per every 1 second.
    Whenever you want to update your output, you can call .updateDom() to let MM also call your .getDom() to redraw the output. (Don’t try to call getDom() directly by yourself. It will not work as your expectation. Rendering is delegated to the MM core.)

    By the way, start() is not a good place to control drawing, because start() is called before your DOM objects are first rendered. Above code is somewhat bad behavior.

    notificationReceived()

    MM and modules are communicating each other with notification. Your module can receive notification and send it also.

    start: function (){
      this.count = 0
    },
    
    getDom: function() {
      var element = document.createElement("div")
      element.className = "myContent"
      element.innerHTML = "Hello, World! " + this.config.foo
      var subElement = document.createElement("p")
      subElement.innerHTML = "Count:" + this.count
      subElement.id = "COUNT"
      element.appendChild(subElement)
      return element
    },
    
    notificationReceived: function(notification, payload, sender) {
      switch(notification) {
        case "DOM_OBJECTS_CREATED":
          var timer = setInterval(()=>{
            this.updateDom()
            this.count++
          }, 1000)
          break
      }
    },
    

    The result looks so same with previous codes. But your timer will be started after when “DOM_OBJECTS_CREATED” notification is received but not when the module is loaded.
    DOM_OBJECTS_CREATED notification is emitted when all of modules are loaded and rendered(with getDom()) first time. At the moment, you can manipulate your output in your module.

    Another way to control output

    Once your DOM is ready(after first calling getDom() and DOM_OBJECTS_CREATED notification is emitted), you can access your DOM with script.

    notificationReceived: function(notification, payload, sender) {
      switch(notification) {
        case "DOM_OBJECTS_CREATED":
          var timer = setInterval(()=>{
            //this.updateDom()
            var countElm = document.getElementById("COUNT")
            countElm.innerHTML = "Count:" + this.count
            this.count++
          }, 1000)
          break
      }
    },
    

    Instead updateDom(), direct access to DOM is used.

    node_helper.js

    But your MMM-Test.js has some limitation. Because it is run on MM framework and Browser(Electron/Chromium or Midori)
    When you need more than what browser can provide, you should use node_helper.js
    By example, your MMM-Test.js cannot read or write local files by usual way (Of course, there is a hack, but that is not the point at this moment.).
    But your node_helper.js can. Or when you need to use other various node modules, node_helper.js exists for that purpose.

    Let’s make node_helper.js

    nano node_helper.js
    

    Copy this code and paste.

    var NodeHelper = require("node_helper")
    
    module.exports = NodeHelper.create({
      start: function() {},
      socketNotificationReceived: function() {},
    })
    

    This is a default template of node_helper.js. Now add some codes.

    var NodeHelper = require("node_helper")
    
    module.exports = NodeHelper.create({
      start: function() {
        this.countDown = 10000000
      },
      socketNotificationReceived: function(notification, payload) {
        switch(notification) {
          case "DO_YOUR_JOB":
            this.sendSocketNotification("I_DID", (this.countDown - payload))
            break
        }
      },
    })
    

    Like MMM-Test.js, start() will be executed when node_helper.js is loaded and connected to your module.
    Between MMM-Test.js and node_helper.js, socketNotification is used for communication. (similar with notification)
    You can get socketNotification with socketNotificationReceived() and can send it by sendSocketNotification().

    Then, you should modify MMM-Test.js

    getDom: function() {
      var element = document.createElement("div")
      element.className = "myContent"
      element.innerHTML = "Hello, World! " + this.config.foo
      var subElement = document.createElement("p")
      subElement.id = "COUNT"
      element.appendChild(subElement)
      return element
    },
    
    notificationReceived: function(notification, payload, sender) {
      switch(notification) {
        case "DOM_OBJECTS_CREATED":
          var timer = setInterval(()=>{
            this.sendSocketNotification("DO_YOUR_JOB", this.count)
            this.count++
          }, 1000)
          break
      }
    },
    
    socketNotificationReceived: function(notification, payload) {
      switch(notification) {
        case "I_DID":
          var elem = document.getElementById("COUNT")
          elem.innerHTML = "Count:" + payload
          break
      }
    },
    

    Result will be like this;

    0_1533643217699_guide_5.png

    Now you made your MMM-Test.js to work with node_helper.js
    Of course, this is not so good example to show what node_helper.js can do.
    But I believe you can understand how node_helper.js and MMM-Test.js work with each other.

    Well. You’ve learned 90% of how to develop MM module. the remains are described in https://github.com/MichMich/MagicMirror/blob/master/modules/README.md
    Good luck to you.

    1 Reply Last reply Reply Quote 7
    • ? Offline
      A Former User
      last edited by Jul 25, 2019, 3:17 PM

      I cant get the text to appear when I run it, I made the Test.js file in the MagicMirror modules folder and copied in what was posted and put the config in the config.js file but when I run it the screens all black, here’s what happens when I try to run it

      pi@raspberrypi:~/MagicMirror/modules $ cd ~/MagicMirror
      pi@raspberrypi:~/MagicMirror $ npm start dev

      magicmirror@2.8.0 start /home/pi/MagicMirror
      sh run-start.sh “dev”

      Starting MagicMirror: v2.8.0
      Loading config …
      Loading module helpers …
      No helper found for module: MMM-Test.
      All module helpers loaded.
      Starting server on port 8080 …
      Server started …
      Sockets connected & modules started …
      Launching application.
      Shutting down server…
      pi@raspberrypi:~/MagicMirror $

      any help would be greatly appreciated I dont see what I’m missing

      1 Reply Last reply Reply Quote 0
      • S Offline
        StuGrunt
        last edited by Apr 15, 2020, 2:02 AM

        It is because there is an error (at least I think so - I am new too) and no instructions on where to put the function.

        1. change the Module.register(“MMM-Timetable”) to Module.register(“MMM-Test”)

        2. The article does not tell you where to put the getDom function when it is first introduced. Replace the getDom: function() {}. with the code shown. In other words, don’t just add it to the file. This article would have benefited from a final section that gave the entire code.

        I think the original author at least expected us to be very familiar with Node.js (fair enough), but alas, I am not so it took a bit of work to figure it out. :-)

        Here it is, for the first part:

        Module.register(“MMM-Test”, {
        defaults: {},
        start: function () {},

        getDom: function() {
        var element = document.createElement(“div”)
        element.className = “myContent”
        element.innerHTML = “Hello, World!”
        return element
        },
        notificationReceived: function() {},
        socketNotificationReceived: function() {},
        })
        _

        cowboysdudeC 1 Reply Last reply Jan 20, 2021, 1:53 PM Reply Quote 0
        • N Offline
          nrayever
          last edited by Jan 17, 2021, 6:46 PM

          Shame, code is really messed up. Not helpful to use it as a guide to start developing modules.

          S 1 Reply Last reply Jan 17, 2021, 6:59 PM Reply Quote 0
          • S Offline
            sdetweil @nrayever
            last edited by Jan 17, 2021, 6:59 PM

            @nrayever see my sample module,
            https://github.com/sdetweil/SampleModule

            and follow the module developers doc

            Sam

            How to add modules

            learning how to use browser developers window for css changes

            N 1 Reply Last reply Jan 18, 2021, 9:41 PM Reply Quote 2
            • N Offline
              nrayever @sdetweil
              last edited by nrayever Jan 18, 2021, 9:42 PM Jan 18, 2021, 9:41 PM

              @sdetweil will try it. I don’t have JS experience that is why I have found it difficult to start.

              S 1 Reply Last reply Jan 18, 2021, 11:35 PM Reply Quote 0
              • S Offline
                sdetweil @nrayever
                last edited by sdetweil Jan 18, 2021, 11:35 PM Jan 18, 2021, 11:35 PM

                @nrayever sorry cant help develop module if u dont know programming and dont want to learn

                Sam

                How to add modules

                learning how to use browser developers window for css changes

                N 1 Reply Last reply Feb 4, 2021, 5:27 PM Reply Quote 1
                • cowboysdudeC Offline
                  cowboysdude Module Developer @StuGrunt
                  last edited by Jan 20, 2021, 1:53 PM

                  @StuGrunt said in Head first developing MM module for extreme beginners:

                  It is because there is an error (at least I think so - I am new too) and no instructions on where to put the function.

                  1. change the Module.register(“MMM-Timetable”) to Module.register(“MMM-Test”)

                  2. The article does not tell you where to put the getDom function when it is first introduced. Replace the getDom: function() {}. with the code shown. In other words, don’t just add it to the file. This article would have benefited from a final section that gave the entire code.

                  I think the original author at least expected us to be very familiar with Node.js (fair enough), but alas, I am not so it took a bit of work to figure it out. :-)

                  Here it is, for the first part:

                  Module.register(“MMM-Test”, {
                  defaults: {},
                  start: function () {},

                  getDom: function() {
                  var element = document.createElement(“div”)
                  element.className = “myContent”
                  element.innerHTML = “Hello, World!”
                  return element
                  },
                  notificationReceived: function() {},
                  socketNotificationReceived: function() {},
                  })
                  _

                  Both of those functions go outside the getDom function pretty much anywhere you want to put them.

                  The socketNotificationReceived function [example below, can be used in either node_helper OR your main.js file. The example below is in my node_helper] :

                  socketNotificationReceived: function(notification, payload) {
                  		if (notification === 'CONFIG') {
                              this.config = payload; 
                          }
                          if (notification === 'GET_CURRENT') {
                              this.getCurrent(payload);
                          }
                          if (notification === 'GET_FORECAST') {
                              if (this.forecast.timestamp === this.getDate() && this.forecast.data !== null) {
                                  this.sendSocketNotification('FORECAST_RESULT', this.forecast.data); 
                                  console.log("Using data we already have");
                              } else { 
                                  this.getForecast();
                  				console.log("Getting new data");
                              }
                          }
                  		
                      }
                  

                  Here is the corresponding one in the main.js

                  socketNotificationReceived: function(notification, payload) {
                          if (notification === "CURRENT_RESULT") {
                              this.processCurrent(payload);
                          }
                          if (notification === "FORECAST_RESULT") {
                              this.processForecasts(payload);
                          }
                  		this.updateDom(this.config.initialLoadDelay);
                      },
                  

                  You can use notificationReceived to receive info from other modules like this:

                  Here are examples of that:

                  notificationReceived: function (notification, payload){ 
                          if (notification === 'CURRENT_RESULT') {
                  			this.processCurrent(payload); 
                          }
                  	},
                  
                  this.sendNotification('CURRENT_RESULT', payload);
                  

                  This is how I send and receive my ‘payload’ from one module to another.
                  The first example is getting my ‘CURRENT_RESULT’ [getting info for a Forecast module from the Current weather module] from the bottom example that is
                  sending out ‘CURRENT_RESULT’…

                  The bottom example will ‘broadcast’ and in reality ANY module can get the data it’s sending out.

                  Hope this helps. It’s a really simple process.

                  1 Reply Last reply Reply Quote 1
                  • S Offline
                    Schmaniel
                    last edited by Schmaniel Jan 21, 2021, 3:10 PM Jan 21, 2021, 2:31 PM

                    How can I test the getDom() html output?
                    I don’t want to restart MM every time when I change something just to look if it worked.

                    S 1 Reply Last reply Jan 21, 2021, 3:12 PM Reply Quote 0
                    • S Offline
                      sdetweil @Schmaniel
                      last edited by Jan 21, 2021, 3:12 PM

                      @Schmaniel ctrl-r to reload the screen

                      Sam

                      How to add modules

                      learning how to use browser developers window for css changes

                      1 Reply Last reply Reply Quote 2
                      • 1
                      • 2
                      • 3
                      • 1 / 3
                      • First post
                        Last post
                      Enjoying MagicMirror? Please consider a donation!
                      MagicMirror created by Michael Teeuw.
                      Forum managed by Sam, technical setup by Karsten.
                      This forum is using NodeBB as its core | Contributors
                      Contact | Privacy Policy