#include "api.h" #include #include #include "commonFS.h" bool spoolman_connected = false; String spoolmanUrl = ""; struct SendToApiParams { String httpType; String spoolsUrl; String updatePayload; }; /* // Spoolman Data { "version":"1.0", "protocol":"openspool", "color_hex":"AF7933", "type":"ABS", "min_temp":175, "max_temp":275, "brand":"Overture" } // FilaMan Data { "version":"1.0", "protocol":"openspool", "color_hex":"AF7933", "type":"ABS", "min_temp":175, "max_temp":275, "brand":"Overture", "sm_id": } */ JsonDocument fetchSingleSpoolInfo(int spoolId) { HTTPClient http; String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId; Serial.print("Rufe Spool-Daten von: "); Serial.println(spoolsUrl); http.begin(spoolsUrl); int httpCode = http.GET(); JsonDocument filteredDoc; if (httpCode == HTTP_CODE_OK) { String payload = http.getString(); JsonDocument doc; DeserializationError error = deserializeJson(doc, payload); if (error) { Serial.print("Fehler beim Parsen der JSON-Antwort: "); Serial.println(error.c_str()); } else { String filamentType = doc["filament"]["material"].as(); String filamentBrand = doc["filament"]["vendor"]["name"].as(); int nozzle_temp_min = 0; int nozzle_temp_max = 0; if (doc["filament"]["extra"]["nozzle_temperature"].is()) { String tempString = doc["filament"]["extra"]["nozzle_temperature"].as(); tempString.replace("[", ""); tempString.replace("]", ""); int commaIndex = tempString.indexOf(','); if (commaIndex != -1) { nozzle_temp_min = tempString.substring(0, commaIndex).toInt(); nozzle_temp_max = tempString.substring(commaIndex + 1).toInt(); } } String filamentColor = doc["filament"]["color_hex"].as(); filamentColor.toUpperCase(); String tray_info_idx = doc["filament"]["extra"]["bambu_idx"].as(); tray_info_idx.replace("\"", ""); String cali_idx = doc["filament"]["extra"]["bambu_cali_id"].as(); // "\"153\"" cali_idx.replace("\"", ""); String bambu_setting_id = doc["filament"]["extra"]["bambu_setting_id"].as(); // "\"PFUSf40e9953b40d3d\"" bambu_setting_id.replace("\"", ""); doc.clear(); filteredDoc["color"] = filamentColor; filteredDoc["type"] = filamentType; filteredDoc["nozzle_temp_min"] = nozzle_temp_min; filteredDoc["nozzle_temp_max"] = nozzle_temp_max; filteredDoc["brand"] = filamentBrand; filteredDoc["tray_info_idx"] = tray_info_idx; filteredDoc["cali_idx"] = cali_idx; filteredDoc["bambu_setting_id"] = bambu_setting_id; } } else { Serial.print("Fehler beim Abrufen der Spool-Daten. HTTP-Code: "); Serial.println(httpCode); } http.end(); return filteredDoc; } void sendToApi(void *parameter) { SendToApiParams* params = (SendToApiParams*)parameter; // Extrahiere die Werte String httpType = params->httpType; String spoolsUrl = params->spoolsUrl; String updatePayload = params->updatePayload; HTTPClient http; http.begin(spoolsUrl); http.addHeader("Content-Type", "application/json"); int httpCode = http.PUT(updatePayload); if (httpType == "PATCH") httpCode = http.PATCH(updatePayload); if (httpCode == HTTP_CODE_OK) { Serial.println("Gewicht der Spule erfolgreich aktualisiert"); } else { Serial.println("Fehler beim Aktualisieren des Gewichts der Spule"); oledShowMessage("Spoolman update failed"); vTaskDelay(2000 / portTICK_PERIOD_MS); } http.end(); // Speicher freigeben delete params; vTaskDelete(NULL); } bool updateSpoolTagId(String uidString, const char* payload) { JsonDocument doc; DeserializationError error = deserializeJson(doc, payload); if (error) { Serial.print("Fehler beim JSON-Parsing: "); Serial.println(error.c_str()); return false; } // Überprüfe, ob die erforderlichen Felder vorhanden sind if (!doc["sm_id"].is() || doc["sm_id"].as() == "") { Serial.println("Keine Spoolman-ID gefunden."); return false; } String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + doc["sm_id"].as(); Serial.print("Update Spule mit URL: "); Serial.println(spoolsUrl); // Update Payload erstellen JsonDocument updateDoc; updateDoc["extra"]["nfc_id"] = "\""+uidString+"\""; 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; } uint8_t updateSpoolWeight(String spoolId, uint16_t weight) { String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId + "/measure"; Serial.print("Update Spule mit URL: "); Serial.println(spoolsUrl); // Update Payload erstellen JsonDocument updateDoc; updateDoc["weight"] = weight; 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 0; } params->httpType = "PUT"; 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 1; } // #### Spoolman init bool checkSpoolmanExtraFields() { HTTPClient http; String checkUrls[] = { spoolmanUrl + apiUrl + "/field/spool", spoolmanUrl + apiUrl + "/field/filament" }; String spoolExtra[] = { "nfc_id" }; String filamentExtra[] = { "nozzle_temperature", "price_meter", "price_gramm", "bambu_setting_id", "bambu_cali_id", "bambu_idx", "bambu_k", "bambu_flow_ratio", "bambu_max_volspeed" }; String spoolExtraFields[] = { "{\"name\": \"NFC ID\"," "\"key\": \"nfc_id\"," "\"field_type\": \"text\"}" }; String filamentExtraFields[] = { "{\"name\": \"Nozzle Temp\"," "\"unit\": \"°C\"," "\"field_type\": \"integer_range\"," "\"default_value\": \"[190,230]\"," "\"key\": \"nozzle_temperature\"}", "{\"name\": \"Price/m\"," "\"unit\": \"€\"," "\"field_type\": \"float\"," "\"key\": \"price_meter\"}", "{\"name\": \"Price/g\"," "\"unit\": \"€\"," "\"field_type\": \"float\"," "\"key\": \"price_gramm\"}", "{\"name\": \"Bambu Setting ID\"," "\"field_type\": \"text\"," "\"key\": \"bambu_setting_id\"}", "{\"name\": \"Bambu Cali ID\"," "\"field_type\": \"text\"," "\"key\": \"bambu_cali_id\"}", "{\"name\": \"Bambu Filament IDX\"," "\"field_type\": \"text\"," "\"key\": \"bambu_idx\"}", "{\"name\": \"Bambu k\"," "\"field_type\": \"float\"," "\"key\": \"bambu_k\"}", "{\"name\": \"Bambu Flow Ratio\"," "\"field_type\": \"float\"," "\"key\": \"bambu_flow_ratio\"}", "{\"name\": \"Bambu Max Vol. Speed\"," "\"unit\": \"mm3/s\"," "\"field_type\": \"integer\"," "\"default_value\": \"12\"," "\"key\": \"bambu_max_volspeed\"}" }; Serial.println("Überprüfe Extrafelder..."); int urlLength = sizeof(checkUrls) / sizeof(checkUrls[0]); for (uint8_t i = 0; i < urlLength; i++) { Serial.println(); Serial.println("-------- Prüfe Felder für "+checkUrls[i]+" --------"); http.begin(checkUrls[i]); int httpCode = http.GET(); if (httpCode == HTTP_CODE_OK) { String payload = http.getString(); JsonDocument doc; DeserializationError error = deserializeJson(doc, payload); if (!error) { String* extraFields; String* extraFieldData; u16_t extraLength; if (i == 0) { extraFields = spoolExtra; extraFieldData = spoolExtraFields; extraLength = sizeof(spoolExtra) / sizeof(spoolExtra[0]); } else { extraFields = filamentExtra; extraFieldData = filamentExtraFields; extraLength = sizeof(filamentExtra) / sizeof(filamentExtra[0]); } for (uint8_t s = 0; s < extraLength; s++) { bool found = false; for (JsonObject field : doc.as()) { if (field["key"].is() && field["key"] == extraFields[s]) { Serial.println("Feld gefunden: " + extraFields[s]); found = true; break; } } if (!found) { Serial.println("Feld nicht gefunden: " + extraFields[s]); // Extrafeld hinzufügen http.begin(checkUrls[i] + "/" + extraFields[s]); http.addHeader("Content-Type", "application/json"); int httpCode = http.POST(extraFieldData[s]); if (httpCode > 0) { // Antwortscode und -nachricht abrufen String response = http.getString(); //Serial.println("HTTP-Code: " + String(httpCode)); //Serial.println("Antwort: " + response); if (httpCode != HTTP_CODE_OK) { return false; } } else { // Fehler beim Senden der Anfrage Serial.println("Fehler beim Senden der Anfrage: " + String(http.errorToString(httpCode))); return false; } //http.end(); } yield(); vTaskDelay(100 / portTICK_PERIOD_MS); } } } http.end(); } Serial.println("-------- ENDE Prüfe Felder --------"); Serial.println(); return true; } bool checkSpoolmanInstance(const String& url) { HTTPClient http; String healthUrl = url + apiUrl + "/health"; Serial.print("Überprüfe Spoolman-Instanz unter: "); Serial.println(healthUrl); http.begin(healthUrl); int httpCode = http.GET(); if (httpCode > 0) { if (httpCode == HTTP_CODE_OK) { oledShowMessage("Spoolman available"); vTaskDelay(1000 / portTICK_PERIOD_MS); String payload = http.getString(); JsonDocument doc; DeserializationError error = deserializeJson(doc, payload); if (!error && doc["status"].is()) { const char* status = doc["status"]; http.end(); if (!checkSpoolmanExtraFields()) { Serial.println("Fehler beim Überprüfen der Extrafelder."); oledShowMessage("Spoolman Error creating Extrafields"); vTaskDelay(2000 / portTICK_PERIOD_MS); return false; } spoolman_connected = true; return strcmp(status, "healthy") == 0; } } } http.end(); return false; } bool saveSpoolmanUrl(const String& url) { if (!checkSpoolmanInstance(url)) return false; JsonDocument doc; doc["url"] = url; Serial.print("Speichere URL in Datei: "); Serial.println(url); if (!saveJsonValue("/spoolman_url.json", doc)) { Serial.println("Fehler beim Speichern der Spoolman-URL."); } spoolmanUrl = url; return true; } String loadSpoolmanUrl() { JsonDocument doc; if (loadJsonValue("/spoolman_url.json", doc) && doc["url"].is()) { return doc["url"].as(); } Serial.println("Keine gültige Spoolman-URL gefunden."); return ""; } bool initSpoolman() { spoolmanUrl = loadSpoolmanUrl(); spoolmanUrl.trim(); if (spoolmanUrl == "") { Serial.println("Keine Spoolman-URL gefunden."); return false; } bool success = checkSpoolmanInstance(spoolmanUrl); if (!success) { Serial.println("Spoolman nicht erreichbar."); return false; } oledShowTopRow(); return true; }