Commit graph

10 commits

Author SHA1 Message Date
jedarden
c3034ae9a2 Fix firmware flashing: correct merge binary, seed overwrite, inline flash UI
- Dockerfile: use --flash_size 4MB and drop OTA data from merge_bin (OTA
  data at 0xc10000 inflated binary to 12.6MB, exceeding 4MB chip flash)
- main.go: seedFirmwareDir now overwrites when source size differs, fixing
  PVC staleness where old 1.6MB app-only binary was never replaced
- onboard.js: renderFlashFirmware() rewritten so all elements (button,
  progress bar, status text, retry help, log panel) are inline in one
  container — no separate floating modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:41:51 -04:00
jedarden
55976c7058 Fix merge_bin flash parameters to match sdkconfig (dio/80m/16MB)
Guru Meditation/IllegalInstruction after flashing was caused by the
merged binary using default flash parameters instead of the project's
settings. esptool merge_bin flags use underscores and go after the
subcommand: --flash_mode dio --flash_freq 80m --flash_size 16MB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 14:09:57 -04:00
jedarden
223b439c5a Use merged firmware binary for esp-web-tools flashing
esptool merge_bin combines bootloader (0x0), partition table (0x8000),
application (0x10000), and OTA data (0xc10000) into a single binary
flashable at offset 0x0 — matching the manifest address and enabling
correct initial flashing via the onboarding wizard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:33:01 -04:00
jedarden
b8684aad68 fix(ci): set-target esp32s3 before idf.py build
ESP-IDF 5.x requires explicit set-target even when CONFIG_IDF_TARGET
is present in sdkconfig.defaults.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 15:09:06 -04:00
jedarden
f2b609a2ef fix(ci): source IDF export.sh in firmware build stage
espressif/idf entrypoint is not invoked in multi-stage builds, so
idf.py is not in PATH. Sourcing export.sh activates the toolchain.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 15:03:40 -04:00
jedarden
6b87040721 feat(ci): build ESP32 firmware in Dockerfile and seed OTA on startup
Add espressif/idf:v5.2 as a multi-stage build step so the firmware
binary is baked into the image at /firmware/spaxel-firmware.bin.
On startup the mothership copies it into /data/firmware/ (PVC) if not
already present, making it immediately available for the onboarding
wizard without a manual upload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 14:58:14 -04:00
jedarden
e44dd345f6 feat: implement comprehensive /healthz endpoint
Add complete health check implementation for Docker HEALTHCHECK and
Traefik health routing with:

Response fields:
- status: "ok" or "degraded"
- uptime_s: seconds since mothership boot
- version: mothership version string
- nodes_online: count of connected nodes
- db: "ok" or "failing" (SELECT 1 with 100ms timeout)
- load_level: 0-3 from load shedding state
- reason: human-readable explanation (only when degraded)

HTTP status codes:
- 200 for healthy (status="ok")
- 503 for degraded (status="degraded")

Degraded conditions:
- Database unreachable
- Load level 3 sustained for >60 seconds
- No nodes connected after 5 minutes uptime

Docker HEALTHCHECK updated to verify status="ok" response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 11:09:36 -04:00
jedarden
a2e00d39d4 fix(docker): use Go 1.25 to match modernc.org/sqlite v1.47 requirement 2026-04-01 22:59:13 -04:00
jedarden
46c3516941 fix(docker): remove invalid HEALTHCHECK directive for distroless image 2026-04-01 22:42:18 -04:00
jedarden
3f2962f945 feat(deploy): Docker packaging with multi-stage build and compose orchestration
- Dockerfile: golang:1.23-bookworm builder → distroless/static-debian12:nonroot
- docker-compose.yml: host networking (required for mDNS), Traefik labels, resource limits
- VERSION: 0.1.0 for image tagging
- .dockerignore: excludes docs, build artifacts, IDE files
- .gitignore: standard Go/ESP-IDF ignores

Key decisions:
- Host networking required: Docker bridge blocks mDNS multicast 224.0.0.251
- distroless/static-debian12:nonroot: no shell, minimal attack surface, UID 65532
- Firmware via volume mount: users provide their own binaries for OTA
- Traefik labels disabled by default: enable SPAXEL_TRAEFIK_ENABLE=true for TLS

Complete: Phase 1 Docker packaging — all foundation items now done
Remaining: Phase 2 signal processing (baseline, deltaRMS, Fresnel zones)
2026-03-26 07:46:15 -04:00