Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,56 @@
# Changelog

## [1.7.3] - 2026-04-20

### Added

- **WiFi keep-awake toggle** — new config option disables ESP32 modem sleep so the scanner stays consistently reachable on the network, at the cost of slightly higher idle current. Defaults off. (#163)
- **`roomonthethird` case files** — community-contributed STEP/STL/F3D case models for the NFC reader, under `usermods/roomonthethird/`. (#165)

### Improved

- **TigerTag partial writes** — writes pre-read pages 4–13 and only send pages whose contents actually changed (grouped into contiguous runs). Full-rewrite fallback on any run failure preserves tag consistency. Reduces NFC transaction time and tag wear on field-level edits. (#13, #164)

### Changed

- **`sendSpoolDetectedMessage` renamed to `sendOpenPrintTagMessage`** — original name was misleading; the function only fires for OpenPrintTag detections. Internal rename, no user-facing behavior change. (#159, #162)

---

## [1.7.2] - 2026-04-14

### Added

- **Bambu Lab MIFARE Classic tag reading** — scanner authenticates to Bambu tags using HKDF-derived MIFARE Classic keys and decodes material, color, weight, remaining filament length, nozzle/bed temperature, and dry time. Published via MQTT `tag/state` and `/api/status`, and shown on the reader page alongside other tag formats. (#24)

### Changed

- Added `.superpowers` and `.DS_Store` to `.gitignore`.

---

## [1.7.1] - 2026-04-13

### Added

- **Pre-emptive spool link in writer flow** — when writing a tag after picking an existing Spoolman spool, the picker selection now links the spool's `nfc_id` to the written tag instead of the auto-sync creating a duplicate Spoolman entry. (#130)
- **Writer Read enrichment polling** — writer pages poll briefly after a tag read to let Spoolman enrichment complete before rendering, plus a format-detection grace period. Avoids partially-populated forms. (#101)

### Fixed

- Writer Read now restores all fields for a full round-trip (prior behavior left some fields blank). (#101)
- Clear stale fields and cancel prior enrichment timer when starting a new Read.
- Skip `remaining_g` in enrichment payloads when the value is 0 to avoid wiping valid weight. (#128)
- Default `initial_weight` to 1000g and derive `remaining` when Spoolman has no weight set. (#128)
- Firefox stale-cache `ReferenceError` on writer pages — shared CSS/JS cache now versioned via `FIRMWARE_VERSION`. (#151)
- Timestamp ordering in pending-link flow to prevent a write-vs-sync race condition.

### Changed

- **Pinned `espressif32@6.10.0`** in `platformio.ini` to prevent auto-upgrade to Arduino 3.x (breaking API changes in Arduino 3.x — e.g. `WiFiClient` includes, `esp_task_wdt_init` signature).

---

## [1.7.0] - 2026-04-11

### Added
Expand Down
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ board_build.partitions = partitions.csv
monitor_speed = 115200
monitor_filters = direct, printable
build_flags =
-DFIRMWARE_VERSION=\"1.7.2\"
-DFIRMWARE_VERSION=\"1.7.3\"
lib_deps =
marcoschwartz/LiquidCrystal_I2C@^1.1.4
bblanchon/ArduinoJson@^7.0.0
Expand Down
50 changes: 31 additions & 19 deletions src/ConfigHTML.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ const char CONFIG_HTML[] PROGMEM = R"rawliteral(
</div>
</div>
</div>
<div class="toggle-row" style="margin-top:10px">
<div>
<span id="wifi_keep_awake_label" class="toggle-label">Keep WiFi radio awake</span>
<div style="font-size:11px;color:#71717A;margin-top:4px">Disables modem sleep. Improves RSSI and response time on weak signals, uses slightly more power.</div>
</div>
<label class="toggle-switch">
<input type="checkbox" id="wifi_keep_awake" aria-labelledby="wifi_keep_awake_label" />
<span class="toggle-track"></span>
</label>
</div>
</section>

<section>
Expand Down Expand Up @@ -126,9 +136,9 @@ const char CONFIG_HTML[] PROGMEM = R"rawliteral(
<section>
<h2 class="section-title">Spoolman</h2>
<div class="toggle-row" style="margin-bottom:14px">
<span class="toggle-label">Enable Spoolman</span>
<span id="spoolman_on_label" class="toggle-label">Enable Spoolman</span>
<label class="toggle-switch">
<input type="checkbox" id="spoolman_on" />
<input type="checkbox" id="spoolman_on" aria-labelledby="spoolman_on_label" />
<span class="toggle-track"></span>
</label>
</div>
Expand All @@ -151,9 +161,9 @@ const char CONFIG_HTML[] PROGMEM = R"rawliteral(
<h2 class="section-title">PrusaLink</h2>
<div class="hint" style="margin-bottom:12px">Connect to a Prusa printer for automatic filament tracking. Get the API key from your printer's web interface.</div>
<div class="toggle-row" style="margin-bottom:14px">
<span class="toggle-label">Enable PrusaLink</span>
<span id="prusalink_on_label" class="toggle-label">Enable PrusaLink</span>
<label class="toggle-switch">
<input type="checkbox" id="prusalink_on" />
<input type="checkbox" id="prusalink_on" aria-labelledby="prusalink_on_label" />
<span class="toggle-track"></span>
</label>
</div>
Expand Down Expand Up @@ -185,52 +195,52 @@ const char CONFIG_HTML[] PROGMEM = R"rawliteral(
<div class="hint" style="margin-bottom:12px">Enable or disable optional hardware peripherals. Changes take effect after reboot.</div>
<div style="display:grid;gap:10px">
<div class="toggle-row">
<span class="toggle-label">LCD Display</span>
<span id="lcd_enabled_label" class="toggle-label">LCD Display</span>
<label class="toggle-switch">
<input type="checkbox" id="lcd_enabled" />
<input type="checkbox" id="lcd_enabled" aria-labelledby="lcd_enabled_label" />
<span class="toggle-track"></span>
</label>
</div>
<div class="toggle-row">
<span class="toggle-label">Status LED</span>
<span id="led_enabled_label" class="toggle-label">Status LED</span>
<label class="toggle-switch">
<input type="checkbox" id="led_enabled" />
<input type="checkbox" id="led_enabled" aria-labelledby="led_enabled_label" />
<span class="toggle-track"></span>
</label>
</div>
<div class="toggle-row">
<span class="toggle-label">3x4 Matrix Keypad</span>
<span id="keypad_enabled_label" class="toggle-label">3x4 Matrix Keypad</span>
<label class="toggle-switch">
<input type="checkbox" id="keypad_enabled" />
<input type="checkbox" id="keypad_enabled" aria-labelledby="keypad_enabled_label" />
<span class="toggle-track"></span>
</label>
</div>
<div class="toggle-row">
<span class="toggle-label">TFT Display (240x240)</span>
<span id="tft_enabled_label" class="toggle-label">TFT Display (240x240)</span>
<label class="toggle-switch">
<input type="checkbox" id="tft_enabled" />
<input type="checkbox" id="tft_enabled" aria-labelledby="tft_enabled_label" />
<span class="toggle-track"></span>
</label>
</div>
<div class="toggle-row" id="tft_driver_row" style="display:none">
<span class="toggle-label">TFT Driver</span>
<select id="tft_driver" style="padding:6px 10px;border-radius:6px;border:1px solid var(--border);background:var(--card);color:var(--text);font-size:0.95em">
<span id="tft_driver_label" class="toggle-label">TFT Driver</span>
<select id="tft_driver" aria-labelledby="tft_driver_label" style="padding:6px 10px;border-radius:6px;border:1px solid var(--border);background:var(--card);color:var(--text);font-size:0.95em">
<option value="st7789">ST7789 (square)</option>
<option value="gc9a01">GC9A01 (round)</option>
</select>
</div>
</div>
<div style="display:grid;gap:10px">
<div class="toggle-row">
<span class="toggle-label">Bambu AMS Dashboard (TFT)</span>
<span id="bambu_dashboard_label" class="toggle-label">Bambu AMS Dashboard (TFT)</span>
<label class="toggle-switch">
<input type="checkbox" id="bambu_dashboard" />
<input type="checkbox" id="bambu_dashboard" aria-labelledby="bambu_dashboard_label" />
<span class="toggle-track"></span>
</label>
</div>
<div class="toggle-row">
<span class="toggle-label">NFC Reader</span>
<select id="nfc_reader" style="padding:6px 10px;border-radius:6px;border:1px solid var(--border);background:var(--card);color:var(--text);font-size:0.95em">
<span id="nfc_reader_label" class="toggle-label">NFC Reader</span>
<select id="nfc_reader" aria-labelledby="nfc_reader_label" style="padding:6px 10px;border-radius:6px;border:1px solid var(--border);background:var(--card);color:var(--text);font-size:0.95em">
<option value="pn5180">PN5180 (ISO15693 + ISO14443A)</option>
<option value="pn532">PN532 (ISO14443A only)</option>
</select>
Expand Down Expand Up @@ -284,6 +294,7 @@ const char CONFIG_HTML[] PROGMEM = R"rawliteral(
});
if (cfg.nfc_reader) document.getElementById('nfc_reader').value = cfg.nfc_reader;
document.getElementById('bambu_dashboard').checked = !!cfg.bambu_dashboard;
document.getElementById('wifi_keep_awake').checked = !!cfg.wifi_keep_awake;
maybeSetValue('moonraker_url', cfg.moonraker_url);
// Password placeholders
if (cfg.wifi_pass_set) document.getElementById('wifi_pass').placeholder = '(set) Leave blank to keep';
Expand Down Expand Up @@ -342,7 +353,8 @@ const char CONFIG_HTML[] PROGMEM = R"rawliteral(
prusalink_on: document.getElementById('prusalink_on').checked ? 1 : 0,
prusalink_url: document.getElementById('prusalink_url').value.trim(),
prusalink_api_key: document.getElementById('prusalink_api_key').value,
bambu_dashboard: document.getElementById('bambu_dashboard').checked ? 1 : 0
bambu_dashboard: document.getElementById('bambu_dashboard').checked ? 1 : 0,
wifi_keep_awake: document.getElementById('wifi_keep_awake').checked ? 1 : 0
};

fetch('/api/config', {
Expand Down
11 changes: 11 additions & 0 deletions src/ConfigurationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static const char* NVS_KEY_NFC_READER = "nfc_reader";
static const char* NVS_KEY_HOSTNAME = "hostname";
static const char* NVS_KEY_LOW_SPOOL = "low_spool_g";
static const char* NVS_KEY_BAMBU_DASH = "bambu_dash";
static const char* NVS_KEY_WIFI_AWAKE = "wifi_awake";

// Sanitize hostname: enforce mDNS naming constraints (lowercase alphanum + hyphens,
// no leading/trailing hyphens) and reject empty strings to avoid boot-time errors.
Expand Down Expand Up @@ -253,6 +254,10 @@ bool ConfigurationManager::loadFromNVS() {
_bambuDashboard = prefs.getBool(NVS_KEY_BAMBU_DASH, false);
anyOverride = true;
}
if (prefs.isKey(NVS_KEY_WIFI_AWAKE)) {
_wifiKeepAwake = prefs.getBool(NVS_KEY_WIFI_AWAKE, false);
anyOverride = true;
}

prefs.end();
return anyOverride;
Expand Down Expand Up @@ -359,6 +364,10 @@ bool ConfigurationManager::isBambuDashboardEnabled() const {
return _bambuDashboard;
}

bool ConfigurationManager::isWifiKeepAwakeEnabled() const {
return _wifiKeepAwake;
}

void ConfigurationManager::getCurrentConfig(ConfigUpdate& out) const {
memset(&out, 0, sizeof(out));
strncpy(out.wifi_ssid, _ssid, sizeof(out.wifi_ssid) - 1);
Expand All @@ -383,6 +392,7 @@ void ConfigurationManager::getCurrentConfig(ConfigUpdate& out) const {
strncpy(out.hostname, _hostname, sizeof(out.hostname) - 1);
out.low_spool_threshold_g = _lowSpoolThreshold;
out.bambu_dashboard = _bambuDashboard ? 1 : 0;
out.wifi_keep_awake = _wifiKeepAwake ? 1 : 0;
}

#ifndef NATIVE_TEST
Expand Down Expand Up @@ -427,6 +437,7 @@ bool ConfigurationManager::saveToNVS(const ConfigUpdate& update) {
prefs.putString(NVS_KEY_HOSTNAME, sanitizedHostname);
prefs.putUShort(NVS_KEY_LOW_SPOOL, update.low_spool_threshold_g);
prefs.putBool(NVS_KEY_BAMBU_DASH, update.bambu_dashboard != 0);
prefs.putBool(NVS_KEY_WIFI_AWAKE, update.wifi_keep_awake != 0);

// Invalidate Spoolman enrichment cache on config change to force re-fetch
// (config change could invalidate cached spool lookups)
Expand Down
6 changes: 6 additions & 0 deletions src/ConfigurationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct ConfigUpdate {
char hostname[33]; // max 32 chars + null
uint16_t low_spool_threshold_g; // grams below which LED breathes (default 100)
uint8_t bambu_dashboard;
uint8_t wifi_keep_awake; // disable WiFi modem sleep (better RSSI, more power)
};

class ConfigurationManager {
Expand Down Expand Up @@ -89,6 +90,10 @@ class ConfigurationManager {

bool isBambuDashboardEnabled() const;

// When true, firmware calls WiFi.setSleep(false) after WiFi.begin so the
// radio stays fully powered. Trades idle current for better RSSI/latency.
bool isWifiKeepAwakeEnabled() const;

// Web config support
void getCurrentConfig(ConfigUpdate& out) const;
bool saveToNVS(const ConfigUpdate& update);
Expand Down Expand Up @@ -139,6 +144,7 @@ class ConfigurationManager {
char _tftDriver[8] = "st7789";
uint16_t _lowSpoolThreshold = 100; // grams
bool _bambuDashboard = false;
bool _wifiKeepAwake = false;

bool _initialized = false;
};
Expand Down
Loading