Compare commits

..

8 Commits

Author SHA1 Message Date
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
Manuel Weiser 3eac0e5ac4 update Discord Link 2025-03-15 16:02:18 +01:00
Manuel Weiser 24d91693d9 update Discord Link 2025-03-15 15:57:46 +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
Manuel Weiser 94c26590c8 remove commented-out subscription topic in MQTT setup 2025-03-10 17:41:14 +01:00
7 changed files with 322 additions and 141 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"
]
}
+1 -1
View File
@@ -9,7 +9,7 @@ Das System integriert sich nahtlos mit der [Spoolman](https://github.com/Donkie/
Weitere Bilder finden Sie im [img Ordner](/img/) Weitere Bilder finden Sie im [img Ordner](/img/)
oder auf meiner Website: [FilaMan Website](https://www.filaman.app) oder auf meiner Website: [FilaMan Website](https://www.filaman.app)
Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU) Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU)
Discord Server: [https://discord.gg/vMAx2gf5](https://discord.gg/vMAx2gf5) Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
### Es gibt jetzt auch ein Wiki, dort sind nochmal alle Funktionen beschrieben: [Wiki](https://github.com/ManuelW77/Filaman/wiki) ### Es gibt jetzt auch ein Wiki, dort sind nochmal alle Funktionen beschrieben: [Wiki](https://github.com/ManuelW77/Filaman/wiki)
+1 -1
View File
@@ -13,7 +13,7 @@ The system integrates seamlessly with [Bambu Lab](https://bambulab.com/en-us) 3D
More Images can be found in the [img Folder](/img/) More Images can be found in the [img Folder](/img/)
or my website: [FilaMan Website](https://www.filaman.app) or my website: [FilaMan Website](https://www.filaman.app)
german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU) german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU)
Discord Server: [https://discord.gg/vMAx2gf5](https://discord.gg/vMAx2gf5) Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
### Now more detailed informations about the usage: [Wiki](https://github.com/ManuelW77/Filaman/wiki) ### Now more detailed informations about the usage: [Wiki](https://github.com/ManuelW77/Filaman/wiki)
+149 -93
View File
@@ -53,7 +53,13 @@ function initWebSocket() {
// Wenn eine existierende Verbindung besteht, diese erst schließen // Wenn eine existierende Verbindung besteht, diese erst schließen
if (socket) { if (socket) {
socket.close(); try {
socket.onclose = null; // Remove onclose handler before closing
socket.onerror = null; // Remove error handler
socket.close();
} catch (e) {
console.error('Error closing existing socket:', e);
}
socket = null; socket = null;
} }
@@ -61,110 +67,80 @@ function initWebSocket() {
socket = new WebSocket('ws://' + window.location.host + '/ws'); socket = new WebSocket('ws://' + window.location.host + '/ws');
socket.onopen = function() { socket.onopen = function() {
console.log('WebSocket connection established');
isConnected = true; isConnected = true;
updateConnectionStatus(); updateConnectionStatus();
startHeartbeat(); // Starte Heartbeat nach erfolgreicher Verbindung startHeartbeat(); // Starte Heartbeat nach erfolgreicher Verbindung
}; };
socket.onclose = function() { socket.onclose = function(event) {
console.log('WebSocket connection closed:', event.code, event.reason);
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
if (heartbeatTimer) clearInterval(heartbeatTimer); if (heartbeatTimer) {
clearInterval(heartbeatTimer);
heartbeatTimer = null;
}
// Nur neue Verbindung versuchen, wenn kein Timer läuft // Nur neue Verbindung versuchen, wenn kein Timer läuft
if (!reconnectTimer) { if (!reconnectTimer) {
reconnectTimer = setTimeout(() => { reconnectTimer = setTimeout(() => {
console.log('Attempting to reconnect...');
initWebSocket(); initWebSocket();
}, RECONNECT_INTERVAL); }, RECONNECT_INTERVAL);
} }
}; };
socket.onerror = function(error) { socket.onerror = function(error) {
console.error('WebSocket error occurred:', error);
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
if (heartbeatTimer) clearInterval(heartbeatTimer); if (heartbeatTimer) {
clearInterval(heartbeatTimer);
// Bei Fehler Verbindung schließen und neu aufbauen heartbeatTimer = null;
if (socket) {
socket.close();
socket = null;
} }
}; };
socket.onmessage = function(event) { socket.onmessage = function(event) {
lastHeartbeatResponse = Date.now(); // Aktualisiere Zeitstempel bei jeder Server-Antwort try {
lastHeartbeatResponse = Date.now();
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.type === 'amsData') {
displayAmsData(data.payload);
} else if (data.type === 'nfcTag') {
updateNfcStatusIndicator(data.payload);
} else if (data.type === 'nfcData') {
updateNfcData(data.payload);
} else if (data.type === 'writeNfcTag') {
handleWriteNfcTagResponse(data.success);
} else if (data.type === 'heartbeat') {
// Optional: Spezifische Behandlung von Heartbeat-Antworten
// Update status dots
const bambuDot = document.getElementById('bambuDot');
const spoolmanDot = document.getElementById('spoolmanDot');
const ramStatus = document.getElementById('ramStatus');
if (bambuDot) { // Handle different message types
bambuDot.className = 'status-dot ' + (data.bambu_connected ? 'online' : 'offline'); switch(data.type) {
// Add click handler only when offline case 'amsData':
if (!data.bambu_connected) { displayAmsData(data.payload);
bambuDot.style.cursor = 'pointer'; break;
bambuDot.onclick = function() { case 'nfcTag':
if (socket && socket.readyState === WebSocket.OPEN) { updateNfcStatusIndicator(data.payload);
socket.send(JSON.stringify({ break;
type: 'reconnect', case 'nfcData':
payload: 'bambu' updateNfcData(data.payload);
})); break;
} case 'writeNfcTag':
}; handleWriteNfcTagResponse(data.success);
} else { break;
bambuDot.style.cursor = 'default'; case 'heartbeat':
bambuDot.onclick = null; handleHeartbeatResponse(data);
} break;
} case 'setSpoolmanSettings':
if (spoolmanDot) { handleSpoolmanSettingsResponse(data);
spoolmanDot.className = 'status-dot ' + (data.spoolman_connected ? 'online' : 'offline'); break;
// Add click handler only when offline default:
if (!data.spoolman_connected) { console.warn('Unknown message type:', data.type);
spoolmanDot.style.cursor = 'pointer';
spoolmanDot.onclick = function() {
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({
type: 'reconnect',
payload: 'spoolman'
}));
}
};
} else {
spoolmanDot.style.cursor = 'default';
spoolmanDot.onclick = null;
}
}
if (ramStatus) {
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) {
console.error('Error processing WebSocket message:', error);
} }
}; };
} catch (error) { } catch (error) {
console.error('Error initializing WebSocket:', error);
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
// Nur neue Verbindung versuchen, wenn kein Timer läuft
if (!reconnectTimer) { if (!reconnectTimer) {
reconnectTimer = setTimeout(() => { reconnectTimer = setTimeout(() => {
console.log('Attempting to reconnect after error...');
initWebSocket(); initWebSocket();
}, RECONNECT_INTERVAL); }, RECONNECT_INTERVAL);
} }
@@ -389,6 +365,7 @@ function updateSpoolButtons(show) {
}); });
} }
// Verbesserte Funktion zum Behandeln von Spoolman Settings
function handleSpoolmanSettings(tray_info_idx, setting_id, cali_idx, nozzle_temp_min, nozzle_temp_max) { function handleSpoolmanSettings(tray_info_idx, setting_id, cali_idx, nozzle_temp_min, nozzle_temp_max) {
// Hole das ausgewählte Filament // Hole das ausgewählte Filament
const selectedText = document.getElementById("selected-filament").textContent; const selectedText = document.getElementById("selected-filament").textContent;
@@ -419,6 +396,7 @@ function handleSpoolmanSettings(tray_info_idx, setting_id, cali_idx, nozzle_temp
} }
} }
// Verbesserte Funktion zum Behandeln von Spool Out
function handleSpoolOut() { function handleSpoolOut() {
// Erstelle Payload // Erstelle Payload
const payload = { const payload = {
@@ -443,17 +421,21 @@ function handleSpoolOut() {
} }
} }
// Neue Funktion zum Behandeln des Spool-In-Klicks // Verbesserte Funktion zum Behandeln des Spool-In-Klicks
function handleSpoolIn(amsId, trayId) { function handleSpoolIn(amsId, trayId) {
console.log("handleSpoolIn called with amsId:", amsId, "trayId:", trayId);
// Prüfe WebSocket Verbindung zuerst // Prüfe WebSocket Verbindung zuerst
if (!socket || socket.readyState !== WebSocket.OPEN) { if (!socket || socket.readyState !== WebSocket.OPEN) {
showNotification("No active WebSocket connection!", false); showNotification("No active WebSocket connection!", false);
console.error("WebSocket not connected"); console.error("WebSocket not connected, state:", socket ? socket.readyState : "no socket");
return; return;
} }
// Hole das ausgewählte Filament // Hole das ausgewählte Filament
const selectedText = document.getElementById("selected-filament").textContent; const selectedText = document.getElementById("selected-filament").textContent;
console.log("Selected filament:", selectedText);
if (selectedText === "Please choose...") { if (selectedText === "Please choose...") {
showNotification("Choose Filament first", false); showNotification("Choose Filament first", false);
return; return;
@@ -466,53 +448,55 @@ function handleSpoolIn(amsId, trayId) {
if (!selectedSpool) { if (!selectedSpool) {
showNotification("Selected Spool not found", false); showNotification("Selected Spool not found", false);
console.error("Selected spool not found in spoolsData");
return; return;
} }
console.log("Found spool data:", selectedSpool);
// Temperaturwerte extrahieren // Temperaturwerte extrahieren
let minTemp = "175"; let minTemp = "175";
let maxTemp = "275"; let maxTemp = "275";
if (Array.isArray(selectedSpool.filament.nozzle_temperature) && if (selectedSpool.filament &&
Array.isArray(selectedSpool.filament.nozzle_temperature) &&
selectedSpool.filament.nozzle_temperature.length >= 2) { selectedSpool.filament.nozzle_temperature.length >= 2) {
minTemp = selectedSpool.filament.nozzle_temperature[0]; minTemp = selectedSpool.filament.nozzle_temperature[0];
maxTemp = selectedSpool.filament.nozzle_temperature[1]; maxTemp = selectedSpool.filament.nozzle_temperature[1];
} }
// Extrahiere bambu_idx
let bambuIdx = "GFL99"; // Default zu Generic PLA
if (selectedSpool.filament?.extra?.bambu_idx) {
bambuIdx = selectedSpool.filament.extra.bambu_idx.replace(/['"]/g, '');
} else if (selectedSpool.extra?.bambu_idx) {
bambuIdx = selectedSpool.extra.bambu_idx.replace(/['"]/g, '');
}
// Erstelle Payload // Erstelle Payload
const payload = { const payload = {
type: 'setBambuSpool', type: 'setBambuSpool',
payload: { payload: {
amsId: amsId, amsId: amsId,
trayId: trayId, trayId: trayId,
color: selectedSpool.filament.color_hex || "FFFFFF", color: selectedSpool.filament && selectedSpool.filament.color_hex ? selectedSpool.filament.color_hex : "FFFFFF",
nozzle_temp_min: parseInt(minTemp), nozzle_temp_min: parseInt(minTemp),
nozzle_temp_max: parseInt(maxTemp), nozzle_temp_max: parseInt(maxTemp),
type: selectedSpool.filament.material, type: selectedSpool.filament && selectedSpool.filament.material ? selectedSpool.filament.material : "PLA",
brand: selectedSpool.filament.vendor.name, brand: selectedSpool.filament && selectedSpool.filament.vendor ? selectedSpool.filament.vendor.name : "",
tray_info_idx: selectedSpool.filament.extra.bambu_idx.replace(/['"]+/g, '').trim(), tray_info_idx: bambuIdx,
cali_idx: "-1" // Default-Wert setzen cali_idx: "-1" // Default-Wert setzen
} }
}; };
// Prüfe, ob der Key cali_idx vorhanden ist und setze ihn console.log("Sending payload:", payload);
if (selectedSpool.filament.extra.bambu_cali_id) {
payload.payload.cali_idx = selectedSpool.filament.extra.bambu_cali_id.replace(/['"]+/g, '').trim();
}
// Prüfe, ob der Key bambu_setting_id vorhanden ist
if (selectedSpool.filament.extra.bambu_setting_id) {
payload.payload.bambu_setting_id = selectedSpool.filament.extra.bambu_setting_id.replace(/['"]+/g, '').trim();
}
console.log("Spool-In Payload:", payload);
try { try {
socket.send(JSON.stringify(payload)); socket.send(JSON.stringify(payload));
showNotification(`Spool set in AMS ${amsId} Tray ${trayId}. Pls wait`, true); showNotification(`Spool settings sent to printer. Please wait...`, true);
} catch (error) { } catch (error) {
console.error("Fehler beim Senden der WebSocket Nachricht:", error); console.error("Error sending WebSocket message:", error);
showNotification("Error while sending", false); showNotification("Error sending spool settings!", false);
} }
} }
@@ -687,3 +671,75 @@ function showNotification(message, isSuccess) {
}, 300); }, 300);
}, 3000); }, 3000);
} }
// Neue Handler-Funktionen für bessere Modularität
function handleHeartbeatResponse(data) {
const bambuDot = document.getElementById('bambuDot');
const spoolmanDot = document.getElementById('spoolmanDot');
const ramStatus = document.getElementById('ramStatus');
if (bambuDot) {
bambuDot.className = 'status-dot ' + (data.bambu_connected ? 'online' : 'offline');
if (!data.bambu_connected) {
bambuDot.style.cursor = 'pointer';
bambuDot.onclick = function() {
sendReconnectRequest('bambu');
};
} else {
bambuDot.style.cursor = 'default';
bambuDot.onclick = null;
}
}
if (spoolmanDot) {
spoolmanDot.className = 'status-dot ' + (data.spoolman_connected ? 'online' : 'offline');
if (!data.spoolman_connected) {
spoolmanDot.style.cursor = 'pointer';
spoolmanDot.onclick = function() {
sendReconnectRequest('spoolman');
};
} else {
spoolmanDot.style.cursor = 'default';
spoolmanDot.onclick = null;
}
}
if (ramStatus) {
ramStatus.textContent = `${data.freeHeap}k`;
}
}
function handleSpoolmanSettingsResponse(data) {
if (data.payload === 'success') {
showNotification(`Spoolman Settings set successfully`, true);
} else {
showNotification(`Error setting Spoolman Settings`, false);
}
}
function sendReconnectRequest(target) {
if (socket?.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({
type: 'reconnect',
payload: target
}));
}
}
// Verbesserte Funktion zum Senden von WebSocket-Nachrichten
function sendWebSocketMessage(message) {
if (!socket || socket.readyState !== WebSocket.OPEN) {
console.error('WebSocket is not connected');
showNotification("Connection error - please try again", false);
return;
}
try {
const jsonString = JSON.stringify(message);
console.log('Sending WebSocket message:', jsonString);
socket.send(jsonString);
} catch (error) {
console.error('Error sending WebSocket message:', error);
showNotification("Error sending message", false);
}
}
+155 -45
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;
} }
// 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()));
return false; // 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.println("MQTT re/connected"); Serial.print("Reconnecting with client ID: ");
Serial.println(clientId);
client.subscribe(report_topic.c_str()); // 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");
// 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,15 +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
// Optional: Topic abonnieren
client.subscribe(report_topic.c_str()); // Subscribe with QoS 1
//client.subscribe(request_topic.c_str()); 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");
@@ -635,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. */
+1 -1
View File
@@ -59,7 +59,7 @@ void initWiFi() {
if(wm_nonblocking) wm.setConfigPortalBlocking(false); if(wm_nonblocking) wm.setConfigPortalBlocking(false);
//wm.setConfigPortalTimeout(320); // Portal nach 5min schließen //wm.setConfigPortalTimeout(320); // Portal nach 5min schließen
wm.setWiFiAutoReconnect(true); wm.setWiFiAutoReconnect(true);
wm.setConnectTimeout(10); wm.setConnectTimeout(5);
oledShowTopRow(); oledShowTopRow();
oledShowMessage("WiFi Setup"); oledShowMessage("WiFi Setup");