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
Default Pick: For pure DIY GPIO control without paying for Nabu Casa or learning the Matter SDK, build the FastAPI + Make.com architecture. It terminates in a single, reliable endpoint that Google Home Routines can trigger instantly.

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)
Mains Voltage Safety: If you eventually wire the relay COM/NO terminals to 120V/240V AC loads, you must use a minimum of 14 AWG stranded wire for the load side, secure all connections in a grounded NEMA enclosure, and treat the low-voltage GPIO side as completely isolated. Never route 3.3V logic wires in the same conduit as AC mains.

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.

  1. Flash Raspberry Pi OS (64-bit, Bookworm) to your microSD using Raspberry Pi Imager. Enable SSH and configure WiFi in the advanced settings.
  2. SSH into your Pi and update the system:
    sudo apt update && sudo apt upgrade -y
    sudo apt install python3-venv python3-pip libgpiod2 -y
  3. Create a project directory and virtual environment:
    mkdir ~/google-home-pi && cd ~/google-home-pi
    python3 -m venv venv
    source venv/bin/activate
  4. 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:

  1. Missing lgpio backend: You didn't set os.environ['GPIOZERO_PIN_FACTORY'] = 'lgpio' at the very top of your script, or you forgot to pip install rpi-lgpio.
  2. Permissions: Your user isn't in the gpio group. Fix: sudo usermod -aG gpio $USER and reboot.

Error 2: Webhook Rejection

Exact String: fastapi.exceptions.RequestValidationError or 405 Method Not Allowed in your Uvicorn logs.

Ranked Causes:

  1. Wrong HTTP Method: Make.com or IFTTT is sending a GET request instead of POST. Ensure your webhook module is configured for POST.
  2. 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 the RelayCommand model.

Error 3: Relay Chatter / Random Toggling

Exact String: No software error; physical relay clicking randomly on boot.

Ranked Causes:

  1. 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.
  2. Active High vs Low mismatch: You set active_high=True in the code, but your optocoupler requires sinking current to ground. Change to active_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:

  1. 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.
  2. Check Cloudflare Tunnel Logs: Run sudo journalctl -u cloudflared. If you see 502 Bad Gateway, your Uvicorn server crashed or isn't running on port 8000.
  3. 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 OK response 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.

Final Recommendation: If you are building this to learn embedded Python and web APIs, stick with the FastAPI build above. If you just want the lights to turn on when you say "Hey Google" and never want to look at a terminal again, wipe the SD card and flash Home Assistant OS.