A New Chapter for MagicMirror: The Community Takes the Lead
Read the statement by Michael Teeuw here.
  • MMM-CalendarExt3

    584
    2 Votes
    584 Posts
    927k Views
    M

    @Ragged4310
    According to the conditions you provided, the previous code cannot be used. Clear definition of the conditions is essential to come up with an appropriate solution.

    First, we need to clearly define the events that need to be collapsed. Based on your description, it seems they are in the form of “Person’s Name - Task.” Are you looking to group them by “Person’s Name”? However, it also seems that you do not want the “Person’s Name” to be exposed. In that case, how should they be displayed? For example, would you like them to be labeled sequentially as “Reservation 1,” “Reservation 2,” and so on?

    Please provide more details about the AS-IS and TO-BE states.

    Alternatively, assigning additional properties to the events to be grouped might also be a good approach. For instance, you could write the person’s name (e.g., Jane Doe) in the location or description field, and only include the task (e.g., Deep Tissue Massage) in the event title. Then, you could group events with the same description together.

  • MMM-SeaConditions - how is your local surf?

    1
    1 Votes
    1 Posts
    27 Views
    H
    Description:

    This MagicMirror² module fetches sea conditions from an API and displays them on the mirror. The module displays a bar graph for a week, including 3 days forecast.

    I am developing this module , because I am diving in the North Sea every week of the year, and I like to know the conditions out there :-)…
    There have been other modules for Surf conditions, but that is all outdated.

    The current version (v1.0) returns sea surface temperatures for a given LatLon location, In the future I may include other conditions like waves, air temperature and wind. I also want to include yearly averages etc…

    screenshots

    image.png

    Download

    You can download the module files at https://github.com/HarrieV8/MMM-SeaConditions, and find more information about the module itself and the API.

    Remarks

    Please test it out and let me know how it works. I use plotly.js to draw a bar graph and I don’t know how it performs on older RPi’s for instance.

  • MMM-MPlayer

    1
    1 Votes
    1 Posts
    43 Views
    M

    I couldnt get the EXT-FreeboxTV module to work on my magic mirror so i gave up, and used chatgpt to help me write a module.

    Its called MMM-MPlayer, and using MPlayer it will open either 1 or 2 Mplayer windows and play whatever files or rtsp streams you like. If you define multiple it will cycle through them, determined by the streamInterval. I am using it to stream 3 Unifi Cameras so that i can keep an eye on the front yard in one window, and an eye on my kids via the cameras we use as nanny cams while they nap/sleep, cycling through those two rooms every 30 seconds.

    Reasons for using MPlayer over something else is that the version of raspbian that I am running on my pi3 has a broken version of VLC, which doesnt respond to command line position arguments, and also cant run OMXplayer. Its the most recent distro, i dont remember the name for it. mplayer works well, and plays on my pi3 just fine, along with all the other stuff i have running.

    Obviously your use case could be for anything, cameras around your house, livestreams you like to watch. Essentially anything that mplayer can play. The module natively responds to the MMM-Pir notification so that it kills and restarts the streams when the PIR module tells the screen to turn off and on, so that the screen acts as it should.

    I don’t feel like actually uploading it to github, but here is the source code, and an example config.

    --------------- CONFIG.js

    { module: 'MMM-MPlayer', // Update the module name here position: 'top_left', // Magic Mirror position config: { useTwoWindows: true, // Use two windows layout: 'row', // Can be 'row' or 'column' windowSize: { width: 525, height: 295 }, // Window size for both windows windowPosition: { x: 12, y: 575 }, // Position of the first window (window1) [window2 is either 5px below or to the right of this window, depending on layout] streamInterval: 30000, streams: { window1: [ 'somthing_else.mp4', 'something.mp4' ], window2: [ 'rtsp://foo', 'rtsp://bar', ] } } },

    ---------------MMM-MPlayer.js

    /* MagicMirror Module: MMM-MPlayer.js * This script communicates with the backend (node_helper.js) to control mplayer window streaming * It starts the stream cycle process only after the DOM is fully loaded. */ Module.register('MMM-MPlayer', { // Define the module's defaults defaults: { useTwoWindows: true, layout: 'column', // Can be 'row' or 'column' windowSize: { width: 640, height: 480 }, windowPosition: { x: 0, y: 0 }, // Position of the first window streamInterval:30000, streams: { window1: [ 'http://stream1.example.com/video1', 'http://stream2.example.com/video1' ], window2: [ 'http://stream1.example.com/video2', 'http://stream2.example.com/video2' ] } }, // Start the module start: function() { console.log('MMM-MPlayer module starting...'); // Send the configuration to the backend this.sendSocketNotification('SET_CONFIG', this.config); // Notify the backend to start the stream cycle (backend will handle stream cycling) //this.sendSocketNotification('START_STREAM_CYCLE'); }, // Define socket notification handlers socketNotificationReceived: function(notification, payload) { switch(notification) { case 'STREAM_CYCLE_STARTED': console.log('Stream cycle process started.'); break; } }, // This function listens to the DOM_CREATED event and starts the stream cycle process notificationReceived: function(notification, payload, sender) { switch(notification) { case 'DOM_OBJECTS_CREATED': console.log('DOM created. Starting the stream cycle process...'); // Send the notification to the backend to initiate the stream cycle this.sendSocketNotification('START_STREAM_CYCLE'); break; case 'MMM_PIR-SCREEN_POWERSTATUS': console.log(`Received PIR Screen Show Notification ${payload}`); if (payload == true) { this.sendSocketNotification('START_STREAM_CYCLE'); } else { this.sendSocketNotification('STOP_STREAM_CYCLE'); } break; } }, getDom: function() { var wrapper = document.createElement("div"); wrapper.innerHTML = ''; return wrapper; } });

    ------------------ NODE HELPER

    const NodeHelper = require('node_helper'); const { spawn } = require('child_process'); const { os } = require('os'); const Log = require('logger'); // Import the Log module from MagicMirror module.exports = NodeHelper.create({ start: function() { Log.info('Starting MMM-MPlayer module...'); this.streams = {}; this.currentStreamIndex = { window1: -1, window2: -1 }; this.mplayerProcesses = { window1: null, window2: null }; // Track mplayer processes for each window this.streamInterval = 30000; this.streamSwitcher = null; }, // Handle socket notifications from the frontend socketNotificationReceived: function(notification, payload) { switch(notification) { case 'SET_CONFIG': Log.info('Received configuration for MMM-MPlayer module'); // Save the configuration this.config = payload; // Adjust layout and start the stream cycle this.adjustLayout(); break; case 'START_STREAM_CYCLE': Log.info('Stream cycle process started.'); this.cycleStreams(); // Start the stream cycle after receiving the notification break; case 'STOP_STREAM_CYCLE': Log.info('Stream cycle process stopped.'); this.stopStreams(); } }, // Start or refresh the streams cycleStreams: function() { //fire up the streams immediately this.switchStream('window1'); this.switchStream('window2'); if (this.streamSwitcher == null) { this.streamSwitcher = setInterval(() => { this.switchStream('window1'); this.switchStream('window2'); }, this.config.streamInterval); // cycle based on the config this.sendSocketNotification('STREAM_CYCLE_STARTED'); } }, stopStreams: function() { if (this.streamSwitcher != null) { clearInterval(this.streamSwitcher); this.killMPlayer('window1'); this.killMPlayer('window2'); this.streamSwitcher = null; this.currentStreamIndex = { window1: -1, window2: -1 }; } }, // Switch the stream for the given window switchStream: function(window) { const windowStreams = this.config.streams[window]; Log.info(`Switching stream for ${window}`); const currentIndex = this.currentStreamIndex[window]; const nextIndex = (currentIndex + 1) % windowStreams.length; // Update stream index this.currentStreamIndex[window] = nextIndex; if (currentIndex != nextIndex) { // Kill the old mplayer process for the window using SIGTERM this.killMPlayer(window); // Launch new mplayer process for the window this.launchMPlayer(windowStreams[nextIndex], window); } }, // Kill any existing mplayer process for a window using SIGTERM killMPlayer: function(window) { const mplayerProcess = this.mplayerProcesses[window]; if (mplayerProcess) { Log.info(`Killing mplayer process for ${window}...${mplayerProcess.pid}`); const killer = spawn(`kill`, [`${mplayerProcess.pid}`]); // Handle standard output and error killer.stdout.on('data', (data) => { Log.debug(`killer [${window}] stdout: ${data}`); }); killer.stderr.on('data', (data) => { Log.error(`killer [${window}] stderr: ${data}`); }); killer.on('close', (code) => { Log.info(`killer process for ${window} exited with code ${code}`); }); } }, // Launch a new mplayer process for the window using spawn launchMPlayer: function(stream, window) { const size = this.config.windowSize; const position = this.config[`${window}Position`] || this.config.windowPosition; // Use specific or general window position // Spawn a new mplayer process const env = { ...process.env, DISPLAY: ':0' }; const mplayerProcess = spawn(`mplayer`, ['-noborder', '-geometry', `${position.x}:${position.y}`, `-xy`, `${size.width}`, `${size.height}`, `${stream}`], {env: env}); //C, Log.info(`Launched mplayer process for ${window} with PID ${mplayerProcess.pid}`); // Track the process for future termination this.mplayerProcesses[window] = mplayerProcess; // Handle standard output and error mplayerProcess.stdout.on('data', (data) => { Log.debug(`mplayer [${window}] stdout: ${data}`); }); mplayerProcess.stderr.on('data', (data) => { //Log.error(`mplayer [${window}] stderr: ${data}`); }); mplayerProcess.on('close', (code) => { Log.info(`mplayer process for ${window} exited with code ${code}`); }); }, // Adjust stream positions and size based on layout adjustLayout: function() { const windowPosition = this.config.windowPosition; // General window position for window1 const windowSize = this.config.windowSize; const layout = this.config.layout; // Calculate position for second window automatically based on layout if (layout === 'column') { // If layout is column, position window 2 below window 1 this.config.window2Position = { x: windowPosition.x, // Same x position y: windowPosition.y + windowSize.height + 5 // y position of window2 is below window1 }; } else if (layout === 'row') { // If layout is row, position window 2 to the right of window 1 this.config.window2Position = { x: windowPosition.x + windowSize.width + 5, // x position of window2 is to the right of window1 y: windowPosition.y // Same y position }; } } });
  • Check out my new Nixie Clock module!

    12
    6 Votes
    12 Posts
    3k Views
    N

    Hey,

    thank you for the nice Module. How can I resize it? Thanks!

  • MMM-Multimonth

    77
    6 Votes
    77 Posts
    17k Views
    N

    @BKeyport Thanks a lot. It’s working…

  • Matter protocol

    5
    1 Votes
    5 Posts
    114 Views
    S

    @minomit

    In another mirror runtime I register the screen device to home assistant via mqtt HA discovery so I can turn it off/on via home assistant automations.

    But what else would you want to know?

  • ShellyPV mit Shelly 2.5

    16
    0 Votes
    16 Posts
    420 Views
    C

    @visionmaster Danke für die Antwort. Die Module sind in GitHub aktualisiert.

    So, issue closed until new devices pop up ;-)

  • MMM-MonthlyCalendar

    4
    0 Votes
    4 Posts
    80 Views
    S

    @DarrenO-0 awesome!! glad you found it…

  • 1 Votes
    5 Posts
    171 Views
    T

    8db7a759-8885-4fe5-a35e-f3f5a2244275-image.png

  • MMM-ShellyPV

    4
    2 Votes
    4 Posts
    267 Views
    C

    @SuVo If you want to run both modules in parallel mode you need of course each module separate: So MMM-ShellyStatusTable and MMM-ShellyPV is needed in the modules folder and config.js file.

    You might discover some error messages during startup. The node_helper.js is nearly the same. But the errors causes no trouble.

    But I’ve just updated the whole module. I wanted to integrate the table in the MMM-ShellyPV module. See the modifications here: ShellyPVUpdate

    I think you’ll like it.

  • not a module, but ical URLs for garbage collection in the Netherlands

    1
    1 Votes
    1 Posts
    86 Views
    H

    based on your home address, the website https://www.afval-ical.nl generates ical URLs for garbage collection schedules from a dozen collectors/areas in the Netherlands…

    It is not a one-time copy but an actual link to the calendar, so updates are processed correctly.

    I generated an ical URL for my area with https://www.avalex.nl/kalender/ and it integrates perfectly with my calendar module

  • MMM-NewsAPI

    103
    2 Votes
    103 Posts
    25k Views
    mumblebajM

    @ufransa Can you check if there are any errors? Check the Console Tab in the Developers Window and check in the pm2 logs if you using pm2 or the terminal if you starting MM with npm start

  • MMM-Forum

    1
    2 Votes
    1 Posts
    79 Views
    KristjanESPERANTOK

    Hello Community!

    I’m pleased to announce my new module, MMM-Forum, which brings unread topics, notifications and messages from this forum directly to your mirror. This module is designed to keep you up to date with what’s going on in the forum.

    It should also work for other NodeBB forums, but hasn’t been tested yet. Feedback would be nice.

    Here’s a (slightly doctored) screenshot of the module in action:
    screenshot.png

    You can find the repository and installation instructions here: https://github.com/KristjanESPERANTO/MMM-Forum.

    Your feedback is invaluable, so please share your thoughts, suggestions or any problems you encounter. I’m not that talented at web design, so please be gentle and give me some pointers, or even better a PR 😁

  • MMM-WeatherAlerts

    28
    2 Votes
    28 Posts
    5k Views
    O

    @mmmallday Great find!

    I did not see MMM-NOAAAlerts on either the 3rd Party Modules (official) or the Magicial Mirror² 3rd Party Modules (official) page.

    I have setup this module and it worked for me. I used 4 decimal places on the lat and long.

  • MMM-OpenWeatherMapForecast stuck on Loading....

    63
    0 Votes
    63 Posts
    20k Views
    R

    Just changed OS to Bookworm and reinstalled MM, stuck with weather modules loading…
    For me, @postb8822 's 29th April 2024 suggestion worked just fine, thank you :)

  • ] MMM-Sensibo: Display Sensibo Thermostats on Your MagicMirror

    2
    2 Votes
    2 Posts
    127 Views
    KristjanESPERANTOK

    @mmmallday Nice! Don’t forget to add it to the module list: https://github.com/MagicMirrorOrg/MagicMirror/wiki/3rd-party-modules 🙂

  • MMM-ShellyStatusTable

    1
    2 Votes
    1 Posts
    124 Views
    C

    Hello,

    finally I finished my first MM-module. I was struggling with the existing shelly modules so I decided to create a new one which uses only the cloud-api in order to be independent from the device itself.

    MMM-ShellyStatusTable

    The MMM-ShellyStatusTable module displays the switch status and power consumption of multiple Shelly devices in a table on the MagicMirror², including a total consumption sum. It regularly updates the data via the Shelly Cloud API Gen 1 and Gen 2+. So it should be independed from the devices in your smart home.

    It is currently hard to say if every device is considered correctly. I have the following devices and it works:

    Shelly Plug / PlugS Shelly Plus Plug S Shelly Plus 1 PM

    Currently no translation is available. It will follow in the next days. But it is not hard to fix by your own, I hope.

    I’m not really a module developer but ChatGPT finally fixed it :-)

    Please try and give me a feedback if you discover some problems. Maybe I can help, but I’m no sure at all :laugh:

  • MMM-NOAAAlerts

    3
    2 Votes
    3 Posts
    493 Views
    KristjanESPERANTOK

    @mattkab Please add it to the module list :-)

  • Rolling 30 day calendar

    2
    0 Votes
    2 Posts
    118 Views
    S

    @siujd2001 css, he gives names in the doc

    i think he has week view not day view

  • MMM-CalendarExt3 - wrong icon shown in legend

    1
    0 Votes
    1 Posts
    81 Views
    L

    Hi @all

    I have an issue with the icons/symbols, that are shown in the legend. Sometimes the legend shows an icon of the event (eventTransformer) instead of the default-calendar-icon. I am using iconify icons.

    For a better understanding please have a look at the screenshot:
    e.g. the yellow calendar. The default icon should be a brick-head one. You can find it e.g. on Monday at “LAC Training”. The Legend instead shows the bread icon. I am using the bread-icon via eventTransformer only for events that calls “Brotbüchse”.
    Why the legend shows this icon instead of the default one?

    CalendarExt3.jpeg

    Here the main code of the calendar module:

    { module: "calendar", header: "TErmINe", //position: "top_left", config: { defaultSymbolClassName: '', useIconify: true, broadcastPastEvents: true, calendars: [ { name: "Ludwig", color: "#CD2626", fetchInterval: 5 * 60 * 1000, symbol: "game-icons:trumpet", url: "webcal:" }, { name: "Albrecht", color: "#EEEE00", fetchInterval: 5 * 60 * 1000, symbol: "ph:lego-smiley-light", url: "webcal:" }, { name: "Samuel", color: "#4876FF", symbol: "healthicons:running", fetchInterval: 5 * 60 * 1000, url: "webcal:" }, { name: "Abfall", color: "#919191", symbol: "solar:trash-bin-minimalistic-outline", fetchInterval: 5 * 60 * 1000, url: "webcal://localhost:8080/" }, { name: "Franziska", symbol: "fluent-emoji-high-contrast:unicorn", /*color: "#800080",*/ color: "#E066FF", fetchInterval: 5 * 60 * 1000, url: "webcal:" }, { name: "Daniel", color: '#008000', symbol: "game-icons:full-motorcycle-helmet", fetchInterval: 5 * 60 * 1000, url: "webcal:" }, { name: "Familie", color: "#FF8C00", symbol: "material-symbols:family-restroom", fetchinterval: 5 * 60 * 1000, url: "webcal:" }, { name: "Jahrestage", color: "#622C00", symbol: "iconoir:birthday-cake", fetchInterval: 5 * 60 * 1000, url: "webcal:" } ] } },

    Here you can find the config of the CalendarExt3 module:

    { module: "MMM-CalendarExt3", position: "upper_third", header: "14-Tage Vorschau", title: "14 Tage Übersicht", config: { refreshInterval: 5 * 60 * 1000, useIconify: true, mode: "week", displayLegend: true, displayEndTime: false, weekIndex: 0, weeksInView: 2, instanceId: "basicCalendar", locale: 'de-DE', useMarquee: true, maxEventLines: 7, fontSize: '17px', eventHeight: '40px', firstDayOfWeek: 1, useWeather: false, showMore: true, skipDuplicated: false, calendarSet: ['Ludwig', 'Samuel', 'Albrecht', 'Daniel','Franziska', 'Familie', 'Abfall', 'Jahrestage'], eventTransformer: (ev) => { if (ev.title.search('Saxophon') > -1) ev.symbol = ["game-icons:saxophone"] if (ev.title.search('Brotbüchse') > -1) ev.symbol = ["ph:bread"] if (ev.title.search('Sport Vorschule') > -1) ev.symbol = ["solar:bottle-outline"] if (ev.title.search('Jugendfeuerwehr') > -1) ev.symbol = ["ph:siren-light"] if (ev.title.search('Gitarre') > -1) ev.symbol = ["ph:guitar-light"] if (ev.title.search('Geburtstag') > -1) ev.symbol = ["simple-line-icons:present"] if (ev.title.search('GTA Fußball') > -1) ev.symbol = ["game-icons:soccer-ball"] if (ev.title.search('GTA Handball') > -1) ev.symbol = ["mdi:handball"] if (ev.title.search('Treffen') > -1) ev.symbol = ["tabler:pacman"] if (ev.title.search('FT:') > -1) ev.symbol = ["ion:calendar-outline"] return ev } } },

    Can you help to find the the root cause of the problem?