diff --git a/README.md b/README.md index 0588208..a6899f6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## BL Led Controller -The BL Led Controller is an ESP8266 / ESP32 based device that connects to your Bambulab X1,X1C,P1P Or P1S and controls the LED strip based on the state of the printer. +The BL Led Controller is an ESP32 based device that connects to your Bambulab X1,X1C,P1P Or P1S and controls the LED strip based on the state of the printer. ### Flashing and Setup 1. go to the [Web Flasher](https://dutchdevelop.github.io/blledsetup/) @@ -12,12 +12,20 @@ The BL Led Controller is an ESP8266 / ESP32 based device that connects to your B 7. Select your WiFi and Enter passwort, Optional enter all the Printer informations 8. enjoy :) -### Features -WiFi Setup: -![1000063279](https://github.com/user-attachments/assets/1cbe01fd-ce1f-4664-909e-7f6f50f6d80a) +![main setup_LED](https://github.com/user-attachments/assets/52778d28-98cd-496e-bfce-aca49cd4de89) +![main_setup_printer](https://github.com/user-attachments/assets/1969e4bd-0887-4a0c-a965-8ec575e23396) +![main_setup_error](https://github.com/user-attachments/assets/b026260c-5c33-4f5c-922a-fcc601cb9be1) +![main_setup_debug](https://github.com/user-attachments/assets/6d5a6e48-b052-4305-99f5-5d9c906eb8c1) +![main_setup_navigation](https://github.com/user-attachments/assets/78041d10-2edb-42e2-b600-6cde735d2d1f) +![setup_wifi](https://github.com/user-attachments/assets/4ef7631c-38f9-4424-ad88-72a335286c27) +![setup_wifi_printer](https://github.com/user-attachments/assets/da354544-710d-4e10-9dff-fc2cc1951857) +![ota](https://github.com/user-attachments/assets/7f223361-f811-4ff4-b3fc-45b2a1222c07) +![backup_restore](https://github.com/user-attachments/assets/b21899ba-c97f-48b6-8bc3-a87797029d14) +![navigation](https://github.com/user-attachments/assets/027fe724-ffc6-453b-ba73-c82c1ddb012e) + + + -OTA Firmware Update: -![1000063277](https://github.com/user-attachments/assets/853fa8cd-def6-47e9-8b23-4a4289651510) - Connects to Bambulab X1,X1C,P1P Or P1S - Controls LED strip based on printer state diff --git a/compress_html.py b/compress_html.py index 2f288e3..b808140 100644 --- a/compress_html.py +++ b/compress_html.py @@ -38,7 +38,7 @@ def compress_and_append_file(input_file, f): compressed_file = input_file + ".gz" with open(input_file, "rb") as infile: - with gzip.open(compressed_file, "wb", compresslevel=6) as outfile: + with gzip.open(compressed_file, "wb", compresslevel=9) as outfile: outfile.write(infile.read()) with open(compressed_file, "rb") as cf: diff --git a/docs/manual.md b/docs/manual.md new file mode 100644 index 0000000..9cefb46 --- /dev/null +++ b/docs/manual.md @@ -0,0 +1,532 @@ +## βš™οΈ BLLED Web Setup – Configuration Guide + +This document describes each setting available in the BLLED Controller setup interface. + +--- + +### πŸ”† Brightness + +**ID:** `brightnessslider` +**Type:** Range (0–100) + +Adjusts the global brightness level of the LED output. +Value is in percent. + +- `0` β†’ LEDs off +- `100` β†’ full brightness (default: `100`) + +--- + +### πŸ§ͺ Maintenance Mode + +**ID:** `maintMode` +**Type:** Checkbox +**Group:** `LEDBehavior` + +When enabled, LEDs stay **permanently on** in white color, regardless of printer state or WiFi/MQTT connection. + +- Always on (white) +- Overrides all other LED modes + +--- + +### 🌈 RGB Cycle Mode + +**ID:** `discoMode` +**Type:** Checkbox +**Group:** `LEDBehavior` + +Activates a continuous RGB color transition cycle for decorative purposes. + +- LED color cycles smoothly through red/green/blue +- Used for visual effects or time-lapse printing + +--- + +### πŸ” Replicate State + +**ID:** `replicateLedState` +**Type:** Checkbox +**Group:** `LEDBehavior` + +Replicates the printer’s internal **chamber light state** on the external LEDs. + +- When the printer turns its own light on/off, BLLED will follow +- Must be connected via MQTT + +#### πŸ”§ Running Color + +- `runningRGB`: LED color (HEX) +- `runningWW`: Warm white value (0–255) +- `runningCW`: Cold white value (0–255) + +These are used while the replicate mode is active and printer light is on. + +--- + +### πŸ§ͺ Color Test Mode + +**ID:** `showtestcolor` +**Type:** Checkbox +**Group:** `LEDBehavior` + +Forces the LEDs to show a fixed test color at all times, regardless of printer state. +Useful for hardware tests and verifying PWM color output. + +#### πŸ”§ Test Color Parameters + +- `testRGB`: HEX color value (e.g., `#3F3CFB`) +- `testWW`: Warm white value (0–255) +- `testCW`: Cold white value (0–255) + +--- + +### πŸ“Ά Show WiFi Strength via LEDs + +**ID:** `debugwifi` +**Type:** Checkbox +**Group:** `LEDBehavior` + +LEDs display WiFi signal strength as color: + +- Green: excellent signal +- Yellow/orange: medium +- Red: poor signal + +This helps determine ESP placement for optimal reception. + +--- + +### 🎬 Finish Indication + +**ID:** `finishIndication` +**Type:** Checkbox + +When a print completes, LEDs change to a dedicated **"Finish" color** for visual feedback. + +#### πŸ”§ Finish Color Parameters + +- `finishColor`: HEX color (e.g., green) +- `finishWW`: Warm white level +- `finishCW`: Cold white level + +#### ⏱ Finish Exit Behavior + +You can configure how and when to leave the "finished" state: + +--- + +### πŸšͺ Exit after Door Action + +**ID:** `finishEndDoor` +**Type:** Checkbox +**Group:** `finishOption` + +Leaves the finish state after the door is opened and closed once (or vice versa). + +--- + +### ⏲️ Exit after Timeout + +**ID:** `finishEndTimer` +**Type:** Checkbox +**Group:** `finishOption` + +Leaves the finish state after a user-defined number of minutes. + +- `finishTimerMins`: Duration in minutes (e.g., `1` = 1 min) + +### πŸ”• Inactivity Timeout + +**ID:** `inactivityEnabled` +**Type:** Checkbox + +Automatically turns off the LEDs after a period of printer inactivity. + +#### πŸ”§ Timeout Duration + +- `inactivityMins`: Number of minutes without activity before LEDs turn off + *(e.g., `30` = 30 minutes)* + +If the door is opened or a new print starts, the LEDs turn back on automatically. + +--- + +### πŸ”¦ Control Chamber Light + +**ID:** `controlChamberLight` +**Type:** Checkbox + +When enabled, the BLLED controller will also send MQTT commands to toggle the printer's internal **chamber light** in sync with: + +- πŸšͺ Door-based LED toggling (on/off) +- βœ… Print start β†’ turns chamber light on +- ⏱ Print finish β†’ turns chamber light off after timeout or door interaction + +> Requires an active MQTT connection to your Bambu printer. + +--- + +### πŸ–¨οΈ Printer Type: P1 Compatibility + +**ID:** `p1Printer` +**Type:** Checkbox +**Group:** `PrinterOptions` + +If checked, adjusts behavior for P1 printers: + +- Disables door switch-related features (P1 has no door sensor) +- Automatically sets all LIDAR-related stage colors to full white (255/255) + +--- + +### πŸ”§ Door Switch Support + +**ID:** `doorSwitch` +**Type:** Checkbox +**Group:** `PrinterOptions` + +Enable this if your printer has a door sensor and you want to use: + +- Double-close gesture to toggle LEDs +- Finish indication reset by door interaction + +> Automatically disabled when `p1Printer` is active. + +--- + +### πŸ› οΈ Stage-Specific LED Colors + +For advanced customization, you can assign LED colors to specific printer stages: + +- `stage14RGB`, `stage14WW`, `stage14CW` β†’ Cleaning Nozzle +- `stage1RGB`, `stage1WW`, `stage1CW` β†’ Bed Leveling +- `stage8RGB`, `stage8WW`, `stage8CW` β†’ Calibrating Extrusion +- `stage9RGB`, `stage9WW`, `stage9CW` β†’ Scanning Bed Surface +- `stage10RGB`, `stage10WW`, `stage10CW` β†’ First Layer Inspection + +Default values are OFF or white depending on printer type. + +### ❗ Error Detection + +**ID:** `errorDetection` +**Type:** Checkbox +**Group:** `PrinterOptions` + +When enabled, BLLED reacts to known printer errors or HMS codes by switching to predefined **alert colors**. + +--- + +### 🎨 Custom Error Colors + +You can assign LED colors for specific error conditions: + +| Condition | ID Prefix | Description | +|------------------------------|----------------|--------------------------------------------| +| WiFi Scan / Setup | `wifiRGB` | Orange by default | +| Pause (User or Gcode) | `pauseRGB` | Blue | +| First Layer Error | `firstlayerRGB`| Blue | +| Nozzle Clog | `nozzleclogRGB`| Blue | +| HMS Serious Severity | `hmsSeriousRGB`| Red | +| HMS Fatal Severity | `hmsFatalRGB` | Red | +| Filament Runout | `filamentRunoutRGB` | Red | +| Front Cover Removed | `frontCoverRGB`| Red | +| Nozzle Temperature Fail | `nozzleTempRGB`| Red | +| Bed Temperature Fail | `bedTempRGB` | Red | + +Each has associated warm/cold white (`WW`/`CW`) sliders to fine-tune tone and intensity. + +--- + +### 🚫 Ignore Specific HMS Codes + +**ID:** `hmsIgnoreList` +**Type:** Textarea (multiline) + +Enter one or more HMS codes (one per line or comma-separated) to suppress LED error response for those codes. + +Example: +HMS_0300_1200_0002_0001 +HMS_0700_2000_0003_0001 + + +--- + +### 🐞 Debug Options + +These options help track behavior for diagnostics: + +| ID | Description | +|------------------|-----------------------------------------------| +| `debuging` | Global debug log output | +| `debugingchange` | Logs only when a value or state changes | +| `mqttdebug` | Logs all MQTT messages to WebSerial/Console | + +--- + +### 🧭 Navigation Buttons + +Located at the bottom of the config page: + +| Button | Target Page | Description | +|---------------------|------------------------|------------------------------------------| +| **WiFi & Printer Setup** | `/wifi` | Configure network and printer credentials | +| **Firmware Update** | `/fwupdate` | Upload new firmware | +| **Backup & Restore** | `/backuprestore` | Save or restore full configuration | +| **Web Serial Log** | `/webserial` | Open debug log console | + + + + + + +## πŸ’Ύ Backup & Restore Configuration + +Access this page at: http://[device-ip]/backuprestore + +Allows you to download or upload the full BLLED configuration (`blledconfig.json`). + +--- + +### πŸ“₯ Backup Current Config + +**Button Label:** `Download Config File` +**Action:** Initiates download of the current `blledconfig.json` file from internal storage. + +- Includes: WiFi, printer IP, serial number, LED settings, HMS ignores, etc. +- Format: JSON file, pretty-formatted + +--- + +### πŸ“€ Restore Config File + +**Form Upload (Drag & Drop or File Picker)** +**Action URL:** `/configrestore` +**Method:** POST + +Uploads a `blledconfig.json` backup file and replaces the current configuration. + +- ⚠️ Device will **restart automatically** after upload +- File is validated for structure and required fields +- No merge – existing settings will be fully replaced + +--- + +## πŸ“‘ WiFi & Printer Setup + +Access this page at: http://[device-ip]/wifi + + +Use this page to configure the device’s WiFi connection and printer link. + +--- + +### πŸ“Ά WiFi Network + +#### πŸ“₯ SSID + +**ID:** `ssid` +**Type:** Text (required) +**Description:** +Name of the WiFi network the device should connect to. + +#### πŸ”’ Password + +**ID:** `password` +**Type:** Password (required) +**Description:** +WiFi password. Will be stored encrypted in the local config. + +> You can view available networks via the πŸ” Scan button. + +--- + +### πŸ–¨οΈ Printer Connection + +#### 🌐 Printer IP + +**ID:** `printerIP` +**Type:** Text +**Placeholder:** `e.g. 192.168.1.100` +**Description:** +IP address of the Bambu printer to receive MQTT status from. Must be reachable on the local network. + +#### πŸ”’ Serial Number + +**ID:** `printerSerial` +**Type:** Text +**Placeholder:** `e.g. BL123456789` +**Description:** +The unique serial number (USN) of your printer, used in MQTT topic handling. + +#### πŸ”‘ Access Code + +**ID:** `accessCode` +**Type:** Text +**Placeholder:** `e.g. Access123` +**Description:** +Used for MQTT authentication with your printer. Obtain this from the Bambu app or device. + +--- + +### πŸ‘€ Web Login (Optional) + +#### πŸ‘₯ Username + +**ID:** `username` +**Type:** Text +Default is blank. If set, it will enable HTTP Basic Auth for accessing the web interface. + +#### πŸ”‘ Password + +**ID:** `userpassword` +**Type:** Password +Used with the above username for securing access to all pages. + +--- + +### πŸ§ͺ Test Connection + +Button: `Test Printer Connection` +Tests MQTT reachability of the printer with the current IP/serial. + +--- + +## πŸ”§ Firmware Update + +Access this page at: http://[device-ip]/fwupdate + + +Allows you to upload and install a new firmware binary file (`.bin`) directly to the controller. + +--- + +### πŸ“€ Firmware Upload + +#### πŸ“„ File Input + +**Type:** File upload +**Accepted File:** `.bin` (firmware binary) +**Form Target:** `/update` (POST) + +- Uploads a new firmware image to flash memory +- File is verified and written immediately +- Progress and status are displayed below + +> ⚠️ The device will reboot automatically after a successful update. + +--- + +### ⏹ Cancel Button + +Cancels the upload process if not yet started. + +--- + +### πŸ’‘ Tip + +Ensure that your binary is built for the correct chip (e.g., ESP32) and compatible with the current hardware revision. + + +## πŸ–₯️ Web Serial Debug Log + +Access this page at: http://[device-ip]/webserial + + +This live interface displays system logs and debug messages from the controller in real time – without using a physical USB connection. + +--- + +### πŸͺ΅ Log Output Console + +**Element:** `textarea` (read-only) +**Function:** Displays all serial output from the controller, including: + +- MQTT messages +- LED state changes +- Door sensor triggers +- WiFi and printer status +- HMS error parsing results + +Output scrolls live as messages are received. + +--- + +### πŸ”§ Controls + +| Button | Function | +|-----------------------|------------------------------------------| +| `Clear Console` | Clears the current log view | +| `Copy` | Copies all visible log contents | +| `Pause Log` | Temporarily pauses real-time updates | +| `Send Command` (input + button) | Sends a command string to the controller via WebSerial (if supported) | + +> Useful for debugging MQTT, LEDs, and print events in real time. + +--- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +### πŸ”¦ Control Chamber Light + +When enabled, the BLLED Controller will automatically control the printer's internal chamber light via MQTT: + +- βœ… Turns the chamber light **on** when a print starts +- ❌ Turns it **off** after the print finishes (based on timeout or door interaction) +- πŸ” Toggles the chamber light together with the LEDs when using the **door double-close gesture** + +> This feature requires a working MQTT connection to your Bambu printer. +> It will not interfere with manual light control or other automations. + + +### πŸ’Ύ Backup & Restore Configuration + +Use these options to save or restore your current BLLED configuration: + +- βœ… **Backup**: Downloads the current configuration (`blledconfig.json`) to your computer +- πŸ” **Restore**: Uploads a previously saved configuration to restore all LED and printer settings +- πŸ”’ Includes printer IP, access code, and all LED behaviors + +> Useful for transferring settings between devices or keeping a safety copy before updates. + +--- + +### ♻️ Factory Reset + +Performs a full reset of the BLLED controller: + +- ❌ Deletes all saved configuration and WiFi credentials from internal storage +- πŸ”„ Automatically restarts the device into Access Point (setup) mode +- 🌐 You’ll need to reconnect and reconfigure via the setup page + +**How to trigger:** +Open your browser and navigate to: http://[device-ip]/factoryreset + + diff --git a/platformio.ini b/platformio.ini index 3a1a670..f3af2dc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,7 +11,7 @@ [env:esp32dev] custom_project_name = BLLC custom_project_codename = Balder -custom_version = 2.1.0 #BLLC_[Major].[Minor].[Patch] +custom_version = 2.2.0 #BLLC_[Major].[Minor].[Patch] platform = espressif32 board = esp32dev framework = arduino @@ -21,11 +21,12 @@ board_build.filesystem = littlefs build_flags = -DVERSION=${this.custom_version} -DSTRVERSION=\""${this.custom_version}"\" + -DCONFIG_ASYNC_TCP_STACK_SIZE=4096 extra_scripts = pre:pre_build.py merge_firmware.py lib_deps = - bblanchon/ArduinoJson@7.4.1 + bblanchon/ArduinoJson@7.4.2 knolleary/pubsubclient@2.8.0 luc-github/ESP32SSDP@1.2.1 ESP32Async/AsyncTCP diff --git a/src/blled/bblPrinterDiscovery.h b/src/blled/bblPrinterDiscovery.h new file mode 100644 index 0000000..b226a00 --- /dev/null +++ b/src/blled/bblPrinterDiscovery.h @@ -0,0 +1,179 @@ +#ifndef _BBLPRINTERDISCOVERY_H +#define _BBLPRINTERDISCOVERY_H + +#include +#include +#include "filesystem.h" // for saveFileSystem() + +#define BBL_SSDP_PORT 2021 +#define BBL_SSDP_MCAST_IP IPAddress(239, 255, 255, 250) +#define BBL_DISCOVERY_INTERVAL 10000UL +#define BBL_MAX_PRINTERS 10 + +struct BBLPrinter +{ + IPAddress ip; + char usn[64]; +}; + +static WiFiUDP bblUdp; +static bool bblUdpInitialized = false; +static unsigned long bblLastDiscovery = 0; + +static BBLPrinter bblLastKnownPrinters[BBL_MAX_PRINTERS]; +static int bblKnownPrinterCount = 0; + +bool bblIsPrinterKnown(IPAddress ip, int *index = nullptr) +{ + for (int i = 0; i < bblKnownPrinterCount; i++) + { + if (bblLastKnownPrinters[i].ip == ip) + { + if (index) + *index = i; + return true; + } + } + return false; +} + +void bblPrintKnownPrinters() +{ + LogSerial.println("[BBLScan] Known printers:"); + if (bblKnownPrinterCount == 0) + { + LogSerial.println(" (none)"); + } + for (int i = 0; i < bblKnownPrinterCount; i++) + { + LogSerial.printf(" [%d] IP: %s", i + 1, bblLastKnownPrinters[i].ip.toString().c_str()); + if (strlen(bblLastKnownPrinters[i].usn) > 0) + { + LogSerial.printf(" [USN: %s]", bblLastKnownPrinters[i].usn); + } + LogSerial.println(); + } +} + +void bblSearchPrinters() +{ + unsigned long now = millis(); + if (now - bblLastDiscovery < BBL_DISCOVERY_INTERVAL) + return; + bblLastDiscovery = now; + + if (!bblUdpInitialized) + { + bblUdp.beginMulticast(BBL_SSDP_MCAST_IP, BBL_SSDP_PORT); + bblUdpInitialized = true; + } + + String msearch = + "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:2021\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: 5\r\n" + "ST: urn:bambulab-com:device:3dprinter:1\r\n\r\n"; + + for (int i = 0; i < 2; i++) + { + bblUdp.beginPacket(BBL_SSDP_MCAST_IP, BBL_SSDP_PORT); + bblUdp.print(msearch); + bblUdp.endPacket(); + delay(250); + } + + if (printerConfig.debuging) + { + LogSerial.println("[BBLScan] Searching for printers..."); + } + + unsigned long start = millis(); + int sessionFound = 0; + IPAddress seenIPs[BBL_MAX_PRINTERS]; + int seenCount = 0; + + while (millis() - start < 5000) + { + int size = bblUdp.parsePacket(); + if (size) + { + IPAddress senderIP = bblUdp.remoteIP(); + + bool alreadySeen = false; + for (int i = 0; i < seenCount; i++) + { + if (seenIPs[i] == senderIP) + { + alreadySeen = true; + break; + } + } + if (alreadySeen) + continue; + if (seenCount < BBL_MAX_PRINTERS) + seenIPs[seenCount++] = senderIP; + + char buffer[512]; + int len = bblUdp.read(buffer, sizeof(buffer) - 1); + buffer[len] = 0; + + String response(buffer); + String usnStr = ""; + int usnPos = response.indexOf("USN:"); + if (usnPos >= 0) + { + int end = response.indexOf("\r\n", usnPos); + usnStr = response.substring(usnPos + 4, end); + usnStr.trim(); + } + + // IP update check for stored USN + if (strlen(printerConfig.serialNumber) > 0 && usnStr.length() > 0 && + strcmp(printerConfig.serialNumber, usnStr.c_str()) == 0) + { + String currentIP = senderIP.toString(); + if (String(printerConfig.printerIP) != currentIP) + { + LogSerial.printf("[BBLScan] Detected matching USN with updated IP (%s β†’ %s). Saving...\n", printerConfig.printerIP, currentIP.c_str()); + strlcpy(printerConfig.printerIP, currentIP.c_str(), sizeof(printerConfig.printerIP)); + saveFileSystem(); + } + } + + int existingIndex = -1; + bool isNewPrinter = !bblIsPrinterKnown(senderIP, &existingIndex); + + if (printerConfig.debuging || (printerConfig.debugingchange && isNewPrinter)) + { + LogSerial.printf("[BBLScan] [%d] IP: %s", ++sessionFound, senderIP.toString().c_str()); + if (usnStr.length()) + { + LogSerial.printf(" [USN: %s]", usnStr.c_str()); + } + LogSerial.println(); + } + + if (isNewPrinter && bblKnownPrinterCount < BBL_MAX_PRINTERS) + { + BBLPrinter &printer = bblLastKnownPrinters[bblKnownPrinterCount++]; + printer.ip = senderIP; + strncpy(printer.usn, usnStr.c_str(), sizeof(printer.usn) - 1); + printer.usn[sizeof(printer.usn) - 1] = 0; + } + } + delay(10); + } + + if (printerConfig.debuging && sessionFound == 0) + { + LogSerial.println("[BBLScan] No printers found."); + } + + if (printerConfig.debuging) + { + bblPrintKnownPrinters(); + } +} + +#endif diff --git a/src/blled/filesystem.h b/src/blled/filesystem.h index f1cf177..03b7ab4 100644 --- a/src/blled/filesystem.h +++ b/src/blled/filesystem.h @@ -3,7 +3,7 @@ #include #include "FS.h" - +#include #include #include #include "types.h" @@ -28,7 +28,7 @@ char *generateRandomString(int length) void saveFileSystem() { - LogSerial.println(F("Saving config")); + LogSerial.println(F("[Filesystem] Saving config")); JsonDocument json; json["ssid"] = globalVariables.SSID; @@ -65,6 +65,7 @@ void saveFileSystem() json["finishTimerMins"] = printerConfig.finishTimeOut; json["inactivityEnabled"] = printerConfig.inactivityEnabled; json["inactivityTimeOut"] = printerConfig.inactivityTimeOut; + json["controlChamberLight"] = printerConfig.controlChamberLight; //control chamber light // Debugging json["debuging"] = printerConfig.debuging; json["debugingchange"] = printerConfig.debugingchange; @@ -120,21 +121,23 @@ void saveFileSystem() json["bedTempRGB"] = printerConfig.bedTempRGB.RGBhex; json["bedTempWW"] = printerConfig.bedTempRGB.ww; json["bedTempCW"] = printerConfig.bedTempRGB.cw; + //HMS Error handling + json["hmsIgnoreList"] = printerConfig.hmsIgnoreList; File configFile = LittleFS.open(configPath, "w"); if (!configFile) { - LogSerial.println(F("Failed to save config")); + LogSerial.println(F("[Filesystem] Failed to save config")); return; } serializeJson(json, configFile); configFile.close(); - LogSerial.println(F("Config Saved")); + LogSerial.println(F("[Filesystem] Config Saved")); } void loadFileSystem() { - LogSerial.println(F("Loading config")); + LogSerial.println(F("[Filesystem] Loading config")); File configFile; int attempts = 0; @@ -146,16 +149,16 @@ void loadFileSystem() break; } attempts++; - LogSerial.println(F("Failed to open config file, retrying..")); + LogSerial.println(F("[Filesystem] Failed to open config file, retrying..")); delay(2000); } if (!configFile) { - LogSerial.print(F("Failed to open config file after ")); + LogSerial.print(F("[Filesystem] Failed to open config file after ")); LogSerial.print(attempts); LogSerial.println(F(" retries")); - LogSerial.println(F("Clearing config")); + LogSerial.println(F("[Filesystem] Clearing config")); // LittleFS.remove(configPath); saveFileSystem(); return; @@ -197,6 +200,7 @@ void loadFileSystem() printerConfig.finish_check = json["finish_check"]; printerConfig.inactivityEnabled = json["inactivityEnabled"]; printerConfig.inactivityTimeOut = json["inactivityTimeOut"]; + printerConfig.controlChamberLight = json["controlChamberLight"]; //control chamber light // Debugging printerConfig.debuging = json["debuging"]; printerConfig.debugingchange = json["debugingchange"]; @@ -222,12 +226,15 @@ void loadFileSystem() printerConfig.frontCoverRGB = hex2rgb(json["frontCoverRGB"], json["frontCoverWW"], json["frontCoverCW"]); printerConfig.nozzleTempRGB = hex2rgb(json["nozzleTempRGB"], json["nozzleTempWW"], json["nozzleTempCW"]); printerConfig.bedTempRGB = hex2rgb(json["bedTempRGB"], json["bedTempWW"], json["bedTempCW"]); - LogSerial.println(F("Loaded config")); + // HMS Error handling + printerConfig.hmsIgnoreList = json["hmsIgnoreList"] | ""; + + LogSerial.println(F("[Filesystem] Loaded config")); } else { - LogSerial.println(F("Failed loading config")); - LogSerial.println(F("Clearing config")); + LogSerial.println(F("[Filesystem] Failed loading config")); + LogSerial.println(F("[Filesystem] Clearing config")); LittleFS.remove(configPath); // LogSerial.println(F("Generating new password")); @@ -240,7 +247,7 @@ void loadFileSystem() void deleteFileSystem() { - LogSerial.println(F("Deleting LittleFS")); + LogSerial.println(F("[Filesystem] Deleting LittleFS")); LittleFS.remove(configPath); } @@ -251,17 +258,17 @@ bool hasFileSystem() void setupFileSystem() { - LogSerial.println(F("Mounting LittleFS")); + LogSerial.println(F("[Filesystem] Mounting LittleFS")); if (!LittleFS.begin()) { - LogSerial.println(F("Failed to mount LittleFS")); + LogSerial.println(F("[Filesystem] Failed to mount LittleFS")); LittleFS.format(); - LogSerial.println(F("Formatting LittleFS")); - LogSerial.println(F("Restarting Device")); + LogSerial.println(F("[Filesystem] Formatting LittleFS")); + LogSerial.println(F("[Filesystem] Restarting Device")); delay(1000); ESP.restart(); } - LogSerial.println(F("Mounted LittleFS")); + LogSerial.println(F("[Filesystem] Mounted LittleFS")); }; #endif \ No newline at end of file diff --git a/src/blled/leds.h b/src/blled/leds.h index 36ae1f8..1d7172a 100644 --- a/src/blled/leds.h +++ b/src/blled/leds.h @@ -3,6 +3,7 @@ #include #include "mqttparsingutility.h" +void controlChamberLight(bool on); // Forward declaration const int redPin = 19; const int greenPin = 18; @@ -132,7 +133,7 @@ void tweenToColor(String strTargetColor, short ww_value = 0, short cw_value = 0) tweenToColor(targetcolor.r, targetcolor.g, targetcolor.b, targetcolor.ww, targetcolor.cw); } // Example: tweenToColor(0xFFACA5) -void tweenToColor(int hexValue, short ww_value = 0, short cw_value = 0) +/* void tweenToColor(int hexValue, short ww_value = 0, short cw_value = 0) { COLOR targetcolor; targetcolor.r = ((hexValue >> 16) & 0xFF) / 255.0; @@ -141,8 +142,17 @@ void tweenToColor(int hexValue, short ww_value = 0, short cw_value = 0) targetcolor.ww = ww_value; targetcolor.cw = cw_value; tweenToColor(targetcolor.r, targetcolor.g, targetcolor.b, targetcolor.ww, targetcolor.cw); +} */ +void tweenToColor(int hexValue, short ww_value = 0, short cw_value = 0) +{ + COLOR targetcolor; + targetcolor.r = (hexValue >> 16) & 0xFF; + targetcolor.g = (hexValue >> 8) & 0xFF; + targetcolor.b = hexValue & 0xFF; + targetcolor.ww = ww_value; + targetcolor.cw = cw_value; + tweenToColor(targetcolor.r, targetcolor.g, targetcolor.b, targetcolor.ww, targetcolor.cw); } - float hue = 0.0; void RGBCycle() @@ -195,7 +205,7 @@ void RGBCycle() ledcWrite(coldChannel, currentCold); } -void printLogs(String Desc, COLOR thisColor) +/* void printLogs(String Desc, COLOR thisColor) { if (printerConfig.debuging || printerConfig.debugingchange) { @@ -219,7 +229,42 @@ void printLogs(String Desc, COLOR thisColor) LogSerial.print(F(" Brightness: ")); LogSerial.println(printerConfig.brightness); }; +} */ +void printLogs(String Desc, COLOR thisColor) +{ + static COLOR lastColor = {-1, -1, -1, -1, -1}; + static String lastDesc = ""; + static unsigned long lastPrintTime = 0; + + // Skip if same state and printed less than 3 seconds ago + if (Desc == lastDesc && + memcmp(&thisColor, &lastColor, sizeof(COLOR)) == 0 && + millis() - lastPrintTime < 3000) + { + return; + } + + if (printerConfig.debuging || printerConfig.debugingchange) + { + LogSerial.printf("%s - Turning LEDs to:", Desc.c_str()); + if ((thisColor.r + thisColor.g + thisColor.b + thisColor.ww + thisColor.cw) == 0) + { + LogSerial.println(" OFF"); + } + else + { + LogSerial.printf(" r:%d g:%d b:%d ww:%d cw:%d Brightness: %d\n", + thisColor.r, thisColor.g, thisColor.b, + thisColor.ww, thisColor.cw, printerConfig.brightness); + } + } + + lastColor = thisColor; + lastDesc = Desc; + lastPrintTime = millis(); } + + void printLogs(String Desc, short r, short g, short b, short ww, short cw) { COLOR tempColor; @@ -290,13 +335,23 @@ void updateleds() // From here the BBLP status sets the colors if (printerConfig.debuging == true) { - LogSerial.println(F("Updating LEDs")); +/* LogSerial.println(F("Updating LEDs")); LogSerial.println(printerVariables.stage); LogSerial.println(printerVariables.gcodeState); LogSerial.println(printerVariables.printerledstate); LogSerial.println(printerVariables.hmsstate); - LogSerial.println(printerVariables.parsedHMSlevel); + LogSerial.println(printerVariables.parsedHMSlevel); */ + + char ledDbgStr[128]; + snprintf(ledDbgStr, sizeof(ledDbgStr), + "[LED] Stage:%d gcodeState:%s printerLedState:%s HMSErr:%s ParsedHMS:%s", + printerVariables.stage, + printerVariables.gcodeState.c_str(), + printerVariables.printerledstate ? "true" : "false", + printerVariables.hmsstate ? "true" : "false", + printerVariables.parsedHMSlevel.c_str()); + LogSerial.println(ledDbgStr); } // Initial Boot @@ -320,7 +375,7 @@ void updateleds() // TOGGLE LIGHTS via DOOR // If door is closed twice in 6 seconds, it will flip the state of the lights - if (printerVariables.doorSwitchTriggered == true) +/* if (printerVariables.doorSwitchTriggered == true) { if (printerConfig.debugingchange) { @@ -348,7 +403,62 @@ void updateleds() } printerVariables.doorSwitchTriggered = false; return; + } */ + if (printerVariables.doorSwitchTriggered == true) +{ + bool ledsAreOff = (currentWarm == 0 && currentCold == 0); + bool chamberLightIsOff = (printerVariables.printerledstate == false); + + if (printerConfig.debugingchange) + { + LogSerial.print(F("Door closed twice within 6 seconds - ")); + + if (ledsAreOff) + LogSerial.print(F("Turning LEDs ON")); + else + LogSerial.print(F("Turning LEDs OFF")); + + if (printerConfig.controlChamberLight) + { + if (ledsAreOff && chamberLightIsOff) + LogSerial.println(F(" + Chamber Light ON")); + else if (!ledsAreOff) + LogSerial.println(F(" + Chamber Light OFF")); + else + LogSerial.println(); + } + else + { + LogSerial.println(); + } + } + + if (ledsAreOff) + { + tweenToColor(0, 0, 0, 255, 255); // WHITE + printerConfig.isIdleOFFActive = false; + + if (printerConfig.controlChamberLight && chamberLightIsOff) + { + controlChamberLight(true); // Turn ON chamber light only if off + } } + else + { + tweenToColor(0, 0, 0, 0, 0); // OFF + printerConfig.isIdleOFFActive = true; + printerConfig.inactivityStartms = millis() - printerConfig.inactivityTimeOut; + + if (printerConfig.controlChamberLight) + { + controlChamberLight(false); // Always OFF on manual off + } + } + + printerVariables.doorSwitchTriggered = false; + return; +} + // RED -- RED -- RED -- RED @@ -439,7 +549,7 @@ void updateleds() // OFF -- OFF -- OFF -- OFF // printer offline and MQTT disconnect more than 5 seconds. - if (printerVariables.online == false && (millis() - printerVariables.disconnectMQTTms) >= 5000) + if (printerVariables.online == false && (millis() - printerVariables.disconnectMQTTms) >= 30000) { tweenToColor(0, 0, 0, 0, 0); // OFF printLogs("Printer offline", 0, 0, 0, 0, 0); @@ -507,6 +617,7 @@ void updateleds() if ((printerVariables.stage == -1 || printerVariables.stage == 255) && !((printerConfig.finishExit && printerVariables.waitingForDoor) || (printerConfig.finishExit == false && ((millis() - printerConfig.finishStartms) < printerConfig.finishTimeOut))) && (millis() - printerConfig.inactivityStartms) > printerConfig.inactivityTimeOut && printerConfig.isIdleOFFActive == false && printerConfig.inactivityEnabled) { tweenToColor(0, 0, 0, 0, 0); // OFF + controlChamberLight(false); // Turn off chamber light via MQTT printerConfig.isIdleOFFActive = true; if (printerConfig.debuging || printerConfig.debugingchange) { @@ -655,6 +766,7 @@ void ledsloop() printerConfig.inactivityStartms = millis(); printerConfig.isIdleOFFActive = false; updateleds(); + controlChamberLight(false); // Turn off chamber light via MQTT } // Need an trigger action to run updateleds() so lights turn off @@ -664,7 +776,13 @@ void ledsloop() // Opening or Closing the Door will turn LEDs back on and restart the timer. updateleds(); } - + //disabled, need testing for future use +/* // Periodic fallback update to ensure MQTT timeout or other updates are evaluated + static unsigned long lastPeriodicUpdate = 0; + if (millis() - lastPeriodicUpdate > 10000) { // every 10 seconds + updateleds(); + lastPeriodicUpdate = millis(); + } */ delay(10); } diff --git a/src/blled/mqttmanager.h b/src/blled/mqttmanager.h index 52659d2..987749f 100644 --- a/src/blled/mqttmanager.h +++ b/src/blled/mqttmanager.h @@ -26,6 +26,7 @@ unsigned long lastMQTTupdate = millis(); TaskHandle_t mqttTaskHandle = NULL; bool mqttTaskRunning = false; +volatile bool mqttConnectInProgress = false; // With a Default BLLED // Expected information when viewing MQTT status messages @@ -44,7 +45,7 @@ bool mqttTaskRunning = false; // FINISH -1 White After door interaction // FINISH -1 OFF Inactivity after 30mins -void connectMqtt() +/* void connectMqtt() { if (WiFi.status() != WL_CONNECTED || WiFi.getMode() != WIFI_MODE_STA) { @@ -62,7 +63,7 @@ void connectMqtt() LogSerial.println(F("Connecting to mqtt...")); if (mqttClient.connect(clientId.c_str(), "bblp", printerConfig.accessCode)) { - LogSerial.print(F("MQTT connected, subscribing to MQTT Topic: ")); + LogSerial.print(F("[MQTT] connected, subscribing to MQTT Topic: ")); LogSerial.println(report_topic); mqttClient.subscribe(report_topic.c_str()); printerVariables.online = true; @@ -88,6 +89,57 @@ void connectMqtt() } } } +} */ + +void connectMqtt() +{ + if (mqttConnectInProgress) + return; + + mqttConnectInProgress = true; + + if (WiFi.status() != WL_CONNECTED || WiFi.getMode() != WIFI_MODE_STA) + { + mqttConnectInProgress = false; + return; + } + + if (strlen(printerConfig.printerIP) == 0 || strlen(printerConfig.accessCode) == 0) + { + Serial.println(F("[MQTT] Abort connect: printerIP oder accessCode wrong or empty")); + mqttConnectInProgress = false; + return; + } + + if (!mqttClient.connected() && (millis() - mqttattempt) >= 3000) + { + // tweenToColor(10, 10, 10, 10, 10); + Serial.println(F("Connecting to mqtt...")); + + if (mqttClient.connect(clientId.c_str(), "bblp", printerConfig.accessCode)) + { + Serial.print(F("[MQTT] connected, subscribing to MQTT Topic: ")); + Serial.println(report_topic); + mqttClient.subscribe(report_topic.c_str()); + printerVariables.online = true; + printerVariables.disconnectMQTTms = 0; + } + else + { + Serial.println(F("Failed to connect with error code: ")); + Serial.print(mqttClient.state()); + Serial.print(F(" ")); + ParseMQTTState(mqttClient.state()); + + if (mqttClient.state() == 5) + { + tweenToColor(127, 0, 0, 0, 0); + mqttattempt = millis() - 3000; + } + } + } + + mqttConnectInProgress = false; } void mqttTask(void *parameter) @@ -136,6 +188,14 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) JsonDocument filter; // Rather than showing the entire message to Serial - grabbing only the pertinent bits for BLLED. // Device Status + + // sniped: implement to get layer num. for hms error, swap back to running state after layer change + /* "print": { + "3D": { + "layer_num": 0, + "total_layer_num": 191 + } */ + filter["print"]["command"] = true; filter["print"]["fail_reason"] = true; filter["print"]["gcode_state"] = true; @@ -170,8 +230,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) || messageobject["print"]["command"] == "clean_print_error" // During error (no info) || messageobject["print"]["command"] == "resume" // After error or pause || messageobject["print"]["command"] == "get_accessories" // After error or pause - || messageobject["print"]["command"] == "prepare" - || messageobject["print"]["command"] == "extrusion_cali_get") + || messageobject["print"]["command"] == "prepare" || messageobject["print"]["command"] == "extrusion_cali_get") { // 1 message per print return; } @@ -194,7 +253,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) if (printerConfig.mqttdebug && (printerConfig.maintMode || printerConfig.testcolorEnabled || printerConfig.discoMode || printerConfig.debugwifi)) { - LogSerial.print(F("MQTT Message Ignored while in ")); + LogSerial.print(F("[MQTT] Message Ignored while in ")); if (printerConfig.maintMode) LogSerial.print(F("Maintenance")); if (printerConfig.testcolorEnabled) @@ -222,7 +281,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) printerVariables.doorOpen = doorState; if (printerConfig.debugingchange) - LogSerial.print(F("MQTT Door ")); + LogSerial.print(F("[MQTT] Door ")); if (printerVariables.doorOpen) { printerVariables.lastdoorOpenms = millis(); @@ -252,7 +311,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) if (printerConfig.debugingchange || printerConfig.debuging) { - LogSerial.print(F("MQTT update - stg_cur now: ")); + LogSerial.print(F("[MQTT] update - stg_cur now: ")); LogSerial.println(printerVariables.stage); } Changed = true; @@ -269,6 +328,11 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) // Never turn off light (due to idle timer) while in this state printerConfig.inactivityStartms = millis(); } + if (mqttgcodeState == "RUNNING" && printerConfig.controlChamberLight && printerVariables.printerledstate == false) + { + controlChamberLight(true); // Turn chamber light ON at print start + LogSerial.println(F("[MQTT] Print started – Chamber Light ON requested")); + } // Onchange of gcodeState... if (printerVariables.gcodeState != mqttgcodeState) @@ -284,7 +348,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) if (printerConfig.debugingchange || printerConfig.debuging) { - LogSerial.print(F("MQTT update - gcode_state now: ")); + LogSerial.print(F("[MQTT] update - gcode_state now: ")); LogSerial.println(printerVariables.gcodeState); } Changed = true; @@ -297,7 +361,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) if (messageobject["print"]["command"] == "pause") { lastMQTTupdate = millis(); - LogSerial.println(F("MQTT update - manual PAUSE")); + LogSerial.println(F("[MQTT] update - manual PAUSE")); printerVariables.gcodeState = "PAUSE"; Changed = true; } @@ -318,7 +382,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) printerConfig.replicate_update = true; if (printerConfig.debugingchange || printerConfig.debuging) { - LogSerial.print(F("MQTT chamber_light now: ")); + LogSerial.print(F("[MQTT] chamber_light now: ")); LogSerial.println(printerVariables.printerledstate); } if (printerVariables.waitingForDoor && printerConfig.finish_check) @@ -344,7 +408,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) lastMQTTupdate = millis(); if (printerConfig.debugingchange || printerConfig.debuging) { - LogSerial.print(F("MQTT led_mode now: ")); + LogSerial.print(F("[MQTT] led_mode now: ")); LogSerial.println(printerVariables.printerledstate); } if (printerVariables.waitingForDoor && printerConfig.finish_check) @@ -365,18 +429,63 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) printerVariables.hmsstate = false; printerVariables.parsedHMSlevel = ""; + /* for (const auto &hms : messageobject["print"]["hms"].as()) + { + if (ParseHMSSeverity(hms["code"]) != "") + { + printerVariables.hmsstate = true; + printerVariables.parsedHMSlevel = ParseHMSSeverity(hms["code"]); + printerVariables.parsedHMScode = ((uint64_t)hms["attr"] << 32) + (uint64_t)hms["code"]; + } + } */ for (const auto &hms : messageobject["print"]["hms"].as()) { + uint64_t code = ((uint64_t)hms["attr"] << 32) + (uint64_t)hms["code"]; + + int chunk1 = (code >> 48); + int chunk2 = (code >> 32) & 0xFFFF; + int chunk3 = (code >> 16) & 0xFFFF; + int chunk4 = code & 0xFFFF; + + char strHMScode[32]; + sprintf(strHMScode, "HMS_%04X_%04X_%04X_%04X", chunk1, chunk2, chunk3, chunk4); + + // Normalize input string (replace '-' with '_', remove whitespace) + String normalizedIgnoreList = printerConfig.hmsIgnoreList; + normalizedIgnoreList.replace("-", "_"); + normalizedIgnoreList.replace(" ", ""); + normalizedIgnoreList.replace("\r", ""); + normalizedIgnoreList.replace("\n", ","); + + // Check if code is in ignore list + if (("," + normalizedIgnoreList + ",").indexOf("," + String(strHMScode) + ",") >= 0) + { + LogSerial.print(F("[MQTT] Ignored HMS Code: ")); + LogSerial.println(strHMScode); + continue; + } + + // Ignore if present in ignore list + if (printerConfig.hmsIgnoreList.indexOf(strHMScode) >= 0) + { + LogSerial.print(F("[MQTT] HMS code ignored: ")); + LogSerial.println(strHMScode); + continue; + } + if (ParseHMSSeverity(hms["code"]) != "") { printerVariables.hmsstate = true; printerVariables.parsedHMSlevel = ParseHMSSeverity(hms["code"]); - printerVariables.parsedHMScode = ((uint64_t)hms["attr"] << 32) + (uint64_t)hms["code"]; + printerVariables.parsedHMScode = code; } } + if (oldHMSlevel != printerVariables.parsedHMSlevel) { - + // example, cap fall off + // Error Code: 0300_1200_0002_0001 ** + //"hms":[{"attr":50336256,"code":131073}] if (printerVariables.parsedHMScode == 0x0C0003000003000B) printerVariables.overridestage = 10; if (printerVariables.parsedHMScode == 0x0300120000020001) @@ -390,11 +499,11 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) if (printerConfig.debuging || printerConfig.debugingchange) { - LogSerial.print(F("MQTT update - parsedHMSlevel now: ")); + LogSerial.print(F("[MQTT] update - parsedHMSlevel now: ")); if (printerVariables.parsedHMSlevel.length() > 0) { LogSerial.print(printerVariables.parsedHMSlevel); - LogSerial.print(F(" Error Code: ")); + LogSerial.print(F(" Error Code: HMS_")); // LogSerial.println(F("https://wiki.bambulab.com/en/x1/troubleshooting/how-to-enter-the-specific-code-page")); int chunk1 = (printerVariables.parsedHMScode >> 48); int chunk2 = (printerVariables.parsedHMScode >> 32) & 0xFFFF; @@ -451,6 +560,41 @@ void mqttCallback(char *topic, byte *payload, unsigned int length) stream.flush(); } +void controlChamberLight(bool on) +{ + LogSerial.printf("[DEBUG] controlChamberLight called with: %s\n", on ? "true" : "false"); + if (!printerConfig.controlChamberLight) + return; + + if (!mqttClient.connected()) + { + LogSerial.println(F("[MQTT] Skipped chamber_light control – MQTT not connected")); + return; + } + + JsonDocument doc; + JsonObject system = doc["system"].to(); + system["command"] = "ledctrl"; + system["sequence_id"] = "blled_auto"; + system["led_node"] = "chamber_light"; + system["led_mode"] = on ? "on" : "off"; + system["led_on_time"] = 500; + system["led_off_time"] = 500; + system["loop_times"] = 0; + system["interval_time"] = 1000; + + String payload; + serializeJson(doc, payload); + + String topic = String("device/") + printerConfig.serialNumber + "/request"; + mqttClient.publish(topic.c_str(), payload.c_str()); + + LogSerial.print(F("[MQTT] Chamber Light ")); + LogSerial.print(on ? F("ON") : F("OFF")); + LogSerial.print(F(" sent to topic: ")); + LogSerial.println(topic); +} + void setupMqtt() { clientId += String(random(0xffff), HEX); @@ -461,8 +605,8 @@ void setupMqtt() report_topic = device_topic + String("/report"); wifiSecureClient.setInsecure(); - wifiSecureClient.setTimeout(3); - mqttClient.setSocketTimeout(3); + wifiSecureClient.setTimeout(10); + mqttClient.setSocketTimeout(10); mqttClient.setBufferSize(1024); mqttClient.setServer(printerConfig.printerIP, 8883); mqttClient.setStream(stream); @@ -474,30 +618,29 @@ void setupMqtt() { BaseType_t result; - #if CONFIG_FREERTOS_UNICORE - result = xTaskCreate( - mqttTask, - "mqttTask", - 6144, - NULL, - 1, - &mqttTaskHandle - ); - #else - result = xTaskCreatePinnedToCore( - mqttTask, - "mqttTask", - 6144, - NULL, - 1, - &mqttTaskHandle, - 1 // Core 1 (App Core) - ); - #endif +#if CONFIG_FREERTOS_UNICORE + result = xTaskCreate( + mqttTask, + "mqttTask", + 6144, + NULL, + 1, + &mqttTaskHandle); +#else + result = xTaskCreatePinnedToCore( + mqttTask, + "mqttTask", + 6144, + NULL, + 1, + &mqttTaskHandle, + 1 // Core 1 (App Core) + ); +#endif if (result == pdPASS) { - LogSerial.println(F("MQTT task successfully started")); + LogSerial.println(F("[MQTT] task successfully started")); } else { @@ -506,7 +649,6 @@ void setupMqtt() } } - void mqttloop() { if (WiFi.status() != WL_CONNECTED || WiFi.getMode() != WIFI_MODE_STA) @@ -522,10 +664,10 @@ void mqttloop() { printerVariables.disconnectMQTTms = millis(); // Record last time MQTT dropped connection - LogSerial.println(F("MQTT dropped during mqttloop")); + LogSerial.println(F("[MQTT] dropped during mqttloop")); ParseMQTTState(mqttClient.state()); } - //delay(500); + // delay(500); connectMqtt(); delay(32); return; diff --git a/src/blled/mqttparsingutility.h b/src/blled/mqttparsingutility.h index ebc7d05..7e24c92 100644 --- a/src/blled/mqttparsingutility.h +++ b/src/blled/mqttparsingutility.h @@ -23,34 +23,34 @@ void ParseMQTTState(int code){ switch (code) { case -4: // MQTT_CONNECTION_TIMEOUT - LogSerial.println(F("MQTT TIMEOUT")); + LogSerial.println(F("[MQTT] Timeout (-4)")); break; case -3: // MQTT_CONNECTION_LOST - LogSerial.println(F("MQTT CONNECTION_LOST")); + LogSerial.println(F("[MQTT] Connection Lost (-3)")); break; case -2: // MQTT_CONNECT_FAILED - LogSerial.println(F("MQTT CONNECT_FAILED")); + LogSerial.println(F("[MQTT] Connection Failed (-2)")); break; case -1: // MQTT_DISCONNECTED - LogSerial.println(F("MQTT DISCONNECTED")); + LogSerial.println(F("[MQTT] Disconnected (-1)")); break; case 0: // MQTT_CONNECTED - LogSerial.println(F("MQTT CONNECTED")); + LogSerial.println(F("[MQTT] Connected (0)")); break; case 1: // MQTT_CONNECT_BAD_PROTOCOL - LogSerial.println(F("MQTT BAD PROTOCOL")); + LogSerial.println(F("[MQTT] Bad protocol (1)")); break; case 2: // MQTT_CONNECT_BAD_CLIENT_ID - LogSerial.println(F("MQTT BAD CLIENT ID")); + LogSerial.println(F("[MQTT] Bad Client ID (2)")); break; case 3: // MQTT_CONNECT_UNAVAILABLE - LogSerial.println(F("MQTT UNAVAILABLE")); + LogSerial.println(F("[MQTT] Unavailable (3)")); break; case 4: // MQTT_CONNECT_BAD_CREDENTIALS - LogSerial.println(F("MQTT BAD CREDENTIALS")); + LogSerial.println(F("[MQTT] Bad Credentials (4)")); break; case 5: // MQTT UNAUTHORIZED - LogSerial.println(F("MQTT UNAUTHORIZED")); + LogSerial.println(F("[MQTT] Unauthorized (5)")); break; } } diff --git a/src/blled/types.h b/src/blled/types.h index ec4bd72..8f5b85e 100644 --- a/src/blled/types.h +++ b/src/blled/types.h @@ -90,6 +90,7 @@ extern "C" bool finish_check = false; //When updateleds() is run, should the TEST LEDS be set? unsigned long finishStartms = 0; // Time the finish countdown is measured from int finishTimeOut = 600000; //300000 = 5 mins + bool controlChamberLight = false; //control chamber light //Inactivity Timout bool inactivityEnabled = true; @@ -118,8 +119,9 @@ extern "C" COLOR frontCoverRGB; COLOR nozzleTempRGB; COLOR bedTempRGB; + // HMS Error Handling + String hmsIgnoreList; // comma-separated list of HMS_XXXX_XXXX_XXXX_XXXX codes to ignore - //char webpagePassword[8]; } PrinterConfig; PrinterConfig printerConfig; diff --git a/src/blled/web-server.h b/src/blled/web-server.h index df0c61c..9ba60a6 100644 --- a/src/blled/web-server.h +++ b/src/blled/web-server.h @@ -38,17 +38,6 @@ void handleSetup(AsyncWebServerRequest *request) request->send(response); } -void handleOldSetup(AsyncWebServerRequest *request) -{ - if (!isAuthorized(request)) - { - return request->requestAuthentication(); - } - AsyncWebServerResponse *response = request->beginResponse(200, setupPageOld_html_gz_mime, setupPageOld_html_gz, setupPageOld_html_gz_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); -} - void handleUpdatePage(AsyncWebServerRequest *request) { if (!isAuthorized(request)) @@ -179,6 +168,10 @@ void handleGetConfig(AsyncWebServerRequest *request) doc["bedTempRGB"] = printerConfig.bedTempRGB.RGBhex; doc["bedTempWW"] = printerConfig.bedTempRGB.ww; doc["bedTempCW"] = printerConfig.bedTempRGB.cw; + // HMS Error Handling + doc["hmsIgnoreList"] = printerConfig.hmsIgnoreList; + // control chamber light + doc["controlChamberLight"] = printerConfig.controlChamberLight; String jsonString; serializeJson(doc, jsonString); @@ -199,6 +192,7 @@ void handlePrinterConfigJson(AsyncWebServerRequest *request) doc["accessCode"] = printerConfig.accessCode; doc["webUser"] = securityVariables.HTTPUser; doc["webPass"] = securityVariables.HTTPPass; + doc["isAPMode"] = (WiFi.getMode() & WIFI_AP); String json; serializeJson(doc, json); @@ -270,6 +264,10 @@ void handleSubmitConfig(AsyncWebServerRequest *request) printerConfig.frontCoverRGB = hex2rgb(getSafeParamValue(request, "frontCoverRGB").c_str(), getSafeParamInt(request, "frontCoverWW"), getSafeParamInt(request, "frontCoverCW")); printerConfig.nozzleTempRGB = hex2rgb(getSafeParamValue(request, "nozzleTempRGB").c_str(), getSafeParamInt(request, "nozzleTempWW"), getSafeParamInt(request, "nozzleTempCW")); printerConfig.bedTempRGB = hex2rgb(getSafeParamValue(request, "bedTempRGB").c_str(), getSafeParamInt(request, "bedTempWW"), getSafeParamInt(request, "bedTempCW")); + // HMS Error handling + printerConfig.hmsIgnoreList = getSafeParamValue(request, "hmsIgnoreList"); + // Control Chamber Light + printerConfig.controlChamberLight = request->hasParam("controlChamberLight", true); saveFileSystem(); LogSerial.println(F("Packet received from setuppage")); @@ -294,12 +292,12 @@ void handleWiFiScan(AsyncWebServerRequest *request) { JsonDocument doc; JsonArray networks = doc["networks"].to(); - int n = WiFi.scanNetworks(); for (int i = 0; i < n; ++i) { JsonObject net = networks.add(); net["ssid"] = WiFi.SSID(i); + net["bssid"] = WiFi.BSSIDstr(i); net["rssi"] = WiFi.RSSI(i); net["enc"] = (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? false : true; } @@ -326,6 +324,10 @@ void handleSubmitWiFi(AsyncWebServerRequest *request) { String ssid = request->getParam("ssid", true)->value(); String pass = request->getParam("pass", true)->value(); + String bssid = request->hasParam("bssid", true) ? request->getParam("bssid", true)->value() : ""; + if (bssid.length() > 0) + strlcpy(printerConfig.BSSID, bssid.c_str(), sizeof(printerConfig.BSSID)); + ssid.trim(); pass.trim(); @@ -441,7 +443,6 @@ void handleDownloadConfigFile(AsyncWebServerRequest *request) request->send(response); } - void handleWebSerialPage(AsyncWebServerRequest *request) { if (!isAuthorized(request)) @@ -451,6 +452,36 @@ void handleWebSerialPage(AsyncWebServerRequest *request) request->send(response); } +void handlePrinterList(AsyncWebServerRequest *request) +{ + JsonDocument doc; + JsonArray arr = doc.to(); + + for (int i = 0; i < bblKnownPrinterCount; i++) + { + JsonObject obj = arr.add(); + obj["ip"] = bblLastKnownPrinters[i].ip.toString(); + obj["usn"] = bblLastKnownPrinters[i].usn; + } + + String json; + serializeJson(doc, json); + request->send(200, "application/json", json); +} + +void handleFactoryReset(AsyncWebServerRequest *request) +{ + if (!isAuthorized(request)) + return request->requestAuthentication(); + + LogSerial.println(F("[FactoryReset] Performing full reset...")); + + deleteFileSystem(); // delete LittleFS config + request->send(200, "text/plain", "Factory reset complete. Restarting..."); + + shouldRestart = true; + restartRequestTime = millis(); +} void handleUploadConfigFileData(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) @@ -519,9 +550,7 @@ void setupWebserver() request->redirect("/wifi"); } else { handleSetup(request); - //handleOldSetup(request); } }); - webServer.on("/old", HTTP_GET, handleOldSetup); webServer.on("/fwupdate", HTTP_GET, handleUpdatePage); webServer.on("/getConfig", HTTP_GET, handleGetConfig); webServer.on("/submitConfig", HTTP_POST, handleSubmitConfig); @@ -536,6 +565,8 @@ void setupWebserver() webServer.on("/backuprestore", HTTP_GET, handleConfigPage); webServer.on("/configfile.json", HTTP_GET, handleDownloadConfigFile); webServer.on("/webserial", HTTP_GET, handleWebSerialPage); + webServer.on("/printerList", HTTP_GET, handlePrinterList); + webServer.on("/factoryreset", HTTP_GET, handleFactoryReset); webServer.on("/configrestore", HTTP_POST, [](AsyncWebServerRequest *request) { if (!isAuthorized(request)) { diff --git a/src/blled/wifi-manager.h b/src/blled/wifi-manager.h index a091f2e..a9aff8b 100644 --- a/src/blled/wifi-manager.h +++ b/src/blled/wifi-manager.h @@ -171,7 +171,7 @@ void startAPMode() { WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); dnsServer.start(53, "*", apIP); - Serial.println(F("[WiFiManager] AP gestartet auf IP: ")); + Serial.print(F("[WiFiManager] AP started on IP: ")); Serial.println(WiFi.softAPIP()); } diff --git a/src/main.cpp b/src/main.cpp index 4ccd435..5bfe818 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,15 +2,17 @@ bool shouldRestart = false; unsigned long restartRequestTime = 0; #include "./blled/logSerial.h" -#include "./blled/web-server.h" -#include "./blled/mqttmanager.h" +#include "./blled/leds.h" #include "./blled/filesystem.h" #include "./blled/types.h" -#include "./blled/leds.h" +#include "./blled/bblPrinterDiscovery.h" +#include "./blled/web-server.h" +#include "./blled/mqttmanager.h" #include "./blled/serialmanager.h" #include "./blled/wifi-manager.h" #include "./blled/ssdp.h" + int wifi_reconnect_count = 0; void defaultcolors() @@ -137,6 +139,10 @@ void loop() { dnsServer.processNextRequest(); } + if(WiFi.status() == WL_CONNECTED && WiFi.getMode() != WIFI_AP) + { + bblSearchPrinters(); + } } if (printerConfig.rescanWiFiNetwork) { diff --git a/src/www/blled.svg b/src/www/blled.svg index 05b1a9a..7c5e9e2 100644 --- a/src/www/blled.svg +++ b/src/www/blled.svg @@ -1,42 +1 @@ - - - - + \ No newline at end of file diff --git a/src/www/colorpicker.html.unused b/src/www/colorpicker.html.unused deleted file mode 100644 index 674d0ee..0000000 --- a/src/www/colorpicker.html.unused +++ /dev/null @@ -1,147 +0,0 @@ - - - - - BLLED Custom Colorpicker - - - - -

LED Farbe wΓ€hlen

-
- -
- - -

-
-
-
-
-
diff --git a/src/www/favicon.png b/src/www/favicon.png
index 753583c..bb00bdf 100644
Binary files a/src/www/favicon.png and b/src/www/favicon.png differ
diff --git a/src/www/setupPage.html b/src/www/setupPage.html
index 9e1273f..95a0fcb 100644
--- a/src/www/setupPage.html
+++ b/src/www/setupPage.html
@@ -122,8 +122,7 @@ 

BLLED LED Settings

Replicate State -
+
BLLED LED Settings Color Test (Always On) -
+
@@ -170,8 +168,7 @@

BLLED LED Settings

Finish Indication -
+
BLLED LED Settings Inactivity Timeout (Minutes) -
+
+ +
+ + Control Chamber Light +
@@ -444,6 +448,12 @@

BLLED LED Settings

step="1">
+
+ Ignore HMS Codes (one per line) + +
@@ -483,7 +493,7 @@

BLLED LED Settings

Navigation

- + @@ -784,6 +794,7 @@

Firmware version: ??.??.??

document.getElementById('finishTimerMins').value = configData.finishTimerMins || 10; document.getElementById('inactivityEnabled').checked = configData.inactivityEnabled || false; document.getElementById('inactivityMins').value = configData.inactivityMins || 30; + document.getElementById('controlChamberLight').checked = configData.controlChamberLight || false; document.getElementById('debuging').checked = configData.debuging || false; document.getElementById('debugingchange').checked = configData.debugingchange || false; document.getElementById('mqttdebug').checked = configData.mqttdebug || false; @@ -835,6 +846,8 @@

Firmware version: ??.??.??

document.getElementById('bedTempRGB').value = configData.bedTempRGB || ''; document.getElementById('bedTempWW').value = configData.bedTempWW || 0; document.getElementById('bedTempCW').value = configData.bedTempCW || 0; + //HMS Error handling + document.getElementById('hmsIgnoreList').value = configData.hmsIgnoreList || ''; updateIdle(); showhideOptions(); diff --git a/src/www/setupPageOld.html b/src/www/setupPageOld.html deleted file mode 100644 index 9031f9b..0000000 --- a/src/www/setupPageOld.html +++ /dev/null @@ -1,1078 +0,0 @@ - - - - - - - - BLLED Setup - - - - - - -
-
- - BLLED Controller - - WiFi-Signal - - - - - - - -
-
-

BLLED LED Settings

-

Firmware version: ??.??.??

-

This page allows you to change the LED behavior.

-
-
- - - - - - - - - - - - - -
- - -

LED - Behaviour (Choose One)

-
- -    Maintenance Mode (Always On) -
-
- -    RGB Color Cycle Mode (Always On) -
-
- -    Replicate LED State -
- -  WW  -  CW  -
-
- -
- - -    Test LED Colors (Always On) -
- -  WW  -  CW  -
-
- - - - - - -
-
- -    Show Wifi Strength via - LEDs -
-
- -

Options

- - - - - - - - - - -
-
- -    Finish Indication -
-
-
- -  WW  -  CW  -
-
- - - -
-
- -    Inactivity Timeout (Minutes) - -
-
- -    Debugging -
-
- -    Debugging OnChange Events -
-
- -    MQTT Logging -
-
-

Printer - Dependant

-
- -    Connecting to a P1 Printer? (No Door - Switch, No Lidar) -
-
- -    Door Switch used for actions (P1 has no - switch) -
- - - - - - -
-

- Stages with Lidar in use (if installed)

-
- -  WW  -  CW  -    Cleaning Nozzle
- - -  WW  -  CW  -    Bed Leveling
- - -  WW  -  CW  -    Calibrating Extrusion
- - -  WW  -  CW  -    Scanning Bed Surface
- - -  WW  -  CW  -    First Layer Inspection
- - -

Customise - Colors

-
- -    Error Detection -
-
- - -  WW  -  CW  -    WiFi Setup / Scanning
- - - -  WW  -  CW  -    Pause (Gcode or User)
- - -  WW  -  CW  -    First Layer Error (Pause for - user)
- - -  WW  -  CW  -    Nozzle Clog (Pause for user)
- - -  WW  -  CW  -    HMS Severity, SERIOUS
- - -  WW  -  CW  -    HMS Severity, FATAL
- - -  WW  -  CW  -    Filament Runout
- - -  WW  -  CW  -    Front Cover Removed
- - -  WW  -  CW  -    Nozzle Temp Fail
- - -  WW  -  CW  -    Bed Temp Fail
-
-
- -
- - - -
- -
-
-
- - - - - - - - - - - \ No newline at end of file diff --git a/src/www/wifiSetup.html b/src/www/wifiSetup.html index a304d31..dba00e4 100644 --- a/src/www/wifiSetup.html +++ b/src/www/wifiSetup.html @@ -21,12 +21,16 @@

BLLED WiFi Setup

- + - +
+ + +
@@ -49,6 +53,30 @@

BLLED WiFi Setup

ℹ️Placeholder
+
+
+

Select Printer

+
+
+ +
+
+