← Back to posts
comparison guide self-hosted · · 10 min read

Zigbee2MQTT vs Z-Wave JS UI vs ESPHome: Self-Hosted Smart Home Bridges Guide 2026

Compare three leading self-hosted smart home bridge platforms: Zigbee2MQTT, Z-Wave JS UI, and ESPHome. Learn which tool best fits your home automation setup with Docker deployment guides and configuration examples.

OS
Editorial Team

Building a reliable smart home shouldn’t require sending your sensor data to the cloud. Open-source smart home bridges let you control Zigbee, Z-Wave, and ESP-based devices locally — keeping your automation private, fast, and independent of vendor servers.

In this guide, we compare the three most popular self-hosted smart home bridge platforms: Zigbee2MQTT, Z-Wave JS UI, and ESPHome. Each serves a different protocol ecosystem, and understanding their strengths helps you choose the right architecture for your home.

For a broader look at IoT platform options, see our self-hosted IoT platform comparison and MQTT broker setup guide. If you’re also setting up a full home automation hub, our Home Assistant vs openHAB comparison covers the control plane layer.

Why Self-Host Your Smart Home Bridge?

Proprietary smart home hubs — Samsung SmartThings, Hubitat, vendor-specific bridges — all share a common problem: your devices communicate through servers you don’t control. When a vendor shuts down a cloud API, raises subscription prices, or changes rate limits, your automations break.

Self-hosted bridges solve this by running entirely on your local network:

  • Zero cloud dependency — device communication happens over local radio protocols (Zigbee, Z-Wave, WiFi) and local MQTT brokers
  • Full data ownership — sensor readings, motion events, and device states stay on your hardware
  • Vendor independence — mix devices from IKEA, Philips Hue, Aqara, Aeotec, and Sonoff on a single platform
  • Lower latency — no round-trip to cloud servers means near-instant automations
  • No subscription fees — run on a Raspberry Pi, old laptop, or Docker server at your home

Quick Comparison

FeatureZigbee2MQTTZ-Wave JS UIESPHome
ProtocolZigbee 3.0Z-Wave (Gen 3/5/7/8)ESP32/ESP8266 WiFi
Stars (GitHub)15,056+1,207+10,936+
Last UpdatedApril 2026April 2026April 2026
LanguageTypeScriptJavaScript/VueC++
MQTT IntegrationNative (required)Native (built-in)Optional via API
Web UIYes (Vue.js)Yes (Vue/Vuetify)No (CLI + OTA)
Device Support4,000+ devices2,000+ devicesESP chips (infinite)
Home AssistantNative integrationNative integrationNative integration
Docker SupportOfficial imageOfficial imageOfficial image
Learning CurveLowLowMedium
Best ForZigbee device hubZ-Wave device hubCustom ESP sensors

Zigbee2MQTT: The Zigbee Standard

Zigbee2MQTT (github.com/Koenkk/zigbee2mqtt) bridges any Zigbee device to an MQTT broker, making it accessible to Home Assistant, Node-RED, or any MQTT client. With over 15,000 GitHub stars and support for 4,000+ devices, it is the most mature open-source Zigbee solution.

How It Works

Zigbee2MQTT runs as a daemon that communicates with a USB Zigbee coordinator (CC2652P, Sonoff Dongle, or ConBee). It translates Zigbee device messages into JSON payloads published to MQTT topics. Home automation software subscribes to those topics and can send commands back through MQTT.

Supported Coordinator Adapters

  • Texas Instruments CC2652P / CC2652R (recommended)
  • Sonoff Zigbee 3.0 USB Dongle Plus (ZBDongle-P, ZBDongle-E)
  • ConBee II / ConBee III (deCONZ protocol)
  • Texas Instruments CC2531 / CC2530 (legacy, limited range)
  • EZSP-based adapters (Silicon Labs)

Docker Deployment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
version: '3.8'
services:
  zigbee2mqtt:
    container_name: zigbee2mqtt
    image: koenkk/zigbee2mqtt:latest
    restart: unless-stopped
    volumes:
      - ./zigbee2mqtt-data:/app/data
      - /run/udev:/run/udev:ro
    ports:
      - 8080:8080
    devices:
      - /dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_V2-if00-port0:/dev/ttyACM0
    environment:
      - TZ=America/New_York

Configuration

The configuration.yaml in the data directory controls the bridge behavior:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
homeassistant: true
permit_join: false
mqtt:
  server: 'mqtt://192.168.1.10:1883'
  user: 'zigbee'
  password: 'your-mqtt-password'
serial:
  port: /dev/ttyACM0
  adapter: zstack
frontend:
  port: 8080
devices:
  '0x00158d00045b2740':
    friendly_name: living_room_motion
    retain: true

Key settings:

  • permit_join: false — disable device pairing after initial setup for security
  • retain: true — keep the last state on MQTT broker for late-joining clients
  • adapter — must match your coordinator chip (zstack, deconz, ezsp, ember)

Device Discovery

Zigbee2MQTT maintains a device database (database.db) that auto-discovers supported devices. When you pair a new device, the bridge queries the Zigbee2MQTT device database for converters — JavaScript modules that translate device-specific Zigbee clusters into standardized MQTT payloads. If a device isn’t supported, community members can submit converters via pull requests.

Z-Wave JS UI: The Z-Wave Hub

Z-Wave JS UI (github.com/zwave-js/zwave-js-ui) provides a web-based control panel for Z-Wave networks with built-in MQTT gateway functionality. It wraps the official zwave-js library (maintained by the Z-Wave JS organization) and adds a Vue.js frontend for network visualization, device configuration, and firmware updates.

How It Works

Unlike Zigbee (which is a single protocol), Z-Wave has multiple regional frequencies and generations. Z-Wave JS UI abstracts these differences through the underlying zwave-js library, providing a unified interface for all Z-Wave devices. The web UI shows your entire mesh topology, signal routes, and per-node health metrics.

Key Features

  • Network topology map — visual representation of routing paths and signal strength between nodes
  • Device configuration editor — change parameters, associations, and wakeup intervals directly from the UI
  • Firmware OTA updates — push firmware updates to Z-Wave devices over the air
  • MQTT auto-discovery — publishes devices to MQTT with Home Assistant discovery payloads
  • Z-Wave JS WebSocket server — expose the Z-Wave API on port 3000 for direct integration

Docker Deployment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: '3.7'
services:
  zwave-js-ui:
    container_name: zwave-js-ui
    image: zwavejs/zwave-js-ui:latest
    restart: always
    tty: true
    stop_signal: SIGINT
    environment:
      - SESSION_SECRET=a-unique-secret-string-here
      - TZ=America/New_York
    networks:
      - zwave
    devices:
      - /dev/serial/by-id/usb-Aeotec_Z-Wave_Stick_7-if00-port0:/dev/zwave
    volumes:
      - zwave-config:/usr/src/app/store
    ports:
      - 8091:8091
      - 3000:3000
networks:
  zwave:
volumes:
  zwave-config:
    name: zwave-config

Reverse Proxy Setup

For remote access (if you need it), put the web UI behind a reverse proxy:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
server {
    listen 80;
    server_name zwave.example.com;

    location / {
        proxy_pass http://127.0.0.1:8091;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

The WebSocket upgrade headers are essential — Z-Wave JS UI uses WebSockets for real-time network visualization.

Supported Hardware

  • Aeotec Z-Stick 7 (recommended, Z-Wave Plus Gen 7)
  • Zooz ZST10 (Gen 5)
  • HomeSeer SmartStick+ (Gen 5)
  • Silicon Labs UZB-1 / UZB-3 (Gen 5)
  • Nortek HUSBZB-1 (dual Z-Wave + Zigbee, legacy)

ESPHome: Build Your Own Sensors

ESPHome (github.com/esphome/esphome) takes a fundamentally different approach. Instead of bridging existing commercial devices, it lets you flash custom firmware onto ESP32, ESP8266, BK72XX, and RP2040 microcontrollers to create your own sensors, switches, and controllers.

With nearly 11,000 GitHub stars, ESPHome is the go-to tool for custom hardware projects. You define components in a YAML configuration file, ESPHome compiles the firmware, and flashes it over USB or OTA (over-the-air).

How It Works

  1. Write a YAML config defining sensors, switches, and automations
  2. ESPHome compiles a standalone firmware binary
  3. Flash to the ESP device via USB or existing WiFi connection
  4. The device runs autonomously, reporting to Home Assistant or MQTT

Example: Temperature and Humidity Sensor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
esphome:
  name: bedroom-sensor
  friendly_name: "Bedroom Temperature Sensor"

esp32:
  board: esp32dev
  framework:
    type: arduino

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

api:
  encryption:
    key: !secret api_key

ota:
  password: !secret ota_password

logger:

i2c:
  sda: GPIO21
  scl: GPIO22

sensor:
  - platform: aht10
    temperature:
      name: "Bedroom Temperature"
      filters:
        - offset: -2.0
    humidity:
      name: "Bedroom Humidity"
    update_interval: 60s

  - platform: wifi_signal
    name: "Bedroom WiFi Signal"
    update_interval: 60s

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO18
      mode: INPUT_PULLUP
    name: "Bedroom Window Contact"
    device_class: window
    filters:
      - delayed_on: 100ms
      - delayed_off: 100ms

Example: Smart Plug with Power Monitoring

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
esphome:
  name: living-room-plug

esp8266:
  board: esp01_1m

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

api:
ota:

logger:

switch:
  - platform: gpio
    name: "Living Room Outlet"
    pin: GPIO12
    id: relay
    restore_mode: RESTORE_DEFAULT_OFF

sensor:
  - platform: hlw8012
    sel_pin: GPIO5
    cf_pin: GPIO14
    cf1_pin: GPIO13
    current:
      name: "Living Room Current"
    voltage:
      name: "Living Room Voltage"
    power:
      name: "Living Room Power"
      filters:
        - calibrate_linear:
            - 0.0 -> 0.0
            - 25.6 -> 60.0
    update_interval: 10s
    change_mode_every: 8

status_led:
  pin:
    number: GPIO0
    inverted: true

Component Ecosystem

ESPHome supports hundreds of components out of the box:

  • Sensors: DHT, BME280, AHT10, DS18B20, ADC, ultrasonic, PIR motion
  • Displays: SSD1306 OLED, ILI9341 LCD, e-ink panels, matrix LED
  • Outputs: PWM dimmers, relay boards, NeoPixel strips, IR blasters
  • Inputs: GPIO buttons, rotary encoders, RFID readers, matrix keypads
  • Protocols: I2C, SPI, UART, 1-Wire, Modbus, CAN bus
  • Communication: Native API (Home Assistant), MQTT, HTTP, ESP-NOW

Docker Deployment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
version: '3.8'
services:
  esphome:
    container_name: esphome
    image: ghcr.io/esphome/esphome:latest
    restart: unless-stopped
    volumes:
      - ./esphome-configs:/config
    network_mode: host
    environment:
      - TZ=America/New_York

Using network_mode: host is recommended for OTA flashing, as the ESPHome dashboard needs to discover devices on the local network. The web dashboard runs on port 6052 by default.

Choosing the Right Platform

Use Zigbee2MQTT when:

  • You have Zigbee devices (lights, sensors, switches, locks)
  • You want the widest device compatibility (IKEA, Aqara, Philips Hue, third-party)
  • You already run an MQTT broker (Mosquitto, EMQX)
  • You prefer a set-and-forget bridge with minimal configuration

Use Z-Wave JS UI when:

  • You have Z-Wave devices (locks, thermostats, blind controllers)
  • You need reliable mesh networking with routing visualization
  • You want over-the-air firmware updates for Z-Wave devices
  • Your devices need long-range penetration through walls (Z-Wave’s 900 MHz advantage)

Use ESPHome when:

  • You want to build custom sensors and controllers from scratch
  • You need precise control over sensor sampling rates and filtering
  • You’re comfortable flashing microcontroller firmware
  • You want devices that are 100% under your control (no vendor firmware)
  • You need specialized sensors (soil moisture, water leak detection, energy monitoring)

Combining All Three

Most serious self-hosted smart home setups use all three platforms together:

  • Zigbee2MQTT handles battery-powered sensors (motion, door/window contacts, temperature)
  • Z-Wave JS UI manages always-powered devices (smart locks, thermostats, blinds)
  • ESPHome powers custom-built devices (energy monitors, garage door controllers, specialized sensors)

All three integrate natively with Home Assistant, which acts as the central automation engine. For the MQTT layer, you’ll need a broker — check our MQTT platform comparison guide for Mosquitto and alternatives.

FAQ

Can Zigbee2MQTT and Z-Wave JS UI run on the same server?

Yes. Both run as separate Docker containers on the same machine. They each require their own USB coordinator dongle (one Zigbee adapter and one Z-Wave stick). Since they communicate over MQTT, they can coexist without conflicts. Assign different MQTT topic prefixes to keep the data organized.

Which USB Zigbee coordinator should I buy for Zigbee2MQTT?

The Sonoff Zigbee 3.0 USB Dongle Plus (model “P” with CC2652P chip) offers the best value — around $20, excellent range, and full Zigbee 3.0 support. For maximum range, the CC2652P-based adapters support up to 100+ devices in a single network. Avoid the older CC2531 for new setups — it has limited memory and can only handle about 15-20 devices.

Do I need Home Assistant to use these tools?

No. Zigbee2MQTT and Z-Wave JS UI publish all device data to MQTT, so any MQTT client can consume it — Node-RED, OpenHAB, custom scripts, or Grafana for visualization. ESPHome supports both the Home Assistant native API and standalone MQTT mode. Home Assistant simply provides the easiest integration path.

Can ESPHome devices work without WiFi?

ESPHome devices require a network connection to report data. However, ESP32 devices support ESP-NOW for peer-to-peer communication without a WiFi network, useful for creating offline mesh sensor networks. For battery-powered sensors, ESPHome supports deep sleep modes that consume less than 20 microamps between readings, enabling months of battery life.

How do I migrate from a proprietary hub to self-hosted?

The process is straightforward:

  1. Install your self-hosted bridge (Docker is recommended)
  2. Connect the USB coordinator dongle
  3. Enable “permit join” mode on the new bridge
  4. Reset each device to factory settings and re-pair with the new bridge
  5. Note that Z-Wave devices must be excluded from the old network first — this is a protocol-level requirement, not a limitation of the software

Is Z-Wave or Zigbee better for a self-hosted smart home?

They serve different use cases. Zigbee supports more devices per network (200+ vs Z-Wave’s 232 theoretical limit), has cheaper hardware, and wider device variety from budget brands. Z-Wave offers better range per hop, less interference (operates at 900 MHz vs Zigbee’s 2.4 GHz), and mandatory interoperability certification. Most users run both: Zigbee for sensors and lights, Z-Wave for locks and thermostats where reliability matters most.

Advertise here
Advertise here