diff --git a/.github/workflows/push-to-blledflasher.yml b/.github/workflows/push-to-blledflasher.yml new file mode 100644 index 0000000..3a5a944 --- /dev/null +++ b/.github/workflows/push-to-blledflasher.yml @@ -0,0 +1,68 @@ +name: Push Firmware to BLLED-Flasher + +on: + release: + types: [published, edited] + +jobs: + push-firmware: + runs-on: ubuntu-latest + + steps: + - name: Checkout BLLEDController-NG + uses: actions/checkout@v3 + + - name: Download .bin from current release + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const owner = context.repo.owner; + const repo = context.repo.repo; + const release = context.payload.release; + const tag = release.tag_name; + + const assets = release.assets.filter(a => a.name.endsWith('.bin')); + if (assets.length === 0) { + core.setFailed("No .bin files found in release"); + return; + } + + fs.mkdirSync('firmware', { recursive: true }); + + for (const asset of assets) { + const dl = await github.rest.repos.getReleaseAsset({ + owner, + repo, + asset_id: asset.id, + headers: { Accept: 'application/octet-stream' } + }); + + fs.writeFileSync(`firmware/${asset.name}`, Buffer.from(dl.data)); + console.log(`✅ Downloaded: ${asset.name}`); + } + + - name: Clone BLLED-Flasher repo + run: | + git clone https://x-access-token:${{ secrets.BLLED_FLASHER_TOKEN }}@github.com/softwarecrash/BLLED-Flasher.git flasher + cp firmware/*.bin flasher/firmware/ + + - name: Generate firmware.json + manifests + run: | + cd flasher + node generateRelease.js + + - name: Commit and Push to BLLED-Flasher + run: | + cd flasher + git config user.name "BLLED Release Bot" + git config user.email "actions@github.com" + git fetch origin + git add firmware/ + if git diff --cached --quiet; then + echo "✅ Keine Änderungen – kein Push." + else + git commit -m "📦 Add firmware from release ${{ github.event.release.tag_name }}" + git push + fi diff --git a/README.md b/README.md index 64b94a0..7848559 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ The BL Led Controller is released under Creative Commons Attribution-NonCommerci - **[Modbot](https://github.com/Modbot)**: Tester for X1C, P1P & P1S - **[xps3riments](https://github.com/xps3riments)**: Inspiration for the foundation of the code - **[longrackslabs](https://github.com/longrackslabs)**: Build process, documentation, developer & community support +- **[SoftWareCrash](https://github.com/softwarecrash)**: Any small unimportant changes ### Author diff --git a/platformio.ini b/platformio.ini index 16a2e97..e96a3ee 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,7 +11,7 @@ [env:esp32dev] custom_project_name = BLLC custom_project_codename = Balder -custom_version = 2.2.2 #BLLC_[Major].[Minor].[Patch] +custom_version = 2.2.3.nightly.070925.1 #BLLC_[Major].[Minor].[Patch] platform = espressif32 board = esp32dev framework = arduino @@ -31,4 +31,4 @@ lib_deps = luc-github/ESP32SSDP@1.2.1 ESP32Async/AsyncTCP ESP32Async/ESPAsyncWebServer - mathieucarbou/MycilaWebSerial@^8.1.1 \ No newline at end of file + mathieucarbou/MycilaWebSerial@^8.1.1 diff --git a/src/blled/AutoGrowBufferStream.h b/src/blled/AutoGrowBufferStream.h index 6589de9..3b226b7 100644 --- a/src/blled/AutoGrowBufferStream.h +++ b/src/blled/AutoGrowBufferStream.h @@ -6,6 +6,7 @@ #include #define BUFFER_INCREMENTS 128 +#define MAX_BUFFER_SIZE 65536 class AutoGrowBufferStream : public Stream { @@ -26,6 +27,11 @@ class AutoGrowBufferStream : public Stream } virtual size_t write(uint8_t byte) { + if (this->_len + 1 > MAX_BUFFER_SIZE) { + LogSerial.println(F("Max buffer size reached — flushing")); + this->flush(); + return 0; + } if (this->_len + 1 > this->buffer_size) { auto tmp = (char*)realloc(this->_buffer, this->buffer_size + BUFFER_INCREMENTS); if (tmp == NULL) { diff --git a/src/blled/leds.h b/src/blled/leds.h index 45e17ad..f9ce327 100644 --- a/src/blled/leds.h +++ b/src/blled/leds.h @@ -422,7 +422,7 @@ void updateleds() if (printerConfig.debugingchange) { - LogSerial.print(F("Door closed twice within 6 seconds - ")); + LogSerial.print(F("Door closed twice within 2 seconds - ")); if (ledsAreOff) LogSerial.print(F("Turning LEDs ON")); diff --git a/src/blled/mqttmanager.h b/src/blled/mqttmanager.h index c590b26..51c2fe4 100644 --- a/src/blled/mqttmanager.h +++ b/src/blled/mqttmanager.h @@ -1,6 +1,8 @@ #ifndef _MQTTMANAGER #define _MQTTMANAGER +#define TASK_RAM 20480 // 20kB for MQTT Task Stack Size + #include #include #include @@ -180,6 +182,7 @@ void mqttTask(void *parameter) mqttTaskRunning = false; vTaskDelete(NULL); + LogSerial.printf("[MQTT Task] HighWaterMark: %d bytes\n", uxTaskGetStackHighWaterMark(NULL)); } void ParseCallback(char *topic, byte *payload, unsigned int length) @@ -188,14 +191,6 @@ 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; @@ -245,7 +240,7 @@ void ParseCallback(char *topic, byte *payload, unsigned int length) if (printerConfig.mqttdebug) { LogSerial.print(F("(Filtered) MQTT payload, [")); - LogSerial.print(millis()); + LogSerial.print(stream.current_length()); LogSerial.print(F("], ")); serializeJson(messageobject, LogSerial); LogSerial.println(); @@ -329,6 +324,7 @@ if (!messageobject["print"]["home_flag"].isNull()) printerVariables.printerledstate = true; printerConfig.replicate_update = false; controlChamberLight(true); + printerVariables.stage = 255; LogSerial.println(F("[MQTT] Door opened – Light forced ON")); } @@ -340,33 +336,44 @@ if (!messageobject["print"]["home_flag"].isNull()) updateleds(); } - // Door closed - else - { - printerVariables.lastdoorClosems = millis(); +else // Door closed +{ + printerVariables.lastdoorClosems = millis(); - // If light was forced on by door, turn it off now - if (printerVariables.chamberLightLocked) - { - printerVariables.chamberLightLocked = false; - printerVariables.printerledstate = false; - controlChamberLight(false); - LogSerial.println(F("[MQTT] Door closed – Light OFF and lock released")); - } + // Turn off chamber light if enabled + if (printerConfig.controlChamberLight) + { + //controlChamberLight(false); + printerVariables.chamberLightLocked = false; + //LogSerial.println(F("[MQTT] Door closed – Chamber light OFF")); + } - // Restart inactivity timer - printerConfig.inactivityStartms = millis(); - printerConfig.isIdleOFFActive = false; + if (!printerConfig.inactivityEnabled) + { + // Turn off LED bar immediately + printerVariables.printerledstate = false; + printerConfig.replicate_update = false; + printerVariables.stage = 999; + tweenToColor(0,0,0,0,0); + controlChamberLight(false); + LogSerial.println(F("[MQTT] Door closed – LED bar OFF (inactivity disabled)")); + } - // Detect double-close toggle - if ((millis() - printerVariables.lastdoorOpenms) < 6000) - { - printerVariables.doorSwitchTriggered = true; - } + // Reset inactivity timer + printerConfig.inactivityStartms = millis(); + printerConfig.isIdleOFFActive = false; + + // Double-close detection + if ((millis() - printerVariables.lastdoorOpenms) < 2000) + { + printerVariables.doorSwitchTriggered = true; + } + + Changed = true; + updateleds(); + +} - Changed = true; - updateleds(); - } } } @@ -680,8 +687,8 @@ void setupMqtt() report_topic = device_topic + String("/report"); wifiSecureClient.setInsecure(); - wifiSecureClient.setTimeout(10); - mqttClient.setSocketTimeout(10); + wifiSecureClient.setTimeout(15); + mqttClient.setSocketTimeout(17); mqttClient.setBufferSize(1024); mqttClient.setServer(printerConfig.printerIP, 8883); mqttClient.setStream(stream); @@ -697,7 +704,7 @@ void setupMqtt() result = xTaskCreate( mqttTask, "mqttTask", - 6144, + TASK_RAM, NULL, 1, &mqttTaskHandle); @@ -705,7 +712,7 @@ void setupMqtt() result = xTaskCreatePinnedToCore( mqttTask, "mqttTask", - 6144, + TASK_RAM, NULL, 1, &mqttTaskHandle, diff --git a/src/blled/types.h b/src/blled/types.h index 0e1f49f..3f8f494 100644 --- a/src/blled/types.h +++ b/src/blled/types.h @@ -42,7 +42,9 @@ extern "C" unsigned long lastdoorClosems = 0; // Last time door was opened unsigned long lastdoorOpenms = 0; // Last time door was closed bool chamberLightLocked = false; // blocks replicate while true + bool ledWasForcedByDoor = false; } PrinterVariables; + PrinterVariables printerVariables; typedef struct SecurityVariables{ // Security @@ -51,7 +53,7 @@ extern "C" }SecurityVariables; SecurityVariables securityVariables; - PrinterVariables printerVariables; + typedef struct GlobalVariablesStruct{ char SSID[32]; diff --git a/src/www/setupPage.html b/src/www/setupPage.html index 13e42ad..00fd4d5 100644 --- a/src/www/setupPage.html +++ b/src/www/setupPage.html @@ -759,118 +759,103 @@

Firmware version: ??.??.??

} } - function updateConfig() { - var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status === 200) { - try { - var configData = JSON.parse(xhr.responseText); - document.getElementById("firmwareversion").textContent = "Firmware Version: " + (configData.firmwareversion || "Unknown version"); - document.getElementById('brightnessslider').value = (configData.brightness !== undefined) ? configData.brightness : 100; - document.getElementById("brightnesssliderDisplay").textContent = "Brightness: " + ((configData.brightness !== undefined) ? configData.brightness : 100) + "%"; - document.getElementById('maintMode').checked = configData.maintMode || false; - document.getElementById('discoMode').checked = configData.discoMode || false; - document.getElementById('replicateLedState').checked = configData.replicateled || false; - document.getElementById('runningRGB').value = configData.runningRGB || ''; - document.getElementById('runningWW').value = configData.runningWW || 255; - document.getElementById('runningCW').value = configData.runningCW || 255; - document.getElementById('showtestcolor').checked = configData.showtestcolor || false; - document.getElementById('testRGB').value = configData.testRGB || ''; - document.getElementById('testWW').value = configData.testWW || 0; - document.getElementById('testCW').value = configData.testCW || 0; - document.getElementById('debugwifi').checked = configData.debugwifi || false; - document.getElementById('finishIndication').checked = configData.finishindication || false; - document.getElementById('finishColor').value = configData.finishColor || ''; - document.getElementById('finishWW').value = configData.finishWW || 0; - document.getElementById('finishCW').value = configData.finishCW || 0; - if (configData.finishExit) { - document.getElementById('finishEndDoor').checked = true; - setFinishExit(document.getElementById('finishEndDoor')); - } else { - document.getElementById('finishEndTimer').checked = true; - setFinishExit(document.getElementById('finishEndTimer')); - } - 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; - document.getElementById('p1Printer').checked = configData.p1Printer || false; - document.getElementById('doorSwitch').checked = configData.doorSwitch || false; - document.getElementById('stage14RGB').value = configData.stage14RGB || ''; - document.getElementById('stage14WW').value = configData.stage14WW || 0; - document.getElementById('stage14CW').value = configData.stage14CW || 0; - document.getElementById('stage1RGB').value = configData.stage1RGB || ''; - document.getElementById('stage1WW').value = configData.stage1WW || 0; - document.getElementById('stage1CW').value = configData.stage1CW || 0; - document.getElementById('stage8RGB').value = configData.stage8RGB || ''; - document.getElementById('stage8WW').value = configData.stage8WW || 0; - document.getElementById('stage8CW').value = configData.stage8CW || 0; - document.getElementById('stage9RGB').value = configData.stage9RGB || ''; - document.getElementById('stage9WW').value = configData.stage9WW || 0; - document.getElementById('stage9CW').value = configData.stage9CW || 0; - document.getElementById('stage10RGB').value = configData.stage10RGB || ''; - document.getElementById('stage10WW').value = configData.stage10WW || 0; - document.getElementById('stage10CW').value = configData.stage10CW || 0; - document.getElementById('errorDetection').checked = configData.errordetection || false; - document.getElementById('wifiRGB').value = configData.wifiRGB || ''; - document.getElementById('wifiWW').value = configData.wifiWW || 0; - document.getElementById('wifiCW').value = configData.wifiCW || 0; - document.getElementById('pauseRGB').value = configData.pauseRGB || ''; - document.getElementById('pauseWW').value = configData.pauseWW || 0; - document.getElementById('pauseCW').value = configData.pauseCW || 0; - document.getElementById('firstlayerRGB').value = configData.firstlayerRGB || ''; - document.getElementById('firstlayerWW').value = configData.firstlayerWW || 0; - document.getElementById('firstlayerCW').value = configData.firstlayerCW || 0; - document.getElementById('nozzleclogRGB').value = configData.nozzleclogRGB || ''; - document.getElementById('nozzleclogWW').value = configData.nozzleclogWW || 0; - document.getElementById('nozzleclogCW').value = configData.nozzleclogCW || 0; - document.getElementById('hmsSeriousRGB').value = configData.hmsSeriousRGB || ''; - document.getElementById('hmsSeriousWW').value = configData.hmsSeriousWW || 0; - document.getElementById('hmsSeriousCW').value = configData.hmsSeriousCW || 0; - document.getElementById('hmsFatalRGB').value = configData.hmsFatalRGB || ''; - document.getElementById('hmsFatalWW').value = configData.hmsFatalWW || 0; - document.getElementById('hmsFatalCW').value = configData.hmsFatalCW || 0; - document.getElementById('filamentRunoutRGB').value = configData.filamentRunoutRGB || ''; - document.getElementById('filamentRunoutWW').value = configData.filamentRunoutWW || 0; - document.getElementById('filamentRunoutCW').value = configData.filamentRunoutCW || 0; - document.getElementById('frontCoverRGB').value = configData.frontCoverRGB || ''; - document.getElementById('frontCoverWW').value = configData.frontCoverWW || 0; - document.getElementById('frontCoverCW').value = configData.frontCoverCW || 0; - document.getElementById('nozzleTempRGB').value = configData.nozzleTempRGB || ''; - document.getElementById('nozzleTempWW').value = configData.nozzleTempWW || 0; - document.getElementById('nozzleTempCW').value = configData.nozzleTempCW || 0; - 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(); - showcustomColors(); - setFinishColor(); - setFinishChoice(); - showMessage("Success", "Configuration loaded successfully!"); - } catch (e) { - console.log(e); - showMessage("Error", "Invalid server response! (" + e + ")."); - } - } else if (xhr.status >= 400 && xhr.status < 500) { - showMessage("Error", "Client Error (" + xhr.status + "): " + (xhr.responseText || "Request failed.")); - } else if (xhr.status >= 500) { - showMessage("Error", "Server Error (" + xhr.status + "): " + (xhr.responseText || "Internal server error.")); + function getSafeNumber(val, fallback) { + return (val !== undefined) ? val : fallback; +} + +function updateConfig() { + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + try { + var configData = JSON.parse(xhr.responseText); + + document.getElementById("firmwareversion").textContent = "Firmware Version: " + (configData.firmwareversion || "Unknown version"); + document.getElementById('brightnessslider').value = getSafeNumber(configData.brightness, 100); + document.getElementById("brightnesssliderDisplay").textContent = "Brightness: " + getSafeNumber(configData.brightness, 100) + "%"; + + document.getElementById('maintMode').checked = configData.maintMode || false; + document.getElementById('discoMode').checked = configData.discoMode || false; + document.getElementById('replicateLedState').checked = configData.replicateled || false; + + document.getElementById('runningRGB').value = configData.runningRGB || ''; + document.getElementById('runningWW').value = getSafeNumber(configData.runningWW, 255); + document.getElementById('runningCW').value = getSafeNumber(configData.runningCW, 255); + + document.getElementById('showtestcolor').checked = configData.showtestcolor || false; + document.getElementById('testRGB').value = configData.testRGB || ''; + document.getElementById('testWW').value = getSafeNumber(configData.testWW, 0); + document.getElementById('testCW').value = getSafeNumber(configData.testCW, 0); + + document.getElementById('debugwifi').checked = configData.debugwifi || false; + document.getElementById('finishIndication').checked = configData.finishindication || false; + document.getElementById('finishColor').value = configData.finishColor || ''; + document.getElementById('finishWW').value = getSafeNumber(configData.finishWW, 0); + document.getElementById('finishCW').value = getSafeNumber(configData.finishCW, 0); + + if (configData.finishExit) { + document.getElementById('finishEndDoor').checked = true; + setFinishExit(document.getElementById('finishEndDoor')); } else { - showMessage("Error", "Unexpected response (" + xhr.status + ")."); + document.getElementById('finishEndTimer').checked = true; + setFinishExit(document.getElementById('finishEndTimer')); } + + document.getElementById('finishTimerMins').value = getSafeNumber(configData.finishTimerMins, 10); + document.getElementById('inactivityEnabled').checked = configData.inactivityEnabled || false; + document.getElementById('inactivityMins').value = getSafeNumber(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; + document.getElementById('p1Printer').checked = configData.p1Printer || false; + document.getElementById('doorSwitch').checked = configData.doorSwitch || false; + + const stages = ['stage14', 'stage1', 'stage8', 'stage9', 'stage10']; + for (const s of stages) { + document.getElementById(`${s}RGB`).value = configData[`${s}RGB`] || ''; + document.getElementById(`${s}WW`).value = getSafeNumber(configData[`${s}WW`], 0); + document.getElementById(`${s}CW`).value = getSafeNumber(configData[`${s}CW`], 0); + } + + document.getElementById('errorDetection').checked = configData.errordetection || false; + + const errorTypes = [ + 'wifi', 'pause', 'firstlayer', 'nozzleclog', 'hmsSerious', 'hmsFatal', + 'filamentRunout', 'frontCover', 'nozzleTemp', 'bedTemp' + ]; + for (const e of errorTypes) { + document.getElementById(`${e}RGB`).value = configData[`${e}RGB`] || ''; + document.getElementById(`${e}WW`).value = getSafeNumber(configData[`${e}WW`], 0); + document.getElementById(`${e}CW`).value = getSafeNumber(configData[`${e}CW`], 0); + } + + document.getElementById('hmsIgnoreList').value = configData.hmsIgnoreList || ''; + + updateIdle(); + showhideOptions(); + showcustomColors(); + setFinishColor(); + setFinishChoice(); + showMessage("Success", "Configuration loaded successfully!"); + } catch (e) { + console.log(e); + showMessage("Error", "Invalid server response! (" + e + ")."); } - }; - xhr.open('GET', '/getConfig', true); - xhr.send(); + } else if (xhr.status >= 400 && xhr.status < 500) { + showMessage("Error", "Client Error (" + xhr.status + "): " + (xhr.responseText || "Request failed.")); + } else if (xhr.status >= 500) { + showMessage("Error", "Server Error (" + xhr.status + "): " + (xhr.responseText || "Internal server error.")); + } else { + showMessage("Error", "Unexpected response (" + xhr.status + ")."); + } } + }; + xhr.open('GET', '/getConfig', true); + xhr.send(); +} window.onload = function () { document.getElementById("brightnessslider").addEventListener("input", function (e) { document.getElementById("brightnesssliderDisplay").textContent = "Brightness: " + e.target.value + "%"; diff --git a/src/www/webSerialPage.html b/src/www/webSerialPage.html index 8292f92..4f9c645 100644 --- a/src/www/webSerialPage.html +++ b/src/www/webSerialPage.html @@ -244,7 +244,7 @@

let websocket; let textArea = document.getElementById("record"); let enableFlowLock = false; - let enableTimestamp = false; + let enableTimestamp = true; let pingTimeout; let connectTimeout; let commandHistory = []; @@ -346,7 +346,7 @@

function terminalWrite(raw) { if (enableTimestamp) { let now = new Date(); - raw = "[" + now.toLocaleTimeString() + "] " + raw + "\n"; + raw = "[" + now.toLocaleTimeString() + "] " + raw /*+ "\n"*/; } textArea.value += raw + "\n"; if (!enableFlowLock) { diff --git a/src/www/wifiSetup.html b/src/www/wifiSetup.html index dba00e4..dd3d0e7 100644 --- a/src/www/wifiSetup.html +++ b/src/www/wifiSetup.html @@ -25,12 +25,25 @@

BLLED WiFi Setup

- + + + +
+ + + + + +
+ @@ -179,7 +192,8 @@

Select Printer

const pass = document.getElementById("password").value; const bssid = document.getElementById("bssid").value; const printerIP = document.getElementById("printerIP").value; - const printerSerial = document.getElementById("printerSerial").value; + //const printerSerial = document.getElementById("printerSerial").value; + const printerSerial = document.getElementById("printerSerial").value.trim().toUpperCase(); const accessCode = document.getElementById("accessCode").value; const webUser = document.getElementById("webUser").value; const webPass = document.getElementById("webPass").value;