To build a dedicated, auto-waking Plex Raspberry Pi client, the most stable hardware target in 2026 remains the Raspberry Pi 4 Model B (4GB) running Raspberry Pi OS Lite. While the Pi 5 offers more CPU headroom, its micro-HDMI CEC implementation still requires active adapters that frequently drop CEC bus states, making the Pi 4's full-size HDMI port the superior choice for reliable home theater control. This guide walks through wiring a PIR motion sensor to GPIO 17 to automatically wake your TV via HDMI-CEC and launch the Plex HTPC app, complete with the Python daemon and debugging steps for the inevitable CEC bus lockups.
Project Spec Sheet & Hardware Requirements
Estimated Time: 90 minutes
Target Board: Raspberry Pi 4 Model B (4GB or 8GB variant)
Target OS: Raspberry Pi OS Lite (64-bit, Bookworm release)
| Component | Exact Model / Variant | Estimated Cost (2026) | Notes |
|---|---|---|---|
| Microcontroller | Raspberry Pi 4 Model B (4GB) | $55.00 | Avoid Pi 5 for CEC builds due to micro-HDMI adapter quirks. |
| Sensor | HC-SR501 PIR Motion Sensor | $3.50 | Adjustable delay and sensitivity pots on board. |
| Power Supply | Official 27W USB-C PSU (5.1V / 5A) | $12.00 | Prevents brownout warnings during 4K HEVC decoding. |
| Storage | SanDisk Extreme 32GB microSD (A2) | $9.00 | A2 rating ensures fast IOPS for OS boot and app caching. |
| Cabling | High-Speed HDMI 2.0 Cable (18Gbps) | $8.00 | Must have Pin 13 (CEC) continuity; avoid ultra-cheap cables. |
Pin Mapping & Wiring the Motion Sensor
The HC-SR501 operates at 5V logic but outputs a 3.3V-compatible HIGH signal when motion is detected, making it safe to wire directly to the Pi 4's GPIO bank without a logic level shifter.
| HC-SR501 Pin | Raspberry Pi 4 Pin (Physical) | GPIO / Power Designation |
|---|---|---|
| VCC (Left) | Pin 2 | 5V Power |
| OUT (Middle) | Pin 11 | GPIO 17 |
| GND (Right) | Pin 6 | Ground |
Wiring Steps:
- Disconnect the Pi from power before attaching jumper wires to the GPIO header.
- Connect the sensor's VCC to Pin 2 (5V), GND to Pin 6, and OUT to Pin 11 (GPIO 17).
- Locate the two orange potentiometers on the HC-SR501. Turn the Time Delay pot fully counter-clockwise (minimum ~3 seconds) and the Sensitivity pot to the 12 o'clock position.
- Mount the sensor facing the room's primary seating area. Pro-tip: Keep the Fresnel lens away from HVAC vents and direct sunlight; thermal drafts will cause false-positive triggers that constantly interrupt your Plex playback.
- Boot the Pi and install the required dependencies:
sudo apt update && sudo apt install python3-gpiozero cec-utils.
The Auto-Wake Python Daemon
This Python script uses the gpiozero library to monitor GPIO 17. When motion is detected, it sends a CEC 'on' command to the TV (Logical Address 0) and launches the Plex HTPC binary. Save this as /opt/plex-autowake/daemon.py.
#!/usr/bin/env python3
"""
Plex HTPC Auto-Wake Daemon via PIR & HDMI-CEC
Target Board: Raspberry Pi 4 Model B (4GB)
OS: Raspberry Pi OS Lite (64-bit, Bookworm)
"""
import subprocess
import time
import logging
import os
from gpiozero import MotionSensor
# --- PIN & PATH DEFINITIONS ---
PIR_GPIO_PIN = 17
CEC_CLIENT_PATH = '/usr/bin/cec-client'
PLEX_HTPC_PATH = '/usr/bin/plex-htpc'
LOG_FILE = '/var/log/plex-autowake.log'
# Configure logging
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def wake_display_and_launch():
"""Sends CEC wake command and launches Plex HTPC if not running."""
logging.info('Motion detected. Waking display via CEC...')
# 1. Wake TV via CEC (Logical address 0 = TV)
try:
subprocess.run(
['bash', '-c', f"echo 'on 0' | {CEC_CLIENT_PATH} -s -d 1"],
check=True,
capture_output=True,
timeout=5
)
logging.info('CEC wake command sent successfully.')
except FileNotFoundError:
logging.error('cec-client not found. Install via: sudo apt install cec-utils')
return
except PermissionError:
logging.error('Permission denied on /dev/cec0. Add user to video group.')
return
except subprocess.TimeoutExpired:
logging.warning('CEC bus timed out. TV might be in deep sleep or CEC disabled.')
# 2. Launch Plex HTPC if not already running
try:
result = subprocess.run(['pgrep', '-x', 'plex-htpc'], capture_output=True)
if result.returncode != 0:
logging.info('Launching Plex HTPC...')
# Run detached from the script's lifecycle
subprocess.Popen(
[PLEX_HTPC_PATH],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
else:
logging.info('Plex HTPC already running.')
except FileNotFoundError:
logging.error(f'Plex binary not found at {PLEX_HTPC_PATH}.')
if __name__ == '__main__':
logging.info('Initializing PIR sensor on GPIO %d...', PIR_GPIO_PIN)
pir = MotionSensor(PIR_GPIO_PIN)
# Allow HC-SR501 to calibrate (takes ~30-60 seconds on boot)
time.sleep(60)
logging.info('Sensor calibrated. Waiting for motion...')
while True:
pir.wait_for_motion()
wake_display_and_launch()
# Debounce: Ignore further motion for 5 minutes while watching
time.sleep(300)
Debugging: CEC Errors and the 'First Three' Checks
HDMI-CEC is notoriously fragile. If your script fails to wake the TV or launch the client, do not rewrite the code immediately. Check the physical and OS-level bus states first.
The First Three Things to Check When It Fails
- HDMI Cable Pin 13 Continuity: Some cheap or older HDMI cables omit the CEC wire (Pin 13) to save copper. Swap to a certified 18Gbps cable.
- TV CEC Menu Settings: TV manufacturers rebrand CEC. Ensure it is enabled in your TV settings (Samsung: Anynet+, LG: SimpLink, Sony: BRAVIA Sync, Hisense: HDMI-CEC).
- Linux User Group Permissions: The
/dev/cec0device node is restricted. Ensure your user is in the correct group by runningsudo usermod -aG video,render $USERand rebooting.
Exact Error Strings and Ranked Causes
PermissionError: [Errno 13] Permission denied: '/dev/cec0'Ranked Causes:
1. (90%) Your user is not in the
video group. Fix: sudo usermod -aG video $USER.2. (10%) AppArmor or SELinux is blocking device access (rare on standard Pi OS, common if you ported this to Ubuntu Server).
FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/cec-client'Ranked Causes:
1. (99%) You forgot to install the CEC utilities. Fix:
sudo apt install cec-utils.2. (1%) You are running a minimal containerized OS where the binary path differs. Use
which cec-client to find it and update CEC_CLIENT_PATH in the script.
unable to open the device on port /dev/cec0 (from cec-client stdout)Ranked Causes:
1. (60%) The HDMI cable is unplugged, or the TV is completely powered off at the wall (cutting the 5V CEC bus power).
2. (30%) The CEC bus is locked up by another device (like a Chromecast or FireStick) spamming the bus. Unplug other CEC devices to test.
3. (10%) The Pi's HDMI port is physically damaged. Test the secondary HDMI port (requires modifying
config.txt to map CEC to HDMI1).
Extending or Simplifying the Build
How to Simplify: If you don't want to maintain a custom Python daemon and Raspberry Pi OS, flash LibreELEC to your SD card. LibreELEC boots directly into Kodi. You can install the official Plex for Kodi add-on from the Kodi repository. LibreELEC handles HDMI-CEC natively via its settings GUI, eliminating the need for GPIO sensors or Python scripts entirely. The trade-off is less control over the underlying OS and slightly heavier resource usage from the Kodi UI layer.
How to Extend: To integrate this Pi into a broader smart home ecosystem, add the paho-mqtt Python library to the daemon. You can publish the playback state (by parsing plex-htpc logs or querying the local Plex API) to an MQTT broker, allowing Home Assistant to automatically dim your smart lights when a movie starts and pause playback if a smart doorbell is pressed.
Frequently Asked Questions
Can I use a Raspberry Pi 5 as a Plex client instead of the Pi 4?
Yes, but with caveats. The Pi 5 uses micro-HDMI ports, which often lack reliable CEC passthrough when using cheap micro-to-full HDMI adapters. If you must use a Pi 5 for its AV1 decoding capabilities, buy a high-quality, explicitly CEC-certified micro-HDMI cable rather than an adapter dongle, and ensure your config.txt includes hdmi_drive=2 to force hotplug detection.
Why does my Plex Raspberry Pi client stutter on 4K HEVC playback?
Stuttering on 4K HEVC (H.265) is almost always a thermal or memory bandwidth issue, not a CPU limitation. The Pi 4's hardware decoder handles HEVC natively, but it generates significant heat. If the SoC hits 80°C, it will thermal throttle. Apply a 5V PWM fan to the GPIO (controlled via pwm-fan overlay in config.txt) and ensure you are using the official 27W power supply to prevent USB/SD bus voltage sag during high-bitrate scene changes.
How do I get audio to pass through to my AVR from the Plex Pi client?
By default, the Pi may decode audio to PCM stereo. To pass through Dolby Digital, DTS, or TrueHD to your Audio/Video Receiver, you must enable audio passthrough in the Plex HTPC settings under Audio > Device Type > HDMI and check the formats your AVR supports. Additionally, add hdmi_audio_edid=1 to your Pi's /boot/firmware/config.txt to force the Pi to read the EDID audio capabilities directly from the AVR rather than the TV.
Is LibreELEC better than Raspberry Pi OS for a Plex client?
It depends on your definition of 'better.' LibreELEC is superior for simplicity; it is a Just-Enough-OS built specifically for Kodi, offering native CEC, automatic refresh rate switching, and a polished 10-foot UI out of the box. However, Raspberry Pi OS Lite is better for control. If you want to run a headless daemon, integrate GPIO sensors, run a Pi-hole DNS sinkhole in the background, or use the official standalone Plex HTPC app instead of the Kodi add-on, Raspberry Pi OS is the required path.






