Digitaler Bilderrahmen (Raspberry Pi Zero 2 W + 15,6'' Touch Screen + MagicMirror)

Einklappen
X
 
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge
  • MarkusCosi
    LoxBus Spammer
    • 28.09.2023
    • 314

    #1

    Digitaler Bilderrahmen (Raspberry Pi Zero 2 W + 15,6'' Touch Screen + MagicMirror)

    Anbei eine Anleitung zu einem digitalen Bilderrahmen "Marke Eigenbau".

    Hintergrund: Es gibt schöne digitale Bilderrahmen fertig zu kaufen. Oftmals kommen diese mit einer Software wie Frameo und haben ein Android OS unter der Haube. Mit ADB lassen sich solche Produkte auch in Loxone einbinden und steuern, siehe hier.

    Allerdings sind die Anpassungsmöglichkeiten sehr beschränkt. Daher wollte ich einen voll konfigurier- und steuerbaren selber bauen, und dabei beim Formfaktor schlank und beim Stromverbrauch gering bleiben. Folgende Anleitung mag vllt. jemandem helfen / inspirieren:

    Hardware:
    • Raspberry Pi "Zero 2 W" + Gehäuse (GeekPi Raspberry Zero 2 W Aluminium case, passive cooling), ca. 39,99€
    • 15,6'' Tragbarer Monitor / Touch Screen, 1920x1080, 1,76 x 35,6 x 21,3 cm; 1,9 kg ca. 115€
    • Netzteil: offizielles Raspberry Pi 5,1V, 3A, USB-C, ca. 13 €
    • Kleinteile / Kabel: ca. 40€
      • MicroSD Karte, 16GB, ca. 10€
      • HDMI: 20cm FPC Flachbandkabel + HDMI Standard male down, mini HDMI straight: ca. 3 x 5,99€ = ca. 18€
      • Adapter: USB-C 180 grad (2x): ca. 6,64€
      • Kabel: Micro-USB - USB-C, 15,2 cm: 5,97 €
      • Y-Kabel: USB-C → USB-C + Micro USB (5V power only, no PD)
    Software Setup:

    Betriebssystem / OS:
    • microSD-Karte in Laptop stecken
    • download, install & run: "Raspberry Pi Imager" für PC/Mac
      • Raspberry Pi Device → Pi Zero 2 W,
      • Raspberry Pi OS (64bit) inkl. Desktop;
      • Storage: Adapter/SD-Karte auswählen
      • Adjust Setting:
        • hostname: z.B. raspberrypi.local;
        • username: NAME; password: PW;
        • WLan einrichten: set your WiFi SSID + Password
      • Ausführen: ca. 10 mins
    • microSD-Karte in Raspberry stecken → Power on.
    • IP fest vergeben am Router: <IP>
    den Rest per SSH am PC/Laptop/Mac in einer Kommando-Zeile / Terminal:
    1. ssh NAME@<IP>(bei SSH Problemen nach neuem Aufsetzen: ssh-keygen -R <IP> → yes) → Passwort eingeben: PW
    2. Raspberry auf den neusten Stand bringen: sudo apt-get update (ca. 1min), dann: sudo apt-get upgrade (ca. 1h). Dann: sudo reboot
    3. disable BLE: sudo nano /boot/firmware/config.txt → add: dtoverlay=disable-bt. Dann: sudo reboot
    4. disable WiFi Power Saving Mode: check: iwconfig → "Power Management: On" → schlecht!
      sudo crontab -e → opens the root crontab in your chosen editor...
      # add the following line at the bottom of the root crontab:
      @reboot /usr/sbin/iw wlan0 set power_save off > /home/<user>/power_save_log.txt 2>&1
    5. ggf. sudo nmtui → Netzwerkeinstellungen konfigurieren / editieren: Netzwerk mit nur 2,4GHz auswählen!
    6. MagicMirror2 installieren: link (siehe Abschnitt: "Automatic Installation Scripts") → ca. 30min. Installiert npm / node. Auch das Skript für pm2 ausführen (siehe "Add using pm2 to autostart MagicMirror at bootup"). Dann: sudo reboot.
    7. MagicMirror Module (MMMs) installieren (z.B.: MMM-Wallpaper → für Bilder-Slideshow im Hintergrund, MMM-CalDAV → für iCloud-Kalender-Einbindung: .env-Datei ist anzupassen!, MMM-CalendarExt3Agenda → Agenda Anzeige + Mini-Kalender, MMM-MoonPhase → Mondphasen-Anzeige, MMM-Pinfo → System-Monitoring, MMM-Remote-Control → macht den Bilderrahmen fernsteuernbar!, MMM-TouchButton → Steuerung über Touch-Display, planetrise → Planeten Auf-&Untergänge): jeweils wie folgt:
    8. Dann: pm2 start MagicMirror ("pm2 stop MagicMirror" → stoppt die App, "pm2 status" zeigt den Status)
    Smartphone → digitaler Bilderrahmen:
    Wenn man eine Synology NAS hat, so kann man einen Ordner für NFS freigeben. Mit der "Drive" App fürs Smartphone kann man dann, sofern bei den Smartphone-Kamera-Einstellungen "maximale Kompatibilität" ausgewählt wurde (→ .jpegs statt .heics), Fotos auf seine NAS hochladen und den entsprechenden Ordner dann per symlink live und direkt als Basis für das MMM-Wallpaper Modul nutzen.

    Stichwort hier: Permanent mount eines NFS Ordners: link, link2, link3 → hier einen Ordner wählen auf den man in der Synology Smart-Phone App Zugriff hat. z.B. einen erstellten "Bilderrahmen"-Ordner im Photos Ordner im home-Verzeichnis.
    sudo nano /etc/fstab → dann folgendes hinzufügen um bei jedem Neustart den Ordner gemounted zu haben:
    <IPSynology>:/volume1/homes /mnt/NAShomes nfs auto,hard,nofail 0 0
    Dann einen symlink erstellen, um im MagicMirror-Modul die NAS-Bilder zu sehen. Den "ImagesL"-Ordner kann man dann im Modul "MMM-Wallpaper Modul" als Quelle für "lokale Dateien" angeben:
    ln -s /mnt/NAShomes/SynologyNAME/Photos/PhotoLibrary/Bilderrahmen ~/MagicMirror/ImagesL

    Auch möglich: manuell per sftp:
    e.g. für SimpleBGSlideshow: imagePaths: [], // resolves relative to MM root. So 'Images' => ~MagicMirror/Images

    Transfer images via sftp (link) → put -r localFolder

    sftp USERNAME@<IP>
    cd MagicMirror/
    lcd Documents/FolderContainingImagesFolder
    put -r ImagesL

    exit
    → Folder named "Images" copied from local PC/Laptop to remote Raspberry /MagicMirror/ImagesL

    Einstellungen des MM:
    Die Einstellungen des MagicMirrors, also das Setup / Aussehen / Positionierung der "Module" (der installierten MMMs) des digitalen Bilderrahmen stellt man dann über die Datei ~MagicMirror/config/config.js ein.
    Hierzu:
    cd ~MagicMirror/config
    nano config.js
    Speichern mit Ctrl + O, Schließen mit Ctrl + O.

    Anbei eine Beispielhafte config.js welche die obigen Module konfiguriert.
    Hierbei sind beispielhaft 4 iCloud-Kalender eingebunden (Icons und Farben sind konfigurierbar). Die Wetter-Vorschau erscheint im Agenda-Modul.

    Code:
    /* Config Sample
     *
     * For more information on how you can configure this file
     * see https://docs.magicmirror.builders/configuration/introduction.html
     * and https://docs.magicmirror.builders/modules/configuration.html
     *
     * You can use environment variables using a `config.js.template` file instead of `config.js`
     * which will be converted to `config.js` while starting. For more information
     * see https://docs.magicmirror.builders/configuration/introduction.html#enviromnent-variables
     */
    let config = {
        address: "0.0.0.0",    // Address to listen on, can be:
                                // - "localhost", "127.0.0.1", "::1" to listen on loopback interface
                                // - another specific IPv4/6 to listen on a specific interface
                                // - "0.0.0.0", "::" to listen on any interface
                                // Default, when address config is left out or empty, is "localhost"
        port: 8080,
        basePath: "/",    // The URL path where MagicMirror² is hosted. If you are using a Reverse proxy
                                        // you must set the sub path here. basePath must end with a /
      
    ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1", "<IPLoxberry>"],    // Set [] to allow all IP addresses
                                        // or add a specific IPv4 of 192.168.1.5 :
                                        // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"],
                                        // or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format :
                                        // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"],
    
        useHttps: false,            // Support HTTPS or not, default "false" will use HTTP
        httpsPrivateKey: "",    // HTTPS private key path, only require when useHttps is true
        httpsCertificate: "",    // HTTPS Certificate path, only require when useHttps is true
    
        language: "de",
        locale: "de-DE",   // this variable is provided as a consistent location
                   // it is currently only used by 3rd party modules. no MagicMirror code uses this value
                   // as we have no usage, we  have no constraints on what this field holds
                   // see https://en.wikipedia.org/wiki/Locale_(computer_software) for the possibilities
    
        logLevel: ["INFO", "LOG", "WARN", "ERROR"], // Add "DEBUG" for even more logging
        timeFormat: 24,
        units: "metric",
    
        modules: [
            {
                module: "alert",
            },
            {
                module: "clock",
                position: "top_left"
            },
            {
                module: "calendar",
                header: "Feiertage",
                //position: "bottom_center",
                config: {
                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                    maximumEntries: 2,
                    fadePoint: 0.25,
                    calendars: [
                        {
                            fetchInterval: 605000, //7 * 24 * 60 * 60 * 1000,
                            symbol: "calendar-xmark",
                            name: "DE-Feiertage",
                            color: "red",
                            url: "https://www.feiertage-deutschland.de/kalender-download/ics/feiertage-deutschland.ics"
                        }
                    ]
                }
            },
            {
                            module: "calendar",
                            header: "iCloud: 1",
                            //position: "bottom_center",
                            config: {
                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                    maximumEntries: 6,
                                    fadePoint: 0.5,
                                    calendars: [
                                            {
                                                  fetchInterval: 630000,
                            symbol: "house",
                            name: "Cal1N",
                                url: "http://localhost:8080/CALDAV/ICLOUD_Cal1.ics",
                                color: "SkyBlue",
                            broadcastPastEvents: true, // <= IMPORTANT to see past events
                            auth: { // REQUIRED
                                      user: "user", // DEFINED in .env file.
                                      pass: "pass",
                                      method: "basic"
                                }
                        },
                                    ]
                            }
                    },
            {
                            module: "calendar",
                            header: "iCloud: 2",
                            //position: "bottom_center",
                            config: {
                                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                                    maximumEntries: 4,
                                    fadePoint: 0.5,
                                    calendars: [
                                            {
                                                    fetchInterval: 620000,
                                                    symbol: "briefcase",
                                                    name: "Cal2N",
                                                    url: "http://localhost:8080/CALDAV/ICLOUD_Cal2.ics",
                                                    color: "Orange",
                                                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                                                    auth: { // REQUIRED
                                                            user: "user", // DEFINED in .env file.
                                                            pass: "pass",
                                                            method: "basic"
                                                    }
                                            },
                                    ]
                            }
                    },
            {
                            module: "calendar",
                            header: "iCloud: 3",
                            //position: "bottom_center",
                            config: {
                                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                                    maximumEntries: 4,
                                    fadePoint: 0.5,
                                    calendars: [
                                            {
                                                    fetchInterval: 610000,
                                                    symbol: "school",
                                                    name: "Cal3N",
                                                    url: "http://localhost:8080/CALDAV/ICLOUD_Cal3.ics",
                                                    color: "Orchid",
                                                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                                                    auth: { // REQUIRED
                                                            user: "user", // DEFINED in .env file.
                                                            pass: "pass",
                                                            method: "basic"
                                                    }
                                            },
                                    ]
                            }
                    },
            {
                            module: "calendar",
                            header: "iCloud: 4",
                            //position: "bottom_center",
                            config: {
                                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                                    maximumEntries: 4,
                                    fadePoint: 0.5,
                                    calendars: [
                                            {
                                                    fetchInterval: 600000,
                                                    symbol: "trash",
                                                    name: "Cal4N",
                                                    url: "http://localhost:8080/CALDAV/ICLOUD_Cal4.ics",
                                                    color: "Gray",
                                                    broadcastPastEvents: true, // <= IMPORTANT to see past events
                                                    auth: { // REQUIRED
                                                            user: "User", // DEFINED in .env file.
                                                            pass: "pass",
                                                            method: "basic"
                                                    }
                                            },
                                    ]
                            }
                    },
            {
                  module: "MMM-CalendarExt3Agenda",
                  position: "top_left",
                  header: "Agenda",
                refreshInterval: 300000,
                  config: {
                        instanceId: "basicCalendar",
                        locale: "de-DE",
                        firstDayOfWeek: 1,
                        startDayIndex: 0,
                    endDayIndex: 7,
                        calendarSet: ["DE-Feiertage", "Cal1N", "Cal2N", "Cal3N", "Cal4N"],
                  }
            },
            {
                module: "weather",
                position: "top_right",
                config: {
                    weatherProvider: "openmeteo",
                    showFeelsLike: false,
                    type: "current",
                    lat: LAT,
                    lon: LON
                }
            },
            {
                module: "weather",
                //position: "top_right",
                header: "Wettervorhersage",
                config: {
                    weatherProvider: "openmeteo",
                    type: "forecast",
                    lat: LAT,
                    lon: LON
                }
            },
            {
                    module: "MMM-Wallpaper",
                    position: "fullscreen_below",
                    config: { // See "Configuration options" for more information.
                    source: "local:/home/NAME/MagicMirror/ImagesL",
                    updateInterval: 600 * 1000,
                    slideInterval: 60 * 1000,
                    crossfade: false,
                    filter: "", //"grayscale(0.5) brightness(0.5)"
                    caption: false,
                    //recurseLocalDirectories: true,
                    //shuffle: true,
                    }
              },
            {
                module: "planetrise",
                position: "top_right",    // This can be any of the regions.
                header: "Planet Rise",
                    config: {  // Place the latitude and longitude of your mirror
                            latitude: LAT,
                            longitude: LON,
                    bodies: {'Sun': '☉',
                                    'Moon': '☽',
                                    //'Mercury': '☿',
                                    'Venus': '♀',
                                    'Mars': '♂',
                                    'Jupiter': '♃',
                                    'Saturn': '♄',
                            }
                    }
            },
            {
                module: "MMM-MoonPhase",
                position: "top_right",
                config: {
                    updateInterval: 43200000,
                    hemisphere: "N",
                    resolution: "detailed",
                    title: true,
                    phase: true,
                    nextFull: false,
                    age: false,
                    phaseAge: true,
                    phaseAgeTotal: true,
                    size: 75,
                    moonAlign: "end",
                    textAlign: "end",
                    alpha: 0.7,
                    riseAndSet: {
                        display: false,
                        lat: LAT,
                        lon: LON,
                        gmtOffset: 2.0
                    }
                }
            },
            {
                  module: "MMM-CalDAV", // This module works in background, so `position` is not needed.
                config: {
                        timeRangeStart: -30, // Get events from 30 days before
                        servers: [
                              { // example of icloud or basic auth
                            envPrefix: "ICLOUD_", // prefix for identifying each server
                            serverUrl: "https://caldav.icloud.com", // Ask to your CALDAV provider
                            targets: ["Cal1", "Cal2", "Cal3", "Cal4"],
                              },
                        ],
                  }
            },
             {
                    module: 'MMM-Pinfo',
                    position: 'bottom_right',
                    config: {
                          refresh: 5000,
                    valueAlign: "right",
                    DEVICE: {
                              displayModel: true,
                        displaySerial: false
                    },
                    NETWORK: {
                        displayIPv4: true
                    },
                    CPU: {
                        displayUsage: true
                    },
                    UPTIME: {
                              displayUptime: true
                        },
                          WARNING: {
                            enable: true,
                            interval: 1000 * 60 * 5,
                            check: {
                                  CPU_TEMP: 65,
                                  CPU_USAGE: 75,
                                  RAM_USED: 80,
                                  STORAGE_USED: 80
                            }
                          },
                    }
              },
            {
                    module: 'MMM-Remote-Control',
                    //position: 'bottom_right', // you can hide this module afterwards from the remote control itself
                config: {
                            customCommand: {
                        monitorOnCommand: 'wlr-randr --output HDMI-A-1 --on',
                            monitorOffCommand: 'wlr-randr --output HDMI-A-1 --off'},  // Optional, See "Using Custom Commands" below
                            showModuleApiMenu: true, // Optional, Enable the Module Controls menu
                            secureEndpoints: false, // Optional, See API/README.md
                    pm2ProcessName: 'MagicMirror',
                    }
                },
            {
                module: "MMM-TouchButton",
                 position: "bottom_left",
                config: {
                        buttons: [
                             {
                                  name: "Shutdown",
                            title: "Shutdown",
                                  icon: "fa fa-power-off",
                                  command: "sudo",
                                  args: "shutdown -h now"
                             },
                        {
                                  name: "MMStop",
                                  title: "Stop MM",
                            icon: "fa fa-stop",
                                  command: "pm2 stop MagicMirror",
                        },
                        {
                                  name: "Next",
                            title: "Next Image",
                                  icon: "fa fa-arrow-right",
                                  notification: "LOAD_NEXT_WALLPAPER",
                        },
                    ]
                   },
              },
        ]
    };
    
    /*************** DO NOT EDIT THE LINE BELOW ***************/
    if (typeof module !== "undefined") { module.exports = config; }
    Styling:
    Ferner kann man die Schriftarten und weitere Details in der custom.css Datei anpassen. Dazu:
    cd ~MagicMirror/css
    nano custom.css

    z.B.: wie folgt:
    Code:
    .normal,
    .dimmed,
    header,
    body {
      color: #fff;
    }
    
    .module.MMM-CalendarExt3Agenda {
      background-color:rgba(0,0,0,0.6);
      border-radius:8px;
      padding:8px;
    }
    
    .MMM-Pinfo {
      opacity: 0.5;
    }
    
    :root {
      --gap-body-top: 30px;
      --gap-body-right: 30px;
      --gap-body-bottom: 30px;
      --gap-body-left: 30px;
    }
    
    .clock   .time {
        font-weight: bold;
    }
    
    .weather .bright {
        font-weight: bold;
    }
    Fernsteuerung / Smart-Home Integration:
    Ferngesteuert werden kann der digitale Bilderrahmen über das Module MMM-Remote-Control, welches eine http-API bereitstellt. Folgende eingaben an einem Terminal (auf Raspberry oder sonstwo) sollten dann funktionieren:

    Restart MM:
    curl -X GET 'http://<IP>:8080/api/restart'

    BRIGHTNESS Control:
    curl -X GET 'http://<IP>:8080/api/brightness/X' (X=0..100)

    Monitor ON/OFF: (link)
    curl -X GET 'http://<IP>:8080/api/monitor/off' bzw. on

    Next image (for "MMM-Wallpaper" module, via notification):
    curl -X GET http://<IP>:8080/api/notification/LOAD_NEXT_WALLPAPER

    Background ON / OFF bzw. Images Slideshow ON / OFF:
    curl -X GET 'http://<IP>:8080/remote?action=SHOW&module=module_10_MMM-Wallpaper'
    curl -X GET 'http://<IP>:8080/remote?action=HIDE&module=module_10_MMM-Wallpaper'


    EXTRA MODULES OFF:
    curl -X GET 'http://<IP>:8080/remote?action=HIDE&module=module_11_planetrise' 'http://<IP>:8080/remote?action=HIDE&module=module_12_MMM-MoonPhase' 'http://<IP>:8080/remote?action=HIDE&module=module_7_MMM-CalendarExt3Agenda' 'http://<IP>:8080/remote?action=HIDE&module=module_14_MMM-Pinfo' 'http://<IP>:8080/remote?action=HIDE&module=module_16_MMM-TouchButton' 'http://<IP>:8080/remote?action=HIDE&module=module_15_MMM-Remote-Control'

    EXTRA MODULES ON:
    curl -X GET 'http://<IP>:8080/remote?action=SHOW&module=module_11_planetrise' 'http://<IP>:8080/remote?action=SHOW&module=module_12_MMM-MoonPhase' 'http://<IP>:8080/remote?action=SHOW&module=module_7_MMM-CalendarExt3Agenda' 'http://<IP>:8080/remote?action=SHOW&module=module_14_MMM-Pinfo' 'http://<IP>:8080/remote?action=SHOW&module=module_16_MMM-TouchButton' 'http://<IP>:8080/remote?action=SHOW&module=module_15_MMM-Remote-Control'

    Nachricht auf den Bildschirm anzeigen:
    curl -X GET 'http://<IP>:8080/api/module/alert/showalert?message=Hello&timer=2000'

    natürlich kann man diese Befehle auch über virtuelle Ausgänge in Loxone absetzen.

    Fazit:
    Der Raspberry Pi Zero 2 W ist etwas träge. Der Raspi-Bilderrahmen ist vollumfänglich konfigurierbar und erlaubt mehr als der fertige Bildschirm von der Stange. Die Einrichtung dauerte allerdings eine ganze Weile bis die richtige Kombination von Modulen und Einstellungen gefunden war. Auch die Stromversorgung scheint wichtig. Aktuell ist der Bildschirm direkt per Raspberry Pi original Netzteil (USB-C) angeschlossen und der Raspberry von dort per USB-C → USB Micro. Update: jetzt sind der Pi und der Bildschirm über ein Y-Splitter-Kabel beide direkt an das Netzteil angeschlossen.

    Bilder / Ergebnis
    Anbei ein Beispiel für einen gekauften Bilderrahmen vs. den Bilderrahmen Marke Eigenbau..
    Stromverbrauch: ca. 6W - 8W (Raspberry + 15,6'' Display) / 2W Standby vs. ca. 17W - 20W für den gekauften Bilderrahmen (21,5'') / 2W Standby.

    Klicke auf die Grafik für eine vergrößerte Ansicht  Name: IMG_7965.jpg Ansichten: 0 Größe: 588,2 KB ID: 464381

    Klicke auf die Grafik für eine vergrößerte Ansicht  Name: Frameo.jpg Ansichten: 0 Größe: 2,53 MB ID: 464060
    Klicke auf die Grafik für eine vergrößerte Ansicht  Name: RaspiZero2W.jpg Ansichten: 0 Größe: 3,08 MB ID: 464059
    Zuletzt geändert von MarkusCosi; 30.06.2025, 13:59.
  • Noschvie
    MS Profi
    • 24.09.2018
    • 584

    #2
    Ein richtiger Luxus-Bilderrahmen :-)

    Kommentar

    • Labmaster
      Lox Guru
      • 20.01.2017
      • 2695

      #3
      Wieviel Leistung zieht das komplette System ?

      Kommentar


      • MarkusCosi
        MarkusCosi kommentierte
        Kommentar bearbeiten
        21,5 Zoll (Produkt): 16W (80% Helligkeit), 20W (max. Helligkeit); variiert um ca. 1W je nach angezeigtem Bild; Sleep-Mode: 1,9W
        15,6 Zoll (Raspberry): 5,8W (30% Helligkeit); 6,1W (50%); 8,5W (max. Helligkeit); variiert um ca. 0,2 W je nach Bild; Bildschirm aus: 2,2W

        Skaliert man den Wert des kleineren Raspberry-Eigenbau-Bilderrahmen über die Bildschirmfläche (21,5''^2/15,6''^2 = 1,9) so kommt man auf vergleichbare Werte, wobei der Eigenbau etwas stromsparender scheint...
        Zuletzt geändert von MarkusCosi; 28.06.2025, 09:21.
    Lädt...