secubox-deb/packages/secubox-zigbee/debian/rules
CyberMind-FR c64b7e569e feat(secubox-zigbee): v2.4.0 rewrite-in-place to LXC + npm + z2m 2.10.1 (closes #241)
Replaces the v1.0.0 host-bound skeleton with the canonical SecuBox LXC
pattern (sibling of mqtt v2.4.0). Depends `secubox-mqtt (>= 2.4)` —
credentials are read from /etc/secubox/secrets/mqtt-z2m at install time
and rendered into z2m's configuration.yaml.

Minimum viable v2.4.0 (operator scope choice 2026-05-20):

* LXC at 10.100.0.111 on br-lxc. Node 20 from NodeSource (Debian
  bookworm only ships Node 18, too old for z2m 2.x).
* zigbee2mqtt 2.10.1 installed from the npm registry (NOT from the
  GitHub tag — the tag ships only TypeScript sources and `npm start`
  requires a working pnpm build chain that broke on v2.0.0 with a
  TS error in worker-timers-broker. The npm tarball ships a pre-built
  dist/ which sidesteps the entire build dance.)
* Hard limits per docs/superpowers/specs/2026-05-20-secubox-zigbee-mqtt-iot-stack.md:
  - permit_join: false in configuration.yaml
  - network_key / pan_id / ext_pan_id: GENERATE
  - daemon User=zigbee2mqtt + dialout group + NoNewPrivileges=true +
    ProtectSystem=strict
* udev rule /etc/udev/rules.d/99-secubox-zigbee.rules creates
  /dev/secubox-zgb when a Sonoff CC2652P (1a86:55d4), ConBee II
  (1cf1:0030), or CP210x (10c4:ea60) is plugged in. LXC config
  bind-mounts /dev/secubox-zgb with create=file,optional so the LXC
  starts whether or not the dongle is present.
* zigbeectl follows the SecuBox CTL grammar:
  - introspection: components / status / access
  - lifecycle:     install / reload (+ stubs)
  - module nouns:  device / network / topology / permit-join
* Host control plane: FastAPI on /run/secubox/zigbee.sock with
  /components, /status, /access, /healthz. Reverse-proxied at
  /api/v1/zigbee/. Reads zigbee2mqtt/bridge/state from the broker
  to populate the bridge component state.

Board-validated on gk2 (no dongle plugged):
    $ zigbeectl status
    lxc       running      zigbee @ 10.100.0.111 on br-lxc
    device    absent       no Zigbee dongle plugged — z2m will idle
    daemon    running      zigbee2mqtt, frontend port 8080
    bridge    unknown      zigbee2mqtt/bridge/state @ 10.100.0.110:1883
    host-api  running      secubox-zigbee.service (uvicorn)
    overall: yellow

    $ curl -I http://10.100.0.111:8080/
    HTTP/1.1 200 OK   # z2m onboarding page (radio absent → onboarding)

    $ curl -sk -H 'Host: admin.gk2.secubox.in' https://192.168.1.200:9443/api/v1/zigbee/status
    {"overall": "yellow", "states": {"lxc":"running","device":"absent",
                                     "daemon":"running","bridge":"unknown"}}

Lessons folded in during the board cycle:

1. z2m 2.x GitHub tags ship only TS sources. The npm tarball ships
   pre-built dist/ — install via `npm install zigbee2mqtt@<ver>`,
   not `git clone + pnpm run build`.
2. `sudo` is broken inside unprivileged LXCs (/etc/sudo.conf is owned
   by mapped uid 100000). Use `runuser -u <user> --` instead.
3. `install -d` on an existing directory doesn't always re-apply
   mode/owner on bookworm — chmod/chown explicitly when widening
   /etc/secubox/secrets/ from the mqtt-default 0700 root:root.
4. Long-standing bug in `config_get` (shared with sibling ctls):
   `cut | tr` returns 0 even when grep matches nothing, so the
   `|| echo $default` never fires. Capture into a variable, test
   empty, then fall back to default.

Out of scope for v2.4.0 (deferred to v2.5):

* Z2MBridge async pub/sub pattern (full /devices, /topology,
  /permit_join, /bind, /ota/* endpoints with request/response
  correlation IDs)
* Frontend authentication (currently LAN-only no-auth)
* Coordinator firmware OTA via the host API

Closes #241
2026-05-20 14:08:05 +02:00

30 lines
1.6 KiB
Makefile
Executable File

#!/usr/bin/make -f
%:
dh $@
override_dh_auto_install:
# Host control plane (FastAPI)
install -d debian/secubox-zigbee/usr/lib/secubox/zigbee
cp -r api debian/secubox-zigbee/usr/lib/secubox/zigbee/
# CTL
install -d debian/secubox-zigbee/usr/sbin
install -m 755 sbin/zigbeectl debian/secubox-zigbee/usr/sbin/zigbeectl
# Web UI
install -d debian/secubox-zigbee/usr/share/secubox/www
[ -d www ] && cp -r www/. debian/secubox-zigbee/usr/share/secubox/www/ || true
# Menu entry
install -d debian/secubox-zigbee/usr/share/secubox/menu.d
[ -d menu.d ] && cp -r menu.d/. debian/secubox-zigbee/usr/share/secubox/menu.d/ || true
# nginx snippet — install to BOTH secubox.d/ and secubox-routes.d/ (per v2.11.1 lesson)
install -d debian/secubox-zigbee/etc/nginx/secubox.d
[ -f nginx/zigbee.conf ] && cp nginx/zigbee.conf debian/secubox-zigbee/etc/nginx/secubox.d/ && (install -d debian/secubox-zigbee/etc/nginx/secubox-routes.d && cp nginx/zigbee.conf debian/secubox-zigbee/etc/nginx/secubox-routes.d/) || true
# Config example
install -d debian/secubox-zigbee/etc/secubox
[ -f conf/zigbee.toml.example ] && cp conf/zigbee.toml.example debian/secubox-zigbee/etc/secubox/zigbee.toml.example || true
# LXC bootstrap
install -d debian/secubox-zigbee/usr/share/secubox/lib/zigbee
[ -d lib/zigbee ] && cp -r lib/zigbee/. debian/secubox-zigbee/usr/share/secubox/lib/zigbee/ || true
# install-lxc.sh must be executable (cp -r doesn't always preserve +x from git)
[ -f debian/secubox-zigbee/usr/share/secubox/lib/zigbee/install-lxc.sh ] && \
chmod 755 debian/secubox-zigbee/usr/share/secubox/lib/zigbee/install-lxc.sh