---
title: "Automating with Google Home & HomeKit"
description: "## The core limitation"
section: home-assistant
raw: "04-assistant-automations.md"
source: ai-generated
tags: home-assistant, home-automation
last-updated: 2026-09-15
---

# Automating with Google Home & HomeKit

> Patterns for making Home Assistant behave well when lights, switches and media are controlled from Google Home or HomeKit — platforms that can only *turn things on and off*, not run your scripts.

## The core limitation

Google Home and HomeKit talk to HA through the **Google Assistant / HomeKit
integrations**. They can:

- turn an entity on/off, and (for lights) set brightness / colour
- run *exposed* scripts and scenes
- query state

They **cannot** run automations, and they won't run a script you forgot to
expose. So any "polish" behaviour — dimming after dark, turning a light off
later, logging the event — has to live in an automation that reacts to the
*state change* the assistant causes, not in the assistant itself.

The general recipe:

1. Expose only the entities and scripts each platform should control
   (exposure is off by default — list them explicitly).
2. Write automations with **`light.turned_on` / `switch.turned_on` triggers**
   targeting those entities. The trigger fires identically whether the change
   came from the HA dashboard, a voice command, or a HomeKit switch on the
   wall — so one automation serves all sources.
3. Add time-of-day / state conditions to shape the behaviour.

## Example: `Light:On:Dim`

The best illustration of the pattern. Bedside lamps exposed to the assistants
are sometimes switched on at full brightness late at night (a voice command or
a HomeKit switch). This automation re-dims them to a safe level:

```yaml
- id: '202607080107'
  description: ''
  triggers:
    - trigger: light.turned_on
      target:
        entity_id:
          - light.light_bedside_1
          - light.light_bedside_2
          - light.light_masterbedroom_1
      options:
        behavior: each
  conditions:
    - condition: state
      entity_id: input_boolean.active
      state: ['on']
    - condition: time
      after: '21:00'
      before: '07:30:00'
    - condition: template
      value_template: >-
        {{ is_state_attr(trigger.entity_id, 'brightness', none) == false and
           state_attr(trigger.entity_id, 'brightness') | int(0) > 15 }}
  actions:
    - sequence:
        - action: light.turn_on
          target:
            entity_id: "{{ trigger.entity_id }}"
          data:
            brightness_pct: 20
  alias: Light:On:Dim
  mode: parallel
  max: 10
```

Design points worth copying:

- **`light.turned_on` + `behavior: each`** — fires once per light, so a voice
  command or scene that hits several lights at once works without any of the
  runs blocking each other (hence `mode: parallel`).
- **Brightness guard (`> 15`)** — leaves alone lights that were switched on at
  (or near) zero brightness, e.g. lights ramping up on their own. This is what
  keeps the automation from fighting devices that manage their own dimming.
- **The visible ramp** — re-setting the light to 20 % brightness ramps it down
  rather than snapping, so it *looks* as if the light came on at the right
  level.
- **Time-of-day condition** — the same light at 8 am is left alone; only the
  21:00–07:30 window gets the treatment.
- **`input_boolean.active` condition** — required when running a cluster so the
  standby doesn't also act (see [High Availability](/home-assistant/02-high-availability/)).

This is the key idea: **react to state, not to the source.** Because the
trigger is on the light itself, the automation works for HomeKit, Google Home,
the dashboard, and any future platform, with zero per-platform code.

## Exposing entities deliberately

Both integrations default to **no exposure** — you list each entity you want
voice-controlled, and you can attach friendly names/areas. Tips:

- Expose *scripts* for multi-entity actions ("Party Lights", "Enough
  Christmas", "Lights Out") rather than making users say one word per light.
  Google Assistant script names are what the user actually says.
- Keep a **separate exposure list per platform**: HomeKit for things people
  reach for on their phones / watch at the bedside (bedside lamps, bedroom
  lights, alarm panel, computers), Google Home for the rest. The same entity
  doesn't need to be in both.
- If you run a cluster, **only the active instance should be connected to the
  assistants** — see the gotchas in [High Availability](/home-assistant/02-high-availability/).
- Watch for entity-ID typos in the exposure lists: a misspelled entity is
  silently not exposed, so "the light is missing from HomeKit" often means a
  typo, not a broken integration.

## Gotchas

- **Assistant changes bypass your scripts.** If a user says "turn on the
  bedside light", the Google Assistant integration calls `light.turn_on`
  directly — any script with dimming logic does *not* run. State-trigger
  automations (like `Light:On:Dim`) are how you recover the behaviour.
- **State reporting.** The Google Assistant integration's
  `report_state` setting controls whether HA pushes entity state changes to
  Google. Leave it on, otherwise voice queries ("is the light on?") can
  answer with stale state.
- **PIN / secure devices.** Voice commands from secure devices (e.g. a Nest
  Hub) require the configured PIN; keep it in secrets, and remember a PIN
  change silently breaks voice control until everyone re-enters it.
- **HomeKit accessory setup.** The HomeKit integration exposes HA as a single
  HomeKit accessory with a room layout; expose the alarm control panel too —
  "Armed" / "Disarmed" from the Home app is a nice touch.

---

## Related

- [High Availability](/home-assistant/02-high-availability/)
- [Light brightness as state](/home-assistant/03-light-brightness-state/)
- [RFID tags & music albums](/home-assistant/05-rfid-music-albums/)

---

## Source Disclaimer

- [x] AI Generated
- [ ] Human Generated
- [ ] AI Edited
- [ ] Human Edited
