A Python service for Raspberry Pi CM5 that automatically controls HDMI display power based on motion detection using an LD2410C radar sensor. The display turns off after a configurable timeout period when no motion is detected, and turns back on immediately when motion is detected.
- Automatic Display Control: Uses Wayland
wlopm
for reliable display power management - Smart Motion Detection: Advanced filtering to prevent false positives from micro-movements
- Configurable Sensitivity: Adjustable thresholds for different environments
- Systemd Integration: Runs as a user service with automatic startup
- Robust Operation: Built-in error handling and recovery mechanisms
- Minimal Dependencies: Lightweight Python implementation
- Raspberry Pi CM5 with GPIO pins
- LD2410C radar sensor
- HDMI display connected to Pi
Connect the LD2410C sensor to your Raspberry Pi:
LD2410C -> Raspberry Pi CM5
VCC -> 5V (Pin 4)
GND -> GND (Pin 6)
TX -> GPIO 14 (Pin 8)
RX -> GPIO 15 (Pin 10)
Pin Layout:
1 3.3V 5V 2
3 GPIO2 5V 4
5 GPIO3 GND 6
7 GPIO4 TX 8 <- LD2410C TX to GPIO 14
9 GND RX 10 <- LD2410C RX to GPIO 15
- Python 3.7+
- lgpio - GPIO access library
- wlopm - Wayland display power management
-
Clone and Install:
git clone <repository-url> motion-standby cd motion-standby ./install_service.sh
-
Start the Service:
systemctl --user start motion-standby
-
Check Status:
systemctl --user status motion-standby
The service is configured via motion_config.json
:
{
"timeout_minutes": 30,
"check_interval_seconds": 1,
"sensor": {
"rx_pin": 14,
"tx_pin": 15
},
"log_level": "INFO",
"detection_threshold": 5,
"motion_duration_min": 3.0,
"cooldown_period": 10.0,
"debounce_time": 0.3
}
Parameter | Default | Description |
---|---|---|
timeout_minutes |
30 | Minutes of inactivity before display turns off |
check_interval_seconds |
1 | How often to check for motion (seconds) |
sensor.rx_pin |
14 | GPIO pin for sensor RX (UART communication) |
sensor.tx_pin |
15 | GPIO pin for sensor TX (UART communication) |
log_level |
INFO | Logging level (DEBUG, INFO, WARNING, ERROR) |
detection_threshold |
5 | Consecutive positive readings required for motion |
motion_duration_min |
3.0 | Minimum seconds of motion to trigger |
cooldown_period |
10.0 | Seconds to wait between motion detections |
debounce_time |
0.3 | Anti-jitter delay between sensor readings |
The LD2410C sensor is very sensitive and may detect micro-movements. The service includes multiple filtering mechanisms:
-
Detection Threshold (
detection_threshold
):- Number of consecutive positive readings needed
- Higher = less sensitive, fewer false positives
- Range: 3-10 (recommended: 5)
-
Motion Duration (
motion_duration_min
):- Minimum time motion must persist
- Filters out brief micro-movements
- Range: 1.0-5.0 seconds (recommended: 3.0)
-
Cooldown Period (
cooldown_period
):- Time to wait after detecting motion before detecting again
- Prevents rapid re-triggering
- Range: 5.0-30.0 seconds (recommended: 10.0)
-
Debounce Time (
debounce_time
):- Anti-jitter delay between sensor readings
- Smooths out electrical noise
- Range: 0.1-1.0 seconds (recommended: 0.3)
For Quiet Environments (minimal movement):
{
"detection_threshold": 3,
"motion_duration_min": 2.0,
"cooldown_period": 5.0
}
For Normal Environments (occasional movement):
{
"detection_threshold": 5,
"motion_duration_min": 3.0,
"cooldown_period": 10.0
}
For Active Environments (frequent movement):
{
"detection_threshold": 7,
"motion_duration_min": 4.0,
"cooldown_period": 15.0
}
For Noisy Environments (many false positives):
{
"detection_threshold": 8,
"motion_duration_min": 5.0,
"cooldown_period": 20.0
}
Use the test mode to validate your configuration:
# Test with debug logging and 1-minute timeout
python3 motion_standby.py --test --no-timeout
# Test with custom timeout
python3 motion_standby.py --test --timeout 2
# Test current configuration
python3 motion_standby.py --test --log-level DEBUG
python3 motion_standby.py [options]
Flag | Description | Example |
---|---|---|
--config FILE |
Use custom configuration file | --config custom.json |
--timeout MINS |
Override timeout setting | --timeout 15 |
--no-timeout |
Use 1-minute timeout for testing | --no-timeout |
--test |
Enable debug logging for testing | --test |
--log-level LEVEL |
Set logging level | --log-level DEBUG |
Quick Test (1-minute timeout, verbose output):
python3 motion_standby.py --test --no-timeout
Custom Timeout Test:
python3 motion_standby.py --timeout 5 --log-level DEBUG
Test with Custom Config:
python3 motion_standby.py --config test_config.json --test
Production Run (normal logging):
python3 motion_standby.py
./install_service.sh
The installation script:
- Creates Python virtual environment
- Installs dependencies
- Sets up sudo permissions for display control
- Creates systemd user service
- Configures Wayland environment variables
# Start service
systemctl --user start motion-standby
# Stop service
systemctl --user stop motion-standby
# Restart service
systemctl --user restart motion-standby
# Check status
systemctl --user status motion-standby
# Enable auto-start
systemctl --user enable motion-standby
# Disable auto-start
systemctl --user disable motion-standby
# View logs
journalctl --user -u motion-standby -f
# View recent logs
journalctl --user -u motion-standby --since "10 minutes ago"
Service Won't Start:
# Check service status for error details
systemctl --user status motion-standby
# Check journal logs
journalctl --user -u motion-standby --no-pager
Display Control Not Working:
# Test wlopm manually
wlopm --off "*"
wlopm --on "*"
# Check Wayland environment
echo $WAYLAND_DISPLAY
echo $XDG_RUNTIME_DIR
# Test sudo permissions
sudo -u $USER wlopm --off "*"
Motion Detection Issues:
# Test in debug mode
python3 motion_standby.py --test --log-level DEBUG
The service consists of three main components:
- DisplayController: Manages HDMI display power using
wlopm
- MotionSensor: Handles LD2410C sensor with intelligent filtering
- MotionStandbyService: Coordinates motion detection and display control
- Raw Sensor Reading: Reads GPIO state from LD2410C sensor
- Debounce Filter: Prevents electrical noise from causing false readings
- Threshold Filter: Requires multiple consecutive positive readings
- Duration Filter: Motion must persist for minimum duration
- Cooldown Filter: Prevents rapid re-triggering
- Valid Motion: Timer resets, display turns on if needed
The service uses wlopm
(Wayland Light Output Power Management) for reliable display control:
- Turn Off:
wlopm --off "*"
- Turns off all displays - Turn On:
wlopm --on "*"
- Turns on all displays - Fallback: Uses framebuffer blanking if wlopm unavailable
- Main Thread: Handles configuration, signals, and service lifecycle
- Motion Thread: Continuously monitors sensor and detects motion
- Timeout Thread: Monitors inactivity timeout and controls display
Display doesn't turn off/on:
- Check that
wlopm
is installed:which wlopm
- Verify Wayland environment:
echo $WAYLAND_DISPLAY
- Test manually:
wlopm --off "*"
Motion not detected:
- Check sensor wiring (RX/TX for UART communication)
- Enable debug logging:
--log-level DEBUG
- Verify sensor power: LD2410C should have power LED
- Check UART communication in logs
Too many false positives:
- Increase
detection_threshold
(try 7-8) - Increase
motion_duration_min
(try 4-5 seconds) - Increase
cooldown_period
(try 15-20 seconds)
Service fails to start:
- Check virtual environment:
ls .venv/bin/python
- Verify permissions:
ls -l motion_standby.py
- Check logs:
journalctl --user -u motion-standby
Enable verbose logging to troubleshoot issues:
python3 motion_standby.py --test --log-level DEBUG
This shows:
- Raw sensor readings
- Filter states
- Motion detection logic
- Display control commands
- Timing information
Normal Operation:
INFO - Motion sensor initialized - Pin:15, Threshold:5, Duration:3.0s, Cooldown:10.0s
INFO - Display controller initialized using wlopm
INFO - Motion Standby Service started successfully
INFO - MOTION DETECTED - Timer reset (30 minutes)
INFO - Standby timeout reached - turning off display
INFO - Display turned OFF
Motion Detection Issues:
DEBUG - Raw sensor reading: True
DEBUG - Recent positives: 3/10 (threshold: 5)
DEBUG - Motion duration: 1.2s (minimum: 3.0s)
DEBUG - Still in cooldown period
- Python 3.7+: Core runtime
- gpiozero: GPIO control library
- pyserial: UART communication for LD2410C sensor
- wlopm: Wayland display power management
- systemd: Service management (Linux)
This project is released under the MIT License. See LICENSE file for details.
AI made this, I just told it what to do for a very specific use case.