A Raspberry Pi Stream Deck Server controlled by ESPHome
I’ve turned one of my Raspberry Pi 4s into a dedicated Stream Deck hub. It’s hooked up to a 32-button Stream Deck that controls devices and automations in Home Assistant, which runs on a separate machine. The Pi’s only job is to sit there, listen, and push out commands — but if it ever hangs or I need to reboot it, I wanted a way to manage it properly without pulling cables.
That’s where the ESP32 comes in. I flashed it with ESPHome and wired it straight into the Pi’s GPIO pins so I can treat the whole setup like a real smart-home appliance: I can power it on, shut it down safely, reboot it, and always know its current state inside Home Assistant.
⸻
How I Wired It
The wiring is pretty simple. Raspberry Pi GPIO14 goes into ESP32 GPIO27, which gives me feedback about whether the Pi is on or off. The Pi’s RUN pins are connected to ESP32 GPIO13, so I can pulse them to power it on. For shutdown and reboot, I used GPIO26 and GPIO13 on the Pi, wired to ESP32 pins that trigger those actions.
This way, the ESP32 can send commands to the Pi, and the Pi can talk back about its state.
⸻
My ESPHome Config
On the ESP32, I wrote an ESPHome config with a few pieces:
- A template switch that acts as the main power control. It checks the binary sensor to see if the Pi is already on before trying to pulse the RUN pins.
- A shutdown switch that pulls Pi GPIO26 high, which my shutdown script listens for.
- A reboot button that does the same thing with GPIO13 for rebooting.
- A binary sensor tied to GPIO14 that tells me if the Pi is running or not.
Here’s the core YAML I’m running:
switch:
- platform: template
name: "Raspberry Pi Switch"
id: raspberry_pi_switch
lambda: |-
return id(raspberry_pi_power_state).state;
turn_on_action:
- if:
condition:
lambda: 'return !id(raspberry_pi_power_state).state;'
then:
- switch.turn_on: turn_on_pi
turn_off_action:
- switch.turn_on: turn_off_pi
- platform: gpio
name: "Turn On Raspberry Pi"
pin: GPIO13
inverted: true
id: turn_on_pi
internal: true
on_turn_on:
- delay: 500ms
- switch.turn_off: turn_on_pi
- platform: gpio
name: "Shutdown Raspberry Pi"
pin: GPIO12
id: turn_off_pi
internal: true
on_turn_on:
- delay: 500ms
- switch.turn_off: turn_off_pi
- platform: gpio
name: "Reboot Raspberry Pi"
pin: GPIO14
id: reboot_pi
internal: true
on_turn_on:
- delay: 500ms
- switch.turn_off: reboot_pi
binary_sensor:
- platform: gpio
pin: GPIO27
name: "Raspberry Pi Power State"
id: raspberry_pi_power_state
device_class: power
filters:
- delayed_on_off: 800ms
⸻
The Pi Side
On the Raspberry Pi, I wrote two tiny Python scripts. One listens on GPIO26 and calls shutdown now, the other listens on GPIO13 and calls reboot. They just loop forever in the background, waiting for a HIGH signal from the ESP32:
# shutdown_monitor.py
import RPi.GPIO as GPIO, time, os
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
while True:
if GPIO.input(26) == GPIO.HIGH:
os.system("sudo shutdown now")
time.sleep(0.5)
# reboot_pi.py
import RPi.GPIO as GPIO, time, os
GPIO.setmode(GPIO.BCM)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
while True:
if GPIO.input(13) == GPIO.HIGH:
os.system("sudo reboot")
time.sleep(0.5)
I wrapped both of these in simple systemd services so they start automatically on boot and restart if they crash. That way, the Pi is always listening for signals from the ESP32.
⸻
What It Feels Like in Practice
Now, inside Home Assistant, the Pi just shows up like any other smart switch. If it’s off, flipping the switch pulses the RUN pins and boots it up. If it’s on, flipping the switch triggers the shutdown script and powers it down cleanly. There’s also a reboot button when I need it. And the binary sensor tied to GPIO14 means I always know its current state.
The best part is how natural it feels. The Pi and Stream Deck live on my desk like a little smart-home console, but behind the scenes it’s running with the same polish you’d expect from a dedicated appliance. Everything is local, reliable, and integrated with the rest of my Home Assistant setup.
It’s one of those projects where the wiring is simple, the software is lightweight, but the result makes my whole setup feel more “finished.”