Skip to content

feat: OpenSpool tag format support (#93)#95

Merged
sjordan0228 merged 11 commits into
devfrom
feature/openspool-support
Apr 4, 2026
Merged

feat: OpenSpool tag format support (#93)#95
sjordan0228 merged 11 commits into
devfrom
feature/openspool-support

Conversation

@sjordan0228
Copy link
Copy Markdown
Contributor

@sjordan0228 sjordan0228 commented Apr 4, 2026

Summary

  • New standalone parser: OpenSpoolParser.cpp/.h — parses NDEF JSON with "protocol":"openspool"
  • Detection in NFCManager scan loop: checks application/json MIME type after OpenTag3D
  • SpoolDetected message with material, brand, color, nozzle temps
  • TFT display label "OS" (pink)
  • Landing page card with OpenSpool logo
  • /img/openspool.png route serving logo from PROGMEM

OpenSpool Tag Format

NTAG 215/216, NDEF record with application/json MIME type:

{"protocol":"openspool","version":"1.0","type":"PLA","color_hex":"FFAABB","brand":"Generic","min_temp":"220","max_temp":"240"}

No writer included

OpenSpool has their own writer app. Landing page card links to reader.

Test Plan

  • pio run -e esp32dev compiles clean
  • pio run -e esp32s3zero compiles clean
  • Scan OpenSpool-formatted NTAG215 — detected, displayed, HA published
  • OpenTag3D tags still detected correctly (regression)
  • TigerTag tags still detected correctly (regression)
  • GenericUid fallback still works for plain NTAGs
  • Landing page shows OpenSpool card with logo
  • review-remote scanner feature/openspool-support passed

Closes #93

Summary by CodeRabbit

  • New Features
    • Read OpenSpool NFC tags: reader shows protocol, version, material, brand, color and nozzle temperature ranges.
    • Web OpenSpool writer: form with color picker, prefill support, write flow, polling verification and status feedback.
    • New OpenSpool writer page, tool card, nav links and embedded OpenSpool logo/asset across the UI.
    • Writer API and on-device writing support for OpenSpool-formatted tags.
    • Detected OpenSpool tags show a dedicated "OS" icon in the interface.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 4, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d00c7825-2a26-49e5-b0d6-19181362f002

📥 Commits

Reviewing files that changed from the base of the PR and between 96247a2 and dd470bf.

📒 Files selected for processing (1)
  • src/WebServerManager.cpp

📝 Walkthrough

Walkthrough

Adds OpenSpool support end-to-end: JSON parser and data type, TagKind and TFT/display tag type, NFC detection and write path (NDEF application/json), ApplicationManager dispatch, web writer UI and API, embedded logo asset, and navigation updates across embedded pages.

Changes

Cohort / File(s) Summary
Parser & types
src/OpenSpoolParser.h, src/OpenSpoolParser.cpp, src/NFCTypes.h
New OpenSpoolData and parseOpenSpool(...); adds TagKind::OpenSpoolTag.
NFC runtime & write flow
src/NFCManager.h, src/NFCManager.cpp, src/NFCWriteTypes.h
Detects OpenSpool NDEF JSON during ISO14443A scans, stores lastOpenSpool_, exposes getLastOpenSpoolData(...), adds sendOpenSpoolMessage(...), and implements WRITE_OPENSPOOL write flow that wraps JSON in NDEF TLV and writes NTAG pages.
Application & display mapping
src/ApplicationManager.cpp, src/DisplayI.h
Maps OpenSpool detection to SPOOL_DETECTED with tag_format="OpenSpool" and assigns DisplaySpoolData::tagType = 6.
Web UI, writer, API & asset
src/OpenSpoolWriterHTML.h, src/OpenSpoolLogo.h, src/WebServerManager.h, src/WebServerManager.cpp
Adds writer HTML, embedded logo PNG, new routes (GET /writer/openspool, GET /img/openspool.png) and POST /api/write-openspool; validates/enqueues writes and extends /api/status with openspool fields.
TFT / visuals
src/TFTManager.h, src/TFTManager.cpp
Adds TAG_TYPE_OPENSPOOL = 6 and draws an "OS" icon with new color for OpenSpool tags.
Landing & navigation updates
src/LandingHTML.h, src/ConfigHTML.h, src/OpenPrintTagWriterHTML.h, src/OpenTag3DWriterHTML.h, src/ReaderHTML.h, src/TigerTagWriterHTML.h, src/TroubleshootingHTML.h, src/UIDRegistrationHTML.h, src/UpdateHTML.h
Adds OpenSpool nav links across multiple embedded HTML pages and landing tool-grid entry referencing /writer/openspool and /img/openspool.png.
Client-side reader UI
src/ReaderHTML.h
Adds renderOpenSpool(s) and integrates rendering when TagKind::OpenSpoolTag is present.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Browser
participant WebServer
participant NFCManager
participant NFC_Tag
participant AppManager
Browser->>WebServer: POST /api/write-openspool (OpenSpool JSON)
WebServer->>NFCManager: Enqueue WRITE_OPENSPOOL with payload
NFCManager->>NFC_Tag: Write NDEF (application/json) to NTAG pages
NFC_Tag-->>NFCManager: ACK / UID
NFCManager->>AppManager: sendOpenSpoolMessage(uid, parsed OpenSpoolData)
AppManager->>WebServer: SPOOL_DETECTED (app message)
WebServer->>Browser: Respond {"success": true}

mermaid
sequenceDiagram
participant NFC_Tag
participant NFCManager
participant AppManager
participant Display
NFC_Tag->>NFCManager: ISO14443A scan (NDEF JSON)
NFCManager->>NFCManager: parseOpenSpool(json)
NFCManager->>AppManager: sendOpenSpoolMessage(uid, OpenSpoolData)
AppManager->>Display: showSpool(DisplaySpoolData with tagType=6)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.39% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding OpenSpool tag format support, which matches the primary objective of the pull request.
Description check ✅ Passed The PR description covers the summary, changes, and test plan sections that align with the template requirements. All critical information is provided.
Linked Issues check ✅ Passed The code changes fully implement all objectives from issue #93: TagKind::OpenSpoolTag added, standalone OpenSpoolParser implemented, detection integrated into NFCManager scan loop, SpoolDetectedPayload populated with OpenSpool fields, display/HA/Spoolman integration done, TFT label added, and landing-page card implemented.
Out of Scope Changes check ✅ Passed All changes are in-scope and directly support OpenSpool tag format support. Navigation updates across multiple HTML pages to link to the OpenSpool reader/writer functionality are expected supporting changes; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/openspool-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/NFCManager.cpp`:
- Around line 1168-1177: The manual strcasecmp chain that sets s.material_type
from os.material should be replaced with the shared string-to-material mapper
used elsewhere in this file (call that existing mapper to convert os.material to
the enum) so you no longer silently default unknown OpenSpool names to PLA;
remove the if/else block around s.material_type, call the common mapper with
os.material to assign s.material_type, and ensure the mapper’s fallback for
unsupported names yields an explicit "unknown/none" value (e.g., 0 or
OPT_MATERIAL_TYPE_UNKNOWN) rather than treating them as PLA.

In `@src/OpenSpoolLogo.h`:
- Around line 4-7: The embedded asset bytes start with JPEG/JFIF but are
named/commented as PNG (symbol OPENSPOOL_LOGO_PNG and the comment mentioning GET
/img/openspool.png); fix this by either re-encoding the binary to a true PNG and
replacing the byte blob while keeping the names, or by renaming the asset and
route to JPEG: rename OPENSPOOL_LOGO_PNG to OPENSPOOL_LOGO_JPG, update the
comment and the GET route from /img/openspool.png to /img/openspool.jpg, and
ensure the request handler serves it with Content-Type image/jpeg (and update
any caches or tooling references accordingly).

In `@src/OpenSpoolParser.cpp`:
- Line 21: Normalize color_hex by stripping any leading '#' before copying into
out.color_hex: read the value from doc["color_hex"] (as currently done), remove
a leading '#' if present, then strncpy the normalized string into out.color_hex
ensuring you pass sizeof(out.color_hex)-1 and null-terminate; reference the
existing usage points strncpy(...) and out.color_hex and note
TFTManager::hexToRgb already strips '#', so perform the normalization here for
cleanliness.
- Line 11: The StaticJsonDocument allocated as StaticJsonDocument<256> in
OpenSpoolParser.cpp is too small for some payloads; replace and resize it to a
larger capacity (e.g., StaticJsonDocument<384> or StaticJsonDocument<512>) to
allow for longer brand names and ArduinoJson DOM overhead, updating the
StaticJsonDocument<256> declaration accordingly (search for the
StaticJsonDocument<256> symbol in OpenSpoolParser.cpp and change the template
argument to 384 or 512).

In `@src/WebServerManager.cpp`:
- Line 25: tagKindToString and handleApiStatus are not handling OpenSpool:
update tagKindToString to return a proper string for TagKind::OpenSpoolTag
(e.g., "OpenSpool") instead of falling through to "Unsupported", and extend
handleApiStatus to add an OpenSpool branch that recognizes OpenSpoolTag, parses
the OpenSpool-specific fields from the scan result (use the OpenSpool-related
types/fields introduced with OpenSpoolLogo.h), and populates the /api/status
response with those parsed fields so OpenSpool scans are reported instead of
"unsupported". Ensure to reference TagKind::OpenSpoolTag, tagKindToString(), and
handleApiStatus() when making the changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: daf5c985-0555-4e69-b729-8dbe52d8a10f

📥 Commits

Reviewing files that changed from the base of the PR and between 473f859 and 236190f.

📒 Files selected for processing (13)
  • src/ApplicationManager.cpp
  • src/DisplayI.h
  • src/LandingHTML.h
  • src/NFCManager.cpp
  • src/NFCManager.h
  • src/NFCTypes.h
  • src/OpenSpoolLogo.h
  • src/OpenSpoolParser.cpp
  • src/OpenSpoolParser.h
  • src/TFTManager.cpp
  • src/TFTManager.h
  • src/WebServerManager.cpp
  • src/WebServerManager.h

Comment thread src/NFCManager.cpp
Comment on lines +1168 to +1177
// Material type lookup
s.material_type = 0;
if (strcasecmp(os.material, "PLA") == 0) s.material_type = OPT_MATERIAL_TYPE_PLA;
else if (strcasecmp(os.material, "PETG") == 0) s.material_type = OPT_MATERIAL_TYPE_PETG;
else if (strcasecmp(os.material, "ABS") == 0) s.material_type = OPT_MATERIAL_TYPE_ABS;
else if (strcasecmp(os.material, "ASA") == 0) s.material_type = OPT_MATERIAL_TYPE_ASA;
else if (strcasecmp(os.material, "TPU") == 0) s.material_type = OPT_MATERIAL_TYPE_TPU;
else if (strcasecmp(os.material, "PA") == 0 || strcasecmp(os.material, "Nylon") == 0) s.material_type = OPT_MATERIAL_TYPE_PA6;
else if (strcasecmp(os.material, "PC") == 0) s.material_type = OPT_MATERIAL_TYPE_PC;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't silently map unsupported OpenSpool materials to PLA.

This branch recognizes far fewer material names than the TigerTag/OpenTag3D paths. Anything outside this list leaves material_type at its default value, so valid OpenSpool materials can be serialized downstream as PLA. This file already uses a shared string-to-material mapper later on; reusing that here would keep the formats aligned and avoid drift.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NFCManager.cpp` around lines 1168 - 1177, The manual strcasecmp chain
that sets s.material_type from os.material should be replaced with the shared
string-to-material mapper used elsewhere in this file (call that existing mapper
to convert os.material to the enum) so you no longer silently default unknown
OpenSpool names to PLA; remove the if/else block around s.material_type, call
the common mapper with os.material to assign s.material_type, and ensure the
mapper’s fallback for unsupported names yields an explicit "unknown/none" value
(e.g., 0 or OPT_MATERIAL_TYPE_UNKNOWN) rather than treating them as PLA.

Comment thread src/OpenSpoolLogo.h
Comment on lines +4 to +7
// OpenSpool logo PNG served at GET /img/openspool.png

static const uint8_t OPENSPOOL_LOGO_PNG[] PROGMEM = {
0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Rename or re-encode this asset so the file type matches.

The blob starts with JPEG/JFIF bytes, but the comment and symbol still call it PNG. The handler currently compensates with image/jpeg, but the mismatch is brittle and easy to propagate into future route, cache, or tooling changes. Either convert the asset to actual PNG or rename the route/identifiers to .jpg.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/OpenSpoolLogo.h` around lines 4 - 7, The embedded asset bytes start with
JPEG/JFIF but are named/commented as PNG (symbol OPENSPOOL_LOGO_PNG and the
comment mentioning GET /img/openspool.png); fix this by either re-encoding the
binary to a true PNG and replacing the byte blob while keeping the names, or by
renaming the asset and route to JPEG: rename OPENSPOOL_LOGO_PNG to
OPENSPOOL_LOGO_JPG, update the comment and the GET route from /img/openspool.png
to /img/openspool.jpg, and ensure the request handler serves it with
Content-Type image/jpeg (and update any caches or tooling references
accordingly).

Comment thread src/OpenSpoolParser.cpp

if (!json || len == 0) return false;

StaticJsonDocument<256> doc;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider increasing JSON document size for robustness.

StaticJsonDocument<256> may be tight for payloads with longer brand names. The example JSON is ~130 bytes raw, and ArduinoJson's DOM overhead can approach 2x. A 64-char brand name alone could push limits.

Consider increasing to StaticJsonDocument<384> or StaticJsonDocument<512> for safety margin.

♻️ Proposed fix
-    StaticJsonDocument<256> doc;
+    StaticJsonDocument<384> doc;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
StaticJsonDocument<256> doc;
StaticJsonDocument<384> doc;
🧰 Tools
🪛 Clang (14.0.6)

[warning] 11-11: variable 'doc' is not initialized

(cppcoreguidelines-init-variables)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/OpenSpoolParser.cpp` at line 11, The StaticJsonDocument allocated as
StaticJsonDocument<256> in OpenSpoolParser.cpp is too small for some payloads;
replace and resize it to a larger capacity (e.g., StaticJsonDocument<384> or
StaticJsonDocument<512>) to allow for longer brand names and ArduinoJson DOM
overhead, updating the StaticJsonDocument<256> declaration accordingly (search
for the StaticJsonDocument<256> symbol in OpenSpoolParser.cpp and change the
template argument to 384 or 512).

Comment thread src/OpenSpoolParser.cpp
strncpy(out.protocol, protocol, sizeof(out.protocol) - 1);
strncpy(out.version, doc["version"] | "1.0", sizeof(out.version) - 1);
strncpy(out.material, doc["type"] | "", sizeof(out.material) - 1);
strncpy(out.color_hex, doc["color_hex"] | "", sizeof(out.color_hex) - 1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider stripping leading # from color_hex for robustness.

The spec indicates color_hex should not include #, but external writers might include it. Downstream code (e.g., TFTManager::hexToRgb) already handles stripping #, but storing it normalized here would be cleaner.

♻️ Optional normalization
-    strncpy(out.color_hex, doc["color_hex"] | "", sizeof(out.color_hex) - 1);
+    const char* rawHex = doc["color_hex"] | "";
+    if (rawHex[0] == '#') rawHex++;  // strip leading #
+    strncpy(out.color_hex, rawHex, sizeof(out.color_hex) - 1);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
strncpy(out.color_hex, doc["color_hex"] | "", sizeof(out.color_hex) - 1);
const char* rawHex = doc["color_hex"] | "";
if (rawHex[0] == '#') rawHex++; // strip leading #
strncpy(out.color_hex, rawHex, sizeof(out.color_hex) - 1);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/OpenSpoolParser.cpp` at line 21, Normalize color_hex by stripping any
leading '#' before copying into out.color_hex: read the value from
doc["color_hex"] (as currently done), remove a leading '#' if present, then
strncpy the normalized string into out.color_hex ensuring you pass
sizeof(out.color_hex)-1 and null-terminate; reference the existing usage points
strncpy(...) and out.color_hex and note TFTManager::hexToRgb already strips '#',
so perform the normalization here for cleanliness.

Comment thread src/WebServerManager.cpp
#include "OpenPrintTagLogo.h"
#include "TigerTagLogo.h"
#include "OpenTag3DLogo.h"
#include "OpenSpoolLogo.h"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Complete the /api/status plumbing for OpenSpool.

This file now adds OpenSpool-specific assets, but tagKindToString() still falls through to "Unsupported" for TagKind::OpenSpoolTag, and handleApiStatus() still has no OpenSpool branch. An OpenSpool scan will therefore come back from /api/status as unsupported with no parsed fields.

Also applies to: 106-106, 237-240

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/WebServerManager.cpp` at line 25, tagKindToString and handleApiStatus are
not handling OpenSpool: update tagKindToString to return a proper string for
TagKind::OpenSpoolTag (e.g., "OpenSpool") instead of falling through to
"Unsupported", and extend handleApiStatus to add an OpenSpool branch that
recognizes OpenSpoolTag, parses the OpenSpool-specific fields from the scan
result (use the OpenSpool-related types/fields introduced with OpenSpoolLogo.h),
and populates the /api/status response with those parsed fields so OpenSpool
scans are reported instead of "unsupported". Ensure to reference
TagKind::OpenSpoolTag, tagKindToString(), and handleApiStatus() when making the
changes.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/NFCManager.cpp (1)

600-605: ⚠️ Potential issue | 🟡 Minor

lastOpenSpoolValid_ not cleared when tag is removed.

When a tag is removed (lines 600-604), lastTigerTagValid_ and lastOpenTag3DValid_ are cleared, but lastOpenSpoolValid_ is not. This could cause stale OpenSpool data to persist.

Proposed fix
                 lastSeenValid = false;
                 lastTigerTagValid_ = false;
                 lastOpenTag3DValid_ = false;
+                lastOpenSpoolValid_ = false;
 
                 // Clear suppression if tag removed
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NFCManager.cpp` around lines 600 - 605, When handling tag removal in the
block that sets currentSpool.present = false (the same area that clears
lastSeenValid, lastTigerTagValid_, and lastOpenTag3DValid_), also clear
lastOpenSpoolValid_ so stale OpenSpool state is not retained; update the
tag-removal sequence in NFCManager.cpp to set lastOpenSpoolValid_ = false
alongside the other validity flags referencing
currentSpool/lastTigerTagValid_/lastOpenTag3DValid_.
src/LandingHTML.h (1)

17-28: ⚠️ Potential issue | 🟡 Minor

Navigation bar is missing the OpenSpool link.

The nav bar includes links to OpenPrintTag, TigerTag, and OpenTag3D writers, but OpenSpool is missing. The OpenSpoolWriterHTML.h shows OpenSpool in its nav (line 24), creating an inconsistency where users can navigate away from the OpenSpool writer but cannot navigate back to it from the landing page nav.

Proposed fix
       <a href="/writer/tigertag">TigerTag</a>
       <a href="/writer/opentag3d">OpenTag3D</a>
+      <a href="/writer/openspool">OpenSpool</a>
       <a href="/register/uid">NFC+</a>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/LandingHTML.h` around lines 17 - 28, Add the missing OpenSpool nav link
to the landing page nav so it matches the writer pages: insert an anchor element
similar to the existing writer links (e.g., <a
href="/writer/openspool">OpenSpool</a>) into the <nav> block alongside
OpenPrintTag, TigerTag and OpenTag3D in LandingHTML.h, using the same
classes/formatting as the other writer links to maintain consistency with
OpenSpoolWriterHTML.h.
♻️ Duplicate comments (3)
src/NFCManager.cpp (1)

1168-1177: ⚠️ Potential issue | 🟠 Major

Limited material type mapping silently defaults unknowns to PLA.

The material type lookup only handles 7 materials (PLA, PETG, ABS, ASA, TPU, PA/Nylon, PC), while the OpenPrintTag library supports 42 material types. Any other material (e.g., PCTG, HIPS, PVB from the writer UI dropdown, or PP, PVA, PEEK, etc.) will silently default to OPT_MATERIAL_TYPE_PLA (0). This misidentifies filament types downstream.

Consider using the shared materialTypeFromString() helper in ConversionUtils for consistency with TigerTag and OpenTag3D paths, or extend this mapping.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NFCManager.cpp` around lines 1168 - 1177, The material mapping in
NFCManager.cpp currently hardcodes seven materials and defaults unknowns to PLA
(s.material_type = OPT_MATERIAL_TYPE_PLA); replace this ad-hoc lookup with the
shared helper to ensure all 42 types are handled consistently—call
ConversionUtils::materialTypeFromString(os.material) (or the equivalent
materialTypeFromString function) to derive s.material_type, and remove or
fallback the existing strcasecmp chain so unknown strings no longer silently map
to PLA. Ensure you include the proper header for ConversionUtils and adjust any
types if the helper returns a different enum/type.
src/WebServerManager.cpp (2)

63-73: ⚠️ Potential issue | 🟠 Major

Missing OpenSpoolTag case in tagKindToString.

The tagKindToString function does not handle TagKind::OpenSpoolTag, causing it to fall through to "Unsupported". This affects /api/status responses when an OpenSpool tag is detected.

Proposed fix
 static const char* tagKindToString(TagKind kind) {
     switch (kind) {
         case TagKind::OpenPrintTag: return "OpenPrintTag";
         case TagKind::GenericUidTag: return "GenericUidTag";
         case TagKind::TigerTag:     return "TigerTag";
         case TagKind::OpenTag3D:    return "OpenTag3D";
         case TagKind::BambuTag:     return "BambuTag";
         case TagKind::BlankTag:     return "BlankTag";
+        case TagKind::OpenSpoolTag: return "OpenSpool";
         default:                    return "Unsupported";
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/WebServerManager.cpp` around lines 63 - 73, The tagKindToString function
is missing handling for TagKind::OpenSpoolTag so that OpenSpool tags fall
through to "Unsupported"; update the switch in tagKindToString to add a case for
TagKind::OpenSpoolTag that returns "OpenSpoolTag" (ensure the case label and
returned string match the naming used for other TagKind cases) so /api/status
reports the correct tag string.

1016-1173: ⚠️ Potential issue | 🟠 Major

handleApiStatus missing OpenSpool branch.

The /api/status handler has specific branches for TigerTag, OpenTag3D, GenericUidTag, and OpenPrintTag, but no branch for OpenSpoolTag. When an OpenSpool tag is detected, the response will not include the parsed OpenSpool fields.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/WebServerManager.cpp` around lines 1016 - 1173, handleApiStatus lacks
handling for TagKind::OpenSpoolTag so when state.kind == TagKind::OpenSpoolTag
the response omits parsed OpenSpool fields; add an else-if branch checking
state.kind == TagKind::OpenSpoolTag (alongside the existing TagKind::TigerTag,
TagKind::OpenTag3D, etc.) that calls
NFCManager::getInstance().getLastOpenSpoolData(openSpoolStruct) (or the
appropriate NFCManager getter), verifies the returned data is valid, creates a
nested JSON object (e.g. doc.createNestedObject("openspool")), and populates it
with the OpenSpool fields you expose (material, manufacturer, color_hex,
remaining_g, diameter_mm, temps/dry info if present) mirroring the style and
null/zero checks used in the other tag branches in
WebServerManager::handleApiStatus.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/NFCManager.cpp`:
- Around line 420-464: Extract the nested OpenSpool NDEF detection block into a
helper function (e.g., bool checkOpenSpoolNdef(const uint8_t* pageData, size_t
bytesRead, size_t ndefStart, size_t headerSize, size_t typeLen, bool sr, /*out*/
OpenSpoolType& openSpoolData)) that encapsulates the MIME check for
"application/json", payload length computation (short vs long record), page
boundary handling using connection_->readISO14443Pages, buffer bounds checks,
and the call to parseOpenSpool; then replace the large nested block in
NFCManager.cpp with a single call that sets isOpenSpool =
checkOpenSpoolNdef(pageData, bytesRead, ndefStart, headerSize, typeLen, sr,
openSpoolData). Ensure the helper uses the same symbols (pageData, ndefStart,
headerSize, typeLen, sr, bytesRead, connection_->readISO14443Pages,
parseOpenSpool, openSpoolData) and preserves existing size limits and fallback
logic.
- Around line 1158-1162: The code uses memset(&s, 0, sizeof(s)) to clear the
AppMessage::payload.spoolDetected struct inside
NFCManager::sendOpenSpoolMessage; replace that with proper value-initialization
(e.g., assign an empty initializer or default-constructed instance to s) so
floating-point members like kg_remaining, density, diameter, initial_weight_g
are set to 0.0 safely and portably; update the function to use s = {} or s =
SpoolDetected{} (matching the actual struct/type name) instead of memset.

In `@src/OpenSpoolWriterHTML.h`:
- Around line 110-126: The Spoolman callback (renderSpoolmanPicker ->
callback(spool)) currently writes f.material directly into the `#type` select
which can create an invalid selection if the value doesn't match any option;
update the handler to check whether document.getElementById('type') already
contains an option with value === f.material and if not either create and append
a new <option> with that value (and a sensible label) before setting .value, or
fall back to a safe default/empty value and mark the field for manual review;
make this change in the callback that reads f.material so the select always ends
up with a valid option.

In `@src/WebServerManager.cpp`:
- Around line 245-248: The response in WebServerManager::handleOpenSpoolLogo is
sending OPENSPOOL_LOGO_PNG via _server.send_P but sets the Content-Type to
"image/jpeg"; update the MIME type to "image/png" so the PNG data
(OPENSPOOL_LOGO_PNG and OPENSPOOL_LOGO_PNG_SIZE) is served with the correct
Content-Type header (modify the _server.send_P call to use "image/png").
- Around line 1558-1563: The JSON is built by snprintf into jsonPayload using
raw user strings (protocol, version, type, color_hex, brand, min_temp,
max_temp), which allows injection; fix by not interpolating unsanitized values
directly—either validate/whitelist each input (e.g., only alphanumerics and a
few safe punctuation) or replace this snprintf construction with a proper JSON
builder (e.g., ArduinoJson::JsonDocument + serialize) or at minimum escape JSON
string characters before formatting (create an escapeJsonString helper and apply
it to protocol/version/type/color_hex/brand/min_temp/max_temp) so the produced
JSON is always well-formed and safe.

---

Outside diff comments:
In `@src/LandingHTML.h`:
- Around line 17-28: Add the missing OpenSpool nav link to the landing page nav
so it matches the writer pages: insert an anchor element similar to the existing
writer links (e.g., <a href="/writer/openspool">OpenSpool</a>) into the <nav>
block alongside OpenPrintTag, TigerTag and OpenTag3D in LandingHTML.h, using the
same classes/formatting as the other writer links to maintain consistency with
OpenSpoolWriterHTML.h.

In `@src/NFCManager.cpp`:
- Around line 600-605: When handling tag removal in the block that sets
currentSpool.present = false (the same area that clears lastSeenValid,
lastTigerTagValid_, and lastOpenTag3DValid_), also clear lastOpenSpoolValid_ so
stale OpenSpool state is not retained; update the tag-removal sequence in
NFCManager.cpp to set lastOpenSpoolValid_ = false alongside the other validity
flags referencing currentSpool/lastTigerTagValid_/lastOpenTag3DValid_.

---

Duplicate comments:
In `@src/NFCManager.cpp`:
- Around line 1168-1177: The material mapping in NFCManager.cpp currently
hardcodes seven materials and defaults unknowns to PLA (s.material_type =
OPT_MATERIAL_TYPE_PLA); replace this ad-hoc lookup with the shared helper to
ensure all 42 types are handled consistently—call
ConversionUtils::materialTypeFromString(os.material) (or the equivalent
materialTypeFromString function) to derive s.material_type, and remove or
fallback the existing strcasecmp chain so unknown strings no longer silently map
to PLA. Ensure you include the proper header for ConversionUtils and adjust any
types if the helper returns a different enum/type.

In `@src/WebServerManager.cpp`:
- Around line 63-73: The tagKindToString function is missing handling for
TagKind::OpenSpoolTag so that OpenSpool tags fall through to "Unsupported";
update the switch in tagKindToString to add a case for TagKind::OpenSpoolTag
that returns "OpenSpoolTag" (ensure the case label and returned string match the
naming used for other TagKind cases) so /api/status reports the correct tag
string.
- Around line 1016-1173: handleApiStatus lacks handling for
TagKind::OpenSpoolTag so when state.kind == TagKind::OpenSpoolTag the response
omits parsed OpenSpool fields; add an else-if branch checking state.kind ==
TagKind::OpenSpoolTag (alongside the existing TagKind::TigerTag,
TagKind::OpenTag3D, etc.) that calls
NFCManager::getInstance().getLastOpenSpoolData(openSpoolStruct) (or the
appropriate NFCManager getter), verifies the returned data is valid, creates a
nested JSON object (e.g. doc.createNestedObject("openspool")), and populates it
with the OpenSpool fields you expose (material, manufacturer, color_hex,
remaining_g, diameter_mm, temps/dry info if present) mirroring the style and
null/zero checks used in the other tag branches in
WebServerManager::handleApiStatus.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5ed9692b-5682-4c90-88e3-43575511e22d

📥 Commits

Reviewing files that changed from the base of the PR and between 236190f and 6ba1d73.

📒 Files selected for processing (6)
  • src/LandingHTML.h
  • src/NFCManager.cpp
  • src/NFCWriteTypes.h
  • src/OpenSpoolWriterHTML.h
  • src/WebServerManager.cpp
  • src/WebServerManager.h

Comment thread src/NFCManager.cpp
Comment on lines +420 to +464

// Check for OpenSpool (application/json + "protocol":"openspool")
if (!isOpenTag3D) {
const char* jsonMime = "application/json";
size_t jsonMimeLen = strlen(jsonMime);
if (typeLen == jsonMimeLen &&
memcmp(pageData + ndefStart + headerSize, jsonMime, jsonMimeLen) == 0) {
uint32_t osPayloadLen = 0;
if (sr) {
osPayloadLen = pageData[ndefStart + 2];
} else {
osPayloadLen = ((uint32_t)pageData[ndefStart + 2] << 24) |
((uint32_t)pageData[ndefStart + 3] << 16) |
((uint32_t)pageData[ndefStart + 4] << 8) |
pageData[ndefStart + 5];
}
uint16_t osOffset = ndefStart + headerSize + typeLen;
uint8_t osPayload[256] = {0};
uint16_t osBytes = 0;

if (osOffset + osPayloadLen <= bytesRead) {
osBytes = (uint16_t)osPayloadLen;
if (osBytes > sizeof(osPayload)) osBytes = sizeof(osPayload);
memcpy(osPayload, pageData + osOffset, osBytes);
} else {
uint8_t osStartPage = 4 + (osOffset / 4);
uint16_t osPagesNeeded = (uint16_t)((osPayloadLen + 3) / 4) + 1;
if (osPagesNeeded > 50) osPagesNeeded = 50;
uint8_t osExtData[256] = {0};
uint16_t osExtRead = connection_->readISO14443Pages(
osStartPage, (uint8_t)osPagesNeeded, osExtData, sizeof(osExtData));
uint16_t osOffInPage = osOffset % 4;
if (osExtRead > osOffInPage) {
osBytes = osExtRead - osOffInPage;
if (osBytes > osPayloadLen) osBytes = (uint16_t)osPayloadLen;
if (osBytes > sizeof(osPayload)) osBytes = sizeof(osPayload);
memcpy(osPayload, osExtData + osOffInPage, osBytes);
}
}

if (osBytes > 0 && parseOpenSpool(osPayload, osBytes, openSpoolData)) {
isOpenSpool = true;
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Deep nesting increases cognitive complexity.

The OpenSpool detection logic adds another level of nesting (up to 13 levels per static analysis). Consider extracting the OpenSpool NDEF check into a helper function to match the structure of tigerTagCheckMagic and improve maintainability.

🧰 Tools
🪛 Clang (14.0.6)

[note] 422-422: +10, including nesting penalty of 9, nesting level increased to 10

(clang)


[note] 425-425: +11, including nesting penalty of 10, nesting level increased to 11

(clang)


[note] 428-428: +12, including nesting penalty of 11, nesting level increased to 12

(clang)


[note] 430-430: +1, nesting level increased to 12

(clang)


[note] 440-440: +12, including nesting penalty of 11, nesting level increased to 12

(clang)


[note] 444-444: +1, nesting level increased to 12

(clang)


[note] 452-452: +13, including nesting penalty of 12, nesting level increased to 13

(clang)


[note] 460-460: +12, including nesting penalty of 11, nesting level increased to 12

(clang)


[warning] 424-424: variable 'jsonMimeLen' is not initialized

(cppcoreguidelines-init-variables)


[warning] 427-427: variable 'osPayloadLen' is not initialized

(cppcoreguidelines-init-variables)


[warning] 428-428: if with identical then and else branches

(bugprone-branch-clone)


[note] 430-430: else branch starts here

(clang)


[warning] 436-436: variable 'osOffset' is not initialized

(cppcoreguidelines-init-variables)


[warning] 438-438: variable 'osBytes' is not initialized

(cppcoreguidelines-init-variables)


[warning] 445-445: variable 'osStartPage' is not initialized

(cppcoreguidelines-init-variables)


[warning] 446-446: variable 'osPagesNeeded' is not initialized

(cppcoreguidelines-init-variables)


[warning] 449-449: variable 'osExtRead' is not initialized

(cppcoreguidelines-init-variables)


[warning] 451-451: variable 'osOffInPage' is not initialized

(cppcoreguidelines-init-variables)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NFCManager.cpp` around lines 420 - 464, Extract the nested OpenSpool NDEF
detection block into a helper function (e.g., bool checkOpenSpoolNdef(const
uint8_t* pageData, size_t bytesRead, size_t ndefStart, size_t headerSize, size_t
typeLen, bool sr, /*out*/ OpenSpoolType& openSpoolData)) that encapsulates the
MIME check for "application/json", payload length computation (short vs long
record), page boundary handling using connection_->readISO14443Pages, buffer
bounds checks, and the call to parseOpenSpool; then replace the large nested
block in NFCManager.cpp with a single call that sets isOpenSpool =
checkOpenSpoolNdef(pageData, bytesRead, ndefStart, headerSize, typeLen, sr,
openSpoolData). Ensure the helper uses the same symbols (pageData, ndefStart,
headerSize, typeLen, sr, bytesRead, connection_->readISO14443Pages,
parseOpenSpool, openSpoolData) and preserves existing size limits and fallback
logic.

Comment thread src/NFCManager.cpp
Comment on lines +1158 to +1162
void NFCManager::sendOpenSpoolMessage(const char* uid, const OpenSpoolData& os) {
AppMessage msg;
msg.type = AppMessageType::SPOOL_DETECTED;
auto& s = msg.payload.spoolDetected;
memset(&s, 0, sizeof(s));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Use member initializer instead of memset on struct containing floats.

memset on a struct containing floating-point members (kg_remaining, density, diameter, initial_weight_g) may produce invalid bit patterns on some platforms. While typically safe on ESP32/IEEE 754, explicit zero-initialization is cleaner.

Proposed fix
 void NFCManager::sendOpenSpoolMessage(const char* uid, const OpenSpoolData& os) {
     AppMessage msg;
     msg.type = AppMessageType::SPOOL_DETECTED;
-    auto& s = msg.payload.spoolDetected;
-    memset(&s, 0, sizeof(s));
+    msg.payload.spoolDetected = {};  // Value-initialize all members
+    auto& s = msg.payload.spoolDetected;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void NFCManager::sendOpenSpoolMessage(const char* uid, const OpenSpoolData& os) {
AppMessage msg;
msg.type = AppMessageType::SPOOL_DETECTED;
auto& s = msg.payload.spoolDetected;
memset(&s, 0, sizeof(s));
void NFCManager::sendOpenSpoolMessage(const char* uid, const OpenSpoolData& os) {
AppMessage msg;
msg.type = AppMessageType::SPOOL_DETECTED;
msg.payload.spoolDetected = {}; // Value-initialize all members
auto& s = msg.payload.spoolDetected;
🧰 Tools
🪛 Clang (14.0.6)

[note] 1158-1158: the definition seen here

(clang)


[warning] 1158-1158: method 'sendOpenSpoolMessage' can be made static

(readability-convert-member-functions-to-static)


[warning] 1158-1158: parameter name 'os' is too short, expected at least 3 characters

(readability-identifier-length)


[warning] 1161-1161: variable name 's' is too short, expected at least 3 characters

(readability-identifier-length)

🪛 Cppcheck (2.20.0)

[portability] 1162-1162: Using memset() on struct which contains a floating point number.

(memsetClassFloat)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/NFCManager.cpp` around lines 1158 - 1162, The code uses memset(&s, 0,
sizeof(s)) to clear the AppMessage::payload.spoolDetected struct inside
NFCManager::sendOpenSpoolMessage; replace that with proper value-initialization
(e.g., assign an empty initializer or default-constructed instance to s) so
floating-point members like kg_remaining, density, diameter, initial_weight_g
are set to 0.0 safely and portably; update the function to use s = {} or s =
SpoolDetected{} (matching the actual struct/type name) instead of memset.

Comment thread src/OpenSpoolWriterHTML.h Outdated
Comment on lines +110 to +126
if (typeof renderSpoolmanPicker === 'function') {
renderSpoolmanPicker('spoolmanPicker', function(spool) {
if (spool.filament) {
var f = spool.filament;
if (f.vendor && f.vendor.name) document.getElementById('brand').value = f.vendor.name;
if (f.material) document.getElementById('type').value = f.material;
if (f.color_hex) {
document.getElementById('color_hex').value = '#' + f.color_hex;
document.getElementById('colorPreview').style.background = '#' + f.color_hex;
}
if (f.settings_extruder_temp) {
document.getElementById('min_temp').value = f.settings_extruder_temp;
document.getElementById('max_temp').value = f.settings_extruder_temp;
}
}
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Spoolman picker callback may set invalid select option value.

When f.material from Spoolman doesn't match any <option> value in the #type select (e.g., "WOOD", "CARBON", or other materials not in the limited dropdown), the select will show no valid selection but the form may still submit. Consider adding the material as a custom option or validating the material type.

Proposed enhancement
           if (f.material) document.getElementById('type').value = f.material;
+          // If material not in dropdown, add it as an option
+          var typeSelect = document.getElementById('type');
+          if (typeSelect.value !== f.material) {
+            var opt = document.createElement('option');
+            opt.value = f.material;
+            opt.textContent = f.material;
+            typeSelect.appendChild(opt);
+            typeSelect.value = f.material;
+          }
🧰 Tools
🪛 Clang (14.0.6)

[error] 110-110: expected identifier or '('

(clang-diagnostic-error)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/OpenSpoolWriterHTML.h` around lines 110 - 126, The Spoolman callback
(renderSpoolmanPicker -> callback(spool)) currently writes f.material directly
into the `#type` select which can create an invalid selection if the value doesn't
match any option; update the handler to check whether
document.getElementById('type') already contains an option with value ===
f.material and if not either create and append a new <option> with that value
(and a sensible label) before setting .value, or fall back to a safe
default/empty value and mark the field for manual review; make this change in
the callback that reads f.material so the select always ends up with a valid
option.

Comment thread src/WebServerManager.cpp
Comment on lines +245 to +248
void WebServerManager::handleOpenSpoolLogo() {
_server.sendHeader("Cache-Control", "public, max-age=86400");
_server.send_P(200, "image/jpeg", reinterpret_cast<const char*>(OPENSPOOL_LOGO_PNG), OPENSPOOL_LOGO_PNG_SIZE);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Content-Type mismatch: serving PNG as JPEG.

The constant OPENSPOOL_LOGO_PNG (and OPENSPOOL_LOGO_PNG_SIZE) suggest this is a PNG image, but the Content-Type is set to image/jpeg. This will cause browsers to misinterpret the image format.

Proposed fix
 void WebServerManager::handleOpenSpoolLogo() {
     _server.sendHeader("Cache-Control", "public, max-age=86400");
-    _server.send_P(200, "image/jpeg", reinterpret_cast<const char*>(OPENSPOOL_LOGO_PNG), OPENSPOOL_LOGO_PNG_SIZE);
+    _server.send_P(200, "image/png", reinterpret_cast<const char*>(OPENSPOOL_LOGO_PNG), OPENSPOOL_LOGO_PNG_SIZE);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void WebServerManager::handleOpenSpoolLogo() {
_server.sendHeader("Cache-Control", "public, max-age=86400");
_server.send_P(200, "image/jpeg", reinterpret_cast<const char*>(OPENSPOOL_LOGO_PNG), OPENSPOOL_LOGO_PNG_SIZE);
}
void WebServerManager::handleOpenSpoolLogo() {
_server.sendHeader("Cache-Control", "public, max-age=86400");
_server.send_P(200, "image/png", reinterpret_cast<const char*>(OPENSPOOL_LOGO_PNG), OPENSPOOL_LOGO_PNG_SIZE);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/WebServerManager.cpp` around lines 245 - 248, The response in
WebServerManager::handleOpenSpoolLogo is sending OPENSPOOL_LOGO_PNG via
_server.send_P but sets the Content-Type to "image/jpeg"; update the MIME type
to "image/png" so the PNG data (OPENSPOOL_LOGO_PNG and OPENSPOOL_LOGO_PNG_SIZE)
is served with the correct Content-Type header (modify the _server.send_P call
to use "image/png").

Comment thread src/WebServerManager.cpp Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/WebServerManager.cpp (1)

1029-1115: ⚠️ Potential issue | 🔴 Critical

OpenSpool-specific data branch is missing from /api/status handler, but suggested fix references non-existent method.

OpenSpoolTag is recognized and parsed (lines 1033, 505), but the API status handler doesn't include parsed OpenSpool fields. The issue is real, but the suggested code won't compile: NFCManager::getInstance().getLastOpenSpoolData() does not exist. NFCManager has the data stored in lastOpenSpool_ and lastOpenSpoolValid_ members, but lacks a public getter method matching the pattern used for TigerTag and OpenTag3D.

To implement this properly: add a public getter method to NFCManager (e.g., bool getLastOpenSpoolData(OpenSpoolData& out)) mirroring the existing getLastTigerTagData() and getLastOpenTag3DData() methods, then add the OpenSpoolTag branch to the API handler.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/WebServerManager.cpp` around lines 1029 - 1115, The API /api/status
handler is missing the OpenSpoolTag branch and the suggested getter used in the
review doesn't exist; add a public
NFCManager::getLastOpenSpoolData(OpenSpoolData& out) method that returns
lastOpenSpoolValid_ and copies lastOpenSpool_ into out (mirroring
getLastTigerTagData/getLastOpenTag3DData), then update the TagKind handling in
WebServerManager.cpp to add an else-if branch for state.kind ==
TagKind::OpenSpool that calls
NFCManager::getInstance().getLastOpenSpoolData(...) and serializes the relevant
OpenSpoolData fields into a nested "openspool" JSON object (similar style to the
TigerTag and OpenTag3D branches).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/WebServerManager.cpp`:
- Around line 1029-1115: The API /api/status handler is missing the OpenSpoolTag
branch and the suggested getter used in the review doesn't exist; add a public
NFCManager::getLastOpenSpoolData(OpenSpoolData& out) method that returns
lastOpenSpoolValid_ and copies lastOpenSpool_ into out (mirroring
getLastTigerTagData/getLastOpenTag3DData), then update the TagKind handling in
WebServerManager.cpp to add an else-if branch for state.kind ==
TagKind::OpenSpool that calls
NFCManager::getInstance().getLastOpenSpoolData(...) and serializes the relevant
OpenSpoolData fields into a nested "openspool" JSON object (similar style to the
TigerTag and OpenTag3D branches).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fbe7dfa8-75ec-44fc-bf49-aacb13c5a035

📥 Commits

Reviewing files that changed from the base of the PR and between 6ba1d73 and 73d8e5b.

📒 Files selected for processing (11)
  • src/ConfigHTML.h
  • src/LandingHTML.h
  • src/OpenPrintTagWriterHTML.h
  • src/OpenSpoolWriterHTML.h
  • src/OpenTag3DWriterHTML.h
  • src/ReaderHTML.h
  • src/TigerTagWriterHTML.h
  • src/TroubleshootingHTML.h
  • src/UIDRegistrationHTML.h
  • src/UpdateHTML.h
  • src/WebServerManager.cpp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant