📄 Read the paper — The Right-to-Repair Board Rescuer Deck (PDF)
An ESP32 with an AMG8833 “Grid-EYE” 8×8 infrared sensor pushes frames over TLS to a VPS. The VPS keeps only the raw 8×8 temperature grid, renders every picture server-side, and streams it to any browser at up to 30 fps. A phone camera can overlay the heat map on the live view to hunt hot components; a vision AI names the component and finds a cheap price.
ESP32 + AMG8833
+-- TLS POST (128 B/frame) --> VPS :8090
+-- SSE (2 PNGs) --> any browser
+-- camera snap --> gallery + AI
_buf). The thermal stream is never written to disk./opt/thermal/gallery/ (index.json + <id>.jpg), capped at 300.Applies to the Processed pane and, when astro is on, to the camera overlay:
[0,255,120]), always on.The colour window, the Otsu threshold and the overlay all read the same normalised field, so they never disagree.
| Control | What it does | Default |
|---|---|---|
| Start astro processing | Turns the whole Processed pipeline on/off. Off = raw, only scaled. | off |
| Render — Sharp / Contour / Blocks | Upscale kernel + contour overlay. Sharp is the cleanest. | Sharp |
| 🔥 Hotspot alarm | Any cell at/above this raises the red alarm banner + beep and marks snapped photos as hot. | 40.0 °C |
| ☀ Stretch | asinh strength, 0 (linear) → 8 (max). Higher = more faint detail, until it saturates. | 2.0 |
| 🔬 Local contrast | Additive CLAHE gain, 0–3. Brings out small differences across the frame. | 1.0 |
| ✂ Sigma clip | Stack outlier rejection strength (0.3–8σ). Low = smoother but can eat faint real detail; high = keeps more noise. 0.15 °C floor always applies. | 3.0 |
| ▤ Stack | Frames averaged, 1–30. More = smoother but slower to react. | 12 |
| 🌈 Colour range | AUTO fits min→max every frame; manual sets the low/high °C that map to blue/red. Never inverts (≥0.5 °C span). | AUTO 30–40 |
Every control is live-synced: change it on one phone and every other viewer updates instantly (badge + toast).
localStorage, so it survives reloads. Reset restores defaults.The Hotspot log sits on the main page and is public — anyone with this link can see every photo and its AI result. Only capturing and deleting need the passcode. Tap any photo to open it full-size.
| Action | Public (no passcode) | With passcode |
|---|---|---|
| Open the camera panel / live overlay | ✅ | ✅ |
| View the gallery / a full photo | ✅ | ✅ |
| Snap a new photo | ❌ 401 | ✅ |
| Delete a photo | ❌ 401 | ✅ |
The passcode is checked server-side and sets an HTTP-only cookie (30 days). It is not in the page source. Old photos auto-delete once the gallery passes 300.
On every snap the VPS runs a background job (key never touches the phone):
snap -> vision model : identify the component under the hotspot box
-> price model : live web search for the cheapest seller
-> stored : shown under the photo
z-ai/glm-5.3-flash. Price: z-ai/glm-5.3-flash:online (web-search grounded).| Route | Purpose |
|---|---|
POST /api/ingest | ESP32 pushes 128 bytes = 64 × int16 (°C×100). Token-gated. |
GET /api/stream | SSE: {seq, mn, mx, avg, thr, stack, astro, g8, p8, hotat, raw, proc} with base64 PNGs. |
GET /api/latest | One snapshot, no stream. |
GET /api/astro?on= · /api/mode?m= · /api/thr?v= · /api/k?v= · /api/lc?v= · /api/stack?v= · /api/range?auto=&lo=&hi= | Live controls; each bumps the sync revision. |
GET /api/auth · POST /api/auth | Auth state / exchange passcode for the cookie. |
POST /api/snap | Save a photo + start the AI job. Needs passcode. |
GET /api/gallery · GET /g/<id>.jpg | List / fetch photos. Public. |
POST /api/gallery/del | Delete a photo. Needs passcode. |
systemctl restart thermal (unit /etc/systemd/system/thermal.service), on 127.0.0.1:8090, fronted by Caddy with streaming (no buffering).THERMAL_PASS (passcode), OPENROUTER_KEY, OR_VISION/OR_PRICE, OR_AI=0 to disable AI, THERMAL_GAL_MAX.AMG8833 · ESP32 · endpoint thermal.144.202.52.34.nip.io