Skip to main content
AI Automation

How to Connect n8n to Home Assistant: Automation Workflows

· · 7 min read

If you’re running Home Assistant and n8n in the same homelab, you have the pieces for something useful: automated workflows that listen to Home Assistant events and act on them without writing YAML. This integration between n8n and Home Assistant is where the value actually starts showing up.

n8n screenshot
n8n u2014 from the official site

Why Connect n8n to Home Assistant

Home Assistant is good at collecting state. n8n is good at deciding what to do with state changes. On their own, they’re fine. Together, they’re more than the sum.

The reason to do this instead of writing Home Assistant automations directly: n8n workflows are visual, versioned, and shareable. If you have complex conditional logic or need to integrate with services outside Home Assistant’s native support, n8n bridges that gap without writing YAML. You also get better error handling and logging.

What I’m showing you here is a simple but real example: when motion is detected in a room, send a notification and log the event to a database. In Home Assistant alone, that’s doable. In n8n, it’s the same three blocks. The difference becomes obvious when you add a fifth condition, or need to hit an external API, or want to retry on failure.

Prerequisites and Network Setup

You need Home Assistant and n8n running on the same network. Both should be in Docker or accessible to each other via hostname.

Home Assistant needs the webhook integration enabled. It’s enabled by default in most installs, but confirm it’s present by checking your configuration.yaml or integrations dashboard. You also need a long-lived access token from Home Assistant. Generate one from your user account settings (click your profile avatar, scroll down, create a token under Long-Lived Access Tokens).

n8n needs network access to Home Assistant. If Home Assistant is at http://homeassistant:8123 on your internal network, n8n will reach it using that hostname. If you’re using a reverse proxy or different port, adjust accordingly.

For this example, assume Home Assistant is running at homeassistant:8123 and n8n at localhost:5678 or wherever you’ve exposed it. Same Docker network is simplest.

Docker Compose Configuration

Here’s what a working stack looks like. This isn’t the full file, just the relevant parts.

version: '3.8'
services:
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:2024.1
    container_name: homeassistant
    restart: unless-stopped
    ports:
      - "8123:8123"
    volumes:
      - ./homeassistant:/config
      - /etc/localtime:/etc/localtime:ro
    environment:
      - TZ=UTC
    networks:
      - homelab

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    ports:
      - "5678:5678"
    volumes:
      - ./n8n:/home/node/.n8n
    environment:
      - N8N_HOST=localhost
      - N8N_PORT=5678
      - NODE_ENV=production
      - WEBHOOK_TUNNEL_URL=http://n8n:5678/
    networks:
      - homelab
    depends_on:
      - homeassistant

networks:
  homelab:
    driver: bridge

The critical part: both services are on the homelab network. n8n can reach Home Assistant by hostname. The webhook tunnel URL tells n8n how to construct URLs for incoming webhooks (relevant if Home Assistant needs to call back).

Setting Up the Home Assistant Webhook in n8n

In n8n, you create a workflow that starts with a Webhook node. This webhook listens for events from Home Assistant.

Create a new workflow. Add a Webhook node as your trigger. Set it to listen on POST. Give it a path like /motion-detected. Save and note the full webhook URL. It should look like http://localhost:5678/webhook/motion-detected (or your actual URL).

Now in Home Assistant, create an automation that fires when motion is detected, and call that webhook. Here’s the YAML:

automation:
  - alias: "Motion Detected - Trigger n8n"
    trigger:
      platform: state
      entity_id: binary_sensor.living_room_motion
      to: "on"
    action:
      - service: webhook.post
        data:
          url: "http://n8n:5678/webhook/motion-detected"
          method: POST
          headers:
            Content-Type: "application/json"
          payload:
            entity_id: "binary_sensor.living_room_motion"
            state: "on"
            timestamp: "{{ now().isoformat() }}"

Home Assistant will POST to n8n every time motion is detected. The payload includes the entity ID, state, and timestamp. Simple.

Test it. Trigger motion in the sensor’s range. Check n8n’s webhook logs (the Webhook node has an inspect/test view). You should see the POST arrive.

Building the Workflow Logic

Once the webhook is receiving data, add logic downstream.

After the Webhook node, add a Function node to parse the incoming data. Then branch: one path sends a notification via the Home Assistant service node, another logs to a database or service of your choice.

Here’s a rough flow:

  1. Webhook receives motion event
  2. Function node extracts entity_id and timestamp
  3. Home Assistant service node triggers a notify service in Home Assistant
  4. Optional: HTTP node or database node logs the event

The Home Assistant service node is where you tell n8n to do something in Home Assistant. Click the plus button, search for Home Assistant, select Service. Configure it:

  • URL: http://homeassistant:8123/api/services/notify/mobile_app_your_phone
  • Authentication: Basic or Bearer token (use your long-lived token)
  • Method: POST
  • Body: {"message": "Motion detected at {{ $json.timestamp }}"}

That sends a notification to your phone via Home Assistant’s mobile app service. Simple. You can chain multiple actions after.

Authentication and Long-Lived Tokens

n8n needs to authenticate to Home Assistant to call its services. Use the long-lived token you generated earlier.

In n8n, when you add a Home Assistant node that requires authentication, create a credential. Set it as type Bearer Token. Paste your token. n8n will include it in the Authorization header on every request to Home Assistant.

Keep that token secret. If you’re committing your n8n workflows to Git, use environment variables instead of hardcoding it. n8n supports environment variable substitution in credentials.

One thing that surprised me: if your Home Assistant instance requires SSL and you’re on a self-signed cert, n8n might reject it by default. You can disable SSL verification in the credential settings if you trust your internal network. Not ideal, but common in homelabs.

Testing and Debugging

Before assuming it works, test each connection point.

First, verify the webhook is listening. In n8n, open the Webhook node, click Test. Home Assistant should be able to POST to that URL. If it times out, check Docker network connectivity and firewall rules.

Second, test the Home Assistant service node in isolation. Click Test on that node. It will attempt to call the Home Assistant API with your token. If it fails, check the token is valid and the URL is reachable.

Third, test the full automation in Home Assistant. Trigger the motion sensor manually (or wait for real motion). Check Home Assistant’s automations dashboard for errors. Check n8n’s execution history for that workflow.

If something fails, check n8n’s logs: docker logs n8n. Look for network errors, JSON parse errors, or auth failures. Home Assistant logs are in config/home-assistant.log if running in Docker.

Common issues: incorrect webhook URL, token expired or wrong, network unreachable between containers, port not exposed.

Running This in Production

Once working, make sure both services restart on failure. Set restart: unless-stopped in Docker Compose (shown above). Persist n8n data to a volume so your workflows survive container recreation.

Monitor execution. n8n has built-in execution history. Set up alerts in n8n itself if a workflow fails repeatedly. You can add a slack or email notification node at the end to tell you when something breaks.

I’ve been running a similar setup for motion detection, temperature logging, and conditional device control for about eight months. It’s stable. The main pain point isn’t the integration itself—it’s remembering that if you restart n8n, Home Assistant keeps sending webhooks to a service that isn’t listening, and those events just vanish. There’s no queue. If that matters for your use case, you’d want to add a queue layer (Redis, RabbitMQ) between them. For my stuff, it doesn’t matter. A missed motion event isn’t critical.

FAQ

Can n8n call Home Assistant services without a webhook?

Yes. You can trigger n8n workflows on a schedule or manually, then use the Home Assistant service node to control devices. The webhook approach is for Home Assistant pushing to n8n. You can also have n8n pull state from Home Assistant via HTTP requests on a timer.

Does Home Assistant need internet access for this to work?

No. This is entirely internal. Home Assistant posts to n8n on your local network. Neither needs external connectivity. That’s the whole point.

What if Home Assistant or n8n restarts?

Home Assistant will keep trying to call the webhook. If n8n is down, those POSTs fail silently. They’re not queued. If you need reliability, add a database queue or use Home Assistant’s native automations as a fallback.

Can I use n8n to modify Home Assistant automations?

Not directly. n8n can’t write to Home Assistant’s automations.yaml. But n8n can call services, trigger scenes, or update input_booleans, which are essentially state variables you can act on in Home Assistant’s own automations. You’re usually combining the two, not replacing one with the other.

What’s the latency between motion detection and action?

Typically under a second on decent hardware. Home Assistant detects motion, posts to n8n (network latency ~10ms), n8n processes (100-300ms depending on nodes), then acts. If you need sub-100ms response, Home Assistant’s native automations are faster.

Explore n8n in our AI Homelab Toolkit.

Share this article