To turn on a Raspberry Pi 5 in a custom enclosure, wire an external momentary switch to the PWR and GND pads near the USB-C port, and use a Python gpiozero script on GPIO 17 to trigger a safe OS shutdown. Unlike older models, the Pi 5 features a dedicated Power Management IC (PMIC) that natively handles wake-from-sleep and hard power latching, eliminating the need for bulky external MOSFET circuits.

This guide targets the Raspberry Pi 5 (8GB variant) running Raspberry Pi OS Bookworm 64-bit. We will cover the hardware wiring, the required EEPROM bootloader configuration, and the exact Python script to handle safe shutdowns without corrupting your SD card.

The Decision Path: How Do You Want to Turn It On?

Before stripping wires, decide which power control architecture fits your physical build. The Pi 5's new PMIC changes the rules for embedded power management.

Scenario Method Concrete Pick
Hard AC cutoff needed (kiosk/remote) Smart Plug + EEPROM Auto-Boot Kasa EP25 + BOOT_UART=1
ATX-style soft latch (battery/solar) External MOSFET HAT Pololu RC Switch #2808
Native PMIC integration (custom enclosure) External tactile switch on PWR pads Custom 2-pin JST + GPIO 17 script (Default Pick)

The Verdict: For 90% of custom enclosure builds, terminating on the Native PMIC integration is the correct choice. It uses the Pi 5's built-in hardware, requires no external relay HATs, and draws zero parasitic current when off.

Parts List & Pin Mapping for the Pi 5 PMIC Circuit

Safety & Hardware Warning: The Pi 5's RP1 I/O chip operates at 3.3V and is highly sensitive to overvoltage. Never wire 5V directly to the GPIO header. The external power button uses the dedicated PMIC pads, which are completely isolated from the 3.3V GPIO logic.

Required Components

  • Board: Raspberry Pi 5 (8GB)
  • OS: Raspberry Pi OS Bookworm 64-bit (Desktop or Lite)
  • Power Supply: Official Raspberry Pi 27W USB-C PD Power Supply (5V/5A). Note: Standard 5V/3A phone chargers will trigger a brownout warning and restrict USB current.
  • Switch: 6x6mm Momentary Tactile Switch (normally open)
  • Wake Connector: 2-pin JST SH 1.0mm pitch cable (for the PMIC pads)
  • Shutdown Resistor: 10kΩ through-hole resistor (for GPIO pull-up)

Pin Mapping Table

Function Pi 5 Pin / Pad Wired To Notes
Hard Wake / Power On PMIC PWR pad Switch Terminal 1 Located near USB-C port
Hard Wake Ground PMIC GND pad Switch Terminal 2 Shorting PWR to GND wakes the board
Safe Shutdown Signal GPIO 17 (Header Pin 11) 10kΩ Resistor -> 3.3V (Pin 1) Pulled high; button pulls low
Shutdown Ground GND (Header Pin 9) Shutdown Switch Terminal 2 Common ground for GPIO logic

Step-by-Step: Wiring and EEPROM Configuration

The Pi 5's bootloader defaults to a low-power halt state that sometimes ignores external wake signals. We must configure the EEPROM before wiring the hardware.

1. Configure the Bootloader EEPROM

  1. Open a terminal on your Pi 5 and edit the EEPROM configuration:
    sudo rpi-eeprom-config --edit
  2. Locate or add the following two lines to ensure the board fully powers down the PMIC and listens for the external pad short:
    POWER_OFF_ON_HALT=1
    WAKE_ON_GPIO=1
  3. Save and exit (Ctrl+O, Enter, Ctrl+X in nano). Reboot the Pi to apply the changes:
    sudo reboot

2. Wire the External Wake Pads

  1. Solder the 2-pin JST SH connector to the PWR and GND pads located just behind the USB-C power connector. These pads are tiny; use flux and a fine-tip iron.
  2. Connect the other end of the JST cable to your external momentary tactile switch.
  3. Press the button. The Pi 5 should immediately boot. Pressing it again while running will trigger a hard reset (we will fix this with the software script next).

3. Wire the GPIO Shutdown Button

  1. Connect one leg of your 10kΩ resistor to Pin 1 (3.3V) and the other leg to Pin 11 (GPIO 17). This creates a hardware pull-up.
  2. Wire your secondary shutdown button between Pin 11 (GPIO 17) and Pin 9 (GND). When pressed, it pulls GPIO 17 low, signaling the OS to shut down safely.

The Safe Shutdown Python Script (Bookworm OS)

Raspberry Pi OS Bookworm deprecated the legacy RPi.GPIO library in favor of lgpio via the gpiozero interface. The script below listens for the GPIO 17 pull-down event, initiates a graceful shutdown, and handles the specific import errors common to the Pi 5.

#!/usr/bin/env python3
"""
Raspberry Pi 5 Safe Shutdown Script
Target: Raspberry Pi 5 (8GB) / Raspberry Pi OS Bookworm 64-bit
Author: ElectricalFlux
"""
import sys
import time
import os
import logging

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

try:
    from gpiozero import Button
except ImportError as e:
    logging.critical(f'Missing dependency: {e}. Run: sudo apt install python3-gpiozero')
    sys.exit(1)
except Exception as e:
    # Catches the common Bookworm lgpio BadPinFactory error
    logging.critical(f'Pin factory error: {e}. Run: sudo apt install python3-lgpio')
    sys.exit(1)

# PIN DEFINITIONS (BCM Numbering)
SHUTDOWN_PIN = 17  # Physical Pin 11
HOLD_TIME = 2.0    # Seconds to hold button to trigger shutdown (prevents accidental bumps)

def initiate_shutdown():
    logging.warning('GPIO 17 pulled low. Initiating safe system shutdown...')
    # Flush filesystem buffers before cutting power
    os.system('sync')
    time.sleep(0.5)
    # Execute shutdown command
    os.system('sudo shutdown -h now')

def main():
    logging.info(f'Initializing shutdown listener on BCM GPIO {SHUTDOWN_PIN}')
    
    # Initialize button with internal pull-up as a fallback to the hardware 10k resistor
    # pull_up=True means the pin reads HIGH (1) normally, and LOW (0) when pressed to GND
    shutdown_btn = Button(SHUTDOWN_PIN, pull_up=True, hold_time=HOLD_TIME, bounce_time=0.1)
    
    # Bind the hold event to our shutdown function
    shutdown_btn.when_held = initiate_shutdown
    
    logging.info('Listener active. Hold button for 2 seconds to shutdown.')
    
    try:
        # Keep the script running in the background
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        logging.info('Script terminated by user.')
        sys.exit(0)

if __name__ == '__main__':
    main()
Deployment Tip: Save this file as /home/pi/safe_shutdown.py. To run it automatically on boot, add it to your crontab using crontab -e and append:
@reboot /usr/bin/python3 /home/pi/safe_shutdown.py &

Debugging: When the Boot Sequence Fails

When integrating custom power circuits on the Pi 5, you will inevitably hit software or hardware snags. Here is how to diagnose them.

The #1 Software Error: BadPinFactory

If your script crashes immediately with the following exact error string:

gpiozero.exc.BadPinFactory: Unable to load any default pin factory!

Ranked Causes & Fixes:

  1. Missing lgpio backend: Bookworm dropped RPi.GPIO. The gpiozero library requires the lgpio C-extension to talk to the Pi 5's RP1 chip.
    Fix: Run sudo apt update && sudo apt install python3-lgpio.
  2. Virtual Environment Isolation: If you are running this inside a Python venv, it cannot see the system-installed lgpio bindings.
    Fix: Recreate your venv using the --system-site-packages flag, or install the pip wheel directly inside the venv.
  3. Peripheral Collision: You have enabled an I2C or SPI overlay in /boot/firmware/config.txt that is hogging the pin factory initialization.
    Fix: Temporarily comment out all dtparam= lines in config.txt and reboot.

Hardware Failure: The First 3 Things to Check

If the software is clean but the physical button refuses to turn on the Raspberry Pi, check these three hardware states:

  1. Power Supply Wattage & PD Negotiation: The Pi 5 requires a 5V/5A USB-C PD handshake to unlock full current limits. If you are using a standard 5V/3A phone charger, the PMIC may refuse to boot under load. Check the boot logs for WARNING: Current limit is 600 mA. Swap to the official 27W Pi PSU.
  2. EEPROM Configuration Persistence: Run vcgencmd bootloader_config | grep POWER_OFF. If it returns POWER_OFF_ON_HALT=0, your EEPROM edit didn't save. Re-run the rpi-eeprom-config command. Without this set to 1, the PMIC stays in a low-power idle state that ignores the external PWR pad short.
  3. Pad Continuity & Solder Bridges: The PWR and GND pads are spaced less than 2mm apart. Use a multimeter in continuity mode to verify your JST connector isn't bridging the two pads with a microscopic solder whisker. A dead short here will prevent the PMIC from latching power.

Extending or Simplifying Your Power Build

Depending on your enclosure constraints and production volume, you may want to pivot from this custom circuit.

How to Simplify (The 'Buy, Don't Build' Route)

If you don't want to solder microscopic JST connectors to the PMIC pads, purchase the Pololu Soft Latching Power Button (RC Switch #2808). It costs around $12, handles up to 15A, and physically cuts the 5V rail to the Pi when shut down. You wire it inline between your USB-C breakout board and the Pi's 5V/GND GPIO pins. It requires no EEPROM tweaks and provides a true zero-parasitic-drain hard cutoff, which is superior for battery-powered remote sensors.

How to Extend (Adding Scheduled Wake)

If your project needs to wake up at a specific time of day (e.g., a remote weather station), the PMIC pads alone won't cut it. Extend the build by adding a DS3231 Real Time Clock (RTC) module wired to the I2C bus (GPIO 2/3). Configure the DS3231's INT/SQW pin to pull low at a specific alarm time, and wire that INT pin directly to the Pi 5's PWR pad. When the alarm triggers, it simulates a physical button press, waking the Pi 5 from its POWER_OFF_ON_HALT state.

For comprehensive pinout diagrams and PMIC specifications, always refer to the official Raspberry Pi 5 Hardware Documentation and the gpiozero library documentation for Bookworm-specific pin factory behaviors.