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

    rkorell

    @rkorell

    58
    Reputation
    19
    Profile views
    362
    Posts
    0
    Followers
    0
    Following
    Joined
    Last Online

    rkorell Unfollow Follow

    Best posts made by rkorell

    • PIR / MQTT - Presence sensor(s) revived

      Dear MagicMirror-ians

      As may already known I was a real fan of MMM-Pir.
      For also good known reasons this nice module is not longer maintained.

      I have a local clone which runs OK but in the meantime I had switched to MMM-MQTTScreenOnOff wich attaches a “better” (radar-) sensor to my mirror. But I’ve missed the progress bar, the dimming and cron-like functionality. In addition the radar sensor is much slower than PIR- caused by a 5 second update intervall as minimum.

      After plenty of tinkering and testing, and above all torturing AI heavily I’m excited to announce:
MMM-PresenceScreenControl is finally out! 🎉

      This module brings together the best of both worlds:
      • The beloved timer bar and auto-dimming from MMM-Pir,
      • The reliability, MQTT support, and simplicity of MMM-MQTTScreenOnOff,
      • All cleaned up, without unnecessary complexity, cryptic cron strings, or weird build tricks.

      A few highlights:
      • Presence detection with PIR, MQTT, or both (whichever triggers first wins)
      • A visual timer bar so you always know how long the screen will stay on
      • Straightforward “ignore” and newly introduced “always-on” time windows using plain times and days—no cryptic cron needed
      • Customizable screen on/off commands—works on Pi, PC, X11, Wayland, CEC, and more
      • Touch mode for remote or manual override (yes, you can poke your mirror awake remotely!)

      If you’re after spinning circles or relay magic, this isn’t your thing (yet 😉).

      But if you want a solid, readable, and maintainable presence module that just works—even (hopefully) after updates—this is for you.

      Give it a try, share your feedback, open pull requests, or ask questions right here or on GitHub:

      Happy mirroring!

      Ralf

      posted in System
      R
      rkorell
    • New Mirror

      Hello to all,
      I’ve started end of last week and today I’m nearly happy with my modules and arrangement.

      Had struggled somtimes with several modules, not all of interest are currently maintained so sometimes I cannot get run it properly.
      Just now I’m “ready” with config - future steps are purchasing the mirror (sample pack is shipping) and build up the frame.
      Tomorrow the PIR sensor will arrive so in addition I have to figure out if and how this works and intergrate this sensor into the build.

      Future step is the integration of a background LED stripe - not sure about this because I’m currently not sure if I’m able to switch this LED on/off in conjunction with monitor (out of MMM-Pir).

      Here a current screenshot:
      MagicMirrorProto.jpg

      I’ve used standards (weather, clock, newsfeed) and:

      MMM-Globe
      MMM-MyGarbage
      MMM-CalendarExt3Agenda
      MMM-Strava
      MMM-NowPlayingOnSpotify
      MMM-ToDoist
      birthdaylist
      MMM-SystemStats
      MMM-SystemInfo
      (MMM-Pir - “installed” but lacking sensor, so disabled and not tested)

      Target Monitor is a 27’’ Samsung device and I will mount this behind a 120cm*60cm mirror.
      (Will post an image, if ready…)

      I’m thinking about enriching the szenario with an 8’’ android tablet for streaming, but not sure…

      Nice rest of the day to all of you, thanks for your really GREAT work and highly motivated assistance in this forum.

      Warmest regards,
      Ralf

      posted in Show your Mirror
      R
      rkorell
    • RE: New Mirror

      And here the target monitor in action - 27’’ Samsung…

      MagicMirrorHardwareSmallresolution.jpg

      Keep you posted.

      Regards,
      Ralf

      posted in Show your Mirror
      R
      rkorell
    • RE: Screen "offline" during specific time of day

      @_V_ My module MMM-PresenceScreenControl Offers a comfortable way to switch on or off during defined times - as much as you like per day as much days as you like.

      Regards,
      Ralf

      posted in Troubleshooting
      R
      rkorell
    • Problems with WLAN connectivity - solved

      Dear mirror fans,
      for your information and reference some findings with my mirror.
      I’m running a MagicMirror on a PI5 with an NVME HAT as boot device.
      My first approach was to de-assemble an original Pi power supply (because of its form factor) and to build this internally into the mirror-frame.
      As reported earlier in a different thread this power supply died due to overheating.

      My next approach was to use a new PI-power supply - this time externally.
      Caused by the circumstances of my installation (power plug far below mirror position and Pi mounted on the top of the mirror) I have used a USB-C to USB-C cable (150cm, 5A) to extend the standard-cable.

      As it turns out now this wasn’t a good idea, ether:
      It worked pretty long (several weeks) good and without any problem.
      But since some days I got more and more really stubborn WLAN losses which were often unrecoverable - only plugging out power supply to reforce a restart helped (I’m working headless as majority of you).

      In the meantime I was able to implement a tiny service which automatically detects the connectivity loss and restarts the WLAN, so a sufficient symptomatic treatment is in place - this discovers connectivity every five minutes, which is OK to me.

      While I was just tinkering I’ve thought it could be a nice idea to identify the root cause and so I added some logging features in the mentioned service.

      Now the interesting (unexpected) finding: Obvious root cause was an undervoltage!

      I’ve searched around (because initially I failed to remember my “cable-extension”) but couldn’t find any reason for this (nothing attached else than the NVME and my mirror doesn’t have anything heavily using the harddisk)…

      Then the additional cable came in my mind and - voilà - this was the root cause - despite its thickness and 5A specification.
      For now I have added some 230V cabeling to the top of the mirror, installed there (outside the mirror frame) a third (de-assembled) PI power supply and connected the standard-long cable of this power supply to the Pi.
      Since then no undervoltage detected (prior to this every few minutes).

      So my learning: Pi is bitchy with cable extensions and tiny undervoltages can lead to heavy WLAN problems.

      May one or the other can benefit from these findings.

      Warm regards,
      Ralf

      posted in General Discussion
      R
      rkorell
    • RE: MMM-Temp2IOT

      @chrisfr1976
      have solved it by myself…
      Used @sdetweil 's tip with developer console and identified CSS classes for the icons.
      Have set

      .MMM-Temp2IOT .iconify {
          font-size: 0px; /* Symbole verschwinden lassen */
      }
      

      in custom.css -
      works :-)

      Warm regards,
      Ralf

      posted in Utilities
      R
      rkorell
    • RE: First MM project - family dashboard

      @cpcode
      Really cool!

      For your families’ whishes: A nice module für RTPS strems of security cams is “MMM-MPlayer” …
      There are several other modules around but the other ones do have several dependencies and requirements.
      MMM-Mplayer use (as name suggest) simply mplayer.
      Works like a charm …
      @myfingersarecold has done a really nice job with this.

      Regards,
      Ralf

      posted in Show your Mirror
      R
      rkorell
    • RE: How to add custom weather icons

      @kool said

      Bumping this back up. Pleeeease help

      Dear @kool ,

      if you are using url as suggested by Sam ( @sdetweil ), you are nearly done.
      As far as I can see from my rookie perspective you do have some redundancies in your config.js (e.g. the unit section: units, tempUnits, windUnits) ) but this shouldn’t disturb.
      As far as I understood you can delete these icontables because you do not use the icon-font but try to use some images from sigle file-URLs instead - so you can delete the whole section iconTable {} with all entries.

      In addition you have to adapt (see above, Sam’s tip) the URL of all you images in your custom.css file.
      (pls. double check, if the files are really in these locations)
      You wrote in your current css

      .weatherforecast .wi-day-sunny {
      content: url("/home/kool/MagicMirror/css/icons/6fas/day.svg") !important;
      
      }
      

      IF your weather-icon files are really in this directory (/home/kool/MagicMirror/css/icons/6fas/) than your css should be as follows:

      .weatherforecast .wi-day-sunny {
       content: url("/css/icons/6fas/day.svg");
      
      

      You do not need the !important flag (in my case)

      second wrong thing besides the URL is your qualifier.

      you are using

      .weatherforecast .wi-something  ....
      

      This cannot be recognized because .weatherforecast is not defined.

      At first you have to decide if you want to have different icons for the current weather and for the weather forecast.
      (In my case this is true).
      IF you would like to have this you have to differentiate the two instances of the weather-module by a “classes” definition.

      For example your first instance of the weather module (current weather) than should be

         module: "weather",
          position: "top_right", // Adjust position as needed
          classes: "weather_current",
          config: {
              weatherProvider: "openmeteo", // Specify the Open-Meteo provider
              apiBase: "https://api.open-meteo.com/v1", // REQUIRED: Base URL for Open-Meteo
      
             lat: xxxx, // REQUIRED: Latitude of the location
              lon: xxxx, // REQUIRED: Longitude of the location
              maxNumberOfDays: 8, // OPTIONAL: Number of forecast days (default is 5)
              pastDays: 0, // OPTIONAL: Number of past days of data to include (default is 0)
         units: "imperial", // Set this to 'imperial' for Fahrenheit and miles per hour
              tempUnits: "imperial", // Make sure to match with 'imperial'
              windUnits: "imperial",
              type: "current", // OPTIONAL: Change to "current" if only current weather data is desired
      
       
          }
      },
      

      (pay attention for the third line: classes: “weather_current”, )
      THIS is your qualifier if you are about to diffrentiate between current weather and weather forecast image-wise.
      (“weather_current” is just an example! you can name it like you want every name is suitable and OK, only pay attention that all of these namings are strictly case sensitive, so Weather is NOT the same as weather"

      Your correct line for custom.css than is:

      .weather_current .wi-day-sunny {
       content: url("/css/icons/6fas/day.svg");
      
      

      and the same dance than for your second instance with DIFFERENT classes-clause in config.js
      (e.g. a " classes: “weather_forecast”, " in the definition of the second weather instance ) results in a custom.css entry like this:

      .weather_forecast .wi-day-sunny {
       content: url("/css/icons/some_other_directory_with_smaller_icons/day.svg");
      
      

      Because the “forecast instance” of the weather module is (in my case) organized as table I found it really useful to differentite these logos - big ones for current, smaller ones for the forecast:

      ScreenFloat Bildschirmfoto von Sublime Text am 14_04_2025, 13_38_51 14_04_2025, 13-38-51.jpg

      If You do NOT like to differentiate the current and forecast instance you do NOT need the classes-phrase in config.js and your correct qualifier is the name of the module (so “weather” ) and your custom.css entry is like this:

      .weather .wi-day-sunny {
       content: url("/css/icons/6fas/day.svg");
      
      

      And this than is valid for both instances.

      Keep in mind that there are a LOT more weather conditions than the two times 5 conditions you have defined in your current custom.css!

      my own definition for the current weather for your reference:

      
      .weather_current .wi-fog  {
      content: url("/css/icons/current/wsymbol_0007_fog.png");
      }
      .weather_current .wi-cloudy  {
      content: url("/css/icons/current/wsymbol_0002_sunny_intervals.png");
      }
      .weather_current .wi-cloudy-windy {
      content: url("/css/icons/current/wsymbol_0004_black_low_cloud.png");
      }
      .weather_current .wi-rain  {
      content: url("/css/icons/current/wsymbol_0018_cloudy_with_heavy_rain.png");
      }
      .weather_current .wi-showers  {
      content: url("/css/icons/current/wsymbol_0017_cloudy_with_light_rain.png");
      }
      .weather_current .wi-thunderstorm  {
      content: url("/css/icons/current/wsymbol_0024_thunderstorms.png");
      }
      .weather_current .wi-snow  {
      content: url("/css/icons/current/wsymbol_0019_cloudy_with_light_snow.png");
      }
      .weather_current .wi-snowflake-cold {
      content: url("/css/icons/current/wsymbol_0020_cloudy_with_heavy_snow.png");
      }
      .weather_current .wi-na {
      content: url("/css/icons/current/wsymbol_0999_unknown.png");
      } 
      
      .weather_current .wi-day-sunny  {
        content: url("/css/icons/current/wsymbol_0001_sunny.png");
      }
      .weather_current .wi-day-cloudy  {
        content: url("/css/icons/current/wsymbol_0043_mostly_cloudy.png");
      }
      .weather_current .wi-day-cloudy-gusts  {
        content: url("/css/icons/current/wsymbol_0004_black_low_cloud.png");
      }
      .weather_current .wi-day-cloudy-windy  {
        content: url("/css/icons/current/wsymbol_0004_black_low_cloud.png");
      }
      .weather_current .wi-cloudy-windy  {
        content: url("/css/icons/current/wsymbol_0004_black_low_cloud.png");
      }
      .weather_current .wi-day-fog  {
        content: url("/css/icons/current/wsymbol_0007_fog.png");
      }
      .weather_current .wi-day-hail  {
        content: url("/css/icons/current/wsymbol_0015_heavy_hail_showers.png");
      }
      .weather_current .wi-day-haze  {
        content: url("/css/icons/current/wsymbol_0005_hazy_sun.png");
      }
      .weather_current .wi-day-lightning  {
        content: url("/css/icons/current/wsymbol_0016_thundery_showers.png");
      }
      .weather_current .wi-day-rain  {
        content: url("/css/icons/current/wsymbol_0085_extreme_rain_showers.png");
      }
      .weather_current .wi-day-rain-mix  {
        content: url("/css/icons/current/wsymbol_0009_light_rain_showers.png");
      }
      .weather_current .wi-day-rain-wind  {
        content: url("/css/icons/current/wsymbol_0010_heavy_rain_showers.png");
      }
      .weather_current .wi-day-showers  {
        content: url("/css/icons/current/wsymbol_0018_cloudy_with_heavy_rain.png");
      }
      .weather_current .wi-day-sleet  {
        content: url("/css/icons/current/wsymbol_0087_heavy_sleet_showers.png");
      }
      .weather_current .wi-day-sleet-storm  {
        content: url("/css/icons/current/wsymbol_0089_heavy_sleet.png");
      }
      .weather_current .wi-day-snow  {
        content: url("/css/icons/current/wsymbol_0011_light_snow_showers.png");
      }
      .weather_current .wi-day-snow-thunderstorm  {
        content: url("/css/icons/current/wsymbol_0057_thundery_snow_showers.png");
      }
      .weather_current .wi-day-snow-wind  {
        content: url("/css/icons/current/wsymbol_0053_blowing_snow.png");
      }
      .weather_current .wi-day-sprinkle  {
        content: url("/css/icons/current/wsymbol_0009_light_rain_showers.png");
      }
      .weather_current .wi-day-storm-showers  {
        content: url("/css/icons/current/wsymbol_0018_cloudy_with_heavy_rain.png");
      }
      .weather_current .wi-day-sunny-overcast  {
        content: url("/css/icons/current/wsymbol_0002_sunny_intervals.png");
      }
      .weather_current .wi-day-thunderstorm  {
        content: url("/css/icons/current/wsymbol_0024_thunderstorms.png");
      }
      .weather_current .wi-day-windy  {
        content: url("/css/icons/current/wsymbol_0060_windy.png");
      }
      .weather_current .wi-solar-eclipse  {
        content: url("/css/icons/current/wsymbol_0005_hazy_sun.png");
      }
      .weather_current .wi-hot  {
        content: url("/css/icons/current/wsymbol_0045_hot.png");
      }
      .weather_current .wi-day-cloudy-high  {
        content: url("/css/icons/current/wsymbol_0006_mist.png");
      }
      .weather_current .wi-day-light-wind  {
        content: url("/css/icons/current/wsymbol_0060_windy.png");
      }
      .weather_current .wi-night-clear  {
        content: url("/css/icons/current/wsymbol_0008_clear_sky_night.png");
      }
      .weather_current .wi-night-alt-cloudy  {
        content: url("/css/icons/current/wsymbol_0041_partly_cloudy_night.png");
      }
      .weather_current .wi-night-alt-partly-cloudy  {
        content: url("/css/icons/current/wsymbol_0041_partly_cloudy_night.png");
      }
      .weather_current .wi-night-alt-cloudy-gusts  {
        content: url("/css/icons/current/wsymbol_0041_partly_cloudy_night.png");
      }
      .weather_current .wi-night-alt-cloudy-windy  {
        content: url("/css/icons/current/wsymbol_0041_partly_cloudy_night.png");
      }
      .weather_current .wi-night-alt-hail  {
        content: url("/css/icons/current/wsymbol_0031_heavy_hail_showers_night.png");
      }
      .weather_current .wi-night-alt-lightning  {
        content: url("/css/icons/current/wsymbol_0032_thundery_showers_night.png");
      }
      .weather_current .wi-night-alt-rain  {
        content: url("/css/icons/current/wsymbol_0025_light_rain_showers_night.png");
      }
      .weather_current .wi-night-alt-rain-mix  {
        content: url("/css/icons/current/wsymbol_0026_heavy_rain_showers_night.png");
      }
      .weather_current .wi-night-alt-rain-wind  {
        content: url("/css/icons/current/wsymbol_0026_heavy_rain_showers_night.png");
      }
      .weather_current .wi-night-alt-showers  {
        content: url("/css/icons/current/wsymbol_0025_light_rain_showers_night.png");
      }
      .weather_current .wi-night-alt-sleet  {
        content: url("/css/icons/current/wsymbol_0029_sleet_showers_night.png");
      }
      .weather_current .wi-night-alt-sleet-storm  {
        content: url("/css/icons/current/wsymbol_0029_sleet_showers_night.png");
      }
      .weather_current .wi-night-alt-snow  {
        content: url("/css/icons/current/wsymbol_0028_heavy_snow_showers_night.png");
      }
      .weather_current .wi-night-alt-snow-thunderstorm  {
        content: url("/css/icons/current/wsymbol_0075_thundery_snow_showers_night.png");
      }
      .weather_current .wi-night-alt-snow-wind  {
        content: url("/css/icons/current/wsymbol_0071_blowing_snow_night.png");
      }
      .weather_current .wi-night-alt-sprinkle  {
        content: url("/css/icons/current/wsymbol_0025_light_rain_showers_night.png");
      }
      .weather_current .wi-night-alt-storm-showers  {
        content: url("/css/icons/current/wsymbol_0026_heavy_rain_showers_night.png");
      }
      .weather_current .wi-night-alt-thunderstorm  {
        content: url("/css/icons/current/wsymbol_0032_thundery_showers_night.png");
      }
      .weather_current .wi-night-cloudy  {
        content: url("/css/icons/current/wsymbol_0041_partly_cloudy_night.png");
      }
      .weather_current .wi-night-cloudy-gusts  {
        content: url("/css/icons/current/wsymbol_0044_mostly_cloudy_night.png");
      }
      .weather_current .wi-night-cloudy-windy  {
        content: url("/css/icons/current/wsymbol_0044_mostly_cloudy_night.png");
      }
      .weather_current .wi-night-fog  {
        content: url("/css/icons/current/wsymbol_0064_fog_night.png");
      }
      .weather_current .wi-night-hail  {
        content: url("/css/icons/current/wsymbol_0039_cloudy_with_heavy_hail_night.png");
      }
      .weather_current .wi-night-lightning  {
        content: url("/css/icons/current/wsymbol_0032_thundery_showers_night.png");
      }
      .weather_current .wi-night-partly-cloudy  {
        content: url("/css/icons/current/wsymbol_0041_partly_cloudy_night.png");
      }
      .weather_current .wi-night-rain  {
        content: url("/css/icons/current/wsymbol_0025_light_rain_showers_night.png");
      }
      .weather_current .wi-night-rain-mix  {
        content: url("/css/icons/current/wsymbol_0026_heavy_rain_showers_night.png");
      }
      .weather_current .wi-night-rain-wind  {
        content: url("/css/icons/current/wsymbol_0025_light_rain_showers_night.png");
      }
      .weather_current .wi-night-showers  {
        content: url("/css/icons/current/wsymbol_0026_heavy_rain_showers_night.png");
      }
      .weather_current .wi-night-sleet  {
        content: url("/css/icons/current/wsymbol_0029_sleet_showers_night.png");
      }
      .weather_current .wi-night-sleet-storm  {
        content: url("/css/icons/current/wsymbol_0029_sleet_showers_night.png");
      }
      .weather_current .wi-night-snow  {
        content: url("/css/icons/current/wsymbol_0027_light_snow_showers_night.png");
      }
      .weather_current .wi-night-snow-thunderstorm  {
        content: url("/css/icons/current/wsymbol_0075_thundery_snow_showers_night.png");
      }
      .weather_current .wi-night-snow-wind  {
        content: url("/css/icons/current/wsymbol_0028_heavy_snow_showers_night.png");
      }
      .weather_current .wi-night-sprinkle  {
        content: url("/css/icons/current/wsymbol_0025_light_rain_showers_night.png");
      }
      .weather_current .wi-night-storm-showers  {
        content: url("/css/icons/current/wsymbol_0026_heavy_rain_showers_night.png");
      }
      .weather_current .wi-night-thunderstorm  {
        content: url("/css/icons/current/wsymbol_0032_thundery_showers_night.png");
      }
      
      
      

      HTH & good luck!
      Ralf

      posted in Development
      R
      rkorell
    • RE: Again -- MMM-Navigate can't get installed.

      @crowimu
      I‘m not using this module and I do not know which of GPIO‘s you are using for your rotary encoder -
      In the module‘s description the author mentioned an eventually necessary modification for some of the PI‘s:

      On some Raspberry Pis it is neccesary to put the following line to /boot/config.txt for the GPIO where "rotary press (SW)" is connected:
      
      gpio=19=ip,pu
      
      Background: Sets your GPIO 19 as input (ip) and pull up (pu) Change the entry according to the GPIO pin you use.
      
      

      Have you double checked this?
      Your error-listing shows „invalid argument , write“ in some context to GPIO…
      May there is a topic for further investigation….

      Good luck!
      Regards,
      Ralf

      posted in Troubleshooting
      R
      rkorell
    • RE: MMM-BambuLabNotify - 3D printer notifications

      @viktorzonix again 404 … Yesterday it was visible - for a short time.
      Unfortunately I’ve missed to clone :-(

      @LuckyDucker - something is really strange with your github …

      Regards,
      Ralf

      posted in Utilities
      R
      rkorell

    Latest posts made by rkorell

    • RE: HDMI turns on without movement

      @Hobbes-0 I would invest in direction of GPIO…
      As I’ve experienced GPIO in bookworm was strongly different as in earlier version - may this applies to Trixie as well?
      If monitor “awakes” suddenly this seem not to be a problem of HDMI-commands ?

      Sorry cannot advice more concrete - I#m still on bookwork, not Trixie.

      Good luck!

      Ralf

      posted in Troubleshooting
      R
      rkorell
    • RE: Problems with WLAN connectivity - solved

      In addition: It’s possible that the old recovery script was part of my problems - due to the above mentioned ping problem.
      For this reason I’ve edited my earlier post and deleted the content of the script.
      I’ve added an “edit note” instead.
      Sorry for confusion and any inconvenience!

      Regards,
      Ralf

      posted in General Discussion
      R
      rkorell
    • RE: Problems with WLAN connectivity - solved

      Dear @schlomm , team,

      as I learned today sometimes system limitations are hard and leads to unwanted results.
      I even got more serioous trouble with my pi and his WIFI so I had to dig in deeper.
      The aproach until now - because of “growing” up - is a “recovery” and a “diagnose” part.
      This leads to - surprise, surprise :-) - inconsistent data and so dignosis is merely impossible.
      For this reason I converged both approches into one script and implemented a 4-stages error-handling and consecutive escalation (until reboot).

      At this stage i had to recognize: almost EVERY test results immediatly in an error at stage 1 (ping) and was resolved at stage 2 (L2/L3 - ICMP problem – checking status of wlan interface).
      To identify root cause for this I - again - dig down deeply (ChatGPT was NOT that helpful!) and found: At systemd level (on my system!?) ping is not in PATH !!!
      So a fully qualified call solved this problem - and most of my “problems” are solved !

      If you are using “ping”, too and stuck in problems in scripts - keep this in mind: “usr/bin/ping” might be really helpful for you.

      If you are interested in, here my current recovery-script - including some useful logging information:

      /usr/local/bin/wlan-recovery.sh
      #!/bin/bash
      # ============================================================================
      # WLAN Recovery Script (Monolithische Version)
      # Autor: Dr.  Ralf Korell, MD 
      # Datum: 2025-10-07
      #
      # Dieses Script wird per systemd-Timer regelmäßig aufgerufen.
      # Es prüft die WLAN-Verbindung in mehreren Stufen und führt nur dann
      # Recovery-Aktionen aus, wenn wirklich eine Unterbrechung vorliegt.
      #
      # Features:
      #   - Mehrstufige Diagnose (Ping, iw, IP, Route)
      #   - Schutz vor Fehlalarmen und Selbstabschüssen
      #   - SSH/VNC-Safe-Mode (keine Unterbrechung aktiver Sessions)
      #   - Logrotation + Statistikdatei
      # ============================================================================
      
      # === Konfiguration ==========================================================
      LOGFILE="/var/log/wlan-recovery.log"
      STATSFILE="/var/log/wlan-recovery.stats"
      MAX_LOG_SIZE=50000              # ~50 KB, dann Logrotation
      PING_TARGET="172.23.56.1"
      MAX_CONSECUTIVE_FAILS=2         # bevor Recovery startet
      COOLDOWN_FILE="/tmp/wlan-recovery.cooldown"
      COOLDOWN_MINUTES=5
      
      # interne Speicherorte (nicht verändern)
      STATEFILE="/tmp/wlan-recovery.state"
      DATE_NOW=$(date "+%Y-%m-%d %H:%M:%S")
      
      # === Hilfsfunktionen ========================================================
      
      log() {
          echo "$DATE_NOW: $1" | tee -a "$LOGFILE"
      }
      
      rotate_log() {
          if [ -f "$LOGFILE" ] && [ $(wc -c <"$LOGFILE") -gt $MAX_LOG_SIZE ]; then
              mv "$LOGFILE" "$LOGFILE.old"
              echo "$DATE_NOW: Log rotated." > "$LOGFILE"
          fi
      }
      
      increment_stat() {
          local key="$1"
          local value
          value=$(grep "^$key=" "$STATSFILE" 2>/dev/null | cut -d= -f2)
          value=$((value + 1))
          grep -v "^$key=" "$STATSFILE" 2>/dev/null > "${STATSFILE}.tmp"
          echo "$key=$value" >> "${STATSFILE}.tmp"
          mv "${STATSFILE}.tmp" "$STATSFILE"
      }
      
      cooldown_active() {
          if [ -f "$COOLDOWN_FILE" ]; then
              local last=$(date -r "$COOLDOWN_FILE" +%s)
              local now=$(date +%s)
              local diff=$(( (now - last) / 60 ))
              [ $diff -lt $COOLDOWN_MINUTES ]
          else
              return 1
          fi
      }
      
      start_cooldown() {
          touch "$COOLDOWN_FILE"
      }
      
      ssh_or_vnc_active() {
          ss -tn state established | grep -Eq '(:22|:5900)'
      }
      
      # === Diagnosefunktionen =====================================================
      
      is_connected_l2() {
          iw dev wlan0 link 2>/dev/null | grep -q "Connected to"
      }
      
      has_ip_l3() {
          ip -4 addr show wlan0 2>/dev/null | grep -q "inet "
      }
      
      has_route() {
          ip route get "$PING_TARGET" 2>/dev/null | grep -q "dev wlan0"
      }
      
      ping_ok() {
          /usr/bin/ping -I wlan0 -c 3 -W 2 "$PING_TARGET" >/dev/null 2>&1
      }
      
      # === Hauptlogik =============================================================
      
      rotate_log
      
      # Init Statsfile falls nicht vorhanden
      [ -f "$STATSFILE" ] || echo -e "success=0\nrecoveries=0\nfailures=0" > "$STATSFILE"
      
      # Lese bisherigen Fehlerzähler
      fails=0
      [ -f "$STATEFILE" ] && fails=$(cat "$STATEFILE")
      
      # Diagnose
      if ping_ok; then
          log "Ping erfolgreich. WLAN funktioniert."
          echo 0 > "$STATEFILE"
          increment_stat "success"
          exit 0
      fi
      
      # Wenn Ping fehlschlägt → weitere Prüfungen
      log "Ping fehlgeschlagen → erweiterte Diagnose..."
      
      if is_connected_l2 && has_ip_l3 && has_route; then
          log "L2/L3 ok → ICMP-Problem (kein Recovery)."
          increment_stat "failures"
          echo 0 > "$STATEFILE"
          exit 0
      fi
      
      # Hier gilt: echte Verbindung gestört
      fails=$((fails + 1))
      echo "$fails" > "$STATEFILE"
      
      if [ $fails -lt $MAX_CONSECUTIVE_FAILS ]; then
          log "Erster Fehler ($fails/$MAX_CONSECUTIVE_FAILS) → Beobachten..."
          increment_stat "failures"
          exit 0
      fi
      
      # Wenn Cooldown läuft → überspringen
      if cooldown_active; then
          log "Cooldown aktiv → Recovery übersprungen."
          exit 0
      fi
      
      # === Recovery-Stufen ========================================================
      
      if ssh_or_vnc_active; then
          log "SSH/VNC aktiv → keine Recovery ausgeführt, nur geloggt."
          increment_stat "failures"
          exit 0
      fi
      
      log "Verbindung tatsächlich gestört → Recovery-Prozess gestartet."
      increment_stat "recoveries"
      
      # Stufe 1: sanfte Reassoziation
      log "→ Stufe 1: wpa_supplicant Reassoziation..."
      wpa_cli -i wlan0 reassociate >/dev/null 2>&1
      sleep 5
      if ping_ok; then
          log "Reassoziation erfolgreich."
          echo 0 > "$STATEFILE"
          start_cooldown
          exit 0
      fi
      
      # Stufe 2: Interface Toggle
      log "→ Stufe 2: Interface Toggle..."
      ip link set wlan0 down
      sleep 2
      ip link set wlan0 up
      sleep 8
      if ping_ok; then
          log "Interface Toggle erfolgreich."
          echo 0 > "$STATEFILE"
          start_cooldown
          exit 0
      fi
      
      # Stufe 3: Treiber-Reload
      log "→ Stufe 3: Treiber-Reload..."
      modprobe -r brcmfmac && modprobe brcmfmac
      sleep 10
      if ping_ok; then
          log "Treiber-Reload erfolgreich."
          echo 0 > "$STATEFILE"
          start_cooldown
          exit 0
      fi
      
      # Wenn alles fehlschlägt
      log "Alle Recovery-Stufen fehlgeschlagen → Fehler bleibt bestehen."
      increment_stat "failures"
      start_cooldown
      exit 1
      

      [EDIT: in script above: changed ping count from -c 1 to -c 3 in:
      /usr/bin/ping -I wlan0 -c 1 -W 2 “$PING_TARGET” >/dev/null 2>&1
      ]
      Warmest regards,
      Ralf

      posted in General Discussion
      R
      rkorell
    • RE: help needed

      @schlomm Yes I had samples from them.

      In the end I‘ve decided to use the monitor in a nice ancient picture frame without any glass.
      So the „mirror“ effect is missing but this fits my usecase better.
      The frame is mounted in our living room and I can see all of the information from every place in the room…

      Warmest regards,
      Ralf

      posted in Show your Mirror
      R
      rkorell
    • RE: help needed

      @andrenajolly :-)
      Yes for sure. For a „whole body mirror“ of this length you need a strong frame and a mirror with at least 6mm of glass.
      Here in Germany we do have some shops which are offering these kind of glass in any size but this an expensive fun …

      Good luck!

      Ralf

      posted in Show your Mirror
      R
      rkorell
    • RE: help needed

      @andrenajolly - most interesting is: what length is “full length” ?
      From this it depends for sure how to build the frame and how to choose right glass (kind of glass, thickness) …

      Kind regards,
      Ralf

      posted in Show your Mirror
      R
      rkorell
    • RE: Problems with WLAN connectivity - solved

      @schlomm Sehr gern und VIEL ERFOLG!

      • melde Dich, wenn Du noch was benötigst.
        Ralf
      posted in General Discussion
      R
      rkorell
    • RE: Cal EXT3 - understanding transforming

      @sdetweil Yes :-)
      therefore I thought a detailed example would be beneficial …
      Warmest regards,
      Ralf

      posted in Troubleshooting
      R
      rkorell
    • RE: Cal EXT3 - understanding transforming

      @_V_ as you might have overseen you can not only check several conditions (as Sam (@sdetweil ) suggested) - separated by else or not but you can make several changes to the same event at one check.

      e.g.:

      eventTransformer: (ev) => {
        if (ev.title.search("Restmüll & Papier & Gelber Sack") !== -1) {ev.isFullday = [true], ev.title = "Alle Tonnen", ev.symbol = [ "fa-regular fa-trash-can" ], ev.color = "fuchsia"}
        if (ev.title.search("Therapie") !== -1) { ev.title = "Sitzung", ev.symbol = [ "fa-solid fa-mug-hot" ], ev.color = "Forestgreen"}
      return ev
         			  }, // end Eventtransformer 
      

      In the above example you can see

      • the modification of the color (as you already had identified,
      • the change of the kind of event (from “scheduled” to “Fullday-Event”)
      • the assignment of a different symbol (with font-awesome-symbols: double check their web-page, keep in mind that only the “STANDARD” (non-payed) versions will be shown in Magic Mirror) and
      • the change of the title of the event.

      Hope this helps.
      Good luck!
      Ralf

      posted in Troubleshooting
      R
      rkorell
    • RE: Problems with WLAN connectivity - solved

      addition:
      the recovery script is: /usr/local/bin/wlan-recovery.sh

      set executable:

      sudo chmod +x /usr/local/bin/wlan-recovery.sh
      
      

      Systemd-Service

      sudo nano /etc/systemd/system/wlan-recovery.service
      

      content:

      [Unit]
      Description=WLAN Recovery Script
      After=network.target
      
      [Service]
      Type=oneshot
      ExecStart=/usr/local/bin/wlan-recovery.sh
      
      

      timer:

      sudo nano /etc/systemd/system/wlan-recovery.timer
      

      content:

      [Unit]
      Description=Run WLAN Recovery every 5 minutes
      
      [Timer]
      OnBootSec=1min
      OnUnitActiveSec=5min
      Persistent=true
      
      [Install]
      WantedBy=timers.target
      
      

      activate this service:

      sudo systemctl daemon-reload
      sudo systemctl enable --now wlan-recovery.timer
      
      

      logfile: /var/log/wlan-recovery.log

      posted in General Discussion
      R
      rkorell