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.

    DIY Module Displays Nothing

    Scheduled Pinned Locked Moved Solved Troubleshooting
    14 Posts 3 Posters 1.2k Views 2 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.
    • H Offline
      hokie-bird
      last edited by

      Hi There - I’ve been working on a module to display the “Now Playing” info (song, artist, cover-art, time remaining) from a particular player of my Lyrion Music Server (formerly Logitech Media Sever) to my MM. (With alot of coding help from Google’s Gemini ai, full disclosure) .

      I have a working node_helper.js that retrieves the JSON data and parses it into the desired variables (text for song, artist and time remaining, URL for coverart ) verified via console.log messages. My LyrionNowPlaying.js is accurate communicating with node_helper.js (verified via browser console messages providing correct data for artist, title etc.) but I simply cant get the module to display anything on the actual MM. I’d be super-grateful for any insight anyone could share to help me troubleshoot, as I’m at a loss and even Gemini is giving up…

      Thanks.

      LyrionNowPlaying.js

      /* MagicMirror² Module: MMM-LyrionNowPlaying */
      
      Module.register("MMM-LyrionNowPlaying", {
      
          // Default module config.
          defaults: {
              updateInterval: 1000, // Update interval in milliseconds (default: 1 second)
              retryDelay: 2500,
              lyrionServer: 'http://localhost:9000', // Lyrion server address for JSON-RPC
              playerName: 'livingroom-mm', // Default player name
              showCoverArt: true,
              coverArtSize: 150, // Size of the cover art image
              fadeSpeed: 4000,
          },
      
          getStyles: function () {
              return ["MMM-LyrionNowPlaying.css"];
          },
      
          start: function() {
              Log.info("Starting module: " + this.name);
              this.nowPlaying = {
                  artist: "",
                  song: "",
                  timeRemaining: "",
                  coverArt: "" 
              };
              this.isPlaying = false; // Track playback state
              this.updateDom(this.config.fadeSpeed); 
              this.scheduleUpdate();
          },
      
          getDom: function() {
              const wrapper = document.createElement("div");
              wrapper.classList.add("wrapper"); 
      
              if (this.isPlaying) {
                  if (this.nowPlaying.coverArt && this.config.showCoverArt) {
                      const coverArtImg = document.createElement("img");
                      coverArtImg.src = this.nowPlaying.coverArt;
                      coverArtImg.width = this.config.coverArtSize;
                      coverArtImg.height = this.config.coverArtSize;
                      coverArtImg.classList.add("coverArt");
                      wrapper.appendChild(coverArtImg);
                  }
      
                  const infoContainer = document.createElement("div");
                  infoContainer.classList.add("infoContainer"); 
      
                  if (this.nowPlaying.artist && this.nowPlaying.song) {
                      const songInfo = document.createElement("div");
                      songInfo.classList.add("songInfo");
                      songInfo.innerHTML = 
                          this.nowPlaying.artist + " - " + 
                          this.nowPlaying.song; 
                      infoContainer.appendChild(songInfo);
                  }
      
                  if (this.nowPlaying.timeRemaining) {
                      const timeRemaining = document.createElement("div");
                      timeRemaining.classList.add("timeRemaining");
                      timeRemaining.innerHTML = "Time Remaining: " + this.nowPlaying.timeRemaining;
                      infoContainer.appendChild(timeRemaining);
                  }
      
                  wrapper.appendChild(infoContainer);
              } else {
                  wrapper.innerHTML = "No song is currently playing."; 
              }
      
              return wrapper;
          },
      
          scheduleUpdate: function() {
              setInterval(() => {
                  this.getLyrionNowPlaying();
              }, this.config.updateInterval);
          },
      
          getLyrionNowPlaying: function() {
              this.sendSocketNotification('GET_LYRION_NOW_PLAYING', {
                  lyrionServer: this.config.lyrionServer,
                  playerName: this.config.playerName
              });
          },
      
          socketNotificationReceived: function(notification, payload) {
              if (notification === 'LYRION_NOW_PLAYING_RESULT') {
                  if (payload.error) {
                      Log.error(`MMM-LyrionNowPlaying: ${payload.error}`);
                  } else {
                      this.nowPlaying = payload;
                      console.log("Received data:", this.nowPlaying); 
      
                      // Update playback state
                      this.isPlaying = (this.nowPlaying.artist && this.nowPlaying.song) ? true : false; 
      
                      // Calculate and update timeRemaining 
                      if (this.nowPlaying.duration > 0 && this.nowPlaying.position >= 0) {
                          this.nowPlaying.timeRemaining = this.formatTime(this.nowPlaying.duration - this.nowPlaying.position); 
                      } else {
                          this.nowPlaying.timeRemaining = ""; 
                      }
      
                      this.updateDom(this.config.fadeSpeed); 
                  }
              }
          },
      
          formatTime: function(seconds) {
              const minutes = Math.floor(seconds / 60);
              const remainingSeconds = seconds % 60;
              return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
          }
      });
      
      

      LyrionNowPlaying.css

      .module.MMM-LyrionNowPlaying {
          width: auto; 
          max-width: 300px; 
          background-color: rgba(255, 255, 255, 0.1); 
          border-radius: 5px; 
          padding: 10px; 
          text-align: center;
      }
      
      .coverArt {
          margin-bottom: 10px;
      }
      
      .infoContainer {
          text-align: center; 
      }
      
      .songInfo {
          font-weight: bold; 
      
      

      Relevant config.js (with correct IP and player name masked):

                      {
                              module: 'MMM-LyrionNowPlaying',
                              position: 'bottom_center',
                              config: {
                                      lyrionServer: 'http://xx.xx.xx.xx:9000', // Use port 9000 for JSON-RPC
                                      playerName: 'YYYYYYY,
                                      // Other config options 
                                      }
                      },
      
      
      S C 3 Replies Last reply Reply Quote 0
      • H Offline
        hokie-bird
        last edited by

        It was the fade! when I switch the fade to 0, even the refresh of 1 seconds works and displays perfectly. @sdetweil you are brilliant!

        Thank you!

        1 Reply Last reply Reply Quote 0
        • S Do not disturb
          sdetweil @hokie-bird
          last edited by

          @hokie-bird cant tell directly, open the developers window, ctrl-shift-i. sources tab,

          find your module in the left navigation, select the js code appears in the right pane, click on your getDom 1st line of code line number.

          hit f5 or ctrl-r to refresh the page

          Sam

          How to add modules

          learning how to use browser developers window for css changes

          S 1 Reply Last reply Reply Quote 0
          • S Do not disturb
            sdetweil @hokie-bird
            last edited by sdetweil

            @hokie-bird also you cannot updateDom() in start()

            use the notification ALL_MODULES_STARTED or DOM_OBJECTS_CREATED
            per the doc.
            also sendSocketNotification to node helper should wait til then too

            Sam

            How to add modules

            learning how to use browser developers window for css changes

            1 Reply Last reply Reply Quote 0
            • C Online
              chrisfr1976 @hokie-bird
              last edited by

              @hokie-bird

              Possible Issues:
              In start(), you call this.scheduleUpdate(), which creates an interval. However, scheduleUpdate() sets a new interval each time it is called. If start() runs multiple times (e.g., on module reloads), multiple intervals will be created.
              Fix: Store the interval in this.updateTimer and clear it before setting a new one:

              scheduleUpdate: function() {
                  if (this.updateTimer) clearInterval(this.updateTimer);
                  this.updateTimer = setInterval(() => {
                      this.getLyrionNowPlaying();
                  }, this.config.updateInterval);
              },
              

              this.nowPlaying.duration and this.nowPlaying.position are used, but there’s no check if they are numbers. Ensure they are valid numbers before calculating.

              if (typeof this.nowPlaying.duration === "number" && typeof this.nowPlaying.position === "number" &&
                  this.nowPlaying.duration > 0 && this.nowPlaying.position >= 0) {
                  this.nowPlaying.timeRemaining = this.formatTime(this.nowPlaying.duration - this.nowPlaying.position);
              } else {
                  this.nowPlaying.timeRemaining = "";
              }
              

              And in your css a closing } is missing But maybe copy+paste mistake.

              Regards, Chris.

              S 1 Reply Last reply Reply Quote 0
              • S Do not disturb
                sdetweil @chrisfr1976
                last edited by

                @chrisfr1976 there are no module reloads, one time per page load

                Sam

                How to add modules

                learning how to use browser developers window for css changes

                1 Reply Last reply Reply Quote 0
                • S Do not disturb
                  sdetweil @sdetweil
                  last edited by sdetweil

                  @hokie-bird as chris mentioned you only need to call setInterval once.

                  but to minimize your code change, you can change them to
                  setTimeout

                  in either case, when your module is hidden, you should stop the timer, and restart it when shown again

                  suspend() and resume() functions will advise when those events happen ( MMM-pages would do those on a cycle to test against )

                  Sam

                  How to add modules

                  learning how to use browser developers window for css changes

                  S 1 Reply Last reply Reply Quote 0
                  • S Do not disturb
                    sdetweil @sdetweil
                    last edited by sdetweil

                    @hokie-bird

                    this test
                    this.isPlaying = (this.nowPlaying.artist && this.nowPlaying.song) ? true : false;

                    will always evaluate to true
                    if artist and song are “”, as strings those will evaluate to true

                    null is a non-true value, but also not a string

                    Sam

                    How to add modules

                    learning how to use browser developers window for css changes

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      hokie-bird
                      last edited by

                      Thanks to all for the suggestions. Ive attempted to incorporate them all, which has yeilded a small bit of progress: now 'No song is playing" appears bottom_center at MM startup for a second or 2, then vanishes nothing displaying again regardless of whether music starts, stops, etc. Browser console still reports data being received, and I cant figure how else to use the Developer Tools to troubleshoot. Here’s the latest code:

                      MMM-LyrionNowPlaying.js

                      /* MagicMirror² Module: MMM-LyrionNowPlaying */
                      
                      Module.register("MMM-LyrionNowPlaying", {
                      
                          // Default module config.
                          defaults: {
                              updateInterval: 1000,
                              retryDelay: 2500,
                              lyrionServer: 'http://localhost:9000',
                              playerName: 'livingroom-mm',
                              showCoverArt: true,
                              coverArtSize: 150,
                              fadeSpeed: 4000,
                          },
                      
                          getStyles: function () {
                              return ["MMM-LyrionNowPlaying.css"];
                          },
                      
                          start: function () {
                              Log.info("Starting module: " + this.name);
                              this.nowPlaying = {
                                  artist: "",
                                  song: "",
                                  timeRemaining: "",
                                  coverArt: ""
                              };
                              this.isPlaying = false;
                              this.updateTimer = null; // Initialize updateTimer
                      
                              this.updateDom(0);
                              this.scheduleUpdate();
                          },
                      
                          notificationReceived: function (notification, payload, sender) {
                              if (notification === "ALL_MODULES_STARTED" || notification === "DOM_OBJECTS_CREATED") {
                                  this.sendSocketNotification('GET_LYRION_NOW_PLAYING', {
                                      lyrionServer: this.config.lyrionServer,
                                      playerName: this.config.playerName
                                  });
                              }
                          },
                      
                          getDom: function () {
                              const wrapper = document.createElement("div");
                              wrapper.classList.add("wrapper");
                      
                              if (this.isPlaying) {
                                  if (this.nowPlaying.coverArt && this.config.showCoverArt) {
                                      const coverArtImg = document.createElement("img");
                                      coverArtImg.src = this.nowPlaying.coverArt;
                                      coverArtImg.width = this.config.coverArtSize;
                                      coverArtImg.height = this.config.coverArtSize;
                                      coverArtImg.classList.add("coverArt");
                                      wrapper.appendChild(coverArtImg);
                                  }
                      
                                  const infoContainer = document.createElement("div");
                                  infoContainer.classList.add("infoContainer");
                      
                                  if (this.nowPlaying.artist && this.nowPlaying.song) {
                                      const songInfo = document.createElement("div");
                                      songInfo.classList.add("songInfo");
                                      songInfo.innerHTML =
                                          this.nowPlaying.artist + " - " +
                                          this.nowPlaying.song;
                                      infoContainer.appendChild(songInfo);
                                  }
                      
                                  if (this.nowPlaying.timeRemaining) {
                                      const timeRemaining = document.createElement("div");
                                      timeRemaining.classList.add("timeRemaining");
                                      timeRemaining.innerHTML = "Time Remaining: " + this.nowPlaying.timeRemaining;
                                      infoContainer.appendChild(timeRemaining);
                                  }
                      
                                  wrapper.appendChild(infoContainer);
                              } else {
                                  wrapper.innerHTML = "No song is currently playing.";
                              }
                      
                              console.log("Generated HTML:", wrapper.innerHTML);
                              return wrapper;
                          },
                      
                          scheduleUpdate: function () {
                              if (this.updateTimer) {
                                  clearInterval(this.updateTimer);
                              }
                      
                              this.updateTimer = setInterval(() => {
                                  this.getLyrionNowPlaying();
                              }, this.config.updateInterval);
                          },
                      
                          getLyrionNowPlaying: function () {
                              this.sendSocketNotification('GET_LYRION_NOW_PLAYING', {
                                  lyrionServer: this.config.lyrionServer,
                                  playerName: this.config.playerName
                              });
                          },
                      
                          socketNotificationReceived: function (notification, payload) {
                              if (notification === 'LYRION_NOW_PLAYING_RESULT') {
                                  if (payload.error) {
                                      Log.error(`MMM-LyrionNowPlaying: ${payload.error}`);
                                  } else {
                                      this.nowPlaying = payload;
                                      console.log("Received data:", this.nowPlaying);
                                      console.log("this.nowPlaying after update:", this.nowPlaying);
                      
                                      // Corrected isPlaying check:
                                      this.isPlaying = (this.nowPlaying.artist && this.nowPlaying.artist !== "" && this.nowPlaying.song && this.nowPlaying.song !== "") ? true : false;
                      
                                      const duration = Number(this.nowPlaying.duration);
                                      const position = Number(this.nowPlaying.position);
                      
                                      if (!isNaN(duration) && !isNaN(position) && duration > 0 && position >= 0) {
                                          this.nowPlaying.timeRemaining = this.formatTime(duration - position);
                                      } else {
                                          this.nowPlaying.timeRemaining = "";
                                      }
                      
                                      this.updateDom(this.config.fadeSpeed);
                                  }
                              }
                          },
                      
                          formatTime: function (seconds) {
                              const minutes = Math.floor(seconds / 60);
                              const remainingSeconds = seconds % 60;
                              return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
                          }
                      });
                      
                      

                      Suggestions welcome and again a huge thank you to the community.

                      S 1 Reply Last reply Reply Quote 0
                      • S Do not disturb
                        sdetweil @hokie-bird
                        last edited by

                        @hokie-bird

                        I built it and fixed minor things…
                        created a dummy node_helper and a dummy album art png.

                        so save yours out of the way,(rename the folder)
                        cd ~/MagicMirror/modules
                        git clone https://github.com/sdetweil/MMM-LyrionNowPlaying

                        test
                        copy your node helper over mine

                        be careful on your update frequency asking the node_helper all the time…

                        once per second is probably too fast…
                        i made mine ignore socketNotifications() til a response was sent (after 5 second delay) from the 1st time.
                        the duration is just number that changes…, duration just a fixed number

                        Sam

                        How to add modules

                        learning how to use browser developers window for css changes

                        1 Reply Last reply Reply Quote 0
                        • H Offline
                          hokie-bird
                          last edited by

                          @sdetweil cant thank you enough for taking the time to do that, WOW!

                          Here’s what I’ve learned. I subbed your LyrionNowPlaying.js in for mine, and results were exactly the same: “No song currently playing” at startup for a second or two, vanishes and never returns despite music starting/stopping. Then I subbed your node_helper.js for mine (with your module.js file and .png) and BOOM! your data and image appeared! Granted, it would appear for 4 seconds or so, disappear for 1-2, then re-appear but progress! So, safe to assume its somehow something in my node_helper? Here’s the latest, and again wildly grateful for your help.

                          node_helper.js

                          const NodeHelper = require('node_helper');
                          const request = require('request');
                          
                          module.exports = NodeHelper.create({
                          
                              start: function() {
                                  console.log("Starting node_helper for: " + this.name);
                                  this.nowPlaying = { 
                                      artist: "", 
                                      song: "",
                                      timeRemaining: "",
                                      duration: 0, 
                                      position: 0,
                                      coverArt: "" 
                                  }; 
                                  this.sendSocketNotification('LYRION_NOW_PLAYING_RESULT', this.nowPlaying); // Send initial empty state
                              },
                          
                              socketNotificationReceived: function(notification, payload) {
                                  if (notification === 'GET_LYRION_NOW_PLAYING') {
                                      this.getLyrionNowPlaying(payload);
                                  }
                              },
                          
                              getLyrionNowPlaying: function(payload) {
                                  const { lyrionServer, playerName } = payload;
                                  const options = {
                                      url: `${lyrionServer}/jsonrpc.js`,
                                      method: 'POST',
                                      headers: {
                                          'Content-Type': 'application/json'
                                      },
                                      body: JSON.stringify({
                                          "id": 1,
                                          "method": "slim.request",
                                          "params": [playerName, ["status", "-", 1, "tags:artist"]] 
                                      })
                                  };
                          
                                  request(options, (error, response, body) => {
                                      if (error) {
                                          console.error(`MMM-LyrionNowPlaying: Error connecting to Lyrion server: ${error}`);
                                          this.sendSocketNotification('LYRION_NOW_PLAYING_RESULT', { error: `Error connecting to Lyrion server: ${error}` });
                                          return;
                                      }
                          
                                      if (response.statusCode !== 200) {
                                          console.error(`MMM-LyrionNowPlaying: Received unexpected status code from Lyrion server: ${response.statusCode}`);
                                          this.sendSocketNotification('LYRION_NOW_PLAYING_RESULT', { error: `Received unexpected status code from Lyrion server: ${response.statusCode}` });
                                          return;
                                      }
                          
                                      try {
                                          const data = JSON.parse(body);
                                          console.log("Raw Data:", data); 
                          
                                          if (!data.result) {
                                              console.error(`MMM-LyrionNowPlaying: Invalid response from Lyrion server: Missing 'result' in response`);
                                              this.sendSocketNotification('LYRION_NOW_PLAYING_RESULT', { error: `Invalid response from Lyrion server: Missing 'result' in response` });
                                              return;
                                          }
                          
                                          if (!data.result.mode || data.result.mode !== 'play') { 
                                              this.nowPlaying = { 
                                                  artist: "", 
                                                  song: "",
                                                  timeRemaining: "",
                                                  duration: 0, 
                                                  position: 0,
                                                  coverArt: "" 
                                              }; 
                                              this.sendSocketNotification('LYRION_NOW_PLAYING_RESULT', this.nowPlaying); // Send "no song" notification immediately
                                              return; 
                                          }
                          
                                          // Handle cases where playlist_loop might be missing or empty
                                          let artist = "Unknown Artist";
                                          let song = "Unknown Song";
                          
                                          if (data.result.playlist_loop && data.result.playlist_loop[0]) {
                                              artist = data.result.playlist_loop[0].artist || "Unknown Artist";
                                              song = data.result.playlist_loop[0].title || "Unknown Song"; 
                                          }
                          
                                          this.nowPlaying = {
                                              artist: artist,
                                              song: song,
                                              duration: data.result.duration || 0, 
                                              position: data.result.time || 0,
                                              coverArt: `${lyrionServer}/music/current/cover.jpg?player=${playerName}` 
                                          }; 
                          
                                          this.nowPlaying.timeRemaining = this.formatTime(this.nowPlaying.duration - this.nowPlaying.position);
                          
                                          this.sendSocketNotification('LYRION_NOW_PLAYING_RESULT', this.nowPlaying); 
                          
                                      } catch (err) {
                                          console.error(`MMM-LyrionNowPlaying: Error parsing Lyrion API response: ${err}`);
                                          this.sendSocketNotification('LYRION_NOW_PLAYING_RESULT', { error: `Error parsing Lyrion API response: ${err}` });
                                      }
                                  });
                              },
                          
                              formatTime: function(seconds) {
                                  const minutes = Math.floor(seconds / 60);
                                  const remainingSeconds = seconds % 60;
                                  return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
                              }
                          });
                          
                          
                          S 1 Reply Last reply Reply Quote 0
                          • 1
                          • 2
                          • 1 / 2
                          • 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