Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
9f7ee13e78 | |||
cf3f6f6741 | |||
b87d43c64e | |||
3d0411e3c1 | |||
9c61b708aa | |||
90f800d042 | |||
a7b1721e1d | |||
e4825d2905 | |||
c1733848d3 | |||
484c95523d | |||
8499613215 | |||
08f37186b4 |
19
CHANGELOG.md
19
CHANGELOG.md
@ -1,5 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.3.96] - 2025-02-25
|
||||||
|
### Added
|
||||||
|
- füge Unterstützung für Spoolman-Einstellungen hinzu und aktualisiere die Benutzeroberfläche
|
||||||
|
- entferne die sendAmsData-Funktion aus der API-Schnittstelle
|
||||||
|
- erweitere Bambu-Credentials um AutoSend-Zeit und aktualisiere die Benutzeroberfläche
|
||||||
|
- erweitere Bambu-Credentials mit AutoSend-Wartezeit und aktualisiere die Benutzeroberfläche
|
||||||
|
- add espRestart function and replace delay with vTaskDelay for OTA update process
|
||||||
|
- implement OTA update functionality with backup and restore for configurations
|
||||||
|
- add own_filaments.json and integrate custom filament loading in bambu.cpp
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- update platformio.ini for version v1.3.96
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- aktualisiere Bedingungen für die AMS-Datenaktualisierung und entferne unnötige Aufrufe
|
||||||
|
- aktualisiere Bedingung für den Fortschritt der OTA-Update-Nachricht
|
||||||
|
- update auto set logic to check RFID tag before setting Bambu spool
|
||||||
|
|
||||||
|
|
||||||
## [1.3.95] - 2025-02-24
|
## [1.3.95] - 2025-02-24
|
||||||
### Changed
|
### Changed
|
||||||
- update webpages for version v1.3.95
|
- update webpages for version v1.3.95
|
||||||
|
31
html/own_filaments.json
Normal file
31
html/own_filaments.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"TPU": "GFU99",
|
||||||
|
"PA": "GFN99",
|
||||||
|
"PA-CF": "GFN98",
|
||||||
|
"PLA": "GFL99",
|
||||||
|
"PLA Silk": "GFL96",
|
||||||
|
"PLA-CF": "GFL98",
|
||||||
|
"PLA High Speed": "GFL95",
|
||||||
|
"PETG": "GFG99",
|
||||||
|
"PETG-CF": "GFG98",
|
||||||
|
"PCTG": "GFG97",
|
||||||
|
"ABS": "GFB99",
|
||||||
|
"ABS+HS": "GFB99",
|
||||||
|
"PC": "GFC99",
|
||||||
|
"PC/ABS": "GFC99",
|
||||||
|
"ASA": "GFB98",
|
||||||
|
"PVA": "GFS99",
|
||||||
|
"HIPS": "GFS98",
|
||||||
|
"PPS-CF": "GFT98",
|
||||||
|
"PPS": "GFT97",
|
||||||
|
"PPA-CF": "GFN97",
|
||||||
|
"PPA-GF": "GFN96",
|
||||||
|
"PE": "GFP99",
|
||||||
|
"PE-CF": "GFP98",
|
||||||
|
"PP": "GFP97",
|
||||||
|
"PP-CF": "GFP96",
|
||||||
|
"PP-GF": "GFP95",
|
||||||
|
"EVA": "GFR99",
|
||||||
|
"PHA": "GFR98",
|
||||||
|
"BVOH": "GFS97"
|
||||||
|
}
|
46
html/rfid.js
46
html/rfid.js
@ -150,6 +150,13 @@ function initWebSocket() {
|
|||||||
ramStatus.textContent = `${data.freeHeap}k`;
|
ramStatus.textContent = `${data.freeHeap}k`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (data.type === 'setSpoolmanSettings') {
|
||||||
|
if (data.payload == 'success') {
|
||||||
|
showNotification(`Spoolman Settings set successfully`, true);
|
||||||
|
} else {
|
||||||
|
showNotification(`Error setting Spoolman Settings`, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
@ -285,6 +292,14 @@ function displayAmsData(amsData) {
|
|||||||
<img src="spool_in.png" alt="Spool In" style="width: 48px; height: 48px; transform: rotate(180deg) scaleX(-1);">
|
<img src="spool_in.png" alt="Spool In" style="width: 48px; height: 48px; transform: rotate(180deg) scaleX(-1);">
|
||||||
</button>`;
|
</button>`;
|
||||||
|
|
||||||
|
const spoolmanButtonHtml = `
|
||||||
|
<button class="spool-button" onclick="handleSpoolmanSettings('${tray.tray_info_idx}', '${tray.setting_id}', '${tray.cali_idx}', '${tray.nozzle_temp_min}', '${tray.nozzle_temp_max}')"
|
||||||
|
style="position: absolute; bottom: 0px; right: 0px;
|
||||||
|
background: none; border: none; padding: 0;
|
||||||
|
cursor: pointer; display: none;">
|
||||||
|
<img src="set_spoolman.png" alt="Spool In" style="width: 38px; height: 38px;">
|
||||||
|
</button>`;
|
||||||
|
|
||||||
if (!hasAnyContent) {
|
if (!hasAnyContent) {
|
||||||
return `
|
return `
|
||||||
<div class="tray">
|
<div class="tray">
|
||||||
@ -348,6 +363,7 @@ function displayAmsData(amsData) {
|
|||||||
${trayDetails}
|
${trayDetails}
|
||||||
${tempHTML}
|
${tempHTML}
|
||||||
${(ams.ams_id === 255 && tray.tray_type !== '') ? outButtonHtml : ''}
|
${(ams.ams_id === 255 && tray.tray_type !== '') ? outButtonHtml : ''}
|
||||||
|
${(tray.setting_id != "" && tray.setting_id != "null") ? spoolmanButtonHtml : ''}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>`;
|
</div>`;
|
||||||
@ -373,6 +389,36 @@ function updateSpoolButtons(show) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSpoolmanSettings(tray_info_idx, setting_id, cali_idx, nozzle_temp_min, nozzle_temp_max) {
|
||||||
|
// Hole das ausgewählte Filament
|
||||||
|
const selectedText = document.getElementById("selected-filament").textContent;
|
||||||
|
|
||||||
|
// Finde die ausgewählte Spule in den Daten
|
||||||
|
const selectedSpool = spoolsData.find(spool =>
|
||||||
|
`${spool.id} | ${spool.filament.name} (${spool.filament.material})` === selectedText
|
||||||
|
);
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
type: 'setSpoolmanSettings',
|
||||||
|
payload: {
|
||||||
|
filament_id: selectedSpool.filament.id,
|
||||||
|
tray_info_idx: tray_info_idx,
|
||||||
|
setting_id: setting_id,
|
||||||
|
cali_idx: cali_idx,
|
||||||
|
temp_min: nozzle_temp_min,
|
||||||
|
temp_max: nozzle_temp_max
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.send(JSON.stringify(payload));
|
||||||
|
showNotification(`Setting send to Spoolman`, true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error while sending settings to Spoolman:", error);
|
||||||
|
showNotification("Error while sending!", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleSpoolOut() {
|
function handleSpoolOut() {
|
||||||
// Erstelle Payload
|
// Erstelle Payload
|
||||||
const payload = {
|
const payload = {
|
||||||
|
BIN
html/set_spoolman.png
Normal file
BIN
html/set_spoolman.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
@ -75,8 +75,9 @@
|
|||||||
const serial = document.getElementById('bambuSerial').value;
|
const serial = document.getElementById('bambuSerial').value;
|
||||||
const code = document.getElementById('bambuCode').value;
|
const code = document.getElementById('bambuCode').value;
|
||||||
const autoSend = document.getElementById('autoSend').checked;
|
const autoSend = document.getElementById('autoSend').checked;
|
||||||
|
const autoSendTime = document.getElementById('autoSendTime').value;
|
||||||
|
|
||||||
fetch(`/api/bambu?bambu_ip=${encodeURIComponent(ip)}&bambu_serialnr=${encodeURIComponent(serial)}&bambu_accesscode=${encodeURIComponent(code)}&autoSend=${autoSend}`)
|
fetch(`/api/bambu?bambu_ip=${encodeURIComponent(ip)}&bambu_serialnr=${encodeURIComponent(serial)}&bambu_accesscode=${encodeURIComponent(code)}&autoSend=${autoSend}&autoSendTime=${autoSendTime}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.healthy) {
|
if (data.healthy) {
|
||||||
@ -122,13 +123,18 @@
|
|||||||
<label for="bambuCode">Access Code:</label>
|
<label for="bambuCode">Access Code:</label>
|
||||||
<input type="text" id="bambuCode" placeholder="Access Code vom Drucker" value="{{bambuCode}}">
|
<input type="text" id="bambuCode" placeholder="Access Code vom Drucker" value="{{bambuCode}}">
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<hr>
|
||||||
If activated, FilaMan will automatically update the next filled tray with the last scanned and weighed spool.
|
<p>If activated, FilaMan will automatically update the next filled tray with the last scanned and weighed spool.</p>
|
||||||
<label for="autoSend">Auto Send to Bambu:</label>
|
<div class="input-group" style="display: flex; margin-bottom: 0;">
|
||||||
<input type="checkbox" id="autoSend" {{autoSendToBambu}}>
|
<label for="autoSend" style="width: 250px; margin-right: 5px;">Auto Send to Bambu:</label>
|
||||||
|
<label for="autoSendTime" style="width: 250px; margin-right: 5px;">Wait time in Seconds:</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-group" style="display: flex;">
|
||||||
|
<input type="checkbox" id="autoSend" {{autoSendToBambu}} style="width: 190px; margin-right: 10px;">
|
||||||
|
<input type="text" id="autoSendTime" placeholder="Time to wait for new Spool" value="{{autoSendTime}}" style="width: 100px;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button onclick="saveBambuCredentials()">Save Bambu Credentials</button>
|
<button style="margin: 0;" onclick="saveBambuCredentials()">Save Bambu Credentials</button>
|
||||||
<p id="bambuStatusMessage"></p>
|
<p id="bambuStatusMessage"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -761,17 +761,19 @@ a:hover {
|
|||||||
right: 20px;
|
right: 20px;
|
||||||
padding: 15px 25px;
|
padding: 15px 25px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: white;
|
color: black;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
animation: slideIn 0.3s ease-out;
|
animation: slideIn 0.3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification.success {
|
.notification.success {
|
||||||
background-color: #28a745;
|
background-color: #28a745;
|
||||||
|
color: black !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification.error {
|
.notification.error {
|
||||||
background-color: #dc3545;
|
background-color: #dc3545;
|
||||||
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification.fade-out {
|
.notification.fade-out {
|
||||||
@ -1013,6 +1015,7 @@ input[type="submit"]:disabled,
|
|||||||
color: #000;
|
color: #000;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
|
text-shadow: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-container {
|
.progress-container {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
version = "1.3.95"
|
version = "1.3.96"
|
||||||
##
|
##
|
||||||
[env:esp32dev]
|
[env:esp32dev]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
|
50
src/api.cpp
50
src/api.cpp
@ -122,9 +122,9 @@ void sendToApi(void *parameter) {
|
|||||||
if (httpType == "PATCH") httpCode = http.PATCH(updatePayload);
|
if (httpType == "PATCH") httpCode = http.PATCH(updatePayload);
|
||||||
|
|
||||||
if (httpCode == HTTP_CODE_OK) {
|
if (httpCode == HTTP_CODE_OK) {
|
||||||
Serial.println("Gewicht der Spule erfolgreich aktualisiert");
|
Serial.println("Spoolman erfolgreich aktualisiert");
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Fehler beim Aktualisieren des Gewichts der Spule");
|
Serial.println("Fehler beim Senden an Spoolman!");
|
||||||
oledShowMessage("Spoolman update failed");
|
oledShowMessage("Spoolman update failed");
|
||||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
@ -223,6 +223,52 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool updateSpoolBambuData(String payload) {
|
||||||
|
JsonDocument doc;
|
||||||
|
DeserializationError error = deserializeJson(doc, payload);
|
||||||
|
if (error) {
|
||||||
|
Serial.print("Fehler beim JSON-Parsing: ");
|
||||||
|
Serial.println(error.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String spoolsUrl = spoolmanUrl + apiUrl + "/filament/" + doc["filament_id"].as<String>();
|
||||||
|
Serial.print("Update Spule mit URL: ");
|
||||||
|
Serial.println(spoolsUrl);
|
||||||
|
|
||||||
|
JsonDocument updateDoc;
|
||||||
|
updateDoc["extra"]["bambu_setting_id"] = "\"" + doc["setting_id"].as<String>() + "\"";
|
||||||
|
updateDoc["extra"]["bambu_cali_id"] = "\"" + doc["cali_idx"].as<String>() + "\"";
|
||||||
|
updateDoc["extra"]["bambu_idx"] = "\"" + doc["tray_info_idx"].as<String>() + "\"";
|
||||||
|
updateDoc["extra"]["nozzle_temperature"] = "[" + doc["temp_min"].as<String>() + "," + doc["temp_max"].as<String>() + "]";
|
||||||
|
|
||||||
|
String updatePayload;
|
||||||
|
serializeJson(updateDoc, updatePayload);
|
||||||
|
Serial.print("Update Payload: ");
|
||||||
|
Serial.println(updatePayload);
|
||||||
|
|
||||||
|
SendToApiParams* params = new SendToApiParams();
|
||||||
|
if (params == nullptr) {
|
||||||
|
Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
params->httpType = "PATCH";
|
||||||
|
params->spoolsUrl = spoolsUrl;
|
||||||
|
params->updatePayload = updatePayload;
|
||||||
|
|
||||||
|
// Erstelle die Task
|
||||||
|
BaseType_t result = xTaskCreate(
|
||||||
|
sendToApi, // Task-Funktion
|
||||||
|
"SendToApiTask", // Task-Name
|
||||||
|
4096, // Stackgröße in Bytes
|
||||||
|
(void*)params, // Parameter
|
||||||
|
0, // Priorität
|
||||||
|
NULL // Task-Handle (nicht benötigt)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// #### Spoolman init
|
// #### Spoolman init
|
||||||
bool checkSpoolmanExtraFields() {
|
bool checkSpoolmanExtraFields() {
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
@ -15,9 +15,9 @@ bool saveSpoolmanUrl(const String& url);
|
|||||||
String loadSpoolmanUrl(); // Neue Funktion zum Laden der URL
|
String loadSpoolmanUrl(); // Neue Funktion zum Laden der URL
|
||||||
bool checkSpoolmanExtraFields(); // Neue Funktion zum Überprüfen der Extrafelder
|
bool checkSpoolmanExtraFields(); // Neue Funktion zum Überprüfen der Extrafelder
|
||||||
JsonDocument fetchSingleSpoolInfo(int spoolId); // API-Funktion für die Webseite
|
JsonDocument fetchSingleSpoolInfo(int spoolId); // API-Funktion für die Webseite
|
||||||
void sendAmsData(AsyncWebSocketClient *client); // Neue Funktion zum Senden von AMS-Daten
|
|
||||||
bool updateSpoolTagId(String uidString, const char* payload); // Neue Funktion zum Aktualisieren eines Spools
|
bool updateSpoolTagId(String uidString, const char* payload); // Neue Funktion zum Aktualisieren eines Spools
|
||||||
uint8_t updateSpoolWeight(String spoolId, uint16_t weight); // Neue Funktion zum Aktualisieren des Gewichts
|
uint8_t updateSpoolWeight(String spoolId, uint16_t weight); // Neue Funktion zum Aktualisieren des Gewichts
|
||||||
bool initSpoolman(); // Neue Funktion zum Initialisieren von Spoolman
|
bool initSpoolman(); // Neue Funktion zum Initialisieren von Spoolman
|
||||||
|
bool updateSpoolBambuData(String payload); // Neue Funktion zum Aktualisieren der Bambu-Daten
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,7 +32,7 @@ int ams_count = 0;
|
|||||||
String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients
|
String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients
|
||||||
AMSData ams_data[MAX_AMS]; // Definition des Arrays;
|
AMSData ams_data[MAX_AMS]; // Definition des Arrays;
|
||||||
|
|
||||||
bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend) {
|
bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend, const String& autoSendTime) {
|
||||||
if (BambuMqttTask) {
|
if (BambuMqttTask) {
|
||||||
vTaskDelete(BambuMqttTask);
|
vTaskDelete(BambuMqttTask);
|
||||||
}
|
}
|
||||||
@ -42,6 +42,7 @@ bool saveBambuCredentials(const String& ip, const String& serialnr, const String
|
|||||||
doc["bambu_accesscode"] = accesscode;
|
doc["bambu_accesscode"] = accesscode;
|
||||||
doc["bambu_serialnr"] = serialnr;
|
doc["bambu_serialnr"] = serialnr;
|
||||||
doc["autoSendToBambu"] = autoSend;
|
doc["autoSendToBambu"] = autoSend;
|
||||||
|
doc["autoSendTime"] = (autoSendTime != "") ? autoSendTime.toInt() : autoSetBambuAmsCounter;
|
||||||
|
|
||||||
if (!saveJsonValue("/bambu_credentials.json", doc)) {
|
if (!saveJsonValue("/bambu_credentials.json", doc)) {
|
||||||
Serial.println("Fehler beim Speichern der Bambu-Credentials.");
|
Serial.println("Fehler beim Speichern der Bambu-Credentials.");
|
||||||
@ -53,6 +54,7 @@ bool saveBambuCredentials(const String& ip, const String& serialnr, const String
|
|||||||
bambu_accesscode = accesscode.c_str();
|
bambu_accesscode = accesscode.c_str();
|
||||||
bambu_serialnr = serialnr.c_str();
|
bambu_serialnr = serialnr.c_str();
|
||||||
autoSendToBambu = autoSend;
|
autoSendToBambu = autoSend;
|
||||||
|
autoSetBambuAmsCounter = autoSendTime.toInt();
|
||||||
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
if (!setupMqtt()) return false;
|
if (!setupMqtt()) return false;
|
||||||
@ -67,7 +69,8 @@ bool loadBambuCredentials() {
|
|||||||
String ip = doc["bambu_ip"].as<String>();
|
String ip = doc["bambu_ip"].as<String>();
|
||||||
String code = doc["bambu_accesscode"].as<String>();
|
String code = doc["bambu_accesscode"].as<String>();
|
||||||
String serial = doc["bambu_serialnr"].as<String>();
|
String serial = doc["bambu_serialnr"].as<String>();
|
||||||
autoSendToBambu = doc["autoSendToBambu"].as<bool>();
|
if (doc["autoSendToBambu"].is<bool>()) autoSendToBambu = doc["autoSendToBambu"].as<bool>();
|
||||||
|
if (doc["autoSendTime"].is<int>()) autoSetBambuAmsCounter = doc["autoSendTime"].as<int>();
|
||||||
|
|
||||||
ip.trim();
|
ip.trim();
|
||||||
code.trim();
|
code.trim();
|
||||||
@ -95,12 +98,37 @@ FilamentResult findFilamentIdx(String brand, String type) {
|
|||||||
// JSON-Dokument für die Filament-Daten erstellen
|
// JSON-Dokument für die Filament-Daten erstellen
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
|
|
||||||
|
// Laden der own_filaments.json
|
||||||
|
String ownFilament = "";
|
||||||
|
if (!loadJsonValue("/own_filaments.json", doc))
|
||||||
|
{
|
||||||
|
Serial.println("Fehler beim Laden der eigenen Filament-Daten");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Durchsuche direkt nach dem Type als Schlüssel
|
||||||
|
if (doc[type].is<String>()) {
|
||||||
|
ownFilament = doc[type].as<String>();
|
||||||
|
}
|
||||||
|
doc.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Laden der bambu_filaments.json
|
// Laden der bambu_filaments.json
|
||||||
if (!loadJsonValue("/bambu_filaments.json", doc)) {
|
if (!loadJsonValue("/bambu_filaments.json", doc))
|
||||||
|
{
|
||||||
Serial.println("Fehler beim Laden der Filament-Daten");
|
Serial.println("Fehler beim Laden der Filament-Daten");
|
||||||
return {"GFL99", "PLA"}; // Fallback auf Generic PLA
|
return {"GFL99", "PLA"}; // Fallback auf Generic PLA
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wenn eigener Typ
|
||||||
|
if (ownFilament != "")
|
||||||
|
{
|
||||||
|
if (doc[ownFilament].is<String>())
|
||||||
|
{
|
||||||
|
return {ownFilament, doc[ownFilament].as<String>()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Erst versuchen wir die exakte Brand + Type Kombination zu finden
|
// 1. Erst versuchen wir die exakte Brand + Type Kombination zu finden
|
||||||
String searchKey;
|
String searchKey;
|
||||||
if (brand == "Bambu" || brand == "Bambulab") {
|
if (brand == "Bambu" || brand == "Bambulab") {
|
||||||
@ -365,13 +393,13 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
|
|||||||
if (vtTray["tray_info_idx"].as<String>() != ams_data[i].trays[0].tray_info_idx ||
|
if (vtTray["tray_info_idx"].as<String>() != ams_data[i].trays[0].tray_info_idx ||
|
||||||
vtTray["tray_type"].as<String>() != ams_data[i].trays[0].tray_type ||
|
vtTray["tray_type"].as<String>() != ams_data[i].trays[0].tray_type ||
|
||||||
vtTray["tray_color"].as<String>() != ams_data[i].trays[0].tray_color ||
|
vtTray["tray_color"].as<String>() != ams_data[i].trays[0].tray_color ||
|
||||||
vtTray["cali_idx"].as<String>() != ams_data[i].trays[0].cali_idx) {
|
(vtTray["tray_type"].as<String>() != "" && vtTray["cali_idx"].as<String>() != ams_data[i].trays[0].cali_idx)) {
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundExternal) hasChanges = true;
|
//if (!foundExternal) hasChanges = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasChanges) return;
|
if (!hasChanges) return;
|
||||||
@ -420,12 +448,14 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
|
|||||||
ams_data[extIdx].trays[0].setting_id = vtTray["setting_id"].as<String>();
|
ams_data[extIdx].trays[0].setting_id = vtTray["setting_id"].as<String>();
|
||||||
ams_data[extIdx].trays[0].cali_idx = vtTray["cali_idx"].as<String>();
|
ams_data[extIdx].trays[0].cali_idx = vtTray["cali_idx"].as<String>();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ams_data[extIdx].trays[0].setting_id = "";
|
||||||
|
ams_data[extIdx].trays[0].cali_idx = "";
|
||||||
|
}
|
||||||
ams_count++; // Erhöhe ams_count für die externe Spule
|
ams_count++; // Erhöhe ams_count für die externe Spule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sende die aktualisierten AMS-Daten
|
|
||||||
//sendAmsData(nullptr);
|
|
||||||
|
|
||||||
// Erstelle JSON für WebSocket-Clients
|
// Erstelle JSON für WebSocket-Clients
|
||||||
JsonDocument wsDoc;
|
JsonDocument wsDoc;
|
||||||
JsonArray wsArray = wsDoc.to<JsonArray>();
|
JsonArray wsArray = wsDoc.to<JsonArray>();
|
||||||
@ -452,10 +482,12 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
serializeJson(wsArray, amsJsonData);
|
serializeJson(wsArray, amsJsonData);
|
||||||
|
Serial.println("AMS data updated");
|
||||||
sendAmsData(nullptr);
|
sendAmsData(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neue Bedingung für ams_filament_setting
|
// Neue Bedingung für ams_filament_setting
|
||||||
else if (doc["print"]["command"] == "ams_filament_setting") {
|
if (doc["print"]["command"] == "ams_filament_setting") {
|
||||||
int amsId = doc["print"]["ams_id"].as<int>();
|
int amsId = doc["print"]["ams_id"].as<int>();
|
||||||
int trayId = doc["print"]["tray_id"].as<int>();
|
int trayId = doc["print"]["tray_id"].as<int>();
|
||||||
String settingId = doc["print"]["setting_id"].as<String>();
|
String settingId = doc["print"]["setting_id"].as<String>();
|
||||||
@ -496,6 +528,7 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
|
|||||||
serializeJson(wsArray, amsJsonData);
|
serializeJson(wsArray, amsJsonData);
|
||||||
|
|
||||||
// Sende an WebSocket Clients
|
// Sende an WebSocket Clients
|
||||||
|
Serial.println("Filament setting updated");
|
||||||
sendAmsData(nullptr);
|
sendAmsData(nullptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ extern bool autoSendToBambu;
|
|||||||
extern int autoSetToBambuSpoolId;
|
extern int autoSetToBambuSpoolId;
|
||||||
|
|
||||||
bool loadBambuCredentials();
|
bool loadBambuCredentials();
|
||||||
bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend);
|
bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend, const String& autoSendTime);
|
||||||
bool setupMqtt();
|
bool setupMqtt();
|
||||||
void mqtt_loop(void * parameter);
|
void mqtt_loop(void * parameter);
|
||||||
bool setBambuSpool(String payload);
|
bool setBambuSpool(String payload);
|
||||||
|
23
src/main.cpp
23
src/main.cpp
@ -109,21 +109,28 @@ void loop() {
|
|||||||
if (currentMillis - lastAmsSendTime >= amsSendInterval)
|
if (currentMillis - lastAmsSendTime >= amsSendInterval)
|
||||||
{
|
{
|
||||||
lastAmsSendTime = currentMillis;
|
lastAmsSendTime = currentMillis;
|
||||||
sendAmsData(nullptr);
|
//sendAmsData(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn Bambu auto set Spool aktiv
|
// Wenn Bambu auto set Spool aktiv
|
||||||
if (autoSendToBambu && autoSetToBambuSpoolId > 0 && currentMillis - lastAutoSetBambuAmsTime >= autoSetBambuAmsInterval)
|
if (autoSendToBambu && autoSetToBambuSpoolId > 0 && currentMillis - lastAutoSetBambuAmsTime >= autoSetBambuAmsInterval)
|
||||||
{
|
{
|
||||||
lastAutoSetBambuAmsTime = currentMillis;
|
if (hasReadRfidTag == 0)
|
||||||
oledShowMessage("Auto Set " + String(autoSetBambuAmsCounter - autoAmsCounter) + "s");
|
{
|
||||||
autoAmsCounter++;
|
lastAutoSetBambuAmsTime = currentMillis;
|
||||||
|
oledShowMessage("Auto Set " + String(autoSetBambuAmsCounter - autoAmsCounter) + "s");
|
||||||
if (autoAmsCounter >= autoSetBambuAmsCounter)
|
autoAmsCounter++;
|
||||||
|
|
||||||
|
if (autoAmsCounter >= autoSetBambuAmsCounter)
|
||||||
|
{
|
||||||
|
autoSetToBambuSpoolId = 0;
|
||||||
|
autoAmsCounter = 0;
|
||||||
|
oledShowWeight(weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
autoSetToBambuSpoolId = 0;
|
|
||||||
autoAmsCounter = 0;
|
autoAmsCounter = 0;
|
||||||
oledShowWeight(weight);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
205
src/ota.cpp
Normal file
205
src/ota.cpp
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <website.h>
|
||||||
|
#include <commonFS.h>
|
||||||
|
|
||||||
|
// Globale Variablen für Config Backups hinzufügen
|
||||||
|
String bambuCredentialsBackup;
|
||||||
|
String spoolmanUrlBackup;
|
||||||
|
|
||||||
|
// Globale Variable für den Update-Typ
|
||||||
|
static int currentUpdateCommand = 0;
|
||||||
|
|
||||||
|
// Globale Update-Variablen
|
||||||
|
static size_t updateTotalSize = 0;
|
||||||
|
static size_t updateWritten = 0;
|
||||||
|
static bool isSpiffsUpdate = false;
|
||||||
|
|
||||||
|
|
||||||
|
void backupJsonConfigs() {
|
||||||
|
// Bambu Credentials backup
|
||||||
|
if (SPIFFS.exists("/bambu_credentials.json")) {
|
||||||
|
File file = SPIFFS.open("/bambu_credentials.json", "r");
|
||||||
|
if (file) {
|
||||||
|
bambuCredentialsBackup = file.readString();
|
||||||
|
file.close();
|
||||||
|
Serial.println("Bambu credentials backed up");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spoolman URL backup
|
||||||
|
if (SPIFFS.exists("/spoolman_url.json")) {
|
||||||
|
File file = SPIFFS.open("/spoolman_url.json", "r");
|
||||||
|
if (file) {
|
||||||
|
spoolmanUrlBackup = file.readString();
|
||||||
|
file.close();
|
||||||
|
Serial.println("Spoolman URL backed up");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreJsonConfigs() {
|
||||||
|
// Restore Bambu credentials
|
||||||
|
if (bambuCredentialsBackup.length() > 0) {
|
||||||
|
File file = SPIFFS.open("/bambu_credentials.json", "w");
|
||||||
|
if (file) {
|
||||||
|
file.print(bambuCredentialsBackup);
|
||||||
|
file.close();
|
||||||
|
Serial.println("Bambu credentials restored");
|
||||||
|
}
|
||||||
|
bambuCredentialsBackup = ""; // Clear backup
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore Spoolman URL
|
||||||
|
if (spoolmanUrlBackup.length() > 0) {
|
||||||
|
File file = SPIFFS.open("/spoolman_url.json", "w");
|
||||||
|
if (file) {
|
||||||
|
file.print(spoolmanUrlBackup);
|
||||||
|
file.close();
|
||||||
|
Serial.println("Spoolman URL restored");
|
||||||
|
}
|
||||||
|
spoolmanUrlBackup = ""; // Clear backup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void espRestart() {
|
||||||
|
yield();
|
||||||
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sendUpdateProgress(int progress, const char* status = nullptr, const char* message = nullptr) {
|
||||||
|
static int lastSentProgress = -1;
|
||||||
|
|
||||||
|
// Verhindere zu häufige Updates
|
||||||
|
if (progress == lastSentProgress && !status && !message) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String progressMsg = "{\"type\":\"updateProgress\",\"progress\":" + String(progress);
|
||||||
|
if (status) {
|
||||||
|
progressMsg += ",\"status\":\"" + String(status) + "\"";
|
||||||
|
}
|
||||||
|
if (message) {
|
||||||
|
progressMsg += ",\"message\":\"" + String(message) + "\"";
|
||||||
|
}
|
||||||
|
progressMsg += "}";
|
||||||
|
|
||||||
|
if (progress >= 100) {
|
||||||
|
// Sende die Nachricht nur einmal für den Abschluss
|
||||||
|
ws.textAll("{\"type\":\"updateProgress\",\"progress\":100,\"status\":\"success\",\"message\":\"Update successful! Restarting device...\"}");
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sende die Nachricht mehrmals mit Verzögerung für wichtige Updates
|
||||||
|
if (status || abs(progress - lastSentProgress) >= 10 || progress == 100) {
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
ws.textAll(progressMsg);
|
||||||
|
delay(100); // Längerer Delay zwischen Nachrichten
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ws.textAll(progressMsg);
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSentProgress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleUpdate(AsyncWebServer &server) {
|
||||||
|
AsyncCallbackWebHandler* updateHandler = new AsyncCallbackWebHandler();
|
||||||
|
updateHandler->setUri("/update");
|
||||||
|
updateHandler->setMethod(HTTP_POST);
|
||||||
|
|
||||||
|
updateHandler->onUpload([](AsyncWebServerRequest *request, String filename,
|
||||||
|
size_t index, uint8_t *data, size_t len, bool final) {
|
||||||
|
if (!index) {
|
||||||
|
updateTotalSize = request->contentLength();
|
||||||
|
updateWritten = 0;
|
||||||
|
isSpiffsUpdate = (filename.indexOf("website") > -1);
|
||||||
|
|
||||||
|
if (isSpiffsUpdate) {
|
||||||
|
// Backup vor dem Update
|
||||||
|
sendUpdateProgress(0, "backup", "Backing up configurations...");
|
||||||
|
delay(200);
|
||||||
|
backupJsonConfigs();
|
||||||
|
delay(200);
|
||||||
|
|
||||||
|
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL);
|
||||||
|
if (!partition || !Update.begin(partition->size, U_SPIFFS)) {
|
||||||
|
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update initialization failed\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendUpdateProgress(5, "starting", "Starting SPIFFS update...");
|
||||||
|
delay(200);
|
||||||
|
} else {
|
||||||
|
if (!Update.begin(updateTotalSize)) {
|
||||||
|
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update initialization failed\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendUpdateProgress(0, "starting", "Starting firmware update...");
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
if (Update.write(data, len) != len) {
|
||||||
|
request->send(400, "application/json", "{\"success\":false,\"message\":\"Write failed\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWritten += len;
|
||||||
|
int currentProgress;
|
||||||
|
|
||||||
|
// Berechne den Fortschritt basierend auf dem Update-Typ
|
||||||
|
if (isSpiffsUpdate) {
|
||||||
|
// SPIFFS: 5-75% für Upload
|
||||||
|
currentProgress = 6 + (updateWritten * 100) / updateTotalSize;
|
||||||
|
} else {
|
||||||
|
// Firmware: 0-100% für Upload
|
||||||
|
currentProgress = 1 + (updateWritten * 100) / updateTotalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lastProgress = -1;
|
||||||
|
if (currentProgress != lastProgress && (currentProgress % 10 == 0 || final)) {
|
||||||
|
sendUpdateProgress(currentProgress, "uploading");
|
||||||
|
oledShowMessage("Update: " + String(currentProgress) + "%");
|
||||||
|
delay(50);
|
||||||
|
lastProgress = currentProgress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (final) {
|
||||||
|
if (Update.end(true)) {
|
||||||
|
if (isSpiffsUpdate) {
|
||||||
|
restoreJsonConfigs();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update finalization failed\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateHandler->onRequest([](AsyncWebServerRequest *request) {
|
||||||
|
if (Update.hasError()) {
|
||||||
|
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update failed\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erste 100% Nachricht
|
||||||
|
ws.textAll("{\"type\":\"updateProgress\",\"progress\":100,\"status\":\"success\",\"message\":\"Update successful! Restarting device...\"}");
|
||||||
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(200, "application/json",
|
||||||
|
"{\"success\":true,\"message\":\"Update successful! Restarting device...\"}");
|
||||||
|
response->addHeader("Connection", "close");
|
||||||
|
request->send(response);
|
||||||
|
|
||||||
|
// Zweite 100% Nachricht zur Sicherheit
|
||||||
|
ws.textAll("{\"type\":\"updateProgress\",\"progress\":100,\"status\":\"success\",\"message\":\"Update successful! Restarting device...\"}");
|
||||||
|
|
||||||
|
espRestart();
|
||||||
|
});
|
||||||
|
|
||||||
|
server.addHandler(updateHandler);
|
||||||
|
}
|
9
src/ota.h
Normal file
9
src/ota.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef OTA_H
|
||||||
|
#define OTA_H
|
||||||
|
|
||||||
|
#include <ArduinoOTA.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
void handleUpdate(AsyncWebServer &server);
|
||||||
|
|
||||||
|
#endif
|
215
src/website.cpp
215
src/website.cpp
@ -9,6 +9,7 @@
|
|||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "ota.h"
|
||||||
|
|
||||||
#ifndef VERSION
|
#ifndef VERSION
|
||||||
#define VERSION "1.1.0"
|
#define VERSION "1.1.0"
|
||||||
@ -23,48 +24,6 @@ AsyncWebSocket ws("/ws");
|
|||||||
uint8_t lastSuccess = 0;
|
uint8_t lastSuccess = 0;
|
||||||
uint8_t lastHasReadRfidTag = 0;
|
uint8_t lastHasReadRfidTag = 0;
|
||||||
|
|
||||||
// Globale Variablen für Config Backups hinzufügen
|
|
||||||
String bambuCredentialsBackup;
|
|
||||||
String spoolmanUrlBackup;
|
|
||||||
|
|
||||||
// Globale Variable für den Update-Typ
|
|
||||||
static int currentUpdateCommand = 0;
|
|
||||||
|
|
||||||
// Globale Update-Variablen
|
|
||||||
static size_t updateTotalSize = 0;
|
|
||||||
static size_t updateWritten = 0;
|
|
||||||
static bool isSpiffsUpdate = false;
|
|
||||||
|
|
||||||
void sendUpdateProgress(int progress, const char* status = nullptr, const char* message = nullptr) {
|
|
||||||
static int lastSentProgress = -1;
|
|
||||||
|
|
||||||
// Verhindere zu häufige Updates
|
|
||||||
if (progress == lastSentProgress && !status && !message) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String progressMsg = "{\"type\":\"updateProgress\",\"progress\":" + String(progress);
|
|
||||||
if (status) {
|
|
||||||
progressMsg += ",\"status\":\"" + String(status) + "\"";
|
|
||||||
}
|
|
||||||
if (message) {
|
|
||||||
progressMsg += ",\"message\":\"" + String(message) + "\"";
|
|
||||||
}
|
|
||||||
progressMsg += "}";
|
|
||||||
|
|
||||||
// Sende die Nachricht mehrmals mit Verzögerung für wichtige Updates
|
|
||||||
if (status || abs(progress - lastSentProgress) >= 10 || progress == 100) {
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
ws.textAll(progressMsg);
|
|
||||||
delay(100); // Längerer Delay zwischen Nachrichten
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ws.textAll(progressMsg);
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastSentProgress = progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
|
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
|
||||||
if (type == WS_EVT_CONNECT) {
|
if (type == WS_EVT_CONNECT) {
|
||||||
@ -136,6 +95,15 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
|
|||||||
setBambuSpool(doc["payload"]);
|
setBambuSpool(doc["payload"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (doc["type"] == "setSpoolmanSettings") {
|
||||||
|
Serial.println(doc["payload"].as<String>());
|
||||||
|
if (updateSpoolBambuData(doc["payload"].as<String>())) {
|
||||||
|
ws.textAll("{\"type\":\"setSpoolmanSettings\",\"payload\":\"success\"}");
|
||||||
|
} else {
|
||||||
|
ws.textAll("{\"type\":\"setSpoolmanSettings\",\"payload\":\"error\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
Serial.println("Unbekannter WebSocket-Typ: " + doc["type"].as<String>());
|
Serial.println("Unbekannter WebSocket-Typ: " + doc["type"].as<String>());
|
||||||
}
|
}
|
||||||
@ -207,105 +175,6 @@ void sendAmsData(AsyncWebSocketClient *client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleUpdate(AsyncWebServer &server) {
|
|
||||||
AsyncCallbackWebHandler* updateHandler = new AsyncCallbackWebHandler();
|
|
||||||
updateHandler->setUri("/update");
|
|
||||||
updateHandler->setMethod(HTTP_POST);
|
|
||||||
|
|
||||||
updateHandler->onUpload([](AsyncWebServerRequest *request, String filename,
|
|
||||||
size_t index, uint8_t *data, size_t len, bool final) {
|
|
||||||
if (!index) {
|
|
||||||
updateTotalSize = request->contentLength();
|
|
||||||
updateWritten = 0;
|
|
||||||
isSpiffsUpdate = (filename.indexOf("website") > -1);
|
|
||||||
|
|
||||||
if (isSpiffsUpdate) {
|
|
||||||
// Backup vor dem Update
|
|
||||||
sendUpdateProgress(0, "backup", "Backing up configurations...");
|
|
||||||
delay(200);
|
|
||||||
backupJsonConfigs();
|
|
||||||
delay(200);
|
|
||||||
|
|
||||||
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL);
|
|
||||||
if (!partition || !Update.begin(partition->size, U_SPIFFS)) {
|
|
||||||
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update initialization failed\"}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendUpdateProgress(5, "starting", "Starting SPIFFS update...");
|
|
||||||
delay(200);
|
|
||||||
} else {
|
|
||||||
if (!Update.begin(updateTotalSize)) {
|
|
||||||
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update initialization failed\"}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendUpdateProgress(0, "starting", "Starting firmware update...");
|
|
||||||
delay(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len) {
|
|
||||||
if (Update.write(data, len) != len) {
|
|
||||||
request->send(400, "application/json", "{\"success\":false,\"message\":\"Write failed\"}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateWritten += len;
|
|
||||||
int currentProgress;
|
|
||||||
|
|
||||||
// Berechne den Fortschritt basierend auf dem Update-Typ
|
|
||||||
if (isSpiffsUpdate) {
|
|
||||||
// SPIFFS: 5-75% für Upload
|
|
||||||
currentProgress = 5 + (updateWritten * 100) / updateTotalSize;
|
|
||||||
} else {
|
|
||||||
// Firmware: 0-100% für Upload
|
|
||||||
currentProgress = 1 + (updateWritten * 100) / updateTotalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lastProgress = -1;
|
|
||||||
if (currentProgress != lastProgress && (currentProgress % 10 == 0 || final)) {
|
|
||||||
sendUpdateProgress(currentProgress, "uploading");
|
|
||||||
oledShowMessage("Update: " + String(currentProgress) + "%");
|
|
||||||
delay(50);
|
|
||||||
lastProgress = currentProgress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (final) {
|
|
||||||
if (Update.end(true)) {
|
|
||||||
if (isSpiffsUpdate) {
|
|
||||||
restoreJsonConfigs();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update finalization failed\"}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateHandler->onRequest([](AsyncWebServerRequest *request) {
|
|
||||||
if (Update.hasError()) {
|
|
||||||
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update failed\"}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Erste 100% Nachricht
|
|
||||||
ws.textAll("{\"type\":\"updateProgress\",\"progress\":100,\"status\":\"success\",\"message\":\"Update successful! Restarting device...\"}");
|
|
||||||
delay(2000); // Längerer Delay für die erste Nachricht
|
|
||||||
|
|
||||||
AsyncWebServerResponse *response = request->beginResponse(200, "application/json",
|
|
||||||
"{\"success\":true,\"message\":\"Update successful! Restarting device...\"}");
|
|
||||||
response->addHeader("Connection", "close");
|
|
||||||
request->send(response);
|
|
||||||
|
|
||||||
// Zweite 100% Nachricht zur Sicherheit
|
|
||||||
ws.textAll("{\"type\":\"updateProgress\",\"progress\":100,\"status\":\"success\",\"message\":\"Update successful! Restarting device...\"}");
|
|
||||||
delay(3000); // Noch längerer Delay vor dem Neustart
|
|
||||||
|
|
||||||
ESP.restart();
|
|
||||||
});
|
|
||||||
|
|
||||||
server.addHandler(updateHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupWebserver(AsyncWebServer &server) {
|
void setupWebserver(AsyncWebServer &server) {
|
||||||
// Deaktiviere alle Debug-Ausgaben
|
// Deaktiviere alle Debug-Ausgaben
|
||||||
Serial.setDebugOutput(false);
|
Serial.setDebugOutput(false);
|
||||||
@ -387,6 +256,7 @@ void setupWebserver(AsyncWebServer &server) {
|
|||||||
html.replace("{{bambuSerial}}", bambuSerial ? bambuSerial : "");
|
html.replace("{{bambuSerial}}", bambuSerial ? bambuSerial : "");
|
||||||
html.replace("{{bambuCode}}", bambuCode ? bambuCode : "");
|
html.replace("{{bambuCode}}", bambuCode ? bambuCode : "");
|
||||||
html.replace("{{autoSendToBambu}}", autoSendToBambu ? "checked" : "");
|
html.replace("{{autoSendToBambu}}", autoSendToBambu ? "checked" : "");
|
||||||
|
html.replace("{{autoSendTime}}", String(autoSetBambuAmsCounter));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -394,6 +264,7 @@ void setupWebserver(AsyncWebServer &server) {
|
|||||||
html.replace("{{bambuSerial}}", "");
|
html.replace("{{bambuSerial}}", "");
|
||||||
html.replace("{{bambuCode}}", "");
|
html.replace("{{bambuCode}}", "");
|
||||||
html.replace("{{autoSendToBambu}}", "");
|
html.replace("{{autoSendToBambu}}", "");
|
||||||
|
html.replace("{{autoSendTime}}", String(autoSetBambuAmsCounter));
|
||||||
}
|
}
|
||||||
|
|
||||||
request->send(200, "text/html", html);
|
request->send(200, "text/html", html);
|
||||||
@ -426,17 +297,19 @@ void setupWebserver(AsyncWebServer &server) {
|
|||||||
String bambu_serialnr = request->getParam("bambu_serialnr")->value();
|
String bambu_serialnr = request->getParam("bambu_serialnr")->value();
|
||||||
String bambu_accesscode = request->getParam("bambu_accesscode")->value();
|
String bambu_accesscode = request->getParam("bambu_accesscode")->value();
|
||||||
bool autoSend = (request->getParam("autoSend")->value() == "true") ? true : false;
|
bool autoSend = (request->getParam("autoSend")->value() == "true") ? true : false;
|
||||||
Serial.println(autoSend);
|
String autoSendTime = request->getParam("autoSendTime")->value();
|
||||||
|
|
||||||
bambu_ip.trim();
|
bambu_ip.trim();
|
||||||
bambu_serialnr.trim();
|
bambu_serialnr.trim();
|
||||||
bambu_accesscode.trim();
|
bambu_accesscode.trim();
|
||||||
|
autoSendTime.trim();
|
||||||
|
|
||||||
if (bambu_ip.length() == 0 || bambu_serialnr.length() == 0 || bambu_accesscode.length() == 0) {
|
if (bambu_ip.length() == 0 || bambu_serialnr.length() == 0 || bambu_accesscode.length() == 0) {
|
||||||
request->send(400, "application/json", "{\"success\": false, \"error\": \"Empty parameter\"}");
|
request->send(400, "application/json", "{\"success\": false, \"error\": \"Empty parameter\"}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = saveBambuCredentials(bambu_ip, bambu_serialnr, bambu_accesscode, autoSend);
|
bool success = saveBambuCredentials(bambu_ip, bambu_serialnr, bambu_accesscode, autoSend, autoSendTime);
|
||||||
|
|
||||||
request->send(200, "application/json", "{\"healthy\": " + String(success ? "true" : "false") + "}");
|
request->send(200, "application/json", "{\"healthy\": " + String(success ? "true" : "false") + "}");
|
||||||
});
|
});
|
||||||
@ -482,6 +355,15 @@ void setupWebserver(AsyncWebServer &server) {
|
|||||||
Serial.println("spool_in.png gesendet");
|
Serial.println("spool_in.png gesendet");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Route für set_spoolman.png
|
||||||
|
server.on("/set_spoolman.png", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/set_spoolman.png.gz", "image/png");
|
||||||
|
response->addHeader("Content-Encoding", "gzip");
|
||||||
|
response->addHeader("Cache-Control", CACHE_CONTROL);
|
||||||
|
request->send(response);
|
||||||
|
Serial.println("set_spoolman.png gesendet");
|
||||||
|
});
|
||||||
|
|
||||||
// Route für JavaScript Dateien
|
// Route für JavaScript Dateien
|
||||||
server.on("/spoolman.js", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/spoolman.js", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
Serial.println("Anfrage für /spoolman.js erhalten");
|
Serial.println("Anfrage für /spoolman.js erhalten");
|
||||||
@ -534,50 +416,3 @@ void setupWebserver(AsyncWebServer &server) {
|
|||||||
server.begin();
|
server.begin();
|
||||||
Serial.println("Webserver gestartet");
|
Serial.println("Webserver gestartet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void backupJsonConfigs() {
|
|
||||||
// Bambu Credentials backup
|
|
||||||
if (SPIFFS.exists("/bambu_credentials.json")) {
|
|
||||||
File file = SPIFFS.open("/bambu_credentials.json", "r");
|
|
||||||
if (file) {
|
|
||||||
bambuCredentialsBackup = file.readString();
|
|
||||||
file.close();
|
|
||||||
Serial.println("Bambu credentials backed up");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spoolman URL backup
|
|
||||||
if (SPIFFS.exists("/spoolman_url.json")) {
|
|
||||||
File file = SPIFFS.open("/spoolman_url.json", "r");
|
|
||||||
if (file) {
|
|
||||||
spoolmanUrlBackup = file.readString();
|
|
||||||
file.close();
|
|
||||||
Serial.println("Spoolman URL backed up");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void restoreJsonConfigs() {
|
|
||||||
// Restore Bambu credentials
|
|
||||||
if (bambuCredentialsBackup.length() > 0) {
|
|
||||||
File file = SPIFFS.open("/bambu_credentials.json", "w");
|
|
||||||
if (file) {
|
|
||||||
file.print(bambuCredentialsBackup);
|
|
||||||
file.close();
|
|
||||||
Serial.println("Bambu credentials restored");
|
|
||||||
}
|
|
||||||
bambuCredentialsBackup = ""; // Clear backup
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore Spoolman URL
|
|
||||||
if (spoolmanUrlBackup.length() > 0) {
|
|
||||||
File file = SPIFFS.open("/spoolman_url.json", "w");
|
|
||||||
if (file) {
|
|
||||||
file.print(spoolmanUrlBackup);
|
|
||||||
file.close();
|
|
||||||
Serial.println("Spoolman URL restored");
|
|
||||||
}
|
|
||||||
spoolmanUrlBackup = ""; // Clear backup
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -19,7 +19,6 @@ extern AsyncWebSocket ws;
|
|||||||
|
|
||||||
// Server-Initialisierung und Handler
|
// Server-Initialisierung und Handler
|
||||||
void initWebServer();
|
void initWebServer();
|
||||||
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
|
|
||||||
void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total);
|
void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total);
|
||||||
void setupWebserver(AsyncWebServer &server);
|
void setupWebserver(AsyncWebServer &server);
|
||||||
|
|
||||||
@ -29,8 +28,4 @@ void sendNfcData(AsyncWebSocketClient *client);
|
|||||||
void foundNfcTag(AsyncWebSocketClient *client, uint8_t success);
|
void foundNfcTag(AsyncWebSocketClient *client, uint8_t success);
|
||||||
void sendWriteResult(AsyncWebSocketClient *client, uint8_t success);
|
void sendWriteResult(AsyncWebSocketClient *client, uint8_t success);
|
||||||
|
|
||||||
// Upgrade-Funktionen
|
|
||||||
void backupJsonConfigs();
|
|
||||||
void restoreJsonConfigs();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user