基于Raspberry Pi 4 GPIO事件触发Xorg空闲时间重置/停止feh屏保的方案咨询(含NodeRed实现路径)
Perfect scenario to solve without reinventing the wheel! Let’s walk through three solid, interrupt-driven solutions that play nice with your existing Node-RED setup and avoid GPIO conflicts:
1. Use Node-RED Directly (Simplest, No Extra Tools)
Since Node-RED already has exclusive access to your GPIO button, leverage that to control the screensaver directly—no need to fight over pins:
- Kill feh when the button is pressed
Add anexecnode to your Node-RED flow, triggered by the GPIO button input. Configure it to run this command:
If you’re running feh with specific arguments (like slideshow mode), make it more precise to avoid killing unrelated processes:pkill fehpkill -f "feh --slideshow /path/to/images" - Reset Xorg idle time (instead of killing feh)
If you prefer to keep feh running but reset the idle timer so your xprintidle script doesn’t trigger it, installxdotoolfirst:
Then use this command in the Node-REDsudo apt install xdotoolexecnode to simulate a tiny, invisible mouse movement (resets the idle counter):
This works because Xorg registers mouse movement as user activity, resetting the idle timer tracked byxdotool mousemove 1 1 && xdotool mousemove 0 0xprintidle.
2. System-Level GPIO Interrupts with libgpiod (Avoid Library Conflicts)
If you want a standalone solution that doesn’t rely on Node-RED, use libgpiod—the official kernel-level GPIO library for Raspberry Pi, which supports multiple processes accessing GPIO pins safely (no conflict with Node-RED’s GPIO usage):
- Install the required packages:
sudo apt install gpiod python3-gpiod - Create a Python script (e.g.,
screensaver_stop.py) with this interrupt-driven code (replace the GPIO pin number with yours):import gpiod import subprocess # Configure your GPIO pin (adjust line number to match your button) CHIP_NAME = "gpiochip0" BUTTON_PIN = 17 # Set up GPIO line for edge detection (adjust edge type for your hardware) chip = gpiod.Chip(CHIP_NAME) button_line = chip.get_line(BUTTON_PIN) request_config = gpiod.line_request() request_config.request_type = gpiod.line_request.EVENT_FALLING_EDGE request_config.consumer = "screensaver_handler" try: button_line.request(request_config) print("Waiting for button press...") while True: # Wait for a GPIO event (interrupt-driven, no polling!) if button_line.event_wait(sec=1): event = button_line.read_event() # Trigger screensaver stop subprocess.run(["pkill", "feh"], check=False) # Optional: Reset idle time instead # subprocess.run(["xdotool", "mousemove", "1", "1", "&&", "xdotool", "mousemove", "0", "0"], shell=True, check=False) finally: button_line.release() chip.close() - Run the script on startup (add it to
rc.localor create a systemd service) so it runs in the background.
3. Inter-Process Communication (IPC) Between Python Script and Node-RED
If you want to keep your existing xprintidle/Python screensaver logic intact, set up IPC to let Node-RED notify the script when the button is pressed:
- Local MQTT Broker: Install Mosquitto on your Pi (
sudo apt install mosquitto mosquitto-clients). In Node-RED, add anMQTT Outnode that sends a message (e.g.,stop_screensaver) to a local topic (likehome/screensaver/control) when the button is pressed. Modify your Python script to subscribe to this topic and trigger the screensaver stop when the message is received. - Unix Socket: Add a simple Unix socket server to your Python script. In Node-RED, use an
execnode to send a short message to the socket (e.g.,echo "stop" | nc -U /tmp/screensaver.sock), which triggers the script to kill feh or reset the idle timer.
内容的提问来源于stack exchange,提问作者Valentino

