Connecting a Raspberry Pi and Google Home to control physical hardware requires bridging a cloud-based voice ecosystem with local GPIO pins. The most reliable, low-latency method in 2026 is not a direct cloud webhook, but a local MQTT broker mediated by Home Assistant. Google Home triggers a routine, Home Assistant publishes an MQTT payload, and a Python script on the Pi toggles the relay. This guide walks through the exact architecture, hardware pinouts for the Pi 5, and the production-ready Python code to make it work.

The Architecture Decision: Bridging Google Home to Raspberry Pi

Before wiring a single pin, you must choose how Google Home communicates with the Pi. Direct integrations often fail due to cloud latency, NAT traversal issues, or deprecated SDKs. Use this decision matrix to select your bridge method.

Integration Method Latency Cloud Dependency Setup Complexity Reliability
Direct Google Actions SDK (Webhook) High (500ms-2s) Full (Requires DDNS/Port Forwarding) High (OAuth, Cloud Console) Low (Fails if internet drops)
Matter Protocol (Python Matter Server) Low (<100ms) None (Local LAN) Extreme (Requires Thread/Wi-Fi border routers) Medium (Still maturing in Python)
Home Assistant OS + MQTT Add-on Low (<150ms) Partial (Google Routine needs cloud, execution is local) Medium (Install HA, add MQTT broker) High (Local broker, persistent state)
Decision Path Termination (Default Pick): Choose Home Assistant OS with the Mosquitto MQTT Add-on. It provides the best balance of local execution speed, persistent state tracking, and seamless Google Home Routine syncing via the official Home Assistant Cloud or manual Google Assistant integration. Direct cloud webhooks are deprecated for hobbyist hardware control, and Matter-over-Python is still too brittle for simple relay switching.

Parts List and Pin Mapping (Pi 5 & Relay)

This build targets the Raspberry Pi 5 (8GB RAM). The Pi 5 uses the new RP1 southbridge chip, which fundamentally changes how GPIO is accessed at the OS level compared to the Pi 4. Older tutorials using RPi.GPIO will fail; we use gpiozero with the lgpio backend.

Bill of Materials

  • Compute: Raspberry Pi 5 (8GB) - ~$80
  • Power: Official 27W USB-C PD Power Supply - ~$12
  • Storage: SanDisk Extreme 32GB microSD (A2 rating) - ~$14
  • Switching: Elegoo 5V Relay Module (Optocoupler isolated, active LOW) - ~$6
  • Wiring: 20cm Female-to-Female Dupont Jumper Wires - ~$4

Pin Mapping Table

The Elegoo relay module is active-LOW, meaning the Pi must pull the GPIO pin to ground (0V) to energize the relay coil. Ensure your relay module has an optocoupler to protect the Pi 5's RP1 chip from flyback voltage spikes.

Pi 5 Physical Pin BCM GPIO Function Relay Module Pin Wire Color (Standard)
Pin 11 GPIO 17 Control Signal IN (Signal) Yellow
Pin 2 5V Power VCC Supply VCC Red
Pin 6 Ground Common Ground GND Black
Safety Callout: Never switch mains voltage (120V/240V AC) directly on the workbench without a fused enclosure. The relay's COM (Common) and NO (Normally Open) terminals will carry your load. Ensure the load does not exceed the relay's rating (typically 10A at 120VAC for standard blue SRD-05VDC-SL-C relays). For inductive loads like motors or dust collectors, add a snubber circuit or use a solid-state relay (SSR).

The Python MQTT Control Script

This script subscribes to an MQTT topic and toggles GPIO 17 based on the payload. It includes robust error handling, graceful shutdown, and explicit pin definitions. It relies on the Eclipse Paho MQTT Python client and gpiozero.

Prerequisites: Run sudo apt install python3-lgpio python3-paho-mqtt and pip3 install gpiozero on your Pi 5.

import paho.mqtt.client as mqtt
from gpiozero import OutputDevice
from signal import pause
import logging
import sys
import json

# --- CONFIGURATION & PIN DEFINITIONS ---
# Target Board: Raspberry Pi 5 (8GB) with RP1 chip
RELAY_PIN = 17          # BCM GPIO 17 (Physical Pin 11)
MQTT_BROKER_IP = "192.168.1.50"  # IP of your Home Assistant/Mosquitto broker
MQTT_PORT = 1883
MQTT_TOPIC = "workshop/dust_collector"
MQTT_USER = "pi_relay_user"
MQTT_PASS = "your_secure_password"

# Initialize logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s"
)
logger = logging.getLogger(__name__)

# Initialize GPIO (Active LOW relay requires active_high=False)
# The lgpio backend is automatically selected on Pi 5 if installed
try:
    relay = OutputDevice(RELAY_PIN, active_high=False, initial_value=False)
    logger.info(f"GPIO {RELAY_PIN} initialized successfully via gpiozero.")
except Exception as e:
    logger.critical(f"Failed to initialize GPIO {RELAY_PIN}: {e}")
    sys.exit(1)

# --- MQTT CALLBACKS ---
def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code == 0:
        logger.info("Connected to MQTT Broker successfully.")
        client.subscribe(MQTT_TOPIC)
        logger.info(f"Subscribed to topic: {MQTT_TOPIC}")
    else:
        logger.error(f"MQTT Connection failed with reason code: {reason_code}")

def on_message(client, userdata, msg):
    try:
        payload = msg.payload.decode('utf-8').strip().upper()
        logger.info(f"Received payload: '{payload}' on {msg.topic}")
        
        # Handle both raw strings and Home Assistant JSON payloads
        if payload in ['ON', 'TRUE', '1'] or '"ON"' in payload:
            relay.on()
            logger.info("Relay ENGAGED (Pin pulled LOW).")
        elif payload in ['OFF', 'FALSE', '0'] or '"OFF"' in payload:
            relay.off()
            logger.info("Relay DISENGAGED (Pin pulled HIGH).")
        else:
            logger.warning(f"Unrecognized payload format: {payload}")
            
    except Exception as e:
        logger.error(f"Error processing message: {e}")

def on_disconnect(client, userdata, reason_code, properties):
    logger.warning(f"Disconnected from broker (Code: {reason_code}). Attempting auto-reconnect...")
    # Ensure relay fails safe (OFF) if connection drops
    relay.off() 

# --- CLIENT SETUP & EXECUTION ---
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.username_pw_set(MQTT_USER, MQTT_PASS)
client.on_connect = on_connect
client.on_message = on_message
client.on_disconnect = on_disconnect

# Enable automatic reconnection with exponential backoff
client.reconnect_delay_set(min_delay=1, max_delay=60)

try:
    logger.info(f"Connecting to MQTT broker at {MQTT_BROKER_IP}:{MQTT_PORT}...")
    client.connect(MQTT_BROKER_IP, MQTT_PORT, keepalive=60)
    logger.info("Entering blocking network loop. Press Ctrl+C to exit.")
    client.loop_forever()
except KeyboardInterrupt:
    logger.info("Shutdown signal received.")
except Exception as e:
    logger.critical(f"Fatal MQTT error: {e}")
finally:
    relay.off()
    relay.close()
    client.disconnect()
    logger.info("GPIO cleaned up and MQTT disconnected. Exiting.")

Debugging: First Three Things to Check When It Fails

When integrating a Raspberry Pi and Google Home via MQTT, failures usually occur at the network boundary or the GPIO hardware abstraction layer. If the relay does not click when you issue a voice command, check these three items in order.

  1. Broker Reachability and VLAN Isolation: The Pi must reach the MQTT broker on port 1883. If you run Home Assistant on a separate VLAN or Docker network, port 1883 might be firewalled. Run nc -zv 192.168.1.50 1883 from the Pi. If it times out, your router's firewall or Docker bridge network is blocking the traffic.
  2. Pi 5 lgpio Backend Installation: The Pi 5's RP1 chip does not support the legacy /dev/mem GPIO access. If python3-lgpio is missing, gpiozero will silently fail or throw a pin access error. Verify installation with apt list --installed | grep lgpio.
  3. Google Home Routine Payload Mismatch: Google Home routines triggering Home Assistant switches often send JSON payloads (e.g., {"state": "ON"}) rather than raw strings. The Python script above handles both, but if you modified the payload parser, ensure your Home Assistant MQTT switch configuration matches the expected string format.

Ranked Error Strings and Causes

Exact Error String Rank Root Cause & Fix
ConnectionRefusedError: [Errno 111] Connection refused 1 (Most Likely) The Mosquitto broker is down, or the IP address in the script is wrong. Check systemctl status mosquitto on the broker host and verify the IP.
gpiozero.exc.GPIOPinInUse: pin 17 is already in use 2 A previous instance of the script crashed without releasing the pin, or another service (like pigpiod) is holding it. Run sudo killall python3 and reboot the Pi.
paho.mqtt.exceptions.MqttException: Connection lost 3 The Wi-Fi/Ethernet link dropped, or the broker forcefully disconnected the client due to a duplicate Client ID. Ensure no other device is using the same MQTT client ID.

Extending and Simplifying the Build

Once the basic voice-controlled relay is operational, you will likely want to refine the physical installation or add feedback loops. Here is how to scale the project up or strip it down.

How to Extend (Add Feedback and Safety)

  • Add Current Sensing: Wire an ACS712 current sensor in series with the relay's load. Feed the analog output to an MCP3008 ADC (since the Pi 5 has no native analog pins). You can now publish the actual amperage draw back to Home Assistant via MQTT, allowing Google Home to announce if the dust collector motor is stalled.
  • Implement a Hardware Override: Wire a physical toggle switch in parallel with the relay's NO terminal. This ensures you can still turn on the workshop equipment if the network goes down, bypassing the Pi entirely.
  • State Retention on Boot: Add a local SQLite database or a simple JSON file write operation in the on_message callback. On script startup, read the last known state and set the GPIO pin accordingly, preventing the relay from defaulting to OFF during a Pi power outage.

How to Simplify (Remove the Pi)

If you realize you do not need the computational overhead of a full Linux OS and Python environment, downgrade the hardware. Replace the Raspberry Pi 5 with an ESP32-WROOM-32 running ESPHome. ESPHome compiles YAML configurations directly into C++ firmware, natively supports MQTT, and integrates with Home Assistant (and by extension, Google Home) out of the box. This reduces power consumption from ~5W to <0.5W and eliminates OS-level maintenance, though you sacrifice the ability to run complex local Python logic alongside the relay control.

For further reading on Google Home hardware integration standards, refer to the official Google Home Developer Console documentation.