football2801 d5a7849fbd feat(story-2.1): firmware provisioning — AP mode, captive portal, QR display, image pull
State machine:
- Boot: check 5s reset-button hold → wipe NVS creds; load saved SSID/pass
- If no creds (or reset): enter_provisioning() — WiFi.softAP + DNS redirect + WebServer
- If creds: attempt_wifi(); on success → normal_operation(); on fail → enter_provisioning()
- normal_operation(): HTTPS GET /api/device/{mac}/image → stream to LittleFS → display;
  204 = keep current stored image; 404 = red fill; server error = yellow fill;
  deep sleep 15 min between polls

Provisioning flow:
- AP SSID: "PictureFrame-{last4hex}" broadcast as open network
- QR on e-ink: WIFI:S:PictureFrame-XXXX;T:nopass;; → phone auto-joins AP
- Captive portal: redirect all DNS to 192.168.4.1; serve minimal HTML form
  (handles iOS /hotspot-detect.html and Android /generate_204 redirects)
- POST /connect: async — respond immediately, attempt WiFi in loop()
  Success: save NVS, show Phase 2 setup QR (green bg) → 2min delay → normal_operation()
  Failure: red fill → restart AP

EPD driver refactor:
- Extracted epd_init/sleep/fill/draw_qr/draw_image_from_file into epd.h + epd.cpp
- epd_draw_qr(): ricmoo/QRCode library; computes modules inline per pixel row
- epd_fill(): solid color in one pass (used for red=no-wifi, yellow=sync-fail)
- epd_draw_image_from_file(): streams LittleFS binary directly to display

Removed: convert_photo.py (pre-rendering moved to server-side Imagick), image.h (PROGMEM array)
Added: config.h, epd.h, epd.cpp; updated platformio.ini (QRCode lib, littlefs fs)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 00:43:53 -04:00
S
Description
Handcrafted e-ink digital picture frame — ESP32 + Waveshare 7.3" + Symfony web app
7.8 MiB
Languages
Python 59.1%
PHP 18.6%
HTML 7.5%
Vue 5.5%
TypeScript 3.6%
Other 5.7%