feat: bootstrap zigbee2mqtt app and diagnostics
This commit is contained in:
parent
d566a84dda
commit
ec81952db1
110
DOCS/ARCHITECTURE_NOTES.md
Normal file
110
DOCS/ARCHITECTURE_NOTES.md
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# SecuBox Architecture Notes
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Last Updated:** 2025-12-28
|
||||||
|
**Status:** Active
|
||||||
|
|
||||||
|
These notes summarize the repository structure, conventions, and supporting tooling gathered from `README.md`, `DOCS/QUICK-START.md`, `DOCS/DEVELOPMENT-GUIDELINES.md`, `DOCS/CODEX.md`, `DOCS/DOCUMENTATION-INDEX.md`, the various module READMEs, and the `secubox-tools/` scripts. Use this as a rapid orientation before extending the platform.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repository Layout (high level)
|
||||||
|
|
||||||
|
- **LuCI modules (`luci-app-*`)** – Each app bundles a LuCI frontend (JS under `htdocs/luci-static`), RPCD backend (shell scripts in `root/usr/libexec/rpcd/`), UCI defaults (`root/etc/config/...`), ACL/menu descriptors, and module-specific README (see e.g. `luci-app-netdata-dashboard/README.md`). Naming conventions follow the “menu path = view path” and “RPC object name = file name” rules emphasized in `DOCS/QUICK-START.md`.
|
||||||
|
- **Themes (`luci-theme-secubox`)** – Provides the shared SecuBox design tokens (`sh-*`, `sb-*` classes, palette, typography). All new UI should import `secubox-theme/secubox-theme.css` and leverage the CSS variables described in `DOCS/DEVELOPMENT-GUIDELINES.md`.
|
||||||
|
- **Core orchestration apps**
|
||||||
|
- `luci-app-secubox`: global hub UI.
|
||||||
|
- `luci-app-system-hub`: system health/remote assistance.
|
||||||
|
- `luci-app-network-modes`: prebuilt router/sniffer modes (bridges, AP, relay, etc.).
|
||||||
|
- `luci-app-vhost-manager`: reverse-proxy/vhost configuration (existing baseline for future work).
|
||||||
|
- **Tooling (`secubox-tools/`)** – Bash/POSIX scripts for validation, building, deployment, permission repair, etc. The README documents workflows such as `validate-modules.sh`, `local-build.sh`, `fix-permissions.sh`, and `deploy-*.sh`.
|
||||||
|
- **Automation & Docs**
|
||||||
|
- `DOCS/` + `docs/`: mirrored, versioned documentation tree (design system, prompts, module templates, validation, permissions, etc.).
|
||||||
|
- `EXAMPLES/` and `templates/`: snippets and scaffolding.
|
||||||
|
- CI workflows live in `.github/workflows/` (referenced from README badges).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Coding & Packaging Standards
|
||||||
|
|
||||||
|
Summarized from `DOCS/QUICK-START.md`, `DOCS/DEVELOPMENT-GUIDELINES.md`, and `DOCS/CODEX.md`:
|
||||||
|
|
||||||
|
1. **RPCD/ubus**
|
||||||
|
- RPC script filename **must** equal the ubus object (e.g., `root/usr/libexec/rpcd/luci.netdata-dashboard` ⇒ `object: 'luci.netdata-dashboard'`).
|
||||||
|
- RPC scripts are executable (755) while JS/CSS assets are 644.
|
||||||
|
- ACL and menu JSON entries shipped under `root/usr/share/rpcd/acl.d/` and `root/usr/share/luci/menu.d/`.
|
||||||
|
2. **LuCI Views**
|
||||||
|
- Menu `path` mirrors `htdocs/luci-static/resources/view/...` location.
|
||||||
|
- Use the SecuBox design system (`sh-*`/`sb-*` classes, Inter + JetBrains Mono, gradients). Avoid inline styles; rely on variables defined in `system-hub/common.css` or `secubox-theme`.
|
||||||
|
3. **UCI-first configuration**
|
||||||
|
- Every feature stores runtime state in `/etc/config/<module>`.
|
||||||
|
- CLI/scripts mutate config via `uci set/commit` and services watch UCI for changes.
|
||||||
|
4. **Service supervision**
|
||||||
|
- Prefer `procd` init scripts (`/etc/init.d/<service>`) for daemons; ensure restart semantics and `ENABLE` flags.
|
||||||
|
5. **Validation workflow**
|
||||||
|
- Run `./secubox-tools/validate-modules.sh` before PRs/releases. It checks permissions, RPC naming, LuCI assets, etc.
|
||||||
|
- Use `./secubox-tools/local-build.sh build <module>` for SDK builds; `fix-permissions.sh` to normalize deployments.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Networking & Firewall Conventions
|
||||||
|
|
||||||
|
Derived from `luci-app-network-modes`, `luci-app-client-guardian`, and docs:
|
||||||
|
|
||||||
|
- Network modes (router/sniffer/AP) are implemented via UCI (`/etc/config/network`, `/etc/config/wireless`) with helper scripts ensuring safe defaults and backups before applying.
|
||||||
|
- Firewall zones follow OpenWrt defaults (lan/wan) with additional zones per feature (IoT, Guest, Quarantine). Changes should add backup/rollback paths and never remove LAN management access.
|
||||||
|
- Reverse proxy/vhost management currently relies on `luci-app-vhost-manager`; new work should extend its UCI schema rather than inventing a parallel config.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Storage & Runtime Expectations
|
||||||
|
|
||||||
|
- Target platform: OpenWrt 24.10.x (and preview 25.12 RC) on ARM64 per `README.md`. Flash is limited; prefer `/srv` or external storage for large artifacts (Docker/LXC images).
|
||||||
|
- Overlay space must be <90% before deploying; quick-start docs include SSH check commands.
|
||||||
|
- `/tmp` is tmpfs; don’t store persistent state there. Use `/srv/<app>` (Zigbee2MQTT), `/var/lib/<app>`, or configurable data roots.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## secubox-tools Highlights
|
||||||
|
|
||||||
|
- `validate-modules.sh` – structural lint, permissions, ubus paths.
|
||||||
|
- `local-build.sh` – OpenWrt SDK automation for building/testing packages (supports multiple arches).
|
||||||
|
- `fix-permissions.sh`, `deploy-*.sh` – remote deployment helpers with backup/restore.
|
||||||
|
- These scripts are POSIX shell friendly and should be leveraged (or extended) for new installers/diagnostics.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Existing Modules & Patterns
|
||||||
|
|
||||||
|
- **Monitoring dashboards** (Netdata, Netifyd, CrowdSec, WireGuard, Traffic Shaper, Bandwidth Manager) provide consistent patterns for:
|
||||||
|
- RPC APIs returning JSON for LuCI views.
|
||||||
|
- JS views using `view.extend`, `poll` auto-refresh, and stat cards built with design system classes.
|
||||||
|
- **Security & NAC modules** (Client Guardian, Auth Guardian) showcase how to integrate with firewall/zones, handle ACL, and present complex forms in LuCI.
|
||||||
|
- **Network orchestration** (Network Modes, System Hub) demonstrates multi-step wizards, health checks, and service controls.
|
||||||
|
- **Theme & Navigation** (luci-theme-secubox, luci-app-secubox) define tab components, cascade helpers, and global CSS/JS assets.
|
||||||
|
|
||||||
|
Use these modules as references when building new “apps” to ensure consistent UX, RPC layout, and packaging.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation Requirements
|
||||||
|
|
||||||
|
- Every new or edited `.md` must follow the metadata header and versioning rules defined in `DOCS/DOCUMENTATION-INDEX.md`.
|
||||||
|
- Cross-link relevant guides (Quick Start, Dev Guidelines, Codex) when introducing new features.
|
||||||
|
- For platform-level additions (App Store, Vhost manager, DMZ mode, etc.), update both `DOCS/` and `docs/` to keep mkdocs + markdown parity.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Future Work Context
|
||||||
|
|
||||||
|
`TODO-ANALYSE.md` highlights ongoing documentation and automation initiatives:
|
||||||
|
- Standardize version headers across documentation.
|
||||||
|
- Add “See Also” cross-links.
|
||||||
|
- Maintain an archive folder for legacy docs.
|
||||||
|
- Build new testing/performance/security guides.
|
||||||
|
|
||||||
|
Keep these in mind when touching docs or adding new features so we converge toward the roadmap.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This document will evolve alongside the App Store, Docker/LXC frameworks, and new wizard/profile systems. Update it whenever repository architecture or workflows change significantly.
|
||||||
@ -206,7 +206,16 @@ Follow this template when creating or revising documentation:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 4. Tools & Scripts Documentation
|
### 4. Embedded Deployment Guides
|
||||||
|
|
||||||
|
#### **embedded/docker-zigbee2mqtt.md** 🔌
|
||||||
|
*Deploy Zigbee2MQTT via Docker on SecuBox (ARM64).*
|
||||||
|
|
||||||
|
Pointer: see `docs/embedded/docker-zigbee2mqtt.md` for the canonical version.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Tools & Scripts Documentation
|
||||||
|
|
||||||
#### **secubox-tools/README.md** 🔧
|
#### **secubox-tools/README.md** 🔧
|
||||||
*Documentation for validation and build tools*
|
*Documentation for validation and build tools*
|
||||||
@ -225,7 +234,7 @@ Follow this template when creating or revising documentation:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 5. Live Demo & Examples
|
### 6. Live Demo & Examples
|
||||||
|
|
||||||
#### **Live Demo Website** 🌐
|
#### **Live Demo Website** 🌐
|
||||||
*Production demo of all modules*
|
*Production demo of all modules*
|
||||||
|
|||||||
7
DOCS/embedded/docker-zigbee2mqtt.md
Normal file
7
DOCS/embedded/docker-zigbee2mqtt.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Docker Zigbee2MQTT on OpenWrt ARM64
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Last Updated:** 2025-12-28
|
||||||
|
**Status:** Active
|
||||||
|
|
||||||
|
See `docs/embedded/docker-zigbee2mqtt.md` for the full guide. This mirrored copy is maintained for MkDocs builds. Keep both files in sync when editing.
|
||||||
7
docs/ARCHITECTURE_NOTES.md
Normal file
7
docs/ARCHITECTURE_NOTES.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# SecuBox Architecture Notes
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Last Updated:** 2025-12-28
|
||||||
|
**Status:** Active
|
||||||
|
|
||||||
|
This file mirrors the architecture summary maintained in `DOCS/ARCHITECTURE_NOTES.md`. See that copy for the canonical version.
|
||||||
@ -206,7 +206,24 @@ Follow this template when creating or revising documentation:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 4. Tools & Scripts Documentation
|
### 4. Embedded Deployment Guides
|
||||||
|
|
||||||
|
#### **embedded/docker-zigbee2mqtt.md** 🔌
|
||||||
|
*Deploy Zigbee2MQTT via Docker on SecuBox (ARM64).*
|
||||||
|
|
||||||
|
**Contents:**
|
||||||
|
- Prerequisite checklist (storage, cgroups, USB coordinator, Docker packages)
|
||||||
|
- Usage of `zigbee2mqttctl` (install/check/update/status/logs)
|
||||||
|
- UCI configuration reference (`/etc/config/zigbee2mqtt`)
|
||||||
|
- Troubleshooting + rollback/uninstall steps
|
||||||
|
|
||||||
|
**When to use:** Setting up Zigbee2MQTT before the LuCI UI is available.
|
||||||
|
|
||||||
|
**Size:** Short (~100 lines)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Tools & Scripts Documentation
|
||||||
|
|
||||||
#### **secubox-tools/README.md** 🔧
|
#### **secubox-tools/README.md** 🔧
|
||||||
*Documentation for validation and build tools*
|
*Documentation for validation and build tools*
|
||||||
@ -225,7 +242,7 @@ Follow this template when creating or revising documentation:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 5. Live Demo & Examples
|
### 6. Live Demo & Examples
|
||||||
|
|
||||||
#### **Live Demo Website** 🌐
|
#### **Live Demo Website** 🌐
|
||||||
*Production demo of all modules*
|
*Production demo of all modules*
|
||||||
|
|||||||
115
docs/embedded/docker-zigbee2mqtt.md
Normal file
115
docs/embedded/docker-zigbee2mqtt.md
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# Docker Zigbee2MQTT on OpenWrt ARM64
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Last Updated:** 2025-12-28
|
||||||
|
**Status:** Active
|
||||||
|
|
||||||
|
This guide explains how to deploy Zigbee2MQTT on SecuBox (OpenWrt ARM64) using the new `secubox-app-zigbee2mqtt` package. The workflow follows upstream guidance from zigbee2mqtt.io while respecting OpenWrt storage constraints, UCI configuration, and procd supervision.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- OpenWrt 24.10.x (or newer) ARM64 build with SecuBox feeds.
|
||||||
|
- Internet connectivity to fetch Docker images.
|
||||||
|
- USB coordinator exposed as `/dev/ttyACM0` (e.g., Sonoff Zigbee 3.0 dongle). Load `kmod-usb-acm`.
|
||||||
|
- At least 200 MB free on overlay or external storage mounted at `/srv`.
|
||||||
|
- Cgroups v1/v2 enabled (verify `/sys/fs/cgroup` exists). Run `scripts/diagnose.sh` for sanity checks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installation Steps
|
||||||
|
|
||||||
|
1. **Install the package:**
|
||||||
|
```sh
|
||||||
|
opkg update
|
||||||
|
opkg install secubox-app-zigbee2mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Bootstrap prerequisites (Docker, storage, config):**
|
||||||
|
```sh
|
||||||
|
zigbee2mqttctl install
|
||||||
|
```
|
||||||
|
This command will:
|
||||||
|
- verify kernel modules, cgroups, USB device, and storage
|
||||||
|
- install `dockerd`, `docker`, `containerd`, and `kmod-usb-acm`
|
||||||
|
- create `/srv/zigbee2mqtt/data` with `configuration.yaml`
|
||||||
|
- pull `ghcr.io/koenkk/zigbee2mqtt:latest`
|
||||||
|
- enable `/etc/init.d/zigbee2mqtt`
|
||||||
|
|
||||||
|
3. **Configure UCI (optional adjustments):**
|
||||||
|
```sh
|
||||||
|
uci set zigbee2mqtt.main.serial_port='/dev/ttyACM0'
|
||||||
|
uci set zigbee2mqtt.main.mqtt_host='mqtt://192.168.8.10:1883'
|
||||||
|
uci set zigbee2mqtt.main.mqtt_username='secubox'
|
||||||
|
uci set zigbee2mqtt.main.mqtt_password='secret'
|
||||||
|
uci commit zigbee2mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Start the service:**
|
||||||
|
```sh
|
||||||
|
/etc/init.d/zigbee2mqtt start
|
||||||
|
```
|
||||||
|
The procd service executes `docker run` in foreground mode and respawns automatically.
|
||||||
|
|
||||||
|
5. **Check logs and status:**
|
||||||
|
```sh
|
||||||
|
zigbee2mqttctl status
|
||||||
|
zigbee2mqttctl logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Upgrade to the latest image:**
|
||||||
|
```sh
|
||||||
|
zigbee2mqttctl update
|
||||||
|
```
|
||||||
|
This pulls the latest container and restarts the service if enabled.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files & Services
|
||||||
|
|
||||||
|
| Path | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `/etc/config/zigbee2mqtt` | UCI configuration (serial port, MQTT, base topic, frontend port, data path). |
|
||||||
|
| `/etc/init.d/zigbee2mqtt` | procd wrapper that invokes `zigbee2mqttctl service-run`. |
|
||||||
|
| `/usr/sbin/zigbee2mqttctl` | Management CLI for install/check/update/status/logs. |
|
||||||
|
| `/srv/zigbee2mqtt/data` | Persistent Zigbee2MQTT state (configuration.yaml, database). |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Symptom | Fix |
|
||||||
|
|---------|-----|
|
||||||
|
| `zigbee2mqttctl install` reports missing cgroups | Ensure `/sys/fs/cgroup` exists and cgroups are enabled in kernel config. |
|
||||||
|
| `/dev/ttyACM0` not found | Load `kmod-usb-acm` and reconnect the Zigbee dongle; verify with `ls -l /dev/ttyACM*`. |
|
||||||
|
| Docker fails to start due to low space | Move `/srv/zigbee2mqtt` to an external drive or free overlay space (`df -h`). |
|
||||||
|
| MQTT authentication errors | Update `mqtt_username`/`mqtt_password` via UCI and restart service. |
|
||||||
|
| Port conflict on 8080 | Change `frontend_port` in UCI, then `/etc/init.d/zigbee2mqtt restart`. |
|
||||||
|
|
||||||
|
Run `scripts/diagnose.sh` for aggregated checks (storage, cgroups, firewall sanity). Use `scripts/smoke_test.sh` to quickly start/stop the Zigbee2MQTT service and verify Docker state.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rollback / Uninstall
|
||||||
|
|
||||||
|
1. Stop and disable the service:
|
||||||
|
```sh
|
||||||
|
/etc/init.d/zigbee2mqtt stop
|
||||||
|
/etc/init.d/zigbee2mqtt disable
|
||||||
|
```
|
||||||
|
2. Remove the container image (optional):
|
||||||
|
```sh
|
||||||
|
docker rm -f secbx-zigbee2mqtt 2>/dev/null
|
||||||
|
docker rmi ghcr.io/koenkk/zigbee2mqtt:latest
|
||||||
|
```
|
||||||
|
3. Remove package:
|
||||||
|
```sh
|
||||||
|
opkg remove secubox-app-zigbee2mqtt
|
||||||
|
```
|
||||||
|
4. Clean data directory if no longer needed:
|
||||||
|
```sh
|
||||||
|
rm -rf /srv/zigbee2mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
Reinstall later by reinstalling the package and rerunning `zigbee2mqttctl install`.
|
||||||
85
scripts/diagnose.sh
Executable file
85
scripts/diagnose.sh
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# SecuBox diagnostic helper.
|
||||||
|
# Checks overlay storage, cgroups availability, serial adapters,
|
||||||
|
# and basic firewall sanity for LAN/WAN zones.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
err() { printf '[ERROR] %s\n' "$*" >&2; }
|
||||||
|
warn() { printf '[WARN] %s\n' "$*" >&2; }
|
||||||
|
info() { printf '[INFO] %s\n' "$*"; }
|
||||||
|
|
||||||
|
check_storage() {
|
||||||
|
local mountpoint="/overlay"
|
||||||
|
local free
|
||||||
|
free=$(df -Pm "$mountpoint" | awk 'NR==2 {print $4}')
|
||||||
|
if [ -z "$free" ]; then
|
||||||
|
err "Unable to read storage usage for $mountpoint"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
info "Overlay free space: ${free}MB"
|
||||||
|
if [ "$free" -lt 100 ]; then
|
||||||
|
warn "Overlay has less than 100MB free. Consider cleaning before installing apps."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_cgroups() {
|
||||||
|
if [ ! -d /sys/fs/cgroup ]; then
|
||||||
|
err "cgroups are not mounted at /sys/fs/cgroup"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if ! mount | grep -q 'cgroup'; then
|
||||||
|
warn "cgroups filesystem present but not mounted. Docker/LXC will fail."
|
||||||
|
else
|
||||||
|
info "cgroups mount detected."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_serial() {
|
||||||
|
if ls /dev/ttyACM* >/dev/null 2>&1; then
|
||||||
|
info "USB ACM device(s): $(ls /dev/ttyACM* 2>/dev/null | tr '\n' ' ')"
|
||||||
|
else
|
||||||
|
warn "No /dev/ttyACM* device detected. Plug Zigbee coordinator or load kmod-usb-acm."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_firewall() {
|
||||||
|
if ! command -v uci >/dev/null 2>&1; then
|
||||||
|
warn "uci not found; skipping firewall checks."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local lan_idx
|
||||||
|
lan_idx=$(uci show firewall | grep -n "name='lan'" | head -n1 | cut -d: -f1 || true)
|
||||||
|
if [ -z "$lan_idx" ]; then
|
||||||
|
warn "Firewall LAN zone missing."
|
||||||
|
else
|
||||||
|
info "Firewall LAN zone detected."
|
||||||
|
fi
|
||||||
|
local wan_idx
|
||||||
|
wan_idx=$(uci show firewall | grep -n "name='wan'" | head -n1 | cut -d: -f1 || true)
|
||||||
|
if [ -z "$wan_idx" ]; then
|
||||||
|
warn "Firewall WAN zone missing."
|
||||||
|
else
|
||||||
|
info "Firewall WAN zone detected."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_docker() {
|
||||||
|
if command -v docker >/dev/null 2>&1; then
|
||||||
|
info "Docker CLI available: $(docker --version 2>/dev/null)"
|
||||||
|
else
|
||||||
|
warn "Docker CLI not found. Install dockerd/docker packages before deploying containers."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
check_storage
|
||||||
|
check_cgroups
|
||||||
|
check_serial
|
||||||
|
check_firewall
|
||||||
|
check_docker
|
||||||
|
info "Diagnostics complete."
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
65
scripts/smoke_test.sh
Executable file
65
scripts/smoke_test.sh
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Basic smoke tests for SecuBox apps.
|
||||||
|
# - Verifies zigbee2mqtt service start/stop.
|
||||||
|
# - Checks Docker container health.
|
||||||
|
# - Optionally exercises MQTT pub/sub if mosquitto-clients installed.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
log() { printf '[SMOKE] %s\n' "$*"; }
|
||||||
|
err() { printf '[ERROR] %s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
ensure_service() {
|
||||||
|
local svc="$1"
|
||||||
|
if [ ! -x "/etc/init.d/$svc" ]; then
|
||||||
|
err "Service $svc not installed."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_zigbee2mqtt() {
|
||||||
|
if ! ensure_service zigbee2mqtt; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
log "Starting zigbee2mqtt..."
|
||||||
|
/etc/init.d/zigbee2mqtt start || return 1
|
||||||
|
sleep 3
|
||||||
|
if docker ps --filter "name=secbx-zigbee2mqtt" --format '{{.Names}}' | grep -q secbx-zigbee2mqtt; then
|
||||||
|
log "Zigbee2MQTT container is running."
|
||||||
|
else
|
||||||
|
err "Zigbee2MQTT container failed to start."
|
||||||
|
fi
|
||||||
|
log "Stopping zigbee2mqtt..."
|
||||||
|
/etc/init.d/zigbee2mqtt stop || true
|
||||||
|
}
|
||||||
|
|
||||||
|
check_mqtt_pubsub() {
|
||||||
|
if ! command -v mosquitto_pub >/dev/null 2>&1; then
|
||||||
|
log "mosquitto-clients not installed; skipping MQTT smoke test."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local topic="secbx/smoke/test"
|
||||||
|
log "Publishing MQTT test message on $topic..."
|
||||||
|
mosquitto_pub -t "$topic" -m "smoke-test" >/dev/null 2>&1 || err "Failed to publish test message."
|
||||||
|
}
|
||||||
|
|
||||||
|
check_ports() {
|
||||||
|
local port
|
||||||
|
for port in 8080; do
|
||||||
|
if netstat -tln 2>/dev/null | grep -q ":$port "; then
|
||||||
|
log "Port $port listening."
|
||||||
|
else
|
||||||
|
log "Port $port not listening (may be expected if zigbee2mqtt is stopped)."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
check_zigbee2mqtt
|
||||||
|
check_mqtt_pubsub
|
||||||
|
check_ports
|
||||||
|
log "Smoke tests completed."
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
42
secubox-app-zigbee2mqtt/Makefile
Normal file
42
secubox-app-zigbee2mqtt/Makefile
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=secubox-app-zigbee2mqtt
|
||||||
|
PKG_RELEASE:=1
|
||||||
|
PKG_VERSION:=1.0.0
|
||||||
|
PKG_MAINTAINER:=CyberMind Studio <contact@cybermind.fr>
|
||||||
|
PKG_LICENSE:=Apache-2.0
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
define Package/secubox-app-zigbee2mqtt
|
||||||
|
SECTION:=utils
|
||||||
|
CATEGORY:=Utilities
|
||||||
|
SUBMENU:=SecuBox Apps
|
||||||
|
TITLE:=SecuBox Zigbee2MQTT docker app
|
||||||
|
DEPENDS:=+uci +libuci +kmod-usb-acm +bash? +dockerd +docker +containerd
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/secubox-app-zigbee2mqtt/description
|
||||||
|
Installer, configuration, and service manager for running Zigbee2MQTT
|
||||||
|
inside Docker on SecuBox-powered OpenWrt systems.
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/secubox-app-zigbee2mqtt/conffiles
|
||||||
|
/etc/config/zigbee2mqtt
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Compile
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/secubox-app-zigbee2mqtt/install
|
||||||
|
$(INSTALL_DIR) $(1)/etc/config
|
||||||
|
$(INSTALL_CONF) ./files/etc/config/zigbee2mqtt $(1)/etc/config/zigbee2mqtt
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/etc/init.d
|
||||||
|
$(INSTALL_BIN) ./files/etc/init.d/zigbee2mqtt $(1)/etc/init.d/zigbee2mqtt
|
||||||
|
|
||||||
|
$(INSTALL_DIR) $(1)/usr/sbin
|
||||||
|
$(INSTALL_BIN) ./files/usr/sbin/zigbee2mqttctl $(1)/usr/sbin/zigbee2mqttctl
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackage,secubox-app-zigbee2mqtt))
|
||||||
12
secubox-app-zigbee2mqtt/files/etc/config/zigbee2mqtt
Normal file
12
secubox-app-zigbee2mqtt/files/etc/config/zigbee2mqtt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
config zigbee2mqtt 'main'
|
||||||
|
option enabled '0'
|
||||||
|
option image 'ghcr.io/koenkk/zigbee2mqtt:latest'
|
||||||
|
option serial_port '/dev/ttyACM0'
|
||||||
|
option mqtt_host 'mqtt://127.0.0.1:1883'
|
||||||
|
option mqtt_username ''
|
||||||
|
option mqtt_password ''
|
||||||
|
option base_topic 'zigbee2mqtt'
|
||||||
|
option frontend_port '8080'
|
||||||
|
option channel '11'
|
||||||
|
option data_path '/srv/zigbee2mqtt'
|
||||||
|
option timezone 'UTC'
|
||||||
23
secubox-app-zigbee2mqtt/files/etc/init.d/zigbee2mqtt
Normal file
23
secubox-app-zigbee2mqtt/files/etc/init.d/zigbee2mqtt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh /etc/rc.common
|
||||||
|
|
||||||
|
START=95
|
||||||
|
STOP=10
|
||||||
|
USE_PROCD=1
|
||||||
|
|
||||||
|
SERVICE_BIN="/usr/sbin/zigbee2mqttctl"
|
||||||
|
|
||||||
|
start_service() {
|
||||||
|
procd_open_instance
|
||||||
|
procd_set_param command "$SERVICE_BIN" service-run
|
||||||
|
procd_set_param respawn 2000 5 5
|
||||||
|
procd_close_instance
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_service() {
|
||||||
|
"$SERVICE_BIN" service-stop >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_service() {
|
||||||
|
stop_service
|
||||||
|
start_service
|
||||||
|
}
|
||||||
208
secubox-app-zigbee2mqtt/files/usr/sbin/zigbee2mqttctl
Normal file
208
secubox-app-zigbee2mqtt/files/usr/sbin/zigbee2mqttctl
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# SecuBox Zigbee2MQTT manager
|
||||||
|
# Handles prerequisite checks, Docker installation, container lifecycle,
|
||||||
|
# and configuration generation using UCI.
|
||||||
|
|
||||||
|
CONFIG="zigbee2mqtt"
|
||||||
|
CONTAINER="secbx-zigbee2mqtt"
|
||||||
|
OPKG_UPDATED=0
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: zigbee2mqttctl <command>
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
install Run prerequisite checks, install Docker packages, prepare data dir
|
||||||
|
check Validate kernel modules, cgroups, storage, and serial access
|
||||||
|
update Pull the latest Zigbee2MQTT image and restart the service
|
||||||
|
status Show container and service status
|
||||||
|
logs Show Docker logs (pass -f to follow)
|
||||||
|
service-run Internal: invoked by procd to run the container
|
||||||
|
service-stop Stop the running container
|
||||||
|
help Show this message
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
require_root() {
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "This command requires root privileges." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
uci_get() {
|
||||||
|
uci -q get "${CONFIG}.main.$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
defaults() {
|
||||||
|
serial_port="$(uci_get serial_port || echo /dev/ttyACM0)"
|
||||||
|
mqtt_host="$(uci_get mqtt_host || echo mqtt://127.0.0.1:1883)"
|
||||||
|
mqtt_user="$(uci_get mqtt_username || printf '')"
|
||||||
|
mqtt_pass="$(uci_get mqtt_password || printf '')"
|
||||||
|
base_topic="$(uci_get base_topic || echo zigbee2mqtt)"
|
||||||
|
frontend_port="$(uci_get frontend_port || echo 8080)"
|
||||||
|
channel="$(uci_get channel || echo 11)"
|
||||||
|
image="$(uci_get image || echo ghcr.io/koenkk/zigbee2mqtt:latest)"
|
||||||
|
data_path="$(uci_get data_path || echo /srv/zigbee2mqtt)"
|
||||||
|
timezone="$(uci_get timezone || echo UTC)"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_dir() {
|
||||||
|
local path="$1"
|
||||||
|
[ -d "$path" ] || mkdir -p "$path"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_packages() {
|
||||||
|
local pkgs="$*"
|
||||||
|
require_root
|
||||||
|
for pkg in $pkgs; do
|
||||||
|
if ! opkg status "$pkg" >/dev/null 2>&1; then
|
||||||
|
if [ "$OPKG_UPDATED" -eq 0 ]; then
|
||||||
|
opkg update || return 1
|
||||||
|
OPKG_UPDATED=1
|
||||||
|
fi
|
||||||
|
opkg install "$pkg" || return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_storage() {
|
||||||
|
local target="$1"
|
||||||
|
local free_kb
|
||||||
|
free_kb=$(df -Pk "${target:-/overlay}" | awk 'NR==2 {print $4}')
|
||||||
|
[ -z "$free_kb" ] && free_kb=0
|
||||||
|
if [ "$free_kb" -lt 102400 ]; then
|
||||||
|
echo "[WARN] Less than 100MB free on ${target:-overlay}. Docker images may fail." >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_cgroups() {
|
||||||
|
if [ ! -d /sys/fs/cgroup ]; then
|
||||||
|
echo "[ERROR] /sys/fs/cgroup missing. Enable cgroups in the kernel." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_serial() {
|
||||||
|
local port="$1"
|
||||||
|
if [ ! -c "$port" ]; then
|
||||||
|
echo "[WARN] Serial device $port not found. Plug the Zigbee coordinator first." >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_prereqs() {
|
||||||
|
defaults
|
||||||
|
check_storage "$data_path"
|
||||||
|
check_cgroups || return 1
|
||||||
|
check_serial "$serial_port"
|
||||||
|
ensure_packages kmod-usb-acm || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_docker() {
|
||||||
|
ensure_packages containerd docker dockerd || return 1
|
||||||
|
/etc/init.d/dockerd enable >/dev/null 2>&1
|
||||||
|
/etc/init.d/dockerd start >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_configuration() {
|
||||||
|
defaults
|
||||||
|
ensure_dir "$data_path/data"
|
||||||
|
cat > "$data_path/data/configuration.yaml" <<EOF
|
||||||
|
homeassistant: true
|
||||||
|
permit_join: false
|
||||||
|
mqtt:
|
||||||
|
base_topic: "${base_topic}"
|
||||||
|
server: "${mqtt_host}"
|
||||||
|
user: "${mqtt_user}"
|
||||||
|
password: "${mqtt_pass}"
|
||||||
|
serial:
|
||||||
|
port: "${serial_port}"
|
||||||
|
advanced:
|
||||||
|
channel: ${channel}
|
||||||
|
frontend:
|
||||||
|
port: ${frontend_port}
|
||||||
|
EOF
|
||||||
|
chmod 600 "$data_path/data/configuration.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
pull_image() {
|
||||||
|
defaults
|
||||||
|
docker pull "$image"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_container() {
|
||||||
|
docker stop "$CONTAINER" >/dev/null 2>&1 || true
|
||||||
|
docker rm "$CONTAINER" >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_install() {
|
||||||
|
require_root
|
||||||
|
check_prereqs || exit 1
|
||||||
|
ensure_docker || exit 1
|
||||||
|
ensure_dir "$data_path"
|
||||||
|
generate_configuration
|
||||||
|
pull_image
|
||||||
|
/etc/init.d/zigbee2mqtt enable
|
||||||
|
echo "Zigbee2MQTT prerequisites installed. Enable with: /etc/init.d/zigbee2mqtt start"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_check() {
|
||||||
|
check_prereqs
|
||||||
|
echo "Prerequisite check completed."
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_update() {
|
||||||
|
require_root
|
||||||
|
defaults
|
||||||
|
pull_image || exit 1
|
||||||
|
if /etc/init.d/zigbee2mqtt enabled >/dev/null 2>&1; then
|
||||||
|
/etc/init.d/zigbee2mqtt restart
|
||||||
|
else
|
||||||
|
echo "Image updated. Restart manually to apply."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
docker ps -a --filter "name=$CONTAINER"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_logs() {
|
||||||
|
docker logs "$@" "$CONTAINER"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_service_run() {
|
||||||
|
require_root
|
||||||
|
check_prereqs || exit 1
|
||||||
|
ensure_docker || exit 1
|
||||||
|
generate_configuration
|
||||||
|
stop_container
|
||||||
|
defaults
|
||||||
|
exec docker run --rm \
|
||||||
|
--name "$CONTAINER" \
|
||||||
|
--device "$serial_port" \
|
||||||
|
-p "${frontend_port}:8080" \
|
||||||
|
-v "$data_path/data:/app/data" \
|
||||||
|
-e TZ="$timezone" \
|
||||||
|
"$image"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_service_stop() {
|
||||||
|
require_root
|
||||||
|
stop_container
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
install) shift; cmd_install "$@";;
|
||||||
|
check) shift; cmd_check "$@";;
|
||||||
|
update) shift; cmd_update "$@";;
|
||||||
|
status) shift; cmd_status "$@";;
|
||||||
|
logs) shift; cmd_logs "$@";;
|
||||||
|
service-run) shift; cmd_service_run "$@";;
|
||||||
|
service-stop) shift; cmd_service_stop "$@";;
|
||||||
|
help|--help|-h|"") usage;;
|
||||||
|
*) echo "Unknown command: $1" >&2; usage >&2; exit 1;;
|
||||||
|
esac
|
||||||
Loading…
Reference in New Issue
Block a user