Building a smart mirror is the ultimate intersection of woodworking, hardware integration, and embedded Linux. While the core MagicMirror² software handles the beautiful UI, the underlying hardware dictates whether your mirror is a responsive dashboard or a laggy, screen-burned paperweight. For a 2026 build, the Raspberry Pi 5 (4GB) running Raspberry Pi OS Bookworm 64-bit is the definitive sweet spot, offering enough headroom to run Electron, local facial recognition, and heavy API polling without choking.

This guide skips the basic 'how to install npm' fluff. We are going straight into wiring a hardware PIR motion sensor to wake the display, writing a robust Bookworm-compatible Python wake script, and debugging the exact Electron crash errors that stall 90% of first-time builds.

Spec Sheet & Parts List

Do not under-power your Pi 5. The MagicMirror Electron wrapper is notoriously memory- and power-hungry during boot. Use the exact variants listed below to avoid brownout warnings and USB disconnects.

ComponentExact Variant / ModelEst. PriceBuild Notes
Compute BoardRaspberry Pi 5 (4GB RAM)$608GB is overkill unless running local LLMs or heavy ML face recognition.
Power SupplyOfficial 27W USB-C PD PSU$12Mandatory for Pi 5. Third-party 5V/3A supplies will throttle the CPU.
Motion SensorHC-SR501 PIR Module$3Adjust the onboard potentiometers to 3s delay and low sensitivity.
Display Panel24-inch 1080p IPS (e.g., Dell P2425H)$130IPS is required for viewing angles. Remove the plastic bezel for the mirror frame.
Mirror GlassTwo-way acrylic (1/8 inch)$45Acrylic is lighter and safer than glass for wall mounting.

Hardware Assembly & GPIO Pin Mapping

To prevent LCD burn-in and save power, the mirror should only be illuminated when someone is standing in front of it. We use the HC-SR501 PIR sensor to trigger the Pi's display power state via GPIO.

Callout Tip: The HC-SR501 has two orange potentiometers. Use a small Phillips screwdriver to turn the Time Delay pot fully counter-clockwise (minimum ~3 seconds) and the Sensitivity pot to the middle. This prevents the sensor from triggering on your cat walking by three rooms away.

PIR to Raspberry Pi Pin Mapping

HC-SR501 PinRaspberry Pi 5 PinGPIO / FunctionWire Color (Typical)
VCCPin 25V PowerRed
GNDPin 6GroundBlack
OUTPin 11GPIO 17Yellow

The Motion-Wake Python Script (Bookworm Compatible)

Raspberry Pi OS Bookworm shifted the default display server from X11 to Wayland. Old tutorials telling you to use xset dpms force off will fail silently. The correct, compositor-agnostic method is to use the vcgencmd utility provided by the Raspberry Pi firmware.

This script targets the Raspberry Pi 4 and 5 on Bookworm 64-bit. It uses the gpiozero library for reliable edge-detection on the PIR pin.

#!/usr/bin/env python3
import time
import subprocess
import logging
from gpiozero import MotionSensor
from threading import Timer

# Target: Raspberry Pi 4 / 5 (Bookworm 64-bit)
PIR_PIN = 17
TIMEOUT_SECONDS = 120

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
pir = MotionSensor(PIR_PIN, queue_len=5, threshold=0.6)

def toggle_display(state):
    # state: 0 = off, 1 = on
    cmd = f'vcgencmd display_power {state}'
    try:
        subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True)
        logging.info(f'Display powered {"ON" if state else "OFF"}')
    except subprocess.CalledProcessError as e:
        logging.error(f'Failed to toggle display: {e.stderr}')

class ScreenSaver:
    def __init__(self, timeout):
        self.timeout = timeout
        self.timer = None
        self.is_awake = False

    def wake(self):
        if not self.is_awake:
            toggle_display(1)
            self.is_awake = True
        self.reset_timer()

    def sleep(self):
        toggle_display(0)
        self.is_awake = False

    def reset_timer(self):
        if self.timer:
            self.timer.cancel()
        self.timer = Timer(self.timeout, self.sleep)
        self.timer.start()

if __name__ == '__main__':
    saver = ScreenSaver(TIMEOUT_SECONDS)
    logging.info('MagicMirror PIR Wake Service Started...')
    
    try:
        # Initial state
        saver.wake()
        
        # Bind events
        pir.when_motion = saver.wake
        
        # Keep script alive
        while True:
            time.sleep(1)
            
    except KeyboardInterrupt:
        logging.info('Shutting down PIR service.')
        if saver.timer:
            saver.timer.cancel()
        toggle_display(1) # Leave screen on upon exit for debugging

Save this as /home/pi/mirror_wake.py and create a systemd service to run it on boot. This ensures your mirror sleeps automatically if you leave the house.

Debugging: Fixing Electron & Boot Errors

If your mirror boots to a black screen or dumps you back to the terminal, you have likely hit an Electron or Node.js dependency failure.

The Exact Error String

The most common failure during npm install on ARM64 boards is:

npm ERR! code 1
npm ERR! path /home/pi/MagicMirror/node_modules/electron
npm ERR! command failed
npm ERR! command sh -c node install.js

First Three Things to Check When It Fails

  1. Node.js Version Mismatch: MagicMirror² currently requires Node.js 20.x or higher. If you are running Node 16 or 18 from an old tutorial, Electron will fail to compile its ARM64 binaries. Purge your current Node and install the 20.x LTS via NodeSource.
  2. Architecture Confusion (armhf vs arm64): If you flashed the 32-bit Raspberry Pi OS but are trying to install 64-bit Electron modules, the install.js script will crash. Verify your OS with uname -m (it should say aarch64).
  3. Network Timeouts: The Electron binary is ~90MB. On a weak WiFi signal, the download times out silently, leaving a corrupted dist folder.

Ranked Causes & Fixes

CauseFix / Command
Corrupted Electron CacheRun rm -rf node_modules/electron/dist then npm run install-mm in the MagicMirror root.
Missing Build ToolsRun sudo apt install build-essential python3-dev to satisfy node-gyp requirements for native modules.
Server.js Boot DelayIf you see ERR_CONNECTION_REFUSED in the Electron logs, your server is booting slower than the UI. Increase the electronOptions.webPreferences.nodeIntegration delay in config.js.

Extending and Simplifying Your Build

Once the core is stable, you have two paths: adding complexity or abstracting it away.

How to Extend:
Add the MMM-Remote-Control module to edit your config.js from your smartphone. For multi-user households, integrate MMM-Face-Reco using a Raspberry Pi Camera Module 3. This module uses OpenCV to detect faces and swap the UI layout based on who is standing in front of the mirror. Note that face recognition will push the Pi 5's CPU usage to ~40%, so ensure your enclosure has passive cooling heatsinks on the SoC.

How to Simplify:
If fighting with npm, Wayland, and systemd services sounds miserable, skip the manual Linux setup entirely. Flash MagicMirror OS (a pre-configured BalenaOS image) directly to your microSD card using the Raspberry Pi Imager. It handles the Electron wrapper, display sleep, and OTA updates via a web dashboard, reducing your setup time from 4 hours to 15 minutes.

MagicMirror Raspberry Pi FAQ

Can I run a MagicMirror Raspberry Pi on a Pi Zero 2 W?

Yes, but with severe limitations. The Pi Zero 2 W has only 512MB of RAM. The Electron wrapper alone consumes ~350MB. If you add more than two lightweight modules (like a basic clock and weather), the system will swap to the microSD card, causing massive lag and card corruption. To use a Zero 2 W, you must run MagicMirror in 'server-only' mode and use a lightweight kiosk browser like Midori instead of Electron.

Why is my MagicMirror Raspberry Pi screen burning in?

Static white text (like the default clock and calendar borders) left on an LCD or OLED panel for weeks will cause permanent image retention. You must implement the PIR motion-wake script provided above to physically cut power to the display backlight when the room is empty. Additionally, enable the built-in screen-saver module in your config.js to shift pixels slightly during idle times.

How do I update MagicMirror modules without breaking the core?

Never run npm update in the root /home/pi/MagicMirror directory; this will overwrite core dependencies and likely break the Electron wrapper. To update a specific third-party module, navigate into its folder (e.g., cd modules/MMM-Weather), run git pull, and then run npm install only if the module's documentation explicitly states that dependencies have changed.

Does the MagicMirror Raspberry Pi work on Raspberry Pi OS Bookworm 64-bit?

Yes, Bookworm 64-bit is the recommended OS for the Pi 5. However, because Bookworm defaults to the Wayland display server instead of X11, older modules that rely on X11 window management (like forced fullscreen or screen rotation scripts) will fail. You must use Wayland-compatible commands like wlr-randr or the firmware-level vcgencmd for display manipulation.