Smart Home Voice DMZ: Zero-Exposure Google Assistant & Node-RED Architecture
A hardened, privacy-first blueprint for integrating Google Assistant / Google Home Minis with Home Assistant and Node-RED without exposing your internal devices, cameras, alarms, or network topology to Google Cloud, and without requiring Nabu Casa or manual Google Home routines.
The Problem with Traditional Voice Integrations
Most official documentation and online tutorials instruct users to expose entire domains:
# ❌ THE TRADITIONAL PRIVACY RISK:
google_assistant:
exposed_domains:
- light
- switch
- cover
- climate
In a home with dozens or hundreds of circuits (KNX, Zigbee, Z-Wave, Lutron), security systems, cameras, and private sensors:
- Google Cloud learns your daily habits: Every motion sensor trip, camera status, door lock state, and light toggle is continuously synchronized to Google HomeGraph.
- Entity pollution: Hundreds of internal technical entities clutter your Google Home app.
- Routine nightmare: Users end up creating dozens of fragile manual routines in the Google Home app to map natural voice commands.
The Solution: The Smart Home DMZ
This architecture treats Google Assistant as an untrusted external input peripheral situated in a Demilitarized Zone (DMZ):
flowchart TD
subgraph Untrusted_Cloud ["Untrusted Cloud (Google Home)"]
User(["🗣️ User Voice Command"]) --> Mini["Google Home Mini"]
Mini --> GCP["Private GCP Smart Home Action"]
end
subgraph DMZ_Boundary ["Home Assistant DMZ Shield"]
GCP -->|"OAuth 2.0 / HTTPS (Fulfillment)"| HA_API["/api/google_assistant"]
HA_API --> Whitelist{"exposed_domains: []\nStrict Whitelist"}
end
subgraph Internal_Private_Mesh ["Protected Local Infrastructure"]
Whitelist -->|"Allowed Direct Controls"| CuratedEntities["Only Curated Entities\n(with native aliases & rooms)"]
Whitelist -->|"Allowed Triggers"| VirtualSwitch["Virtual Proxy Switch\n(template switch)"]
VirtualSwitch -->|"State Change"| NodeRED["Node-RED Event Bus"]
NodeRED -->|"Auto-Reset (<150ms)"| VirtualSwitch
NodeRED -->|"Orchestrate"| InternalMesh["KNX / Security / Zigbee / Automation Engine"]
end
classDef cloud fill:#ea4335,stroke:#b31412,stroke-width:2px,color:#fff;
classDef dmz fill:#fbbc05,stroke:#d68a00,stroke-width:2px,color:#000;
classDef local fill:#34a853,stroke:#1e7e34,stroke-width:2px,color:#fff;
class Untrusted_Cloud cloud;
class DMZ_Boundary dmz;
class Internal_Private_Mesh local;
Key Principles
- Strict Zero-Exposure Whitelist (
exposed_domains: []): Google Cloud sees only what you explicitly define. Your internal topology, cameras, sensors, and alarms remain invisible. - Virtual Proxy Event Bus: Voice triggers activate stateless virtual template switches in Home Assistant that Node-RED listens to and resets in <150ms, ready for immediate reuse.
- Routine-Free Natural Language: Native Home Assistant
aliases:androom:definitions map speech directly inside Home Assistant, completely eliminating the need for manual Google Home app routines.
Quick Reference: Dual-Audience Navigation
| I am a… | Recommended Path |
|---|---|
| 🧑💻 Human Engineer | Follow the step-by-step phases below: Phase 1 through Phase 5. |
| 🤖 AI Coding Agent (Claude, Cursor, Copilot) | Read the structured prompt at docs/AGENT_INSTRUCTIONS.md and execute the configuration directly. |
Prerequisites
Before starting, ensure you have:
- A Home Assistant instance accessible via public HTTPS with a valid SSL certificate (e.g. Cloudflare Tunnel, DuckDNS, NGINX SSL).
- A standard Google account.
- At least one Google Home Mini, Nest speaker, or the Google Home mobile app.
- Node-RED (optional, only needed if you plan to dispatch complex automations from voice).
Phase 1: Google Cloud & Actions Console Setup
You do not need a paid Nabu Casa subscription or a published public Google Action to achieve native integration. You will create a private, self-hosted developer action in Test mode.
Step 1.1: Create Project in Google Actions Console
- Navigate to the Google Actions Console.
- Click New Project and name it (e.g.
ha-private-bridge). - Select Smart Home as the project type and click Start Building.
Step 1.2: Set Up Fulfillment URL
- Under Quick Setup, click Name your Smart Home action (e.g.
HA Bridge). - Under Build your Action, click Add Action(s).
- Enter your Home Assistant public HTTPS fulfillment URL:
https://ha.yourdomain.com/api/google_assistant(Must have a valid SSL certificate like Let’s Encrypt / Cloudflare).
Step 1.3: Configure OAuth 2.0 Account Linking
Under Advanced Options > Account Linking:
- Client ID:
https://oauth-redirect.googleusercontent.com/r/[YOUR_PROJECT_ID](Replace
[YOUR_PROJECT_ID]with your exact Google Cloud project ID from Project Settings). - Client Secret: Any non-empty string (e.g.
placeholder_secret). - Authorization URL:
https://ha.yourdomain.com/auth/authorize - Token URL:
https://ha.yourdomain.com/auth/token - Scopes:
emailandname(press Enter after each). - Google to transmit clientID & secret via HTTP basic auth header: Unchecked.
Step 1.4: Service Account Key (For Local State Reporting)
- Go to the Google Cloud IAM & Admin Console with your project selected.
- Click Create Service Account (Name:
home-assistant). - Assign the role: Service Account Token Creator.
- Click into the new service account > Keys > Add Key > Create new key (JSON).
- Download the JSON file, rename it to
service_account.json, and place it in the same directory as your YAML package file (e.g./config/packages/).
Step 1.5: Enable HomeGraph API & App Branding Requirement
- In Google Cloud Console, go to APIs & Services > Library and search for HomeGraph API. Click Enable.
- Go to APIs & Services > OAuth consent screen:
- Set User Type to External.
- Add your Google account email to Test Users.
- In Actions Console > Deploy > Directory information:
- Upload any square 144x144 PNG image as the Small Icon (Google requires this before allowing Test deployment).
- Click Test > On device testing to activate the simulator.
Step 1.6: Link Account in the Google Home Mobile App
- Open the Google Home app on your mobile phone.
- Tap Devices > Add (+) > Works with Google.
- Look for your action prefixed with
[test](e.g.[test] HA Bridge). - Tap it and log in with your Home Assistant user credentials.
- Once authenticated, your whitelisted entities will appear instantly in the app.
Phase 2: Home Assistant Hardened Package
Ensure packages are enabled in your configuration.yaml:
homeassistant:
packages: !include_dir_named packages
Then add the following package to /config/packages/google_assistant_dmz.yaml (with service_account.json in the same directory):
# ------------------------------------------------------------------------------
# 1. Virtual Helper & Proxy Switch (Event Bus)
# ------------------------------------------------------------------------------
input_boolean:
voice_event_bus:
name: "Voice Event Bus"
icon: mdi:microphone-message
template:
- switch:
- name: "Voice Trigger Event"
unique_id: voice_trigger_event_dmz
state: ""
turn_on:
- action: input_boolean.turn_on
target:
entity_id: input_boolean.voice_event_bus
turn_off:
- action: input_boolean.turn_off
target:
entity_id: input_boolean.voice_event_bus
# ------------------------------------------------------------------------------
# 2. Hardened Google Assistant Configuration
# ------------------------------------------------------------------------------
google_assistant:
project_id: my-voice-bridge-1234
service_account: !include service_account.json
report_state: true
# STRICT ZERO-EXPOSURE: Empty list prevents automatic exposure of any real devices
exposed_domains: []
# Explicit Entity Whitelist
entity_config:
# Virtual trigger switch for Node-RED
switch.voice_trigger_event:
name: "Voice Trigger"
aliases:
- "voice trigger"
- "trigger event"
expose: true
# Direct physical device with native aliases and room grouping
light.living_room_ambient_light:
name: "Living Room Lights"
room: "Living Room"
aliases:
- "main lights"
- "living room lights"
- "ambient light"
expose: true
cover.living_room_blinds:
name: "Living Room Blinds"
room: "Living Room"
aliases:
- "roller blinds"
- "window blinds"
expose: true
Phase 3: Node-RED Auto-Reset Pipeline
To trigger complex automations (e.g., exit modes, multi-room scenes, sequence dispatches) via voice without state lockup:
- Import the template flow:
templates/nodered/google_dmz_flow.json. - The flow listens for
switch.voice_trigger_eventtransitioning toon. - An
api-call-servicenode immediately turns the switch backoff(<150ms). - A downstream function/action node handles the business logic.
sequenceDiagram
autonumber
actor User as 🗣️ User
participant Mini as Google Mini
participant HA as Home Assistant
participant NR as Node-RED Flow
participant Hardware as Real Hardware (KNX / Relays)
User->>Mini: "Hey Google, turn on Voice Trigger"
Mini->>HA: API Call: switch.turn_on (Voice Trigger)
HA->>NR: State Change Event: 'on'
par Immediate Auto-Reset (<150ms)
NR->>HA: Call Service: switch.turn_off
Note over HA,NR: Switch is now stateless and ready for reuse
and Execute Automation
NR->>Hardware: Execute Complex Multi-Step Action
end
Mini-->>User: "Chime / OK"
Phase 4: Room Awareness Without Routines
Google Home supports contextual room awareness natively when configured properly:
- In the Google Home app, assign your physical Google Home Mini to a room (e.g.
Office). - Assign the Home Assistant entities exposed in that room to the same room (
room: "Office"). - Now, whenever you speak to that specific Mini:
- Saying “Hey Google, turn on the lights” will only turn on the lights in that room.
- Saying “Hey Google, close the blinds” will only close the blinds in that room.
- Result: You never have to create separate Google Home routines for each speaker or room.
Phase 5: Troubleshooting & Gotchas
| Symptom / Error | Root Cause | Solution |
|---|---|---|
| “Could not reach [test] HA Bridge” on mobile app during linking | Client ID mismatch or incorrect OAuth URL | Ensure Client ID in Actions Console is strictly https://oauth-redirect.googleusercontent.com/r/[YOUR_PROJECT_ID]. |
| Consent screen says “Giving access to [stray_username]” | Stray Client ID was typed into the Actions Console | Reset Client ID to the standard redirect URL format above. |
| Google says “That device isn’t set up yet” | HomeGraph is out of sync | In Home Assistant Developer Tools > Actions, call google_assistant.request_sync. |
| Action Console Test deployment blocked | Missing icon | Upload any 144x144 PNG under Deploy > Directory Information. |
| HA Repair: “Deprecated switch platform” | Using legacy switch: - platform: template |
Update to modern template format: template: - switch:. |
Repository Templates
- 📄 Home Assistant Package:
templates/homeassistant/google_assistant_dmz.yaml - 📄 Node-RED Flow:
templates/nodered/google_dmz_flow.json - 📄 Agent Automation Prompt:
docs/AGENT_INSTRUCTIONS.md
Contributing & License
Contributions, updates, and community suggestions are welcome via Pull Requests. Distributed under the MIT License. See LICENSE for details.