fix(esp): route daily noon capture through the restart cold-start - #150
Merged
Conversation
cofade
marked this pull request as ready for review
June 6, 2026 22:30
The scheduled noon capture was a bare single esp_camera_fb_get() after ~8h of sensor idle; a field module uploaded near-black noon frames while a restart always produced a good image (see #143). loop()'s noon branch now calls primeCameraLikeBoot() — a PWDN power-cycle + reinit + 3-frame warm-up, the same cold-start the boot path runs — before the grab. The reinit goes through a new non-aborting recoverCameraSoft() (the boot path keeps initEspCamera()'s abort(), load-bearing for OTA rollback): a reinit failure or an all-NULL warm-up skips that day's capture and retries next loop rather than panicking a marginal board or committing the day on a dead sensor. lastCaptureDay is set only when prime AND upload both succeed, mirroring the first-capture-on-boot gate. A bench A/B on healthy hardware could not reproduce the black frame (neither the missing warm-up nor the VGA/DRAM path), so this is an explicitly unvalidated mitigation — see the chapter-11 lesson and #143. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cofade
force-pushed
the
fix/esp-noon-capture-restart-path
branch
from
June 6, 2026 22:35
c527c0d to
97e46e2
Compare
schutera
pushed a commit
that referenced
this pull request
Jun 7, 2026
…for #150 noon-capture re-prime PR #150 (noon-capture camera re-prime, #143) merged the firmware source but left VERSION=carpenter / SEQUENCE=4 — identical to the deployed release, so field modules on carpenter/seq4 would never pull it and a rebuilt seq4 binary would silently drift (see #132). Cut a real release: woolcarder / sequence 5. Built with build.sh (production URLs, geo key), republished homepage/public + dist firmware.{bin,app.bin,json}. app_md5=9d3742d7b3c76ecc62d35a6a6f1bfc72 app_size=1156640. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
17 tasks
cofade
pushed a commit
that referenced
this pull request
Sep 1, 2026
- correct the TLS call-site count: geolocation handshake runs only on NVS geo cache miss (~1 in 14 boots, kGeoCacheMaxBoots), so setup() does TLS up to four times, not 'at least four' - drop the false 'appears nowhere in this repo' claim (the sentence itself and an unrelated 8192 chunk size exist); say 'no repo file configures or references it' - merge the obsolete-PIO-core entry into the existing PlatformIO section and reattach the orphaned explicit-interpreter tail - the Makefile/CI do not 'always write python -m platformio' - reword to the true claim (a bare pio resolves to whatever pio.exe is on PATH) - chapter 11: link the fix to the SEQUENCE-bumped release requirement (#150/#132 silent no-ops) and spell out that free heap != free stack - troubleshooting: note the addr2line addresses are dump-specific
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Issue #143: a field module uploaded near-black images at its daily noon capture, while a power-cycle restart always produced a good image. This routes the noon capture through the same proven-good camera cold-start the boot/restart path uses.
This is a mitigation, not a confirmed fix — #143 stays open (see "Honesty" below).
What the bench investigation found (and ruled out)
Reproduced both capture paths on a healthy bench module (
hive-02, COM9) against a local stack and compared cold vs warm frames directly:So the issue's leading hypothesis ("noon skips the warm-up") is disproven on healthy hardware — its candidate fix would have changed nothing. The affected board's "PSRAM not found" is itself a hardware-fault symptom (with
reset_reason=7watchdog +flash read err, and variable black severity), so the root cause is most likely that board's marginal hardware, which a healthy bench board cannot emulate by flipping a code path. Full writeup: the chapter-11 lesson in this PR + the issue comment.The change
primeCameraLikeBoot()(ESP32-CAM/ESP32-CAM.ino): PWDN power-cycle + reinit + 3-frame warm-up before the noon grab — the restart cold-start.recoverCameraSoft()(esp_init.cpp): the noon re-prime must neverabort()from steady-state — on a marginal board that would risk a daily panic → reboot → (after 3) firmware rollback. The boot path keepsinitEspCamera()'sabort()(load-bearing for OTA rollback), gated by a newabortOnFailureparam (defaulttrue, so every existing caller is unchanged).lastCaptureDayis set only when prime and upload both succeed (mirrors the first-capture-on-boot gate).Honesty: this is an unvalidated mitigation
The bench could not reproduce the failure on healthy hardware, so the fix could not be confirmed. The code comments and docs say so explicitly. It routes the daily image through the one path observed to always work, which is robust regardless of the (likely hardware) mechanism — but it intentionally leaves #143 open until the on-
b0696test settles the root cause.Out of scope / follow-up
masonfirmware geo-TLS waste + twoloop()hardening gaps) is tracked in ESP firmware: harden against silent offline (WiFi-health reboot fallback + heartbeat retry) #149.Testing
Done:
pio run -e esp32cambuilds clean.lib/helper touched).longhorn+ a throwaway diagnostic) and confirmed the boot / cold / warm capture paths upload to a local stack; compared frames directly (the table above).senior-reviewer; the non-aborting design + warm-up-NULL gate are the result.Could NOT do — needs the affected board (
b0696ef23a08, or any "PSRAM not found" board) on USB:$env:DEV_SERVER_HOST="192.168.178.49"(your dev-box LAN IP);pio run -d ESP32-CAM -e esp32cam -t upload --upload-port COM9— or flash via the web installer.python scripts/esp_capture.py COM9 90— confirm-- priming camera (restart-equivalent cold-start), theloop:primeCamera:noonbreadcrumb, and non-NULLprime warm-up frame N OK (… bytes)lines.tm_hour == 12to the current hour, or set the device clock) and confirm the uploaded noon frame is well-exposed, not near-black.🤖 Generated with Claude Code