If you want to integrate Google Home with Raspberry Pi to control physical hardware via voice commands, you need a bridge between Google's cloud and your Pi's GPIO pins. The most robust, zero-subscription method in 2026 is running a lightweight FastAPI webhook server on the Pi, exposing it via a Cloudflare Tunnel, and triggering it through Google Home Routines using a free Make.com automation flow.
This guide targets the Raspberry Pi 5 (4GB variant) running Raspberry Pi OS Bookworm (64-bit). We will use the modern lgpio backend, as the legacy RPi.GPIO library is officially deprecated and broken on Bookworm.
The Architecture Decision: Bridging Google Home and Pi
Before wiring a single pin, you must choose how Google Home talks to your Pi. Google does not allow raw HTTP webhooks directly from the Google Home app without a middleware bridge. Use this decision tree to pick your path.
| If your priority is... | Choose this Architecture | Middleware Required |
|---|---|---|
| Zero cost, fast setup, no local server bloat | FastAPI on Pi + Cloudflare Tunnel + Make.com Webhook | Make.com (Free Tier) |
| Local-only execution, no internet dependency | Home Assistant OS on Pi + Nabu Casa ($65/yr) | Home Assistant + Nabu Casa |
| Native Google Home discovery (no routines needed) | Matter Protocol Endpoint (ESP32 wired to Pi) | Google Home Developer Console + Matter SDK |
Hardware BOM and GPIO Pin Mapping
The Raspberry Pi 5 operates at 3.3V logic. Standard 5V Arduino relay modules will not trigger reliably and can backfeed voltage into the Pi's SoC. You must use a 3.3V-native relay or an optocoupler module designed for 3.3V logic.
Parts List
- Board: Raspberry Pi 5 (4GB RAM) - ~$60
- Power: CanaKit 35W USB-C Pi 5 Power Supply (Official spec) - ~$20
- Relay Module: HiLetgo 4-Channel 3.3V Relay Module with Optocoupler - ~$9
- Load (Bench Safe): 12V DC LED Strip (Do not test with 120V AC mains until you have a licensed electrician verify your enclosure and wire gauges).
- Wiring: 22 AWG solid core jumper wires.
Pin Mapping Table (BCM Numbering)
The code below uses Broadcom (BCM) pin numbering. Physical pin numbers are provided for your ribbon cable reference.
| BCM Pin | Physical Pin | Relay Channel | Function |
|---|---|---|---|
| 17 | 11 | IN1 | Relay 1 Control (Active LOW) |
| 27 | 13 | IN2 | Relay 2 Control (Active LOW) |
| 22 | 15 | IN3 | Relay 3 Control (Active LOW) |
| 23 | 16 | IN4 | Relay 4 Control (Active LOW) |
| GND | 9 | GND | Common Ground (Pi to Relay VCC-) |
| 3.3V | 1 | VCC | Optocoupler LED Power (3.3V) |
Software Setup: FastAPI Webhook Server
We use FastAPI because it is asynchronous, lightweight, and automatically generates documentation. We use gpiozero with the lgpio factory to comply with Raspberry Pi OS Bookworm requirements.
- Flash Raspberry Pi OS (64-bit, Bookworm) to your microSD using Raspberry Pi Imager. Enable SSH and configure WiFi in the advanced settings.
- SSH into your Pi and update the system:
sudo apt update && sudo apt upgrade -y sudo apt install python3-venv python3-pip libgpiod2 -y - Create a project directory and virtual environment:
mkdir ~/google-home-pi && cd ~/google-home-pi python3 -m venv venv source venv/bin/activate - Install the required Python packages:
pip install fastapi uvicorn gpiozero rpi-lgpio pydantic
The Complete Python Control Code
Save the following code as main.py in your project directory. This script initializes the pins, sets up a POST endpoint, and includes a static API key dependency to prevent unauthorized toggling if your Cloudflare tunnel is exposed.
import os
import logging
from fastapi import FastAPI, HTTPException, Header, Depends
from gpiozero import OutputDevice
from pydantic import BaseModel
# CRITICAL: Force lgpio backend for Pi 5 / Bookworm OS compatibility
os.environ['GPIOZERO_PIN_FACTORY'] = 'lgpio'
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Pin Definitions (BCM)
RELAY_PINS = {
1: 17,
2: 27,
3: 22,
4: 23
}
# Initialize Relays (Active LOW for standard optocoupler modules)
relays = {}
for ch, pin in RELAY_PINS.items():
try:
relays[ch] = OutputDevice(pin, active_high=False, initial_value=False)
logger.info(f"Initialized Relay {ch} on BCM Pin {pin}")
except Exception as e:
logger.error(f"Failed to initialize pin {pin}: {e}")
app = FastAPI(title="Pi GPIO Webhook Controller")
# Security: Replace this with a strong random string in production
API_KEY = "super_secret_make_com_webhook_key_2026"
async def verify_api_key(authorization: str = Header(...)):
if authorization != f"Bearer {API_KEY}":
raise HTTPException(status_code=401, detail="Invalid API Key")
class RelayCommand(BaseModel):
relay_id: int
state: bool # True = ON (Normally Open closed), False = OFF
@app.post("/api/v1/relay", dependencies=[Depends(verify_api_key)])
async def control_relay(command: RelayCommand):
if command.relay_id not in relays:
raise HTTPException(status_code=404, detail=f"Relay ID {command.relay_id} not found. Valid IDs: {list(relays.keys())}")
relay = relays[command.relay_id]
try:
if command.state:
relay.on()
logger.info(f"Relay {command.relay_id} turned ON")
return {"status": "success", "message": f"Relay {command.relay_id} is now ON"}
else:
relay.off()
logger.info(f"Relay {command.relay_id} turned OFF")
return {"status": "success", "message": f"Relay {command.relay_id} is now OFF"}
except Exception as e:
logger.error(f"Hardware toggle failed: {e}")
raise HTTPException(status_code=500, detail=f"Hardware error: {str(e)}")
if __name__ == "__main__":
import uvicorn
# Run on port 8000, accessible on local network
uvicorn.run(app, host="0.0.0.0", port=8000)
To run the server, execute: python3 main.py. To expose this to Google Home, install cloudflared on the Pi and create a tunnel pointing to http://localhost:8000. In Make.com, create a scenario: Google Home Routine Trigger -> Webhooks (POST) -> Paste your Cloudflare URL and Bearer token.
Debugging: Exact Error Strings and Fixes
When working with Pi 5 hardware and web frameworks, you will hit specific roadblocks. Here are the exact error strings and how to fix them.
Error 1: GPIO Access Denied
Exact String: RuntimeError: No access to /dev/mem. Try running as root! or gpiozero.exc.PinFactoryFallback: Falling back to rpigpio... ImportError: No module named 'RPi.GPIO'
Ranked Causes:
- Missing lgpio backend: You didn't set
os.environ['GPIOZERO_PIN_FACTORY'] = 'lgpio'at the very top of your script, or you forgot topip install rpi-lgpio. - Permissions: Your user isn't in the
gpiogroup. Fix:sudo usermod -aG gpio $USERand reboot.
Error 2: Webhook Rejection
Exact String: fastapi.exceptions.RequestValidationError or 405 Method Not Allowed in your Uvicorn logs.
Ranked Causes:
- Wrong HTTP Method: Make.com or IFTTT is sending a
GETrequest instead ofPOST. Ensure your webhook module is configured for POST. - JSON Payload Mismatch: The webhook is sending
{"relay": 1, "power": "on"}but Pydantic expects{"relay_id": 1, "state": true}. Map your Make.com JSON keys exactly to theRelayCommandmodel.
Error 3: Relay Chatter / Random Toggling
Exact String: No software error; physical relay clicking randomly on boot.
Ranked Causes:
- Floating Pins on Boot: The Pi's GPIO pins float during the bootloader phase before Python initializes. Fix: Wire a 10kΩ pull-up resistor between 3.3V and the IN pins, or use a relay module with built-in pull-ups.
- Active High vs Low mismatch: You set
active_high=Truein the code, but your optocoupler requires sinking current to ground. Change toactive_high=False.
First Three Things to Check When It Fails
If Google Home says "Okay" but the relay doesn't click, run this diagnostic sequence before rewriting code:
- Test the Tunnel Locally: Use
curl -X POST http://localhost:8000/api/v1/relay -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" -d '{"relay_id": 1, "state": true}'. If this fails, the issue is Python/Hardware, not Google Home. - Check Cloudflare Tunnel Logs: Run
sudo journalctl -u cloudflared. If you see502 Bad Gateway, your Uvicorn server crashed or isn't running on port 8000. - Verify Make.com Webhook History: Open your Make.com scenario, click the webhook module, and view the "History" tab. Ensure Google Home actually triggered the scenario and that Make.com received a
200 OKresponse from your Pi.
How to Extend or Simplify the Build
Once you have the baseline working, you will likely want to change the scope of the project. Here is how to pivot based on your end goal.
How to Extend (Add PWM Dimming or Sensors)
If you want to dim a 12V LED strip instead of just toggling it, swap the OutputDevice class for PWMLED in gpiozero. Note that hardware PWM on the Pi 5 is limited to specific pins (GPIO 12, 13, 18, 19). You will need to update the RelayCommand Pydantic model to accept a brightness: float parameter (0.0 to 1.0) instead of a boolean state.
How to Simplify (Ditch the Custom Code)
If maintaining a FastAPI server and Cloudflare tunnel feels like overkill, install Home Assistant OS (HAOS) on the Pi. HAOS has a built-in "GPIO" integration and the "Google Assistant" integration (via Nabu Casa). You will lose the custom Python coding experience, but you gain a visual UI, native Google Home local execution, and automatic SSL handling.






