Skip to content

add native Zigbee2MQTT and Z-Wave JS UI launchd daemons on dungeon#56

Open
GregHilston wants to merge 1 commit intomasterfrom
claude/smart-home-native-services-XXADy
Open

add native Zigbee2MQTT and Z-Wave JS UI launchd daemons on dungeon#56
GregHilston wants to merge 1 commit intomasterfrom
claude/smart-home-native-services-XXADy

Conversation

@GregHilston
Copy link
Copy Markdown
Owner

Completes part two of the smart-home migration. Part one (containerized Home Assistant) landed in GregHilston/home-lab#16.

These services must run natively on macOS rather than in OrbStack because OrbStack's Linux VM has no USB passthrough — the Zigbee coordinator and Z-Wave controller are only visible to the host as /dev/cu.usbserial-* devices.

Summary

  • New nixos/modules/darwin/smart-home.nix, imported from nixos/hosts/macs/dungeon/default.nix.
  • Both binaries installed via homebrew.brews (nixpkgs derivations are Linux-first and flaky on aarch64-darwin; brew formulae are actively maintained for Apple Silicon and match the existing pattern for server-class binaries on dungeon — orbstack, docker, tailscale).
  • Two launchd.daemons matching the precedent set by prevent-sleep, mount-unraid-data, and healthcheck-ping: KeepAlive + RunAtLoad + ThrottleInterval=30 + /var/log/*.log outputs.
  • Config dirs at /Users/ghilston/home-lab-config/{zigbee2mqtt,zwave-js-ui}/ mirroring the SERVER_CONFIG_BASE convention from home-lab.
  • Z2M configuration.yaml rendered via pkgs.writeText and seeded to disk on first activation only, so manual edits (notably the real /dev/cu.usbserial-* port, filled in post-deploy) are never clobbered by subsequent just dr dungeon runs. To re-render, delete the file on dungeon and re-activate.
  • Z-Wave JS UI configured via env vars: web UI on :8091, WebSocket server on :3000 (both bound 0.0.0.0 so HA inside OrbStack can reach it via host.docker.internal or the LAN IP).
  • Optional secrets file at nixos/secrets/smart-home.json (gitignored), schema documented in the module. No new flake inputs — matches the "nothing fancy" posture the repo already has toward secrets. Keys: zigbee_serial_port, zwave_serial_port, mqtt_user, mqtt_password, zwavejs_session_secret. All optional; sensible defaults otherwise (placeholder serial ports, anonymous MQTT matching the current broker, zwave-js-ui generates its own session secret).

Test plan

  • just dt dungeon passes (dry build — I could not run this from the sandbox; needs verification on dungeon)
  • just dr dungeon activates cleanly
  • sudo launchctl list | grep -E 'zigbee2mqtt|zwave-js-ui' shows both daemons loaded
  • /var/log/zigbee2mqtt.log and /var/log/zwave-js-ui.log exist and show the expected startup errors about the placeholder serial ports (until the todos below are handled)

Manual follow-ups (deferred — not in this PR)

  • Fill in the real serial port paths. Run ls /dev/cu.* on dungeon to identify the Zigbee coordinator and Z-Wave controller, then either:
    • edit /Users/ghilston/home-lab-config/zigbee2mqtt/configuration.yaml directly (Z2M) and set ZWAVEJS_DEVICE via a secrets file (Z-Wave), OR
    • drop a nixos/secrets/smart-home.json with zigbee_serial_port and zwave_serial_port and re-run just dr dungeon.
    • Until this is done, the daemons will loop-restart trying to open the placeholder device — harmless but noisy in the logs.
  • macOS Application Firewall. Allow inbound on 3000, 8080, and 8091 from the OrbStack bridge so HA (inside the VM) can reach Z-Wave JS UI's WS server and the Z2M / Z-Wave web UIs. This repo does not currently manage networking.applicationFirewall, so handle via System Settings once on dungeon.
  • home-lab follow-up PR. Add Caddyfile entries:
    • zigbee2mqtt.grehg2.xyzhost.docker.internal:8080
    • zwave-js-ui.grehg2.xyzhost.docker.internal:8091
    • And matching homepage/services.yaml entries under the Smart Home group.
  • HA UI configuration. Once the serial ports are set and the daemons are running:
    • Add the MQTT integration pointing at localhost:1883 — it will auto-discover Zigbee devices via the zigbee2mqtt/ topic.
    • Add the Z-Wave JS integration pointing at ws://<dungeon-lan-ip>:3000.

Completes part two of the smart-home migration (home-lab PR #16 landed
the containerized Home Assistant side). These services must run natively
on macOS rather than in OrbStack because OrbStack's Linux VM has no USB
passthrough — the Zigbee coordinator and Z-Wave controller are only
visible to the host as /dev/cu.usbserial-* devices.

- New nixos/modules/darwin/smart-home.nix imported by the dungeon host.
- Both binaries installed via homebrew.brews (nixpkgs derivations are
  Linux-first and flaky on aarch64-darwin; brew formulae are actively
  maintained for Apple Silicon and match the existing pattern for
  server-class binaries on dungeon).
- Two launchd.daemons (matching the precedent set by prevent-sleep,
  mount-unraid-data, healthcheck-ping) with KeepAlive + RunAtLoad +
  ThrottleInterval=30 and /var/log/*.log outputs.
- Config dirs at /Users/ghilston/home-lab-config/{zigbee2mqtt,zwave-js-ui}/
  mirroring the SERVER_CONFIG_BASE convention from home-lab.
- Z2M configuration.yaml is rendered from nix via pkgs.writeText and
  seeded to disk on first activation only, so manual edits (notably the
  real /dev/cu.usbserial-* port, filled in post-deploy) are never
  clobbered by subsequent 'just dr dungeon' runs. To re-render, delete
  the file on dungeon and re-activate.
- Z-Wave JS UI is configured via environment variables: web UI on :8091,
  WebSocket server on :3000 (both bound 0.0.0.0 so HA inside OrbStack
  can reach it via host.docker.internal or the LAN IP).
- Optional secrets file at nixos/secrets/smart-home.json (gitignored)
  with schema documented in the module. No new flake inputs added —
  this matches the 'nothing fancy' posture the repo already has toward
  secrets. Keys: zigbee_serial_port, zwave_serial_port, mqtt_user,
  mqtt_password, zwavejs_session_secret. All optional; sensible defaults
  otherwise (placeholder serial ports, anonymous MQTT matching the
  current broker config, zwave-js-ui generates its own session secret).

Deferred / manual follow-ups (NOT in this commit):

1. Fill in the real Zigbee and Z-Wave serial port paths on dungeon.
   Run 'ls /dev/cu.*' to identify them, then either:
   - edit /Users/ghilston/home-lab-config/zigbee2mqtt/configuration.yaml
     directly (Z2M) and set ZWAVEJS_DEVICE via a secrets file (Z-Wave), OR
   - drop a nixos/secrets/smart-home.json with zigbee_serial_port and
     zwave_serial_port and re-run 'just dr dungeon'.
   Until then, the daemons will loop-restart trying to open the
   placeholder device — harmless but noisy in the logs.

2. macOS Application Firewall: allow inbound on 3000, 8080, and 8091
   from the OrbStack bridge so HA (inside the VM) can reach Z-Wave JS
   UI's WS server and the Z2M / Z-Wave web UIs. This repo does not
   currently manage applicationFirewall, so handle via System Settings
   once on dungeon.

3. home-lab repo follow-up PR: add Caddyfile entries for
   zigbee2mqtt.grehg2.xyz -> host.docker.internal:8080 and
   zwave-js-ui.grehg2.xyz -> host.docker.internal:8091, and add the
   matching homepage/services.yaml entries under the Smart Home group.

4. HA UI: once the serial ports are set and the daemons are running,
   add the MQTT integration (localhost:1883 -> auto-discovers Zigbee
   devices via zigbee2mqtt/ topic) and the Z-Wave JS integration
   (ws://<dungeon-lan-ip>:3000).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants