diff --git a/src/ApplicationManager.cpp b/src/ApplicationManager.cpp index b331807..7086d4a 100644 --- a/src/ApplicationManager.cpp +++ b/src/ApplicationManager.cpp @@ -18,6 +18,7 @@ #include #include #include + #include extern LEDManager ledManager; #else #include "platform/NativePlatform.h" @@ -60,6 +61,30 @@ bool ApplicationManager::begin(DisplayI* display) { } Serial.println("ApplicationManager: Message queue created"); + +#ifndef NATIVE_TEST + // Load cached tray dashboard from NVS + bool dashEnabled = ConfigurationManager::getInstance().isBambuDashboardEnabled(); + if (dashEnabled) { + Preferences prefs; + prefs.begin("spoolsense", true); + size_t len = prefs.getBytesLength("tray_dash"); + if (len == sizeof(TrayDashboardState)) { + prefs.getBytes("tray_dash", &trayDashboardState_, sizeof(TrayDashboardState)); + if (trayDashboardState_.has_data && display_) { + display_->showTrayDashboard(trayDashboardState_); + Serial.printf("ApplicationManager: Loaded cached tray dashboard, %d trays\n", + trayDashboardState_.tray_count); + } else if (display_) { + display_->showText("SpoolSense", "AMS Ready"); + } + } else if (display_) { + display_->showText("SpoolSense", "AMS Ready"); + } + prefs.end(); + } +#endif + return true; } @@ -133,6 +158,22 @@ void ApplicationManager::processMessages() { } } + // Bambu dashboard revert: after scan interruption, return to dashboard + if (dashboardRevertAt_ != 0) { + uint32_t elapsedMs = static_cast(millis() - dashboardRevertAt_); + if (elapsedMs >= DASHBOARD_REVERT_DELAY_MS) { + dashboardRevertAt_ = 0; +#ifndef NATIVE_TEST + bool dashEnabled = ConfigurationManager::getInstance().isBambuDashboardEnabled(); +#else + bool dashEnabled = false; +#endif + if (dashEnabled && trayDashboardState_.has_data && display_) { + display_->showTrayDashboard(trayDashboardState_); + } + } + } + } // ── Display ───────────────────────────────────────────────────────────────── @@ -254,6 +295,10 @@ void ApplicationManager::handleMessage(const AppMessage& msg) { case AppMessageType::KEYPAD_CANCEL: handleKeypadCancel(); break; + + case AppMessageType::TRAY_UPDATE: + handleTrayUpdate(); + break; } } @@ -404,6 +449,12 @@ void ApplicationManager::handleSpoolDetected(const AppMessage& msg) { else if (strcmp(s.tag_format, "OpenSpool") == 0) spool.tagType = 6; else spool.tagType = 0; display_->showSpool(spool); + +#ifndef NATIVE_TEST + if (ConfigurationManager::getInstance().isBambuDashboardEnabled() && trayDashboardState_.has_data) { + dashboardRevertAt_ = millis(); + } +#endif } else if (display_) { Serial.printf("ApplicationManager: Skipping LCD update for already displayed spool %s\n", msg.payload.spoolDetected.spool_id); } @@ -640,6 +691,12 @@ void ApplicationManager::handleBlankTagDetected(const AppMessage& msg) { lastDisplayedSpoolId[0] = '\0'; // Clear smart tag display — allow re-display if tag swapped display_->showText4("**** Spool ****", "*** Scanned ***", "Unknown Tag", "Use app to setup"); + +#ifndef NATIVE_TEST + if (ConfigurationManager::getInstance().isBambuDashboardEnabled() && trayDashboardState_.has_data) { + dashboardRevertAt_ = millis(); + } +#endif } // HA MQTT: publish blank tag detected @@ -680,6 +737,12 @@ void ApplicationManager::handleGenericTagDetected(const AppMessage& msg) { lastDisplayedSpoolId[0] = '\0'; // Clear smart tag display — allow re-display if tag swapped display_->showText4("**** Spool ****", "*** Scanned ***", "Generic Tag", "Checking Spoolman"); + +#ifndef NATIVE_TEST + if (ConfigurationManager::getInstance().isBambuDashboardEnabled() && trayDashboardState_.has_data) { + dashboardRevertAt_ = millis(); + } +#endif } // HA MQTT: publish generic tag (UID only, awaiting Spoolman lookup) @@ -1206,6 +1269,38 @@ void ApplicationManager::handleKeypadCancel() { } } +// ── Tray Dashboard ────────────────────────────────────────────────────────── + +void ApplicationManager::updateTrayDashboard(const TrayDashboardState& state) { + trayDashboardState_ = state; +} + +const TrayDashboardState& ApplicationManager::getTrayDashboardState() const { + return trayDashboardState_; +} + +void ApplicationManager::handleTrayUpdate() { +#ifndef NATIVE_TEST + // Persist to NVS + Preferences prefs; + prefs.begin("spoolsense", false); + prefs.putBytes("tray_dash", &trayDashboardState_, sizeof(TrayDashboardState)); + prefs.end(); +#endif + + Serial.printf("ApplicationManager: Tray dashboard updated, %d trays\n", + trayDashboardState_.tray_count); + +#ifndef NATIVE_TEST + bool dashEnabled = ConfigurationManager::getInstance().isBambuDashboardEnabled(); +#else + bool dashEnabled = false; +#endif + if (dashEnabled && display_) { + display_->showTrayDashboard(trayDashboardState_); + } +} + bool ApplicationManager::sendAssignSpool(const char* toolNumber) { // Send ASSIGN_SPOOL TOOL=Tn gcode to Moonraker (Klipper-AFC integration) #ifndef NATIVE_TEST diff --git a/src/ApplicationManager.h b/src/ApplicationManager.h index 8a6e513..9f6bc07 100644 --- a/src/ApplicationManager.h +++ b/src/ApplicationManager.h @@ -3,6 +3,7 @@ #include #include "IPrinterStrategy.h" // for MAX_TOOLS constant +#include "TrayDashboardTypes.h" #ifdef NATIVE_TEST #include "platform/NativePlatform.h" @@ -30,6 +31,7 @@ enum class AppMessageType { KEYPAD_DIGIT, KEYPAD_CONFIRM, KEYPAD_CANCEL, + TRAY_UPDATE, }; enum class AutomationMode : uint8_t { @@ -180,6 +182,8 @@ class ApplicationManager { AutomationMode getAutomationMode() const { return automationMode; } void setAutomationMode(AutomationMode mode) { automationMode = mode; } SmartTagEnrichment getSmartTagEnrichment() const { return smartTagEnrichment_; } + void updateTrayDashboard(const TrayDashboardState& state); + const TrayDashboardState& getTrayDashboardState() const; #ifdef NATIVE_TEST void resetForTest() { if (messageQueue) { vQueueDelete(messageQueue); messageQueue = nullptr; } @@ -247,6 +251,11 @@ class ApplicationManager { // Enrichment data from Spoolman UID lookup for the current smart tag SmartTagEnrichment smartTagEnrichment_; + // Bambu AMS tray dashboard state + TrayDashboardState trayDashboardState_ = {}; + uint32_t dashboardRevertAt_ = 0; + static constexpr uint32_t DASHBOARD_REVERT_DELAY_MS = 5000; + // Handlers void handlePrintStarted(const AppMessage& msg); void handlePrintEnded(const AppMessage& msg); @@ -262,6 +271,7 @@ class ApplicationManager { void handleKeypadDigit(const AppMessage& msg); void handleKeypadConfirm(); void handleKeypadCancel(); + void handleTrayUpdate(); bool sendAssignSpool(const char* toolNumber); void finishPrint(float gramsUsed, bool canceled); void enqueueSpoolmanSync(const SpoolDetectedPayload& spool); diff --git a/src/ConfigHTML.h b/src/ConfigHTML.h index f647211..55a6291 100644 --- a/src/ConfigHTML.h +++ b/src/ConfigHTML.h @@ -219,6 +219,16 @@ const char CONFIG_HTML[] PROGMEM = R"rawliteral( + +

Bambu

+
+ AMS Tray Dashboard (TFT only) + +
+
NFC Reader