From fab35e8e7c0a88a750d71ebbf9e29f53a61fbc78 Mon Sep 17 00:00:00 2001 From: dohertj2 Date: Fri, 9 Oct 2026 07:23:22 -0400 Subject: [PATCH] Document Z-Wave JS and Zigbee2MQTT on Docker host; drop Raspberry Pi docs - raspi_zwave.md -> zwave_zigbee.md: zwavejs + zigbee2mqtt containers, Z-Net G8 ports 2001/2002 - Remove obsolete migratezwave.md plan - Add containers to docker.md, MQTT/Zigbee notes to ha.md, component entry to CLAUDE.md --- CLAUDE.md | 1 + docker.md | 4 ++- ha.md | 4 +-- migratezwave.md | 79 ------------------------------------------------- raspi_zwave.md | 55 ---------------------------------- zwave_zigbee.md | 68 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 137 deletions(-) delete mode 100644 migratezwave.md delete mode 100644 raspi_zwave.md create mode 100644 zwave_zigbee.md diff --git a/CLAUDE.md b/CLAUDE.md index e3219d3..88c40d7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,4 +27,5 @@ Credentials live inline in each component's `.md` file under its **Access** sect - [Veeam Server](veeam.md) — Windows Server 2025 at 10.100.0.30, Veeam B&R 12.3, backup server. **Read veeam.md for credentials and connection details.** - [Desktop](desktop.md) — Windows PC, dual-homed on LAN_100 (10.100.0.49) and DATA_50 (10.50.0.49) - [Wonderware Dev VM](ww.md) — Windows 10 ESXi VM at 10.100.0.48, OpenSSH (passwordless) +- [Z-Wave & Zigbee](zwave_zigbee.md) — HomeSeer Z-Net G8 at 10.200.0.106 hosts both radios (Z-Wave on :2001, SmartStick ZB on :2002). `zwavejs` (HA → ws://10.100.0.35:3100) and `zigbee2mqtt` (→ HA Mosquitto) containers on the Docker host, deployed via the playbook. Old Raspberry Pi is gone. - [Unifi Network](unifi.md) — UDM Pro gateway + USW Pro Aggregation central switch, API access via key diff --git a/docker.md b/docker.md index f60f6c3..b341564 100644 --- a/docker.md +++ b/docker.md @@ -100,6 +100,8 @@ All 21 containers running. Most are on the `traefik` network. | Container | Image | URL | Port | Purpose | |-----------|-------|-----|------|---------| | semaphore | semaphoreui/semaphore:latest | http://10.100.0.35:3000 | 3000 | Ansible UI | +| zwavejs | zwavejs/zwave-js-ui:latest | zwave.dohertylan.com | 8091 (UI), 3100→3000 (HA websocket) | Z-Wave JS UI for HA — see [zwave_zigbee.md](zwave_zigbee.md) | +| zigbee2mqtt | koenkk/zigbee2mqtt:latest | zigbee.dohertylan.com | 8080 (UI, Traefik only) | Zigbee coordinator → HA Mosquitto — see [zwave_zigbee.md](zwave_zigbee.md) | ### lmxopcua (carry `project=lmxopcua` label) @@ -138,7 +140,7 @@ All compose files are under `/opt//docker-compose.yml`: /opt/tautulli/ /opt/nzbget/ /opt/vpn_downloads/ /opt/uptime_kuma/ /opt/stash/ /opt/utilities/ /opt/semaphore/ /opt/ilo_fan/ -/opt/plex/ +/opt/plex/ /opt/zwavejs/ /opt/zigbee2mqtt/ /opt/otopcua-mssql/ /opt/otopcua-modbus/ /opt/otopcua-abcip/ /opt/otopcua-s7/ /opt/otopcua-opcuaclient/ ``` diff --git a/ha.md b/ha.md index c0ea211..f7c93fc 100644 --- a/ha.md +++ b/ha.md @@ -43,8 +43,8 @@ | Category | Integrations | |----------|-------------| -| **Z-Wave / Zigbee / Matter** | zwave_js, matter | -| **MQTT / ESPHome** | mqtt, esphome | +| **Z-Wave / Zigbee / Matter** | zwave_js, matter, Zigbee via Zigbee2MQTT over mqtt — see [zwave_zigbee.md](zwave_zigbee.md) | +| **MQTT / ESPHome** | mqtt (Mosquitto broker add-on; logins `caffha`, `watermgr`, `zigbee2mqtt`), esphome | | **WiFi Devices** | shelly, ac_infinity, flair, midea_dehumidifier_lan, govee_ble | | **Appliances** | ge_home, roborock | | **Media** | sonos, apple_tv, cast, webostv | diff --git a/migratezwave.md b/migratezwave.md deleted file mode 100644 index af6cfc0..0000000 --- a/migratezwave.md +++ /dev/null @@ -1,79 +0,0 @@ -# Migrate Z-Wave JS from Raspberry Pi to Home Assistant - -## Context - -Z-Wave JS UI currently runs on a Raspberry Pi (10.200.0.190) as a Docker container, connecting to the Z-Net G8 controller at `tcp://10.200.0.106:2001`. Home Assistant then connects to the Raspi's websocket on port 3000. This adds an unnecessary hop and dependency on the Raspi. Since the Z-Net G8 is network-based, HA can connect to it directly. - -**Current**: HA → ws:3000 → Raspi (Z-Wave JS UI Docker) → tcp:2001 → Z-Net G8 -**Target**: HA → Z-Wave JS add-on (local) → tcp:2001 → Z-Net G8 - -## Current State - -- **219 Z-Wave entities** in HA -- **~23 Z-Wave nodes** with custom names (DownstairsBathroomFan, GarageSensor1, etc.) -- **Security keys** (S0, S2 Auth/Unauth/Access Control, LR) configured in Z-Wave JS UI -- Device pairings stored in Z-Net G8 NVM (persist regardless of software change) -- Raspi also runs: zigbee2mqtt, portainer_agent, ouroboros (these stay on the Raspi) - -## Recommended Approach: Z-Wave JS UI Add-on on HAOS - -Install the **Z-Wave JS UI community add-on** on HAOS rather than the official Z-Wave JS add-on. Reasons: -- Same software as current setup → minimal risk -- Keeps the full web UI for network management -- HomeSeer docs specifically recommend Z-Wave JS UI for Z-Net controllers -- Security keys and node names can be migrated directly - -## Steps - -### 1. Backup current Z-Wave JS UI on Raspi -- Create NVM backup from the Z-Wave JS UI web interface (http://10.200.0.190:8091) -- Copy the store directory from the Raspi container: `sudo docker exec zwavejs2mqtt tar czf /tmp/zwave-store-backup.tar.gz /usr/src/app/store/` -- Copy backup locally: `scp dohertj2@10.200.0.190:/tmp/zwave-store-backup.tar.gz ./` -- Save the settings.json (contains security keys and TCP port config) - -### 2. Stop Z-Wave JS UI on Raspi -- `ssh dohertj2@10.200.0.190 "sudo docker stop zwavejs2mqtt"` -- This releases the TCP connection to the Z-Net G8 (only one client can hold it) - -### 3. Install Z-Wave JS UI add-on on HAOS -- Via HA web UI: Settings → Add-ons → Add-on Store → search "Z-Wave JS UI" (community add-on) -- OR via API if possible: add the community add-on repository and install - -### 4. Configure the add-on -- Set serial port to `tcp://10.200.0.106:2001` -- Enter the existing security keys: - - S2_Unauthenticated: `015BD790CCDB08172CBD12754C73E4D3` - - S2_AccessControl: `B3F99B99EE958BFAE813A84FD3586E2A` - - S0_Legacy: `FBF63F5E6515286C3AB8CC9E5F275B46` - - S2_Authenticated: `67E9ECD830733A1E1BEB22DC0EAA2739` - - S2_Authenticated_LR: `2176EE246C67320A42F2C0A23932E9B5` - - S2_AccessControl_LR: `E534F94FCD0BE8B42F056F2F3548002E` -- Start the add-on - -### 5. Reconfigure HA Z-Wave JS integration -- Remove the current zwave_js integration (pointing to ws://10.200.0.190:3000) -- Re-add it pointing to the local add-on's websocket (ws://localhost:3000 or the add-on's internal URL) -- Verify all 219 entities are rediscovered with correct names/device assignments - -### 6. Verify -- Check all Z-Wave nodes are online in the Z-Wave JS UI add-on -- Confirm entity count matches (~219) -- Test a few devices (turn a light on/off, check a sensor reading) -- Verify automations that use Z-Wave devices still work - -### 7. Cleanup -- Remove the zwavejs2mqtt container from the Raspi: `sudo docker rm zwavejs2mqtt` -- Update `raspi_zwave.md` to reflect new architecture - -## Risk Mitigation - -- **Rollback**: If anything goes wrong, stop the HA add-on, restart the Raspi container, and re-point the integration back -- **Entity IDs**: Removing and re-adding the integration may change entity IDs. HA should re-discover them with the same unique IDs from Z-Wave JS, but automations/dashboards may need updating if not -- **Cross-VLAN**: HA (10.100.0.40, VLAN 100) must be able to reach Z-Net G8 (10.200.0.106, VLAN 200) on TCP port 2001 — confirmed allowed - -## Verification - -1. Entity count: `curl -s http://10.100.0.40:8123/api/template -d '{"template":"{{ integration_entities(\"zwave_js\") | list | length }}"}' ` should return ~219 -2. Z-Wave JS UI web interface accessible from HA add-on -3. Test device control via HA -4. Check HA logs for Z-Wave errors diff --git a/raspi_zwave.md b/raspi_zwave.md deleted file mode 100644 index 902a54f..0000000 --- a/raspi_zwave.md +++ /dev/null @@ -1,55 +0,0 @@ -# Z-Wave Infrastructure - -## Architecture - -``` -HA (10.100.0.40) --ws:3000--> Raspberry Pi (10.200.0.190) --tcp:2001--> Z-Net G8 (10.200.0.106) - (Z-Wave JS UI) (Z-Wave radio controller) -``` - -## Z-Net G8 (Z-Wave Controller) - -- **Hostname**: Z-Net-G8 -- **IP**: 10.200.0.106 (IOT_200, VLAN 200) -- **MAC**: 02:53:ec:d0:de:dd -- **Manufacturer**: HomeSeer Technologies -- **Role**: Z-Wave radio controller (Node 1), serial-over-TCP on port 2001 - -## Raspberry Pi (Z-Wave JS UI Host) - -- **Hostname**: zwave -- **IP**: 10.200.0.190 (IOT_200, VLAN 200) -- **MAC**: e4:5f:01:02:3c:26 -- **Hardware**: Raspberry Pi (Raspberry Pi Trading Ltd) -- **SSH**: `ssh dohertj2@10.200.0.190` (passwordless) -- **Web UI**: http://10.200.0.190:8091 -- **Z-Wave JS websocket**: ws://10.200.0.190:3000 - -### Docker Containers - -| Container | Image | Ports | -|-----------|-------|-------| -| zwavejs2mqtt | zwavejs/zwave-js-ui:latest | 3000 (websocket), 8091 (web UI) | -| zigbee2mqtt | koenkk/zigbee2mqtt:latest | — | -| portainer_agent | portainer/agent:2.21.5 | 9001 | -| ouroboros | pyouroboros/ouroboros | — | - -### Z-Wave JS Config - -- **Serial port**: `tcp://10.200.0.106:2001` (Z-Net G8 over network) -- **Z-Wave region**: 1 (US) -- **Server port**: 3000 (websocket for HA) -- **Status**: ready - -## Home Assistant Integration - -- **Integration**: zwave_js -- **Connects to**: ws://10.200.0.190:3000 -- **Node 1**: HomeSeer Z-Wave Shield with External Antenna (Z-Net G8) - -## Notes - -- Both devices sit on the IoT VLAN (10.200.0.0/24) -- HA connects cross-VLAN (LAN_100 -> IOT_200) to the Raspi websocket -- The Raspi also runs Zigbee2MQTT (separate Zigbee network) -- Tracked by Unifi as device_tracker.zwave (Raspi) and device_tracker.z_net_g8 (controller) diff --git a/zwave_zigbee.md b/zwave_zigbee.md new file mode 100644 index 0000000..454549e --- /dev/null +++ b/zwave_zigbee.md @@ -0,0 +1,68 @@ +# Z-Wave & Zigbee Infrastructure + +## Architecture + +``` +Z-Wave: HA (10.100.0.40) --ws:3100--> Docker host (10.100.0.35) zwavejs --tcp:2001--> Z-Net G8 (10.200.0.106) Z-Wave radio +Zigbee: HA Mosquitto (10.100.0.40:1883) <--mqtt-- Docker host zigbee2mqtt --tcp:2002--> Z-Net G8 SmartStick ZB (USB) +``` + +Both radios live on the Z-Net G8; both controller apps run as containers on the Docker host, deployed by the Ansible playbook (`~/playbook`, roles `zwavejs` and `zigbee2mqtt`). + +The Raspberry Pi (10.200.0.190) that previously hosted Z-Wave JS UI is gone. + +## Z-Net G8 (Z-Wave Controller) + +- **Hostname**: Z-Net-G8 +- **IP**: 10.200.0.106 (IOT_200, VLAN 200) +- **MAC**: 02:53:ec:d0:de:dd +- **Manufacturer**: HomeSeer Technologies +- **Role**: Z-Wave radio controller (Node 1), serial-over-TCP on port 2001 +- **Zigbee**: HomeSeer SmartStick ZB plugged into the Z-Net's USB, exposed on port **2002** (2003 is for older Sonoff ZBDongle-E revisions). Requires Z-Net firmware ≥ 1.0.27 (running 1.0.27). +- **Web UI**: http://10.200.0.106/ + +## Z-Wave JS UI (container on the Docker host) + +- **Host**: [Docker Server](docker.md) — `ssh dohertj2@10.100.0.35` +- **Container**: `zwavejs` (`zwavejs/zwave-js-ui:latest`), restart `unless-stopped`, created 2026-07-03 +- **Compose file**: `/opt/zwavejs/docker-compose.yml` (templated by playbook role `zwavejs`) +- **Store/data**: `/opt/zwavejs/store` → `/usr/src/app/store` (`settings.json`, `nodes.json`, `backups/`) +- **Network**: `traefik` +- **Web UI**: https://zwave.dohertylan.com (Traefik → port 8091, Authelia SSO; Z-Wave JS UI's own auth is disabled) +- **Z-Wave JS websocket**: ws://10.100.0.35:3100 (host 3100 → container 3000) + +### Z-Wave JS Config + +- **Serial port**: `tcp://10.200.0.106:2001` (Z-Net G8 over network) +- **Z-Wave region**: 1 (US) +- **Server port**: 3000 in container (published as 3100) + +## Home Assistant Integration + +- **Integration**: zwave_js +- **Connects to**: ws://10.100.0.35:3100 +- **Size**: 25 devices, 296 entities (2026-10-09) +- **Node 1**: HomeSeer Z-Wave Shield with External Antenna (Z-Net G8) +- Two stale `not_loaded` config entries remain (an old "Z-Wave JS" entry and a Silicon Labs CP2102N USB serial entry) + +## Zigbee2MQTT (container on the Docker host) + +- **Container**: `zigbee2mqtt` (`koenkk/zigbee2mqtt:latest`, 2.14.2 at deploy), restart `unless-stopped`, deployed 2026-10-09 +- **Playbook role**: `zigbee2mqtt` — `sudo ansible-playbook site.yml -i localhost, -c local --tags zigbee2mqtt --limit localhost` from `~/playbook` (Semaphore currently has no project configured) +- **Compose file**: `/opt/zigbee2mqtt/docker-compose.yml` +- **Data**: `/opt/zigbee2mqtt/data` → `/app/data` (`configuration.yaml` holds the generated network key — back it up; `coordinator_backup.json`) +- **Config ownership**: `configuration.yaml` is seeded once by Ansible (never overwritten); MQTT, serial and frontend settings are enforced by `ZIGBEE2MQTT_CONFIG_*` env vars in the compose file +- **Web UI**: https://zigbee.dohertylan.com (Traefik → port 8080, Authelia SSO) +- **Coordinator**: `tcp://10.200.0.106:2002`, adapter `ember`, EmberZNet 7.4.3, IEEE 0x8c8b48fffe2dd481 +- **Network**: channel 25, PAN ID 64462 (0xFBCE) — new network formed 2026-10-09; all devices must be (re)paired +- **MQTT**: HA's Mosquitto broker add-on at mqtt://10.100.0.40:1883, base topic `zigbee2mqtt`, HA discovery enabled + - **User**: `zigbee2mqtt` / **Password**: `Aywm6DjOR3bfSo9c7zDoWDxX` (login in the Mosquitto add-on options; also in the playbook role defaults) + +### Pairing devices + +Turn on **Permit join** in the Zigbee2MQTT web UI (or the `switch.zigbee2mqtt_bridge_permit_join` entity in HA), then reset/pair the device. It appears in HA automatically via MQTT discovery. + +## Notes + +- Z-Net G8 is on the IoT VLAN; the Docker host reaches it cross-VLAN (or via its IOT_200 interface 10.200.0.35) +- Tracked by Unifi as device_tracker.z_net_g8