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.

  hardware_uart: UART1

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

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

  id: zac93
  uart_id: uart_zwave
  port: 6638

  - platform: stream_server
      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.


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.


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.

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.

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.


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