5 Commits

Author SHA1 Message Date
95de2470b8 Implement provider plugin architecture (#9) with local directory provider (#10)
Plugin framework for photo source backends:
- PhotoProvider ABC with lifecycle hooks, auth flow, cache control
- @register_provider decorator + registry for auto-discovery
- ProviderManager handles instance lifecycle, config persistence,
  aggregated photo pool with weighted random selection
- ProviderCache: in-memory list cache (per-provider TTL), disk-based
  thumbnail cache, optional full image cache for remote providers
- Per-image settings migrated from bare filenames to composite keys
  (provider_id:photo_id) with automatic one-time migration + backup

Local directory provider included as reference implementation — wraps
the existing filesystem logic into the provider interface with upload
and delete support.

All existing endpoints preserved with composite key routing. ESP32
firmware unchanged — still hits GET /photo, gets a JPEG.

New API: /api/providers/* for managing provider instances, auth flows,
and cache control.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 23:40:15 -05:00
75e4d0b786 Replace simulator sliders with WYSIWYG crop tool
The simulator now shows the full source image with a draggable crop
window overlay. Drag the frame over the photo to position the crop —
dimmed regions show what gets cut. The dithered e-paper preview renders
live in the side panel.

Mode toggle: "Fill" (zoom with draggable pan) vs "Fit" (letterbox).
Save persists per-image settings used when the ESP32 fetches the photo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:38:55 -05:00
dd4f8e950d Add display simulator, orientation support, and per-image crop settings
- E-paper display simulator: Python port of the C++ Floyd-Steinberg
  dithering (same palette, same coefficients) with side-by-side preview
  in the web UI. Interactive pan/zoom controls with live re-rendering.

- Frame orientation: landscape / portrait_cw / portrait_ccw setting
  controls logical display dimensions (800x480 vs 480x800). Images are
  rotated to match the physical buffer after processing.

- Display modes: zoom (cover+crop) and letterbox (fit with padding),
  configurable globally and per-image. Zoom mode supports pan_x/pan_y
  (0.0-1.0) to control crop position.

- Settings persistence: frame settings, per-image settings, and frame
  state stored as JSON, surviving restarts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 16:32:38 -05:00
4642b90366 Wire WiFi creds via .env + build-time injection, add heartbeat reporting
Adopts the weather-display pattern: .env file parsed by tools/load_env.py
and injected as -D compiler flags. WIFI_NETWORKS uses "SSID:password" format.
ESP32 now sends a heartbeat POST after each display update so the server
can track frame status for the HA integration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:28:20 -05:00
4ddda58b43 Initial project: ESP32-S3 e-ink photo frame with web UI
ESP32-S3 firmware (PlatformIO) that fetches JPEGs from a photo server,
decodes on-device with PSRAM, Floyd-Steinberg dithers to the Spectra 6
6-color palette, and displays on a 7.3" GDEP073E01 e-paper panel.
Deep sleeps 1 hour between updates.

Photo server (Python/Flask) with web UI for photo management, Traefik
routing at photos.haunt.house with Google OAuth, and Home Assistant
REST sensor integration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:33:16 -05:00