Make a Z-wave to WiFi bridge with esphome stream server and Zooz ZAC93 GPIO

A few people have asked so I figured I’d share this method to use the new Zooz ZAC93 800-series GPIO module with an ESP32 running esphome and UART stream server component. This is effectively a zwave-serial-to-IP-over-WiFi bridge. The ESP32 does not process any zwave packets, it just presents the raw UART as a TCP serial connection which is used by zwave-js-ui running on a server elsewhere on the LAN.

First off, I know there are WiFi haters out there who will think this is nuts, but (a) sometimes you just can’t put a wired Z-wave hub where you want in your house and this solution gives you the flexibility to put one almost anywhere you want, for under $20, and (b) my WiFi is quite solid, with 50+ devices in a downtown apartment seeing dozens of networks. Friends don’t let friends use their ISP router for WiFi.

Another bonus: this solution gives the added option of bluetooth proxying on the ESP32, whereas if used atop a raspberry pi, bluetooth has to be disabled in the kernel to enable the GPIO UART. (there might be a workaround for this, but none of the Zooz docs mention it).

For background, the Zooz ZAC93 GPIO module is a UART (serial) module specifically designed to sit atop a raspberry pi. I had it on an old Pi Zero W for a while, and it worked fine running zwave-js-ui under docker, but the OS on sdcard was painfully slow (and a failure waiting to happen). A new Zero 2 would be better, but they are extremely hard to get lately, and frankly I got tired of running a full separate OS for a zwave hub. I already had a few ESP32s sitting around looking for work so I thought I’d give this a try. Disclaimer that I am not using this for my production network yet, but I’ve been testing it for a few weeks and haven’t seen any dropouts or issues.

Basic wiring diagram is just to connect four pins from the ESP32 to the ZAC93: 3.3V, ground, Tx and Rx. Unfortunately the pins don’t perfectly lineup for a module-on-board match, so I used Dupont cables. I used GPIO1 for Tx and GPIO3 for Rx, which is the existing UART0, meaning it’s best to move the esphome logging to uart1 (or disable) to avoid conflict. I’ve attached some images for wiring.

In esphome, here are the relevant details for the firmware configuration. Note the baud rate worked best as 115200. A binary sensor is also created, thanks to the stream_server component, to let you know when the serial stream has an active TCP connection.

logger:
  hardware_uart: UART1

uart:
  id: uart_zwave
  tx_pin: GPIO1
  rx_pin: GPIO3
  baud_rate: 115200

external_components:
  - source: github://oxan/esphome-stream-server

stream_server:
  id: zac93
  uart_id: uart_zwave
  port: 6638

binary_sensor:
  - platform: stream_server
    connected:
      name: Connected


After compiling and installing the ESP32 firmware, it should be ready to use. In zwave-js-ui, just enter tcp://ip:port as the location of the zwave serial module, and it will open a connection and cause the the binary sensor (which I renamed zwave server) to be Connected. You should be able to open the debug logs and see the driver polling the card for details like RSSI readings.

zwavejsui
binary-sensor

For added peace of mind, you can create an automation that alerts you if the binary sensor becomes disconnected for more than, say, 30 seconds.

7 Likes

This is great.
I may pick up a ZAC93 next time I’m in the US and try this.

Any updates? Is this still working well for you?

Hello, any news in “esp home stream server” project? I cant run server on esp32 or ESP8266.
When I try to connect to the server, I see a connection attempt in the log, but the connection is immediately closed without any response.
Tomas

does this still work?

Yes, it’s still working, although I don’t have any nodes other than the controller yet; I may wait until the 800-series supports restoring from an earlier-series NVM backup so I don’t have to exclude and re-add dozens of devices. I’ve had it “connected” for several months now.

I just upgraded ZAC93 firmware to 1.2 using HA/zwavejs websocket (I got a timeout error but it appears to have worked). I also just upgraded the esp32 to esphome 2023.12.5 including a “pio system prune” to make sure everything is up to date. No issues with connecting and viewing debug messages in zwavejs-ui, but I did discover a DNS misconfiguration that only now needed fixing.

1 Like

I use this daily, it works perfectly and has for many months. There are instructions that I followed that allowed me to include the Zooz dongle in as a secondary controller, and ultimately transfer this new dongle to become the primary. It required a bit of work to get it to use the node ID 1 (maybe it was 0?). But has been rock solid.

Can you explain a bit more? This is my first zwave dongle so am not familiar with NVM restore and firmware updates.

I assume since this will be my first z wave device, I don’t really have to worry about restoring from an older dongle?

How do you update the firmware on the module without a Pi? esphome or it can be done with the zwave integration?

The HA Documation for zwave says the 800 series long range is not supported, what does this mean exactly with this esp version.

Did you do this by connecting the ZAC93 with a USB-TTY and your older Zooz USB dongle into the same PC and do the include/exclude controller, controller shift, virtual devices to force node id dance in Simplicity Studio I’ve read about?

zwavejs can upgrade controller fw directly

1 Like

We got a Zooz ZAC93 the other day, and decided to set this up last night to replace the Zooz ZST10. The ZST10 worked fine since we got it ~1.5 years ago, but it had to be connected directly to the Home Assistant device, which limited where that device could live physically in the house.

I flashed ESPHome onto an ESP32, set the configuration as described in the first post, connected the ZAC93 with some dupont cables (making sure to reverse RX/TX), changed the “Serial Port” in Z-Wave JS UI to tcp://<zac93-hostname>:6638, and it connected!

I spent maybe ~30 minutes trying to figure out how to transfer devices from the old controller to the new one. Landed on a YouTube video by @cornellrwilliams that looked promising (and straight-forward) only to find that you can only use the Z-Wave Controller in Simplicity Studio on Windows devices.

In the end I excluded all the devices from the old controller, and included them into the new one. We only have 7 devices. So, it only took 15-20 minutes. A minor improvement is that the old network had phantom nodes we couldn’t get rid of, but the new network doesn’t have those. They were likely from some bad pairing. A nice surprise is that all of the devices included on the first try each time. Another good thing is that all of the devices that support S2 use it with the ZAC93, whereas some of the S2 devices never used it with the ZST10.

So far, it’s been solid. Devices show up in Home Assistant, as expected. Pings work, as expected. We got rid of this need to have a USB dongle hanging off of a USB hub (because of “network interference”). And best of all, we can move the Home Assistant device elsewhere!

tl;dr; This project still works as of January 2024.

1 Like

Also, thanks @peterxian for sharing the original post! This was a simple project to put together and has worked really well so far.

1 Like

Just as an FYI for anyone else that comes across this thread/post, you can connect the ZAC93 to a Windows PC running Simplicity Studio by using a USB-TTL device. I used an Adafruit USB to TTL Serial Cable (but any USB-TTL should work) to complete the steps in the above mentioned video and successfully migrated from a ZST10-700 to a ZAC93 this month.

2 Likes

Thanks to everyone in this thread I was able to migrate my old Zwave Nortek USB Husbzb-1 to the POE Zwave from tubezb using the zooz ZAC93. I did have to migrate using simplicity studio using the video linked above, which was a bit of a pain in order to migrate. Most of my challenge was the old husbzb not allowing me to add virtual devices. I had to add the virtual devices to the ZAC93 up to 231, then add the husbzb back as 232 to then swap the ZAC93 back in a node 1 again.

Once the ZAC93 was node 1 again, the “virtual devices” were no longer seen as virtual devices but just failed nodes. I did not remove the failed virtual devices using Simplicity Stuido since it takes a while to remove each failed node manually. I added it back to ZwavejsUI waited a long while for it to finish starting up (it seemed to try to contact each failed node 3 times) then used the remove failed to automatically remove all of them for me. It probably took longer this way, but was much less manual work.

I used the Adafruit USB to TTL serial cable mentioned by @wwwryan - the wiring was pretty straight forward, it does say 3.3v on the zooz ZAC93 and 5v on the cable, but it worked just fine. The Rx/Tx needed to be swapped for me to be able to see it in simplicity studio, I think that is due to rx in and tx out. Once it was wired correctly Simplicity Studio was able to automatically find and install the drivers.

In Simplicity Studio I initially was not able to see the husbzb usb stick, I had to manually install the drivers as described here: Nortec HUSBZB USB Stick Windows Drivers - #3 by kraig109 - 🛎️ Get Help - Hubitat

1 Like

Are people using the esp based bridge to the zac93 as their main / one and only z wave controller?

I have this setup and it “works” (I’ve been able to upgrade the zac93 to version 1.2). The thing is, I just purchased 2x kwikset home connect 620 door locks and I can’t get them to pair with the controller. The locks are s2 capable and so is the zac93.

Ive tried smart start and also manually adding the node which requires the confirmation pin. Smart start doesn’t seem to work at all and manually adding the locks ends up with “unknown manufacturer and product” which exposes no locking entities, only z wave Info elentities.

I am at a loss. If it were only 1 lock doing it, I could blame a faulty lock but, I don’t think both locks are bad and are failing in the exact same way. The only thing I can think of is it’s the zac93 or the esp bridge but, that makes no sense because I did 2 firmware upgrades using the esp bridge.

Any insight would be great, I have my own post about this issue with more details and some logs at:

Any idea what I am doing wrong. I have installed the firmware using ESPHome and I can ping the ip address issued. But the Z-Wave JS can’t open the port (6638).

2024-11-12T23:13:05.415Z DRIVER   version 13.10.3
2024-11-12T23:13:05.415Z DRIVER   
2024-11-12T23:13:05.415Z DRIVER   starting driver...
2024-11-12T23:13:05.415Z DRIVER   opening serial port tcp://192.168.123.190:6638
2024-11-12T23:13:15.906Z DRIVER   Failed to open the serial port: connect ECONNREFUSED 192.168.123.190:6638
2024-11-12T23:13:15.907Z DRIVER   destroying driver instance...
2024-11-12 18:13:15.908 INFO STORE: Restarting client in 15 seconds, retry 17
2024-11-12T23:13:15.908Z DRIVER   driver instance destroyed
2024-11-12 18:13:30.911 INFO STORE: Client closed
2024-11-12 18:13:30.916 INFO STORE: Connecting to tcp://192.168.123.190:6638
2024-11-12 18:13:30.916 INFO STORE: Setting user callbacks
****************************************************************
This is the jac93lr32.yaml:

esphome:
  name: jac93lr32
  friendly_name: jac93lr32

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  hardware_uart: UART1

uart:
  id: uart_zwave
  tx_pin: GPIO1
  rx_pin: GPIO3
  baud_rate: 115200

external_components:
  - source: github://oxan/esphome-stream-server

stream_server:
  id: zac93
  uart_id: uart_zwave
  port: 6638

binary_sensor:
  - platform: stream_server
    connected:
      name: Connected

# Enable Home Assistant API
api:
  encryption:
    key: "removed"

ota:
  - platform: esphome
    password: "removed"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Jac93Lr32 Fallback Hotspot"
    password: "28SmTUn2ImxN"

captive_portal:

Any help would be appreciated. Thanks

Are you using an esp as the z wave controller host?

Connection refused is usually an unopen port.

Yes ESP32 Wroom-32
Used ESPHome to set up.
Open port on ESP32 device? I assume not router…
Never had to do that.
I can ping from network so know it’s connected to WiFi.

So you have a TCP serial2net server setup on the esp32 right?

Please explain how you’re setup. Do you have a zooz zac93 connected to an esp32 over UART?

It should work, although I am using esp-idf framework instead of arduino but it should be fine. Presumably you are using Z-Wave JS UI to enter the tcp:// location of the Z-wave adapter.

Assuming you’ve discovered the device in HA, maybe add these sensors to your esphome config so you can check that you have sufficient signal and are trying to connect to the right IP address:

sensor:
  - platform: wifi_signal
    name: WiFi Signal
    update_interval: 60s

text_sensor:
  - platform: wifi_info
    ip_address:
      name: "IP Address"