diff --git a/docs/superpowers/specs/2026-06-03-naruto-zigbee2mqtt-design.md b/docs/superpowers/specs/2026-06-03-naruto-zigbee2mqtt-design.md new file mode 100644 index 0000000..846a8a5 --- /dev/null +++ b/docs/superpowers/specs/2026-06-03-naruto-zigbee2mqtt-design.md @@ -0,0 +1,82 @@ +# Zigbee2MQTT + Mosquitto on naruto — Design Spec + +**Date:** 2026-06-03 + +## Goal + +Run Zigbee2MQTT and Mosquitto as Docker containers on naruto, managed by the `raspberry_pi` Ansible role. Home Assistant (running in k3s) connects to Mosquitto over the LAN. + +## Hardware + +- Host: naruto (Pi 4, 192.168.20.13) +- Zigbee coordinator: SONOFF Dongle Lite MG21 on `/dev/ttyUSB0` +- Stable by-id path: `/dev/serial/by-id/usb-SONOFF_SONOFF_Dongle_Lite_MG21_0263f93f46a2ef11b078926661ce3355-if00-port0` + +## Architecture + +Two containers via Docker Compose on naruto. Ansible templates all configs and manages the stack. Home Assistant adds the MQTT integration pointing at `192.168.20.13:1883`. + +``` +[SONOFF Dongle /dev/ttyUSB0] + | +[zigbee2mqtt container] + | MQTT (internal docker network) +[mosquitto container] :1883 + | +[Home Assistant in k3s] — via LAN 192.168.20.13:1883 +``` + +## Directory Layout on naruto + +``` +/opt/docker/ + config/ + mosquitto/ + mosquitto.conf + data/ + log/ + zigbee2mqtt/ + configuration.yaml + data/ + compose/ + docker-compose.yml +``` + +## Mosquitto Config + +- Listens on port 1883 +- No authentication (internal LAN only) +- Persistence enabled, logs to `/opt/docker/config/mosquitto/log/` + +## Zigbee2MQTT Config + +- Serial port: `/dev/serial/by-id/usb-SONOFF_SONOFF_Dongle_Lite_MG21_0263f93f46a2ef11b078926661ce3355-if00-port0` +- MQTT broker: `mqtt://mosquitto:1883` (internal docker network) +- Network key: stored in `vars/group_vars/raspberry_pi/secrets.yaml` as `vault_raspberry_pi.zigbee2mqtt.network_key` +- Frontend enabled on port 8080 for local device management + +## Secrets + +`vars/group_vars/raspberry_pi/secrets.yaml` (vault-encrypted, placeholder for now): + +```yaml +vault_raspberry_pi: + zigbee2mqtt: + network_key: "YOUR_ZIGBEE_NETWORK_KEY" +``` + +## Ansible Changes + +| Action | Path | Responsibility | +|--------|------|----------------| +| Modify | `roles/raspberry_pi/tasks/main.yaml` | Include numbered task files | +| Create | `roles/raspberry_pi/tasks/10_directories.yaml` | Create `/opt/docker/` tree | +| Create | `roles/raspberry_pi/tasks/20_zigbee2mqtt.yaml` | Template configs, start compose | +| Create | `roles/raspberry_pi/templates/zigbee2mqtt/docker-compose.yml.j2` | Compose file | +| Create | `roles/raspberry_pi/templates/zigbee2mqtt/mosquitto.conf.j2` | Mosquitto config | +| Create | `roles/raspberry_pi/templates/zigbee2mqtt/z2m-configuration.yaml.j2` | Zigbee2MQTT config | +| Create | `vars/group_vars/raspberry_pi/secrets.yaml` | Network key placeholder | + +## Host Constraint + +The `raspberry_pi` role applies to both naruto and pi. The Zigbee2MQTT tasks must be guarded with `when: inventory_hostname == 'naruto'` since the USB dongle is only on naruto.