Compare commits

..

7 Commits

Author SHA1 Message Date
tugsi f1a9c3c5d4 -Abfrage Error gefixt, wenn leer dann kein Error mehr 2025-03-17 11:19:28 +01:00
tugsi ccca159a10 rfid.js wieder auf Originalstand gebracht 2025-03-17 09:31:26 +01:00
tugsi 70c8b7bdc0 Delete data directory
Old and not used... Testing from SPIFFS
2025-03-16 19:40:05 +01:00
tugsi c574cc964e Merge branch 'Bambu-Serie-X-MQTT-Fix' of https://github.com/tugsi/Filaman into Bambu-Serie-X-MQTT-Fix 2025-03-16 19:35:08 +01:00
tugsi 9262865b56 - X1C MQTT Fix
- Spoolman Settings Fix
- Spoolman Out Fix
- Spoolman In Fix
2025-03-16 19:30:37 +01:00
tugsi f7c01eb5f0 Merge remote-tracking branch 'upstream/main' into Bambu-Serie-X-MQTT-Fix 2025-03-14 17:43:52 +01:00
tugsi a41ef9e75a docs: update changelog and header for version v1.4.1
- Die MQTT-Puffergröße auf 16.384 Byte (16 KB) erhöht.
Dies sollte ausreichen, um Ihre 15.403 Byte große JSON-Nutzlast mit etwas mehr Spielraum zu verarbeiten. Diese Änderung ermöglicht es dem MQTT-Client, größere JSON-Nachrichten ohne Kürzung zu empfangen und zu verarbeiten.

Einige wichtige Hinweise zu dieser Änderung:
Die neue Puffergröße von 16 KB verbraucht mehr RAM, der ESP32 sollte jedoch ausreichend Speicher dafür haben.
Die Größe ist auf 16 KB festgelegt, um über die benötigten 15.403 Byte hinaus zusätzlichen Puffer-Overhead bereitzustellen.

Diese Änderung betrifft nur den MQTT-Empfangspuffer
--
- Die Task-Stack-Größe von 8192 auf 16384 Wörter erhöht, um mehr Speicher für die JSON-Verarbeitung bereitzustellen
---
- Erhöhung des Keepalive-Intervalls auf 60 Sekunden
- Verbesserte Fehlerbehandlung und Debugging-Ausgaben
- Detaillierte Statusmeldungen für die MQTT-Verbindung
- Periodische Verbindungsüberprüfung alle 30 Sekunden
- Bessere Handhabung von Verbindungsverlusten
---
- Verwendung einer eindeutigen Client-ID mit Zufallssuffix
- Erhöhung der QoS (Quality of Service) auf 1 für zuverlässigere Übertragung
- Einstellung eines Socket-Timeouts von 60 Sekunden
- Aktivierung von Clean Session und Will Message
- Verbessertes Verbindungs-Logging
2025-03-14 17:42:26 +01:00
4 changed files with 225 additions and 99 deletions
+5
View File
@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
+10
View File
@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}
+17 -17
View File
@@ -60,13 +60,13 @@ function initWebSocket() {
try { try {
socket = new WebSocket('ws://' + window.location.host + '/ws'); socket = new WebSocket('ws://' + window.location.host + '/ws');
socket.onopen = function() { socket.onopen = function () {
isConnected = true; isConnected = true;
updateConnectionStatus(); updateConnectionStatus();
startHeartbeat(); // Starte Heartbeat nach erfolgreicher Verbindung startHeartbeat(); // Starte Heartbeat nach erfolgreicher Verbindung
}; };
socket.onclose = function() { socket.onclose = function () {
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
if (heartbeatTimer) clearInterval(heartbeatTimer); if (heartbeatTimer) clearInterval(heartbeatTimer);
@@ -79,7 +79,7 @@ function initWebSocket() {
} }
}; };
socket.onerror = function(error) { socket.onerror = function (error) {
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
if (heartbeatTimer) clearInterval(heartbeatTimer); if (heartbeatTimer) clearInterval(heartbeatTimer);
@@ -91,7 +91,7 @@ function initWebSocket() {
} }
}; };
socket.onmessage = function(event) { socket.onmessage = function (event) {
lastHeartbeatResponse = Date.now(); // Aktualisiere Zeitstempel bei jeder Server-Antwort lastHeartbeatResponse = Date.now(); // Aktualisiere Zeitstempel bei jeder Server-Antwort
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
@@ -115,7 +115,7 @@ function initWebSocket() {
// Add click handler only when offline // Add click handler only when offline
if (!data.bambu_connected) { if (!data.bambu_connected) {
bambuDot.style.cursor = 'pointer'; bambuDot.style.cursor = 'pointer';
bambuDot.onclick = function() { bambuDot.onclick = function () {
if (socket && socket.readyState === WebSocket.OPEN) { if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({
type: 'reconnect', type: 'reconnect',
@@ -133,7 +133,7 @@ function initWebSocket() {
// Add click handler only when offline // Add click handler only when offline
if (!data.spoolman_connected) { if (!data.spoolman_connected) {
spoolmanDot.style.cursor = 'pointer'; spoolmanDot.style.cursor = 'pointer';
spoolmanDot.onclick = function() { spoolmanDot.onclick = function () {
if (socket && socket.readyState === WebSocket.OPEN) { if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ socket.send(JSON.stringify({
type: 'reconnect', type: 'reconnect',
@@ -189,26 +189,26 @@ function updateConnectionStatus() {
} }
// Event Listeners // Event Listeners
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
initWebSocket(); initWebSocket();
// Event Listener für Checkbox // Event Listener für Checkbox
document.getElementById("onlyWithoutSmId").addEventListener("change", function() { document.getElementById("onlyWithoutSmId").addEventListener("change", function () {
const spoolsData = window.getSpoolData(); const spoolsData = window.getSpoolData();
window.populateVendorDropdown(spoolsData); window.populateVendorDropdown(spoolsData);
}); });
}); });
// Event Listener für Spoolman Events // Event Listener für Spoolman Events
document.addEventListener('spoolDataLoaded', function(event) { document.addEventListener('spoolDataLoaded', function (event) {
window.populateVendorDropdown(event.detail); window.populateVendorDropdown(event.detail);
}); });
document.addEventListener('spoolmanError', function(event) { document.addEventListener('spoolmanError', function (event) {
showNotification(`Spoolman Error: ${event.detail.message}`, false); showNotification(`Spoolman Error: ${event.detail.message}`, false);
}); });
document.addEventListener('filamentSelected', function(event) { document.addEventListener('filamentSelected', function (event) {
updateNfcInfo(); updateNfcInfo();
// Zeige Spool-Buttons wenn ein Filament ausgewählt wurde // Zeige Spool-Buttons wenn ein Filament ausgewählt wurde
const selectedText = document.getElementById("selected-filament").textContent; const selectedText = document.getElementById("selected-filament").textContent;
@@ -218,12 +218,12 @@ document.addEventListener('filamentSelected', function(event) {
// Hilfsfunktion für kontrastreiche Textfarbe // Hilfsfunktion für kontrastreiche Textfarbe
function getContrastColor(hexcolor) { function getContrastColor(hexcolor) {
// Konvertiere Hex zu RGB // Konvertiere Hex zu RGB
const r = parseInt(hexcolor.substr(0,2),16); const r = parseInt(hexcolor.substr(0, 2), 16);
const g = parseInt(hexcolor.substr(2,2),16); const g = parseInt(hexcolor.substr(2, 2), 16);
const b = parseInt(hexcolor.substr(4,2),16); const b = parseInt(hexcolor.substr(4, 2), 16);
// Berechne Helligkeit (YIQ Formel) // Berechne Helligkeit (YIQ Formel)
const yiq = ((r*299)+(g*587)+(b*114))/1000; const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
// Return schwarz oder weiß basierend auf Helligkeit // Return schwarz oder weiß basierend auf Helligkeit
return (yiq >= 128) ? '#000000' : '#FFFFFF'; return (yiq >= 128) ? '#000000' : '#FFFFFF';
@@ -283,7 +283,7 @@ function displayAmsData(amsData) {
<img src="spool_in.png" alt="Spool In" style="width: 48px; height: 48px;"> <img src="spool_in.png" alt="Spool In" style="width: 48px; height: 48px;">
</button>`; </button>`;
// Nur für nicht-leere Trays den Button-HTML erstellen // Nur für nicht-leere Trays den Button-HTML erstellen
const outButtonHtml = ` const outButtonHtml = `
<button class="spool-button" onclick="handleSpoolOut()" <button class="spool-button" onclick="handleSpoolOut()"
style="position: absolute; top: -35px; right: -15px; style="position: absolute; top: -35px; right: -15px;
@@ -490,7 +490,7 @@ function handleSpoolIn(amsId, trayId) {
nozzle_temp_max: parseInt(maxTemp), nozzle_temp_max: parseInt(maxTemp),
type: selectedSpool.filament.material, type: selectedSpool.filament.material,
brand: selectedSpool.filament.vendor.name, brand: selectedSpool.filament.vendor.name,
tray_info_idx: selectedSpool.filament.extra.bambu_idx.replace(/['"]+/g, '').trim(), tray_info_idx: selectedSpool.filament.extra.bambu_idx?.replace(/['"]+/g, '').trim() || '',
cali_idx: "-1" // Default-Wert setzen cali_idx: "-1" // Default-Wert setzen
} }
}; };
+154 -43
View File
@@ -18,7 +18,7 @@ PubSubClient client(sslClient);
TaskHandle_t BambuMqttTask; TaskHandle_t BambuMqttTask;
String report_topic = ""; String report_topic = "";
//String request_topic = ""; String request_topic = "";
const char* bambu_username = "bblp"; const char* bambu_username = "bblp";
const char* bambu_ip = nullptr; const char* bambu_ip = nullptr;
const char* bambu_accesscode = nullptr; const char* bambu_accesscode = nullptr;
@@ -92,7 +92,7 @@ bool loadBambuCredentials() {
bambu_serialnr = g_bambu_serialnr.c_str(); bambu_serialnr = g_bambu_serialnr.c_str();
report_topic = "device/" + String(bambu_serialnr) + "/report"; report_topic = "device/" + String(bambu_serialnr) + "/report";
//request_topic = "device/" + String(bambu_serialnr) + "/request"; request_topic = "device/" + String(bambu_serialnr) + "/request";
return true; return true;
} }
Serial.println("Keine gültigen Bambu-Credentials gefunden."); Serial.println("Keine gültigen Bambu-Credentials gefunden.");
@@ -197,18 +197,69 @@ FilamentResult findFilamentIdx(String brand, String type) {
} }
bool sendMqttMessage(const String& payload) { bool sendMqttMessage(const String& payload) {
Serial.println("Sending MQTT message"); // Check MQTT client state first
Serial.println(payload); if (!client.connected()) {
if (client.publish(report_topic.c_str(), payload.c_str())) Serial.println("Error: MQTT client not connected when trying to send message");
{ Serial.print("MQTT client state: ");
return true; Serial.println(client.state());
return false;
} }
return false; // Check if request_topic is empty
if (request_topic.isEmpty()) {
Serial.println("Error: request_topic is empty!");
return false;
}
// Check payload
if (payload.isEmpty()) {
Serial.println("Error: Empty payload!");
return false;
}
Serial.println("Attempting to send MQTT message:");
Serial.println("Topic: " + request_topic);
Serial.println("Payload: " + payload);
Serial.println("Payload length: " + String(payload.length()));
// Try to publish with QoS 1 and retain flag false
bool published = client.publish(request_topic.c_str(), payload.c_str(), false);
if (published) {
Serial.println("MQTT message published successfully");
return true;
} else {
Serial.println("Failed to publish MQTT message");
Serial.print("MQTT client state after publish attempt: ");
Serial.println(client.state());
// Additional error information
switch(client.state()) {
case -4:
Serial.println("Reason: Connection timeout");
break;
case -3:
Serial.println("Reason: Connection lost");
break;
case -2:
Serial.println("Reason: Connect failed");
break;
case -1:
Serial.println("Reason: Disconnected");
break;
case 0:
Serial.println("Reason: Connected but publish failed");
break;
default:
Serial.println("Reason: Unknown error");
break;
}
return false;
}
} }
bool setBambuSpool(String payload) { bool setBambuSpool(String payload) {
Serial.println("Spool settings in"); Serial.println("Spool settings received from WebSocket");
Serial.println(payload); Serial.println(payload);
// Parse the JSON // Parse the JSON
@@ -220,21 +271,28 @@ bool setBambuSpool(String payload) {
return false; return false;
} }
int amsId = doc["amsId"]; // Check if we have all required fields
int trayId = doc["trayId"]; if (!doc["amsId"].is<int>() || !doc["trayId"].is<int>()) {
Serial.println("Error: Missing or invalid required fields in payload");
return false;
}
int amsId = doc["amsId"].as<int>();
int trayId = doc["trayId"].as<int>();
String color = doc["color"].as<String>(); String color = doc["color"].as<String>();
color.toUpperCase(); color.toUpperCase();
int minTemp = doc["nozzle_temp_min"]; int minTemp = doc["nozzle_temp_min"] | 0; // Default to 0 if not present
int maxTemp = doc["nozzle_temp_max"]; int maxTemp = doc["nozzle_temp_max"] | 0; // Default to 0 if not present
String type = doc["type"].as<String>(); String type = doc["type"] | ""; // Default to empty string if not present
(type == "PLA+") ? type = "PLA" : type; (type == "PLA+") ? type = "PLA" : type;
String brand = doc["brand"].as<String>(); String brand = doc["brand"] | ""; // Default to empty string if not present
String tray_info_idx = (doc["tray_info_idx"].as<String>() != "-1") ? doc["tray_info_idx"].as<String>() : ""; String tray_info_idx = (doc["tray_info_idx"].as<String>() != "-1") ? doc["tray_info_idx"].as<String>() : "";
if (tray_info_idx == "") { if (tray_info_idx == "") {
if (brand != "" && type != "") { if (brand != "" && type != "") {
FilamentResult result = findFilamentIdx(brand, type); FilamentResult result = findFilamentIdx(brand, type);
tray_info_idx = result.key; tray_info_idx = result.key;
type = result.type; // Aktualisiere den type mit dem gefundenen Basistyp type = result.type; // Aktualisiere den type mit dem gefundenen Basistyp
Serial.println("Found filament idx: " + tray_info_idx + " for type: " + type);
} }
} }
String setting_id = doc["bambu_setting_id"].as<String>(); String setting_id = doc["bambu_setting_id"].as<String>();
@@ -242,6 +300,7 @@ bool setBambuSpool(String payload) {
doc.clear(); doc.clear();
// Create MQTT message
doc["print"]["sequence_id"] = "0"; doc["print"]["sequence_id"] = "0";
doc["print"]["command"] = "ams_filament_setting"; doc["print"]["command"] = "ams_filament_setting";
doc["print"]["ams_id"] = amsId < 200 ? amsId : 255; doc["print"]["ams_id"] = amsId < 200 ? amsId : 255;
@@ -250,26 +309,25 @@ bool setBambuSpool(String payload) {
doc["print"]["nozzle_temp_min"] = minTemp; doc["print"]["nozzle_temp_min"] = minTemp;
doc["print"]["nozzle_temp_max"] = maxTemp; doc["print"]["nozzle_temp_max"] = maxTemp;
doc["print"]["tray_type"] = type; doc["print"]["tray_type"] = type;
//doc["print"]["cali_idx"] = (cali_idx != "") ? cali_idx : "";
doc["print"]["tray_info_idx"] = tray_info_idx; doc["print"]["tray_info_idx"] = tray_info_idx;
doc["print"]["setting_id"] = setting_id; doc["print"]["setting_id"] = setting_id;
// Serialize the JSON // Serialize and send MQTT message
String output; String output;
serializeJson(doc, output); serializeJson(doc, output);
Serial.println("Sending to Bambu printer:");
Serial.println(output);
if (sendMqttMessage(output)) { if (!sendMqttMessage(output)) {
Serial.println("Spool successfully set"); Serial.println("Failed to send filament settings to printer");
}
else
{
Serial.println("Failed to set spool");
return false; return false;
} }
Serial.println("Filament settings sent successfully");
doc.clear(); doc.clear();
yield(); yield();
// Send calibration if available
if (cali_idx != "") { if (cali_idx != "") {
yield(); yield();
doc["print"]["sequence_id"] = "0"; doc["print"]["sequence_id"] = "0";
@@ -278,21 +336,18 @@ bool setBambuSpool(String payload) {
doc["print"]["nozzle_diameter"] = "0.4"; doc["print"]["nozzle_diameter"] = "0.4";
doc["print"]["cali_idx"] = cali_idx.toInt(); doc["print"]["cali_idx"] = cali_idx.toInt();
doc["print"]["tray_id"] = trayId < 200 ? trayId : 254; doc["print"]["tray_id"] = trayId < 200 ? trayId : 254;
//doc["print"]["ams_id"] = amsId < 200 ? amsId : 255;
// Serialize the JSON
String output; String output;
serializeJson(doc, output); serializeJson(doc, output);
Serial.println("Sending calibration to printer:");
Serial.println(output);
if (sendMqttMessage(output)) { if (!sendMqttMessage(output)) {
Serial.println("Extrusion calibration successfully set"); Serial.println("Failed to send calibration settings to printer");
}
else
{
Serial.println("Failed to set extrusion calibration");
return false; return false;
} }
Serial.println("Calibration settings sent successfully");
doc.clear(); doc.clear();
yield(); yield();
} }
@@ -549,20 +604,47 @@ void reconnect() {
uint8_t retries = 0; uint8_t retries = 0;
while (!client.connected()) { while (!client.connected()) {
Serial.println("Attempting MQTT re/connection..."); Serial.println("Attempting MQTT re/connection...");
Serial.print("State before connect: ");
Serial.println(client.state());
bambu_connected = false; bambu_connected = false;
oledShowTopRow(); oledShowTopRow();
// Attempt to connect // Generate a random client ID suffix
if (client.connect(bambu_serialnr, bambu_username, bambu_accesscode)) { String clientId = String(bambu_serialnr) + "_" + String(random(0xffff), HEX);
Serial.print("Reconnecting with client ID: ");
Serial.println(clientId);
// Attempt to connect with clean session and will message
if (client.connect(clientId.c_str(), bambu_username, bambu_accesscode, nullptr, 0, true, nullptr)) {
Serial.println("MQTT re/connected"); Serial.println("MQTT re/connected");
client.subscribe(report_topic.c_str()); // Subscribe with QoS 1
if (client.subscribe(report_topic.c_str(), 1)) {
Serial.println("Successfully subscribed to topic with QoS 1: " + report_topic);
} else {
Serial.println("Failed to subscribe to topic: " + report_topic);
}
bambu_connected = true; bambu_connected = true;
oledShowTopRow(); oledShowTopRow();
} else { } else {
int state = client.state();
Serial.print("failed, rc="); Serial.print("failed, rc=");
Serial.print(client.state()); Serial.print(state);
Serial.println(" try again in 5 seconds"); Serial.print(" (");
// Print detailed error message
switch(state) {
case -4: Serial.print("MQTT_CONNECTION_TIMEOUT"); break;
case -3: Serial.print("MQTT_CONNECTION_LOST"); break;
case -2: Serial.print("MQTT_CONNECT_FAILED"); break;
case -1: Serial.print("MQTT_DISCONNECTED"); break;
case 1: Serial.print("MQTT_CONNECT_BAD_PROTOCOL"); break;
case 2: Serial.print("MQTT_CONNECT_BAD_CLIENT_ID"); break;
case 3: Serial.print("MQTT_CONNECT_UNAVAILABLE"); break;
case 4: Serial.print("MQTT_CONNECT_BAD_CREDENTIALS"); break;
case 5: Serial.print("MQTT_CONNECT_UNAUTHORIZED"); break;
default: Serial.print("UNKNOWN"); break;
}
Serial.println(") try again in 5 seconds");
bambu_connected = false; bambu_connected = false;
oledShowTopRow(); oledShowTopRow();
@@ -570,11 +652,9 @@ void reconnect() {
vTaskDelay(5000 / portTICK_PERIOD_MS); vTaskDelay(5000 / portTICK_PERIOD_MS);
if (retries > 5) { if (retries > 5) {
Serial.println("Disable Bambu MQTT Task after 5 retries"); Serial.println("Disable Bambu MQTT Task after 5 retries");
//vTaskSuspend(BambuMqttTask);
vTaskDelete(BambuMqttTask); vTaskDelete(BambuMqttTask);
break; break;
} }
retries++; retries++;
} }
} }
@@ -582,17 +662,32 @@ void reconnect() {
void mqtt_loop(void * parameter) { void mqtt_loop(void * parameter) {
Serial.println("Bambu MQTT Task gestartet"); Serial.println("Bambu MQTT Task gestartet");
unsigned long lastCheck = 0;
for(;;) { for(;;) {
if (pauseBambuMqttTask) { if (pauseBambuMqttTask) {
vTaskDelay(10000); vTaskDelay(10000);
continue;
} }
unsigned long now = millis();
if (!client.connected()) { if (!client.connected()) {
Serial.println("Connection lost, attempting reconnect...");
reconnect(); reconnect();
yield(); yield();
esp_task_wdt_reset(); esp_task_wdt_reset();
vTaskDelay(100); vTaskDelay(100);
continue;
} }
// Periodically check connection status
if (now - lastCheck > 30000) { // Check every 30 seconds
Serial.print("MQTT Status Check - Connected: ");
Serial.println(client.connected() ? "Yes" : "No");
lastCheck = now;
}
client.loop(); client.loop();
yield(); yield();
esp_task_wdt_reset(); esp_task_wdt_reset();
@@ -617,14 +712,30 @@ bool setupMqtt() {
sslClient.setInsecure(); sslClient.setInsecure();
client.setServer(bambu_ip, 8883); client.setServer(bambu_ip, 8883);
// Generate a random client ID suffix
String clientId = String(bambu_serialnr) + "_" + String(random(0xffff), HEX);
// MQTT Connection Options
client.setKeepAlive(60);
client.setSocketTimeout(60); // Increase socket timeout
Serial.print("Connecting with client ID: ");
Serial.println(clientId);
// Verbinden mit dem MQTT-Server // Verbinden mit dem MQTT-Server
bool connected = true; bool connected = true;
if (client.connect(bambu_serialnr, bambu_username, bambu_accesscode)) if (client.connect(clientId.c_str(), bambu_username, bambu_accesscode, nullptr, 0, true, nullptr))
{ {
client.setCallback(mqtt_callback); client.setCallback(mqtt_callback);
client.setBufferSize(5120); client.setBufferSize(16384); // Increased to 16KB to handle larger JSON
client.subscribe(report_topic.c_str());
//client.subscribe(request_topic.c_str()); // Subscribe with QoS 1
if (client.subscribe(report_topic.c_str(), 1)) {
Serial.println("Successfully subscribed to topic with QoS 1: " + report_topic);
} else {
Serial.println("Failed to subscribe to topic: " + report_topic);
}
Serial.println("MQTT-Client initialisiert"); Serial.println("MQTT-Client initialisiert");
oledShowMessage("Bambu Connected"); oledShowMessage("Bambu Connected");
@@ -634,7 +745,7 @@ bool setupMqtt() {
xTaskCreatePinnedToCore( xTaskCreatePinnedToCore(
mqtt_loop, /* Function to implement the task */ mqtt_loop, /* Function to implement the task */
"BambuMqtt", /* Name of the task */ "BambuMqtt", /* Name of the task */
8192, /* Stack size in words */ 16384, /* Stack size in words */
NULL, /* Task input parameter */ NULL, /* Task input parameter */
mqttTaskPrio, /* Priority of the task */ mqttTaskPrio, /* Priority of the task */
&BambuMqttTask, /* Task handle. */ &BambuMqttTask, /* Task handle. */