Tutorials 9 min read

Automate the opening of a connected garage with Home Assistant in 2026

Connect a motorized garage door to Home Assistant: a Zigbee contact sensor to know its state, a relay module to operate it, and careful automations (alert when it stays open, light at night).

See our picks
S By Selfhostr Team · no sponsored content
Automate the opening of a connected garage with Home Assistant in 2026
ⓘ ⓘ This article may contain affiliate links (no extra cost to you, it funds the site). As an Amazon Associate, Selfhostr earns from qualifying purchases. See the disclosure.
⏱️
~45 min
Duration
🎚️
Intermediate
Difficulty
💶
Moderate
Cost
📦
Home Assistant in a Docker container + motorized garage door
Key prerequisite

👍 What we like

  • ✓Real door state visible everywhere (app, dashboard, notifications)
  • ✓Control from the Home Assistant app, no remote needed
  • ✓Everything stays local: the Zigbee network depends on no cloud
  • ✓Combines with lighting, alarm or presence detection

👎 What to watch

  • ✕Operating the door requires a relay module on top of the sensor
  • ✕Wiring on the opener's terminal block: read its manual first
  • ✕Remote control does not replace the opener's safety features (photo-eyes, obstacle detection)

🏆 Our picks

Affiliate links · same price for you
Recommended
Sonoff Zigbee 3.0 USB Dongle Plus-E (ZBDongle-E)

Sonoff Zigbee 3.0 USB Dongle Plus-E (ZBDongle-E)

Voir sur Amazon

Amazon · price and availability on the listing

Recommended
📦

Sonoff SNZB-04P

Voir sur Amazon

Amazon · price and availability on the listing

See all our recommended gear in the shop.

📑 Contents ▾

A connected garage door is really two separate functions. Knowing its state (open or closed) is the job of a contact sensor, here the Sonoff SNZB-04P on Zigbee. Operating it is the job of a dry-contact relay module that “presses” the opener’s wall button for you. This tutorial sets up the Zigbee coordinator in Home Assistant (running in a Docker container), adds the sensor, combines sensor and relay into a “Garage” entity, then adds careful automations: an alert when the door stays open and lighting at night. We deliberately do not automate opening: a door that opens by itself on a false trigger is a garage open to anyone.

Prerequisites

  • Home Assistant running in a Docker container (named homeassistant in this guide), with Docker Compose
  • A Zigbee coordinator: here the Sonoff Zigbee 3.0 USB Dongle Plus-E (ZBDongle-E)
  • A Zigbee contact sensor: here the Sonoff SNZB-04P
  • To operate the door: a dry-contact relay module (Zigbee or Wi-Fi) supported by Home Assistant, and an opener with push-button terminals (see its manual)
  • SSH access to the machine running Docker
  • The Home Assistant interface on port 8123 of your local network (no need to expose it to the Internet)

Step-by-step installation

Step 1: Plug in the Zigbee coordinator and pass it to the container

Plug the dongle into a USB port, ideally at the end of a short USB extension cable: USB 3 ports and the machine’s case interfere with the 2.4 GHz band. Then find its stable path on the host:

ls -l /dev/serial/by-id/

A line containing Sonoff or ITead should appear, linking to ttyUSB0 or ttyACM0. Use the full /dev/serial/by-id/... path rather than ttyUSB0, which can change after a reboot. Add it to the Home Assistant service in your docker-compose.yml:

services:
  homeassistant:
    # ... your existing configuration (image, volumes, network_mode, etc.)
    devices:
      - /dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_V2_XXXXXX-if00-port0:/dev/zigbee

Replace the part before :/dev/zigbee with the exact path you found, then recreate the container:

docker compose up -d homeassistant

Check that it worked:

docker exec homeassistant ls -l /dev/zigbee

The device should be listed. If the command answers “No such file or directory”, the path in the Compose file does not match the output of ls -l /dev/serial/by-id/.

Step 2: Add the Zigbee Home Automation (ZHA) integration

In Home Assistant, open Settings > Devices & services > Add integration, then choose Zigbee Home Automation. Enter /dev/zigbee when the wizard asks for the serial device and let it create a new Zigbee network. The ZBDongle-E is a Silicon Labs coordinator: if the radio type is requested, choose EZSP.

Check that it worked:

docker logs homeassistant --since 10m 2>&1 | grep -i -E "zha|zigbee" | tail -n 20

No port connection error should appear, and the ZHA integration should show in Devices & services with the coordinator as its first device.

Step 3: Pair the SNZB-04P contact sensor

In the ZHA integration, click Add device. Put the SNZB-04P in pairing mode by holding its button until its LED blinks (the exact duration is in its manual). The sensor usually appears within seconds. Rename its contact entity to binary_sensor.garage_porte so you can copy the examples as they are.

Mount the sensor on the door and its magnet on the frame, aligned when the door is closed. On an up-and-over or sectional door, place it at the top of the door, where the gap with the frame is clearest when opening.

Check that it worked: open Developer tools > States, search for binary_sensor.garage_porte, then open and close the door. The state should switch from off (closed) to on (open) and back.

Step 4: Wire and add the relay module

The relay is wired in parallel with the opener’s wall push-button, on the terminals provided for it (see the opener’s manual). Cut power to the opener before working on it. Then add the relay to Home Assistant with its integration (ZHA if it is Zigbee) and rename its entity to switch.garage_relais.

Most openers expect a pulse: a short contact, like a button press. If your relay has a pulse (“inching”) mode, enable it. Otherwise the script below generates the pulse. Create it in Settings > Automations & scenes > Scripts > Add script, ⋮ menu > Edit in YAML:

alias: "Garage - impulsion"
mode: single
sequence:
  - action: switch.turn_on
    target:
      entity_id: switch.garage_relais
  - delay: "00:00:01"
  - action: switch.turn_off
    target:
      entity_id: switch.garage_relais

Save it with the ID garage_impulsion. Run it once with the door in sight: the opener should react as if the button had been pressed.

Step 5: Create the “Garage” entity

A cover entity combines the state (the sensor) and the control (the script) in a single card, with open and close buttons. Add this block to configuration.yaml (in the configuration folder mounted into the container):

template:
  - cover:
      - name: "Garage"
        device_class: garage
        state: "{{ 'open' if is_state('binary_sensor.garage_porte', 'on') else 'closed' }}"
        open_cover:
          - condition: state
            entity_id: binary_sensor.garage_porte
            state: "off"
          - action: script.garage_impulsion
        close_cover:
          - condition: state
            entity_id: binary_sensor.garage_porte
            state: "on"
          - action: script.garage_impulsion

The condition before each pulse prevents “open” from closing a door that is already open: the opener itself simply reverses its movement on every pulse.

Check the configuration before restarting:

docker exec homeassistant python -m homeassistant --script check_config --config /config

The command should report no error. Then restart Home Assistant (Settings > System > power menu > Restart): the cover.garage entity appears, with the door state and both buttons.

Step 6: Get an alert when the door stays open

This is the most useful automation day to day. Create it in Settings > Automations & scenes > Create automation > Create new automation, ⋮ menu > Edit in YAML. Replace notify.mobile_app_mon_telephone with your phone’s notification service (it appears once the Home Assistant app is installed and signed in):

alias: "Garage left open"
triggers:
  - trigger: state
    entity_id: binary_sensor.garage_porte
    to: "on"
    for: "00:10:00"
actions:
  - action: notify.mobile_app_mon_telephone
    data:
      title: "Garage"
      message: "The garage door has been open for 10 minutes."

Check that it worked: leave the door open for a little more than 10 minutes. The notification should arrive, and the run shows in the automation’s trace (⋮ menu > Traces).

Step 7: Turn on the light at night

Same method. Replace light.garage with your own light:

alias: "Garage - light at night"
triggers:
  - trigger: state
    entity_id: binary_sensor.garage_porte
    from: "off"
    to: "on"
conditions:
  - condition: state
    entity_id: sun.sun
    state: "below_horizon"
actions:
  - action: light.turn_on
    target:
      entity_id: light.garage

Check that it worked: after sunset, open the door. The light should turn on and the trace should show the sun.sun condition as passed.

Step 8 (optional): Scheduled closing in the evening

If your opener has working photo-eyes and obstacle detection, you can have it close at a fixed time when it was left open. Without those safety features, do not do this.

alias: "Garage - evening closing"
triggers:
  - trigger: time
    at: "22:30:00"
conditions:
  - condition: state
    entity_id: binary_sensor.garage_porte
    state: "on"
actions:
  - action: notify.mobile_app_mon_telephone
    data:
      message: "Garage door left open: closing now."
  - action: cover.close_cover
    target:
      entity_id: cover.garage

Check it on the first evening: the notification should arrive and the door should close. Then confirm in the traces that the condition was evaluated.

Verification checks

  • docker exec homeassistant ls -l /dev/zigbee lists the coordinator
  • docker exec homeassistant python -m homeassistant --script check_config --config /config reports no error
  • In Developer tools > States, binary_sensor.garage_porte follows the door and cover.garage shows open or closed
  • The Garage card’s “close” button does nothing when the door is already closed (the condition blocks the pulse)
  • The automations from steps 6 and 7 show a trace after a real test

Security and best practices

A garage door control is a key to your home. Do not expose port 8123 directly to the Internet: use a VPN (WireGuard, Tailscale) or an HTTPS reverse proxy. Enable two-factor authentication for Home Assistant accounts and do not give other household members an administrator account. The Zigbee network (the zigbee.db file and ZHA configuration) lives in Home Assistant’s configuration folder: back it up regularly, for example with tar czf ha-config-$(date +%F).tar.gz -C /path/to config, adjusting the path to your volume. Update Home Assistant with docker compose pull homeassistant && docker compose up -d homeassistant after reading the release notes. Finally, keep the original remote and wall button: home automation adds to the opener, it does not replace it.

Troubleshooting common errors

  • ZHA cannot find the coordinator -> the device is not passed to the container -> check the devices section of the Compose file and the output of docker exec homeassistant ls -l /dev/zigbee, then recreate the container.
  • The sensor pairs, then drops off -> insufficient range or 2.4 GHz interference -> move the dongle away from the machine with a USB extension cable and add a mains-powered Zigbee device (plug or relay), which acts as a repeater.
  • The door opens, then immediately closes -> the relay stays closed too long or sends two pulses -> disable the relay’s pulse mode if the script already does it, or the other way round.
  • The door state is inverted -> sensor mounted upside down or magnet misaligned -> adjust its position. The step 5 state template assumes on = open.
  • check_config reports a cover error -> YAML indentation, or a template: key already present elsewhere in configuration.yaml -> group all blocks under a single template: key.

FAQ

Is my Zigbee sensor compatible with ZHA?

Most Zigbee 3.0 sensors are. For a specific model, check the community compatibility database zigbee.blakadder.com, which lists for each device whether it works with ZHA and Zigbee2MQTT.

ZHA or Zigbee2MQTT?

Both work with the ZBDongle-E. ZHA is built into Home Assistant and is enough for this guide. Zigbee2MQTT also needs an MQTT broker, but often supports recent devices sooner and exposes more settings.

Can I skip the relay module?

To know the door state, yes: the sensor is enough, and steps 6 and 7 work without a relay. To operate the door from Home Assistant, you need a relay, or an opener that has its own Home Assistant integration.

How do I limit interference with Wi-Fi?

Zigbee and Wi-Fi share the 2.4 GHz band. Zigbee channels 15, 20 and 25 overlap least with Wi-Fi channels 1, 6 and 11. A USB extension cable that moves the dongle away from the machine helps as much as the channel choice.

Read also

Tags: home assistantself-hostingzigbeeautomationgarage

Related

Tutorials

Deploy n8n with Docker and HTTPS in 2026: Complete Tutorial (Postgres, Reverse Proxy, Persistence)

Step-by-step 2026 guide to self-host n8n, the no-code automation platform, using Docker Compose. Features PostgreSQL, workflow persistence, automatic HTTPS via Caddy and Let's Encrypt, credential encryption, backups, and hardening. Ready-to-use configs.

Read
Tutorials

Configure Dockge to manage your Docker containers in 2026

Learn how to install and configure Dockge, a lightweight and self-hosted Docker Compose stack manager, perfect for homelabs and self-hosting.

Read
Tutorials

Measure Your Home Lab's Electricity Consumption in 2026

Measure your homelab's power draw: a Brennenstuhl PM 231 E plug-in meter for single devices, a Shelly EM Gen3 in the electrical panel, readings from its RPC API, and history in Home Assistant on Docker.

Read