ESP32 Filesystem Uploader: Verify Device Bytes After the Host Build

A filesystem image on the host does not show what an ESP32 currently reads. Keep the intended byte sequences beside the readback record instead of treating a build filename as device evidence.

Compare entered byte sequences against the original LF-only payloads. Textarea newline normalization cannot hide the difference because line endings are represented as explicit hex bytes.

ESP32 Filesystem Uploader: Verify Device Bytes After the Host Build
ESP32 Filesystem Uploader: Verify Device Bytes After the Host Build
Open the full example ↗

Separate the firmware and filesystem artifacts

The uploader maintainer's README distinguishes an upload operation from a build-only operation that writes mklittlefs.bin in the sketch directory. It describes Arduino IDE 2.2.1 or higher and includes board-specific notes, including an Arduino Nano ESP32 DFU exception. Confirm the actual board, core, IDE, plugin, and upload arrangement before applying the instructions. LittleFS uploader README.

A successful firmware compilation does not establish the device's filesystem contents. Likewise, a filesystem image build does not prove the intended firmware is running. Record the two source/build artifacts separately rather than using one success message for both.

Specify two original files exactly

Use this original packaging fixture:

Host source path Expected device path Exact content contract Expected length
data/index.html /index.html ASCII demo, followed by one LF 5 bytes
data/config.json /config.json ASCII {"mode":"demo"}, followed by one LF 16 bytes

Neither file has a BOM or CRLF. The filenames are part of the exercise; the short index.html content is a byte marker, not a completed website.

The source-file lengths total 21 bytes. That is not the filesystem image's length or the partition capacity: filesystem packaging has its own overhead. Record the actual built image length only when the image exists.

To make the expected sequence unambiguous, the two file payloads are:

/index.html: 64 65 6D 6F 0A
/config.json: 7B 22 6D 6F 64 65 22 3A 22 64 65 6D 6F 22 7D 0A

Those are hexadecimal byte descriptions, not literal file contents to paste into the two source files. Create those source files and check their hashes before building the filesystem image.

Bind the image to its source revision

For a later build, retain source path, exact bytes, byte length, and source hash. Add the build command or selected IDE action, plugin/core versions, actual partition configuration, resulting image filename, image hash, and build outcome.

Do not guess a flash address or capacity from a generic ESP32 tutorial. The selected board and partition layout determine the applicable configuration. A correctly named old image may still encode yesterday's source files.

If either source file or a build setting changes, retire the old image's acceptance for the new revision. An unchanged filename is not an unchanged artifact.

Plan read-only verification without formatting on failure

Espressif's example shows filesystem mounting, file opening, and reading, but it also contains formatting-on-mount-failure and write/delete routines. Use the mounting and reading concepts for this separate verification design; the full example is not a read-only verifier to run unchanged. Espressif LittleFS example.

The verifier must mount with formatting disabled under the confirmed installed API. If mounting fails, stop and report that condition. Do not format a filesystem to turn the failure into a success. Do not write, append, rename, or delete files during this check.

After a successful mount, inspect /index.html and /config.json as regular files. Record path, actual size, bytes read, and comparison with the original manifest. Missing files and failed reads need explicit outcomes; they are not zero-byte matches.

The source comparison is exact. A configuration may parse as the same JSON while differing in whitespace or encoding. For this fixture, a CRLF ending changes index.html to six bytes and config.json to seventeen. A UTF-8 BOM would also change each sequence. Preserve those differences in the ledger instead of silently normalizing them away.

Keep upload status and read-back evidence distinct

Stage Evidence needed What it does not establish alone
Host source Exact two-file manifest A device contains these files
Image build Image artifact and source/config revision That image was uploaded
Filesystem upload Actual selected device/configuration and outcome Every expected file's bytes match
Device verification Mount result and exact path/byte comparisons Firmware or website behavior beyond this check

Leave actual fields blank until the authorized native device work occurs. Record board identity, selected port or applicable upload transport, core/library API, partition layout, and image revision before that work. A mount failure, stale image, missing file, or wrong byte sequence holds acceptance.

Try the worked example

Compare the default LF fixture for 5-byte and 16-byte matches. Load the CRLF test to compare six and seventeen bytes against the originals. Keep the mismatch rather than normalizing it away. Source-byte totals are not filesystem image size.

This compares entered hex byte records locally; it does not connect to hardware, mount, build, flash, upload, or prove actual device contents.

Recreate this example

Build one complete self-contained HTML page for this task: compare entered hexadecimal byte sequences against the exact original source manifest.

Use these exact original practice data and worked expectations: Map data/index.html to /index.html: its contents are demo followed by LF, totaling 5 bytes. Map data/config.json to /config.json: its contents are {"mode":"demo"} followed by LF, totaling 16 bytes. The two source files total 21 bytes, independently of the image length or partition size. Their CRLF variants contain 6 and 17 bytes.

Implement the following useful local interactions: Provide two hexadecimal-byte textareas, Compare, Load CRLF test, Restore LF. Parse whitespace-separated two-digit hex bytes; reject malformed or missing input. Compare every byte and report actual and expected lengths. Represent LF as 0A and CRLF as 0D 0A; do not claim textareas preserve raw line-ending bytes. Preserve the supplied source text and distinguish an uncomputed state, a successful local result, and an invalid or incomplete input. Update output only from the current input snapshot. An input edit must retire stale feedback until the reader runs the relevant action again. Do not silently invent missing values or replace a failing case with a success.

Design the page as a compact source-and-result developer workbench with readable code, labeled inputs, and a separate explanation area. Put a compact task heading, actual sample data, the main result, and usable controls early enough to be useful on a narrow screen. Use readable text of at least 16px, generous paragraph spacing, strong contrast, native labels, accessible buttons, and visible keyboard focus. Stack long records at 360px and wrap code without page-level horizontal overflow.

Use type=button and explicit querySelector-based click handlers rather than relying on form submission. If Enter is useful, handle it only on the relevant input and ignore isComposing. Keep effects within this open page; no remote dependencies, network calls, persistence, fake downloads, or automated sending. This compares entered hex byte records locally; it does not connect to hardware, mount, build, flash, upload, or prove actual device contents. Place worked explanations beside their data and identify teacher or synthetic examples clearly. Output only the complete HTML document, with inline styles and script and LF line endings.

Review the two-file readback text comparator in NOS

Use a formatting-disabled native mount and actual path/byte reads for device acceptance. Review the 5/16-byte LF targets beside the 6/17-byte CRLF mismatch in NOS, and revise eligible static readback instructions in visual editing mode before checking the device.

Keep reading