Compare commits
	
		
			33 Commits
		
	
	
		
			v1.5.12-be
			...
			v1.5.12-be
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 02febfa943 | |||
| 257f4df800 | |||
| bff6e72219 | |||
| 26e905050d | |||
| 046f770a52 | |||
| 2587227e78 | |||
| 0f19dc4f46 | |||
| 721dac1ead | |||
| 08abd1a37f | |||
| da78861613 | |||
| 9231a303f3 | |||
| d12e766cd7 | |||
| af7bc23703 | |||
| de39892f64 | |||
| 40cb835e51 | |||
| eb9d9e74f4 | |||
| d8af3f45e5 | |||
| 96bb8f9c7c | |||
| b8b6893cd0 | |||
| 0a246c1fe4 | |||
| 965ea5da1e | |||
| b8b6f637f2 | |||
| 12044b657b | |||
| 95433b4842 | |||
| 54275f2ac9 | |||
| fbd9cb66f1 | |||
| f1cdd3f41d | |||
| d897817020 | |||
| 686eb22232 | |||
| a2816da654 | |||
| cc8f1cfd7b | |||
| d195f76d5e | |||
| 6bed3b086c | 
							
								
								
									
										81
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,5 +1,86 @@ | |||||||
| # Changelog | # Changelog | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta12] - 2025-08-29 | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta12 | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - reset NFC state on API send failure to allow retry | ||||||
|  | - update createdFilamentId reset value to 65535 for better task handling | ||||||
|  | - update createdVendorId reset value to 65535 for improved API handling | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta11] - 2025-08-29 | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta11 | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - update spoolman ID reset values to 65535 for better API response detection | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta10] - 2025-08-29 | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta10 | ||||||
|  | - streamline task creation in checkVendor and checkFilament functions | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta9] - 2025-08-29 | ||||||
|  | ### Added | ||||||
|  | - update vendor and filament ID handling to use NULL and add delays for stability | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta9 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta8] - 2025-08-29 | ||||||
|  | ### Added | ||||||
|  | - add delay to ensure proper setting of vendor and filament IDs after API state changes | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta8 | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - correct color_hex key usage and comment out unused date fields in spool creation | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta7] - 2025-08-29 | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta7 | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - improve API state handling and vendor name formatting | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta6] - 2025-08-29 | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta6 | ||||||
|  | - improve task synchronization in vendor, filament, and spool creation functions | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta5] - 2025-08-29 | ||||||
|  | ### Added | ||||||
|  | - enhance NDEF decoding with detailed validation and debugging output | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta5 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta4] - 2025-08-29 | ||||||
|  | ### Added | ||||||
|  | - enhance NDEF decoding to validate structure and extract JSON payload | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta4 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.12-beta3] - 2025-08-29 | ||||||
|  | ### Added | ||||||
|  | - add logging for decoded JSON data in NFC processing | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for beta version v1.5.12-beta3 | ||||||
|  |  | ||||||
|  |  | ||||||
| ## [1.5.12-beta2] - 2025-08-29 | ## [1.5.12-beta2] - 2025-08-29 | ||||||
| ### Changed | ### Changed | ||||||
| - update platformio.ini for beta version v1.5.12-beta2 | - update platformio.ini for beta version v1.5.12-beta2 | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| ; https://docs.platformio.org/page/projectconf.html | ; https://docs.platformio.org/page/projectconf.html | ||||||
|  |  | ||||||
| [common] | [common] | ||||||
| version = "1.5.12-beta2" | version = "1.5.12-beta12" | ||||||
| to_old_version = "1.5.0" | to_old_version = "1.5.0" | ||||||
|  |  | ||||||
| ## | ## | ||||||
|   | |||||||
							
								
								
									
										202
									
								
								src/api.cpp
									
									
									
									
									
								
							
							
						
						
									
										202
									
								
								src/api.cpp
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ | |||||||
| #include <Preferences.h> | #include <Preferences.h> | ||||||
| #include "debug.h" | #include "debug.h" | ||||||
| #include "scale.h" | #include "scale.h" | ||||||
|  | #include "nfc.h" | ||||||
| #include <time.h> | #include <time.h> | ||||||
| volatile spoolmanApiStateType spoolmanApiState = API_IDLE; | volatile spoolmanApiStateType spoolmanApiState = API_IDLE; | ||||||
|  |  | ||||||
| @@ -121,7 +122,7 @@ void sendToApi(void *parameter) { | |||||||
|  |  | ||||||
|     // Wait until API is IDLE |     // Wait until API is IDLE | ||||||
|     while(spoolmanApiState != API_IDLE){ |     while(spoolmanApiState != API_IDLE){ | ||||||
|         Serial.println("Waiting!"); |         vTaskDelay(100 / portTICK_PERIOD_MS); | ||||||
|         yield(); |         yield(); | ||||||
|     } |     } | ||||||
|     spoolmanApiState = API_TRANSMITTING; |     spoolmanApiState = API_TRANSMITTING; | ||||||
| @@ -151,7 +152,7 @@ void sendToApi(void *parameter) { | |||||||
|     else httpCode = http.PUT(updatePayload); |     else httpCode = http.PUT(updatePayload); | ||||||
|  |  | ||||||
|     if (httpCode == HTTP_CODE_OK) { |     if (httpCode == HTTP_CODE_OK) { | ||||||
|         Serial.println("Spoolman erfolgreich aktualisiert"); |         Serial.println("Spoolman Abfrage erfolgreich"); | ||||||
|  |  | ||||||
|         // Restgewicht der Spule auslesen |         // Restgewicht der Spule auslesen | ||||||
|         String payload = http.getString(); |         String payload = http.getString(); | ||||||
| @@ -345,9 +346,8 @@ void sendToApi(void *parameter) { | |||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         Serial.println("Fehler beim Senden an Spoolman! HTTP Code: " + String(httpCode)); |         Serial.println("Fehler beim Senden an Spoolman! HTTP Code: " + String(httpCode)); | ||||||
|  |  | ||||||
|         // TBD: really required? |  | ||||||
|         vTaskDelay(2000 / portTICK_PERIOD_MS); |         vTaskDelay(2000 / portTICK_PERIOD_MS); | ||||||
|  |         nfcReaderState = NFC_IDLE; // Reset NFC state to allow retry | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     http.end(); |     http.end(); | ||||||
| @@ -616,7 +616,8 @@ bool updateSpoolBambuData(String payload) { | |||||||
| uint16_t createVendor(String vendor) { | uint16_t createVendor(String vendor) { | ||||||
|     // Create new vendor in Spoolman database using task system |     // Create new vendor in Spoolman database using task system | ||||||
|     // Note: Due to async nature, the ID will be stored in createdVendorId global variable |     // Note: Due to async nature, the ID will be stored in createdVendorId global variable | ||||||
|     createdVendorId = 0; // Reset previous value |     // Note: This function assumes that the caller has already ensured API is IDLE | ||||||
|  |     createdVendorId = 65535; // Reset previous value | ||||||
|      |      | ||||||
|     String spoolsUrl = spoolmanUrl + apiUrl + "/vendor"; |     String spoolsUrl = spoolmanUrl + apiUrl + "/vendor"; | ||||||
|     Serial.print("Create vendor with URL: "); |     Serial.print("Create vendor with URL: "); | ||||||
| @@ -645,19 +646,18 @@ uint16_t createVendor(String vendor) { | |||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = vendorPayload; |     params->updatePayload = vendorPayload; | ||||||
|  |  | ||||||
|     // Check if API is idle before creating task |     // Create task without additional API state check since caller ensures synchronization | ||||||
|     if(spoolmanApiState == API_IDLE){ |     BaseType_t result = xTaskCreate( | ||||||
|         // Erstelle die Task |         sendToApi,                // Task-Funktion | ||||||
|         BaseType_t result = xTaskCreate( |         "SendToApiTask",          // Task-Name | ||||||
|             sendToApi,                // Task-Funktion |         6144,                     // Stackgröße in Bytes | ||||||
|             "SendToApiTask",          // Task-Name |         (void*)params,            // Parameter | ||||||
|             6144,                     // Stackgröße in Bytes |         0,                        // Priorität | ||||||
|             (void*)params,            // Parameter |         NULL                      // Task-Handle (nicht benötigt) | ||||||
|             0,                        // Priorität |     ); | ||||||
|             NULL                      // Task-Handle (nicht benötigt) |  | ||||||
|         ); |     if (result != pdPASS) { | ||||||
|     } else { |         Serial.println("Failed to create vendor task!"); | ||||||
|         Serial.println("Not spawning new task, API still active!"); |  | ||||||
|         delete params; |         delete params; | ||||||
|         vendorDoc.clear(); |         vendorDoc.clear(); | ||||||
|         return 0; |         return 0; | ||||||
| @@ -667,8 +667,8 @@ uint16_t createVendor(String vendor) { | |||||||
|      |      | ||||||
|     // Wait for task completion and return the created vendor ID |     // Wait for task completion and return the created vendor ID | ||||||
|     // Note: createdVendorId will be set by sendToApi when response is received |     // Note: createdVendorId will be set by sendToApi when response is received | ||||||
|     while(spoolmanApiState != API_IDLE) { |     while(createdVendorId == 65535) { | ||||||
|         vTaskDelay(100 / portTICK_PERIOD_MS); |         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     return createdVendorId; |     return createdVendorId; | ||||||
| @@ -676,9 +676,12 @@ uint16_t createVendor(String vendor) { | |||||||
|  |  | ||||||
| uint16_t checkVendor(String vendor) { | uint16_t checkVendor(String vendor) { | ||||||
|     // Check if vendor exists using task system |     // Check if vendor exists using task system | ||||||
|     foundVendorId = 0; // Reset previous value |     foundVendorId = 65535; // Reset to invalid value to detect when API response is received | ||||||
|      |      | ||||||
|     String spoolsUrl = spoolmanUrl + apiUrl + "/vendor?name=" + vendor; |     String vendorName = vendor; | ||||||
|  |     vendorName.trim(); | ||||||
|  |     vendorName.replace(" ", "+"); | ||||||
|  |     String spoolsUrl = spoolmanUrl + apiUrl + "/vendor?name=" + vendorName; | ||||||
|     Serial.print("Check vendor with URL: "); |     Serial.print("Check vendor with URL: "); | ||||||
|     Serial.println(spoolsUrl); |     Serial.println(spoolsUrl); | ||||||
|  |  | ||||||
| @@ -693,25 +696,25 @@ uint16_t checkVendor(String vendor) { | |||||||
|     params->updatePayload = ""; // Empty for GET request |     params->updatePayload = ""; // Empty for GET request | ||||||
|  |  | ||||||
|     // Check if API is idle before creating task |     // Check if API is idle before creating task | ||||||
|     if(spoolmanApiState == API_IDLE){ |     while (spoolmanApiState != API_IDLE) | ||||||
|         // Erstelle die Task |     { | ||||||
|         BaseType_t result = xTaskCreate( |         vTaskDelay(100 / portTICK_PERIOD_MS); | ||||||
|             sendToApi,                // Task-Funktion |  | ||||||
|             "SendToApiTask",          // Task-Name |  | ||||||
|             6144,                     // Stackgröße in Bytes |  | ||||||
|             (void*)params,            // Parameter |  | ||||||
|             0,                        // Priorität |  | ||||||
|             NULL                      // Task-Handle (nicht benötigt) |  | ||||||
|         ); |  | ||||||
|     } else { |  | ||||||
|         Serial.println("Not spawning new task, API still active!"); |  | ||||||
|         delete params; |  | ||||||
|         return 0; |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     // Wait for task completion |     // Erstelle die Task | ||||||
|     while(spoolmanApiState != API_IDLE) { |     BaseType_t result = xTaskCreate( | ||||||
|         vTaskDelay(100 / portTICK_PERIOD_MS); |         sendToApi,                // Task-Funktion | ||||||
|  |         "SendToApiTask",          // Task-Name | ||||||
|  |         6144,                     // Stackgröße in Bytes | ||||||
|  |         (void*)params,            // Parameter | ||||||
|  |         0,                        // Priorität | ||||||
|  |         NULL                      // Task-Handle (nicht benötigt) | ||||||
|  |     ); | ||||||
|  |      | ||||||
|  |     // Wait until foundVendorId is updated by the API response (not 65535 anymore) | ||||||
|  |     while (foundVendorId == 65535) | ||||||
|  |     { | ||||||
|  |         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Check if vendor was found |     // Check if vendor was found | ||||||
| @@ -736,7 +739,8 @@ uint16_t checkVendor(String vendor) { | |||||||
| uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | ||||||
|     // Create new filament in Spoolman database using task system |     // Create new filament in Spoolman database using task system | ||||||
|     // Note: Due to async nature, the ID will be stored in createdFilamentId global variable |     // Note: Due to async nature, the ID will be stored in createdFilamentId global variable | ||||||
|     createdFilamentId = 0; // Reset previous value |     // Note: This function assumes that the caller has already ensured API is IDLE | ||||||
|  |     createdFilamentId = 65535; // Reset previous value | ||||||
|      |      | ||||||
|     String spoolsUrl = spoolmanUrl + apiUrl + "/filament"; |     String spoolsUrl = spoolmanUrl + apiUrl + "/filament"; | ||||||
|     Serial.print("Create filament with URL: "); |     Serial.print("Create filament with URL: "); | ||||||
| @@ -744,16 +748,16 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | |||||||
|  |  | ||||||
|     // Create JSON payload for filament creation |     // Create JSON payload for filament creation | ||||||
|     JsonDocument filamentDoc; |     JsonDocument filamentDoc; | ||||||
|     filamentDoc["name"] = payload["name"].as<String>(); |     filamentDoc["name"] = payload["color_name"].as<String>(); | ||||||
|     filamentDoc["vendor_id"] = String(vendorId); |     filamentDoc["vendor_id"] = String(vendorId); | ||||||
|     filamentDoc["material"] = payload["type"].as<String>(); |     filamentDoc["material"] = payload["type"].as<String>(); | ||||||
|     filamentDoc["density"] = (payload["density"].is<String>() && payload["density"].as<String>().length() > 0) ? payload["density"].as<String>() : "1.24"; |     filamentDoc["density"] = (payload["density"].is<String>() && payload["density"].as<String>().length() > 0) ? payload["density"].as<String>() : "1.24"; | ||||||
|     filamentDoc["diameter"] = (payload["diameter"].is<String>() && payload["diameter"].as<String>().length() > 0) ? payload["diameter"].as<String>() : "1.75"; |     filamentDoc["diameter"] = (payload["diameter"].is<String>() && payload["diameter"].as<String>().length() > 0) ? payload["diameter"].as<String>() : "1.75"; | ||||||
|     filamentDoc["weight"] = payload["weight"].as<String>(); |     filamentDoc["weight"] = String(weight); | ||||||
|     filamentDoc["spool_weight"] = payload["spool_weight"].as<String>(); |     filamentDoc["spool_weight"] = payload["spool_weight"].as<String>(); | ||||||
|     filamentDoc["article_number"] = payload["artnr"].as<String>(); |     filamentDoc["article_number"] = payload["artnr"].as<String>(); | ||||||
|     filamentDoc["extruder_temp"] = payload["extruder_temp"].is<String>() ? payload["extruder_temp"].as<String>() : ""; |     filamentDoc["settings_extruder_temp"] = payload["extruder_temp"].is<String>() ? payload["extruder_temp"].as<String>() : ""; | ||||||
|     filamentDoc["bed_temp"] = payload["bed_temp"].is<String>() ? payload["bed_temp"].as<String>() : ""; |     filamentDoc["settings_bed_temp"] = payload["bed_temp"].is<String>() ? payload["bed_temp"].as<String>() : ""; | ||||||
|      |      | ||||||
|     if (payload["artnr"].is<String>()) |     if (payload["artnr"].is<String>()) | ||||||
|     { |     { | ||||||
| @@ -771,7 +775,7 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | |||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         filamentDoc["color_hex"] = (payload["color"].is<String>() && payload["color"].as<String>().length() >= 6) ? payload["color"].as<String>() : "FFFFFF"; |         filamentDoc["color_hex"] = (payload["color_hex"].is<String>() && payload["color_hex"].as<String>().length() >= 6) ? payload["color_hex"].as<String>() : "FFFFFF"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     String filamentPayload; |     String filamentPayload; | ||||||
| @@ -790,19 +794,18 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | |||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = filamentPayload; |     params->updatePayload = filamentPayload; | ||||||
|  |  | ||||||
|     // Check if API is idle before creating task |     // Create task without additional API state check since caller ensures synchronization | ||||||
|     if(spoolmanApiState == API_IDLE){ |     BaseType_t result = xTaskCreate( | ||||||
|         // Erstelle die Task |         sendToApi,                // Task-Funktion | ||||||
|         BaseType_t result = xTaskCreate( |         "SendToApiTask",          // Task-Name | ||||||
|             sendToApi,                // Task-Funktion |         6144,                     // Stackgröße in Bytes | ||||||
|             "SendToApiTask",          // Task-Name |         (void*)params,            // Parameter | ||||||
|             6144,                     // Stackgröße in Bytes |         0,                        // Priorität | ||||||
|             (void*)params,            // Parameter |         NULL                      // Task-Handle (nicht benötigt) | ||||||
|             0,                        // Priorität |     ); | ||||||
|             NULL                      // Task-Handle (nicht benötigt) |  | ||||||
|         ); |     if (result != pdPASS) { | ||||||
|     } else { |         Serial.println("Failed to create filament task!"); | ||||||
|         Serial.println("Not spawning new task, API still active!"); |  | ||||||
|         delete params; |         delete params; | ||||||
|         filamentDoc.clear(); |         filamentDoc.clear(); | ||||||
|         return 0; |         return 0; | ||||||
| @@ -812,8 +815,8 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | |||||||
|      |      | ||||||
|     // Wait for task completion and return the created filament ID |     // Wait for task completion and return the created filament ID | ||||||
|     // Note: createdFilamentId will be set by sendToApi when response is received |     // Note: createdFilamentId will be set by sendToApi when response is received | ||||||
|     while(spoolmanApiState != API_IDLE) { |     while(createdFilamentId == 65535) { | ||||||
|         vTaskDelay(100 / portTICK_PERIOD_MS); |         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     return createdFilamentId; |     return createdFilamentId; | ||||||
| @@ -821,7 +824,7 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) { | |||||||
|  |  | ||||||
| uint16_t checkFilament(uint16_t vendorId, const JsonDocument& payload) { | uint16_t checkFilament(uint16_t vendorId, const JsonDocument& payload) { | ||||||
|     // Check if filament exists using task system |     // Check if filament exists using task system | ||||||
|     foundFilamentId = 0; // Reset previous value |     foundFilamentId = 65535; // Reset to invalid value to detect when API response is received | ||||||
|  |  | ||||||
|     String spoolsUrl = spoolmanUrl + apiUrl + "/filament?vendor.id=" + String(vendorId) + "&external_id=" + String(payload["artnr"].as<String>()); |     String spoolsUrl = spoolmanUrl + apiUrl + "/filament?vendor.id=" + String(vendorId) + "&external_id=" + String(payload["artnr"].as<String>()); | ||||||
|     Serial.print("Check filament with URL: "); |     Serial.print("Check filament with URL: "); | ||||||
| @@ -837,26 +840,19 @@ uint16_t checkFilament(uint16_t vendorId, const JsonDocument& payload) { | |||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = ""; // Empty for GET request |     params->updatePayload = ""; // Empty for GET request | ||||||
|  |  | ||||||
|     // Check if API is idle before creating task |      // Erstelle die Task | ||||||
|     if(spoolmanApiState == API_IDLE){ |     BaseType_t result = xTaskCreate( | ||||||
|         // Erstelle die Task |         sendToApi,                // Task-Funktion | ||||||
|         BaseType_t result = xTaskCreate( |         "SendToApiTask",          // Task-Name | ||||||
|             sendToApi,                // Task-Funktion |         6144,                     // Stackgröße in Bytes | ||||||
|             "SendToApiTask",          // Task-Name |         (void*)params,            // Parameter | ||||||
|             6144,                     // Stackgröße in Bytes |         0,                        // Priorität | ||||||
|             (void*)params,            // Parameter |         NULL                      // Task-Handle (nicht benötigt) | ||||||
|             0,                        // Priorität |     ); | ||||||
|             NULL                      // Task-Handle (nicht benötigt) |  | ||||||
|         ); |  | ||||||
|     } else { |  | ||||||
|         Serial.println("Not spawning new task, API still active!"); |  | ||||||
|         delete params; |  | ||||||
|         return 0; |  | ||||||
|     } |  | ||||||
|      |      | ||||||
|     // Wait for task completion |     // Wait until foundFilamentId is updated by the API response (not 65535 anymore) | ||||||
|     while(spoolmanApiState != API_IDLE) { |     while (foundFilamentId == 65535) { | ||||||
|         vTaskDelay(100 / portTICK_PERIOD_MS); |         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Check if filament was found |     // Check if filament was found | ||||||
| @@ -881,22 +877,22 @@ uint16_t checkFilament(uint16_t vendorId, const JsonDocument& payload) { | |||||||
| uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& payload, String uidString) { | uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& payload, String uidString) { | ||||||
|     // Create new spool in Spoolman database using task system |     // Create new spool in Spoolman database using task system | ||||||
|     // Note: Due to async nature, the ID will be stored in createdSpoolId global variable |     // Note: Due to async nature, the ID will be stored in createdSpoolId global variable | ||||||
|     createdSpoolId = 0; // Reset previous value |     // Note: This function assumes that the caller has already ensured API is IDLE | ||||||
|  |     createdSpoolId = 65535; // Reset to invalid value to detect when API response is received | ||||||
|      |      | ||||||
|     String spoolsUrl = spoolmanUrl + apiUrl + "/spool"; |     String spoolsUrl = spoolmanUrl + apiUrl + "/spool"; | ||||||
|     Serial.print("Create spool with URL: "); |     Serial.print("Create spool with URL: "); | ||||||
|     Serial.println(spoolsUrl); |     Serial.println(spoolsUrl); | ||||||
|     String currentDate = getCurrentDateISO8601(); |     //String currentDate = getCurrentDateISO8601(); | ||||||
|  |  | ||||||
|     // Create JSON payload for spool creation |     // Create JSON payload for spool creation | ||||||
|     JsonDocument spoolDoc; |     JsonDocument spoolDoc; | ||||||
|     spoolDoc["first_used"] = String(currentDate); |     //spoolDoc["first_used"] = String(currentDate); | ||||||
|     spoolDoc["last_used"] = String(currentDate); |     //spoolDoc["last_used"] = String(currentDate); | ||||||
|     spoolDoc["filament_id"] = String(filamentId); |     spoolDoc["filament_id"] = String(filamentId); | ||||||
|     spoolDoc["initial_weight"] = weight > 10 ? String(weight) : "1000"; |     spoolDoc["initial_weight"] = weight > 10 ? String(weight-payload["spool_weight"].as<int>()) : "1000"; | ||||||
|     spoolDoc["spool_weight"] = (payload["spool_weight"].is<String>() && payload["spool_weight"].as<String>().length() > 0) ? payload["spool_weight"].as<String>() : "180"; |     spoolDoc["spool_weight"] = (payload["spool_weight"].is<String>() && payload["spool_weight"].as<String>().length() > 0) ? payload["spool_weight"].as<String>() : "180"; | ||||||
|     spoolDoc["remaining_weight"] = (payload["weight"].is<String>() && payload["weight"].as<String>().length() > 0) ? payload["weight"].as<String>() : "1000"; |     spoolDoc["remaining_weight"] = (payload["weight"].is<String>() && payload["weight"].as<String>().length() > 0) ? payload["weight"].as<String>() : "1000"; | ||||||
|     spoolDoc["used_weight"] = "0"; |  | ||||||
|     spoolDoc["lot_nr"] = (payload["lotnr"].is<String>() && payload["lotnr"].as<String>().length() > 0) ? payload["lotnr"].as<String>() : ""; |     spoolDoc["lot_nr"] = (payload["lotnr"].is<String>() && payload["lotnr"].as<String>().length() > 0) ? payload["lotnr"].as<String>() : ""; | ||||||
|     spoolDoc["comment"] = "automatically generated"; |     spoolDoc["comment"] = "automatically generated"; | ||||||
|     spoolDoc["extra"]["nfc_id"] = "\"" + uidString + "\""; |     spoolDoc["extra"]["nfc_id"] = "\"" + uidString + "\""; | ||||||
| @@ -918,35 +914,37 @@ uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& paylo | |||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = spoolPayload; |     params->updatePayload = spoolPayload; | ||||||
|  |  | ||||||
|     // Check if API is idle before creating task |     // Create task without additional API state check since caller ensures synchronization | ||||||
|     if(spoolmanApiState == API_IDLE){ |     BaseType_t result = xTaskCreate( | ||||||
|         // Erstelle die Task |         sendToApi,                // Task-Funktion | ||||||
|         BaseType_t result = xTaskCreate( |         "SendToApiTask",          // Task-Name | ||||||
|             sendToApi,                // Task-Funktion |         6144,                     // Stackgröße in Bytes | ||||||
|             "SendToApiTask",          // Task-Name |         (void*)params,            // Parameter | ||||||
|             6144,                     // Stackgröße in Bytes |         0,                        // Priorität | ||||||
|             (void*)params,            // Parameter |         NULL                      // Task-Handle (nicht benötigt) | ||||||
|             0,                        // Priorität |     ); | ||||||
|             NULL                      // Task-Handle (nicht benötigt) |  | ||||||
|         ); |     if (result != pdPASS) { | ||||||
|     } else { |         Serial.println("Failed to create spool task!"); | ||||||
|         Serial.println("Not spawning new task, API still active!"); |  | ||||||
|         delete params; |         delete params; | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     // Wait for task completion and return the created spool ID |     // Wait for task completion and return the created spool ID | ||||||
|     // Note: createdSpoolId will be set by sendToApi when response is received |     // Note: createdSpoolId will be set by sendToApi when response is received | ||||||
|     while(spoolmanApiState != API_IDLE) { |     while(createdSpoolId == 65535) { | ||||||
|         vTaskDelay(100 / portTICK_PERIOD_MS); |         vTaskDelay(50 / portTICK_PERIOD_MS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // daten mit startWriteJsonToTag schreiben |     // Write data to tag with startWriteJsonToTag | ||||||
|     // void startWriteJsonToTag(const bool isSpoolTag, const char* payload); |     // void startWriteJsonToTag(const bool isSpoolTag, const char* payload); | ||||||
|     payload["sm_id"].set(String(createdSpoolId)); |     payload["sm_id"].set(String(createdSpoolId)); | ||||||
|      |      | ||||||
|     String payloadString; |     String payloadString; | ||||||
|     serializeJson(payload, payloadString); |     serializeJson(payload, payloadString); | ||||||
|  |      | ||||||
|  |     nfcReaderState = NFC_IDLE; | ||||||
|  |     vTaskDelay(50 / portTICK_PERIOD_MS); | ||||||
|     startWriteJsonToTag(true, payloadString.c_str()); |     startWriteJsonToTag(true, payloadString.c_str()); | ||||||
|  |  | ||||||
|     return createdSpoolId; |     return createdSpoolId; | ||||||
|   | |||||||
							
								
								
									
										633
									
								
								src/nfc.cpp
									
									
									
									
									
								
							
							
						
						
									
										633
									
								
								src/nfc.cpp
									
									
									
									
									
								
							| @@ -99,9 +99,7 @@ bool formatNdefTag() { | |||||||
|     } |     } | ||||||
|    |    | ||||||
|     return success; |     return success; | ||||||
|   } | }uint16_t readTagSize() | ||||||
|  |  | ||||||
| uint16_t readTagSize() |  | ||||||
| { | { | ||||||
|   uint8_t buffer[4]; |   uint8_t buffer[4]; | ||||||
|   memset(buffer, 0, 4); |   memset(buffer, 0, 4); | ||||||
| @@ -109,113 +107,594 @@ uint16_t readTagSize() | |||||||
|   return buffer[2]*8; |   return buffer[2]*8; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | String detectNtagType() | ||||||
|  | { | ||||||
|  |   // Read capability container from page 3 to determine exact NTAG type | ||||||
|  |   uint8_t ccBuffer[4]; | ||||||
|  |   memset(ccBuffer, 0, 4); | ||||||
|  |    | ||||||
|  |   if (!nfc.ntag2xx_ReadPage(3, ccBuffer)) { | ||||||
|  |     Serial.println("Failed to read capability container"); | ||||||
|  |     return "UNKNOWN"; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Also read configuration pages to get more info | ||||||
|  |   uint8_t configBuffer[4]; | ||||||
|  |   memset(configBuffer, 0, 4); | ||||||
|  |    | ||||||
|  |   Serial.print("Capability Container: "); | ||||||
|  |   for (int i = 0; i < 4; i++) { | ||||||
|  |     if (ccBuffer[i] < 0x10) Serial.print("0"); | ||||||
|  |     Serial.print(ccBuffer[i], HEX); | ||||||
|  |     Serial.print(" "); | ||||||
|  |   } | ||||||
|  |   Serial.println(); | ||||||
|  |  | ||||||
|  |   // NTAG type detection based on capability container | ||||||
|  |   // CC[2] contains the data area size in bytes / 8 | ||||||
|  |   uint16_t dataAreaSize = ccBuffer[2] * 8; | ||||||
|  |    | ||||||
|  |   Serial.print("Data area size from CC: "); | ||||||
|  |   Serial.println(dataAreaSize); | ||||||
|  |  | ||||||
|  |   // Try to read different configuration pages to determine exact type | ||||||
|  |   String tagType = "UNKNOWN"; | ||||||
|  |    | ||||||
|  |   // Try to read page 41 (NTAG213 ends at page 39, so this should fail) | ||||||
|  |   uint8_t testBuffer[4]; | ||||||
|  |   bool canReadPage41 = nfc.ntag2xx_ReadPage(41, testBuffer); | ||||||
|  |    | ||||||
|  |   // Try to read page 130 (NTAG215 ends at page 129, so this should fail for NTAG213/215) | ||||||
|  |   bool canReadPage130 = nfc.ntag2xx_ReadPage(130, testBuffer); | ||||||
|  |  | ||||||
|  |   if (dataAreaSize <= 180 && !canReadPage41) { | ||||||
|  |     tagType = "NTAG213"; | ||||||
|  |     Serial.println("Detected: NTAG213 (cannot read beyond page 39)"); | ||||||
|  |   } else if (dataAreaSize <= 540 && canReadPage41 && !canReadPage130) { | ||||||
|  |     tagType = "NTAG215"; | ||||||
|  |     Serial.println("Detected: NTAG215 (can read page 41, cannot read page 130)"); | ||||||
|  |   } else if (dataAreaSize <= 928 && canReadPage130) { | ||||||
|  |     tagType = "NTAG216"; | ||||||
|  |     Serial.println("Detected: NTAG216 (can read page 130)"); | ||||||
|  |   } else { | ||||||
|  |     // Fallback: use data area size from capability container | ||||||
|  |     if (dataAreaSize <= 180) { | ||||||
|  |       tagType = "NTAG213"; | ||||||
|  |       Serial.println("Fallback detection: NTAG213 based on data area size"); | ||||||
|  |     } else if (dataAreaSize <= 540) { | ||||||
|  |       tagType = "NTAG215"; | ||||||
|  |       Serial.println("Fallback detection: NTAG215 based on data area size"); | ||||||
|  |     } else { | ||||||
|  |       tagType = "NTAG216"; | ||||||
|  |       Serial.println("Fallback detection: NTAG216 based on data area size"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   return tagType; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint16_t getAvailableUserDataSize() | ||||||
|  | { | ||||||
|  |   String tagType = detectNtagType(); | ||||||
|  |   uint16_t userDataSize = 0; | ||||||
|  |    | ||||||
|  |   if (tagType == "NTAG213") { | ||||||
|  |     // NTAG213: User data from page 4-39 (36 pages * 4 bytes = 144 bytes) | ||||||
|  |     userDataSize = 144; | ||||||
|  |     Serial.println("NTAG213 confirmed - 144 bytes user data available"); | ||||||
|  |   } else if (tagType == "NTAG215") { | ||||||
|  |     // NTAG215: User data from page 4-129 (126 pages * 4 bytes = 504 bytes) | ||||||
|  |     userDataSize = 504; | ||||||
|  |     Serial.println("NTAG215 confirmed - 504 bytes user data available"); | ||||||
|  |   } else if (tagType == "NTAG216") { | ||||||
|  |     // NTAG216: User data from page 4-225 (222 pages * 4 bytes = 888 bytes) | ||||||
|  |     userDataSize = 888; | ||||||
|  |     Serial.println("NTAG216 confirmed - 888 bytes user data available"); | ||||||
|  |   } else { | ||||||
|  |     // Unknown tag type, use conservative estimate | ||||||
|  |     uint16_t tagSize = readTagSize(); | ||||||
|  |     userDataSize = tagSize - 60; // Reserve 60 bytes for headers/config | ||||||
|  |     Serial.print("Unknown NTAG type, using conservative estimate: "); | ||||||
|  |     Serial.println(userDataSize); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   return userDataSize; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint16_t getMaxUserDataPages() | ||||||
|  | { | ||||||
|  |   String tagType = detectNtagType(); | ||||||
|  |   uint16_t maxPages = 0; | ||||||
|  |    | ||||||
|  |   if (tagType == "NTAG213") { | ||||||
|  |     maxPages = 39; // Pages 4-39 are user data | ||||||
|  |   } else if (tagType == "NTAG215") { | ||||||
|  |     maxPages = 129; // Pages 4-129 are user data | ||||||
|  |   } else if (tagType == "NTAG216") { | ||||||
|  |     maxPages = 225; // Pages 4-225 are user data | ||||||
|  |   } else { | ||||||
|  |     // Conservative fallback | ||||||
|  |     maxPages = 39; | ||||||
|  |     Serial.println("Unknown tag type, using NTAG213 page limit as fallback"); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   Serial.print("Maximum writable page: "); | ||||||
|  |   Serial.println(maxPages); | ||||||
|  |   return maxPages; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool clearUserDataArea() { | ||||||
|  |     // IMPORTANT: Only clear user data pages, NOT configuration pages | ||||||
|  |     // NTAG layout: Pages 0-3 (header), 4-N (user data), N+1-N+3 (config) - NEVER touch config! | ||||||
|  |     String tagType = detectNtagType(); | ||||||
|  |      | ||||||
|  |     // Calculate safe user data page ranges (NEVER touch config pages!) | ||||||
|  |     uint16_t firstUserPage = 4; | ||||||
|  |     uint16_t lastUserPage = 0; | ||||||
|  |      | ||||||
|  |     if (tagType == "NTAG213") { | ||||||
|  |         lastUserPage = 39;  // Pages 40-42 are config - DO NOT TOUCH! | ||||||
|  |         Serial.println("NTAG213: Sichere Löschung Seiten 4-39"); | ||||||
|  |     } else if (tagType == "NTAG215") { | ||||||
|  |         lastUserPage = 129; // Pages 130-132 are config - DO NOT TOUCH! | ||||||
|  |         Serial.println("NTAG215: Sichere Löschung Seiten 4-129"); | ||||||
|  |     } else if (tagType == "NTAG216") { | ||||||
|  |         lastUserPage = 225; // Pages 226-228 are config - DO NOT TOUCH! | ||||||
|  |         Serial.println("NTAG216: Sichere Löschung Seiten 4-225"); | ||||||
|  |     } else { | ||||||
|  |         // Conservative fallback - only clear a small safe area | ||||||
|  |         lastUserPage = 39; | ||||||
|  |         Serial.println("UNKNOWN TAG: Konservative Löschung Seiten 4-39"); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     Serial.println("WARNUNG: Vollständiges Löschen kann Tag beschädigen!"); | ||||||
|  |     Serial.println("Verwende stattdessen selective NDEF-Überschreibung..."); | ||||||
|  |      | ||||||
|  |     // Instead of clearing everything, just write a minimal NDEF structure | ||||||
|  |     // This is much safer and preserves tag integrity | ||||||
|  |     return initializeNdefStructure(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool initializeNdefStructure() { | ||||||
|  |     // Write minimal NDEF structure without destroying the tag | ||||||
|  |     // This creates a clean slate while preserving tag functionality | ||||||
|  |      | ||||||
|  |     Serial.println("Initialisiere sichere NDEF-Struktur..."); | ||||||
|  |      | ||||||
|  |     // Minimal NDEF structure: TLV with empty message | ||||||
|  |     uint8_t minimalNdef[8] = { | ||||||
|  |         0x03,           // NDEF Message TLV Tag | ||||||
|  |         0x03,           // Length (3 bytes for minimal empty record) | ||||||
|  |         0xD0,           // NDEF Record Header (TNF=0x0:Empty + SR + ME + MB) | ||||||
|  |         0x00,           // Type Length (0 = empty record) | ||||||
|  |         0x00,           // Payload Length (0 = empty record) | ||||||
|  |         0xFE,           // Terminator TLV | ||||||
|  |         0x00, 0x00      // Padding | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     // Write the minimal structure starting at page 4 | ||||||
|  |     uint8_t pageBuffer[4]; | ||||||
|  |      | ||||||
|  |     for (int i = 0; i < 8; i += 4) { | ||||||
|  |         memcpy(pageBuffer, &minimalNdef[i], 4); | ||||||
|  |          | ||||||
|  |         if (!nfc.ntag2xx_WritePage(4 + (i / 4), pageBuffer)) { | ||||||
|  |             Serial.print("Fehler beim Initialisieren von Seite "); | ||||||
|  |             Serial.println(4 + (i / 4)); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         Serial.print("Seite "); | ||||||
|  |         Serial.print(4 + (i / 4)); | ||||||
|  |         Serial.print(" initialisiert: "); | ||||||
|  |         for (int j = 0; j < 4; j++) { | ||||||
|  |             if (pageBuffer[j] < 0x10) Serial.print("0"); | ||||||
|  |             Serial.print(pageBuffer[j], HEX); | ||||||
|  |             Serial.print(" "); | ||||||
|  |         } | ||||||
|  |         Serial.println(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     Serial.println("✓ Sichere NDEF-Struktur initialisiert"); | ||||||
|  |     Serial.println("✓ Tag bleibt funktionsfähig und überschreibbar"); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| uint8_t ntag2xx_WriteNDEF(const char *payload) { | uint8_t ntag2xx_WriteNDEF(const char *payload) { | ||||||
|  |   // Determine exact tag type and capabilities first | ||||||
|  |   String tagType = detectNtagType(); | ||||||
|   uint16_t tagSize = readTagSize(); |   uint16_t tagSize = readTagSize(); | ||||||
|   Serial.print("Tag Size: ");Serial.println(tagSize); |   uint16_t availableUserData = getAvailableUserDataSize(); | ||||||
|  |   uint16_t maxWritablePage = getMaxUserDataPages(); | ||||||
|  |    | ||||||
|  |   Serial.println("=== NFC TAG ANALYSIS ==="); | ||||||
|  |   Serial.print("Tag Type: ");Serial.println(tagType); | ||||||
|  |   Serial.print("Total Tag Size: ");Serial.println(tagSize); | ||||||
|  |   Serial.print("Available User Data: ");Serial.println(availableUserData); | ||||||
|  |   Serial.print("Max Writable Page: ");Serial.println(maxWritablePage); | ||||||
|  |   Serial.println("========================"); | ||||||
|  |  | ||||||
|   uint8_t pageBuffer[4] = {0, 0, 0, 0}; |   uint8_t pageBuffer[4] = {0, 0, 0, 0}; | ||||||
|   Serial.println("Beginne mit dem Schreiben der NDEF-Nachricht..."); |   Serial.println("Beginne mit dem Schreiben der NDEF-Nachricht..."); | ||||||
|    |    | ||||||
|   // Figure out how long the string is |   // Figure out how long the string is | ||||||
|   uint8_t len = strlen(payload); |   uint16_t payloadLen = strlen(payload); | ||||||
|   Serial.print("Länge der Payload: "); |   Serial.print("Länge der Payload: "); | ||||||
|   Serial.println(len); |   Serial.println(payloadLen); | ||||||
|    |    | ||||||
|   Serial.print("Payload: ");Serial.println(payload); |   Serial.print("Payload: ");Serial.println(payload); | ||||||
|  |  | ||||||
|   // Setup the record header |   // MIME type for JSON | ||||||
|   // See NFCForum-TS-Type-2-Tag_1.1.pdf for details |   const char mimeType[] = "application/json"; | ||||||
|   uint8_t pageHeader[21] = { |   uint8_t mimeTypeLen = strlen(mimeType); | ||||||
|     /* NDEF Message TLV - JSON Record */ |  | ||||||
|     0x03, /* Tag Field (0x03 = NDEF Message) */ |  | ||||||
|     (uint8_t)(len+3+16), /* Payload Length (including NDEF header) */ |  | ||||||
|     0xD2, /* NDEF Record Header (TNF=0x2:MIME Media + SR + ME + MB) */ |  | ||||||
|     0x10, /* Type Length for the record type indicator */ |  | ||||||
|     (uint8_t)(len), /* Payload len */ |  | ||||||
|     'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o', 'n', '/', 'j', 's', 'o', 'n' |  | ||||||
|   }; |  | ||||||
|    |    | ||||||
|   // Make sure the URI payload will fit in dataLen (include 0xFE trailer) |   // Calculate NDEF record size | ||||||
|   if ((len < 1) || (len + 1 > (tagSize - sizeof(pageHeader))))  |   uint8_t ndefRecordHeaderSize = 3; // Header byte + Type Length + Payload Length (short record) | ||||||
|   { |   uint16_t ndefRecordSize = ndefRecordHeaderSize + mimeTypeLen + payloadLen; | ||||||
|  |    | ||||||
|  |   // Calculate TLV size - need to check if we need extended length format | ||||||
|  |   uint8_t tlvHeaderSize; | ||||||
|  |   uint16_t totalTlvSize; | ||||||
|  |    | ||||||
|  |   if (ndefRecordSize <= 254) { | ||||||
|  |     // Standard TLV format: Tag (1) + Length (1) + Value (ndefRecordSize) | ||||||
|  |     tlvHeaderSize = 2; | ||||||
|  |     totalTlvSize = tlvHeaderSize + ndefRecordSize + 1; // +1 for terminator TLV | ||||||
|  |   } else { | ||||||
|  |     // Extended TLV format: Tag (1) + 0xFF + Length (2) + Value (ndefRecordSize)   | ||||||
|  |     tlvHeaderSize = 4; | ||||||
|  |     totalTlvSize = tlvHeaderSize + ndefRecordSize + 1; // +1 for terminator TLV | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Serial.print("NDEF Record Size: "); | ||||||
|  |   Serial.println(ndefRecordSize); | ||||||
|  |   Serial.print("Total TLV Size: "); | ||||||
|  |   Serial.println(totalTlvSize); | ||||||
|  |  | ||||||
|  |   // Check if the message fits in the available user data space | ||||||
|  |   if (totalTlvSize > availableUserData) { | ||||||
|     Serial.println(); |     Serial.println(); | ||||||
|     Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!"); |     Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!"); | ||||||
|     Serial.println("Fehler: Die Nutzlast passt nicht in die Datenlänge."); |     Serial.println("FEHLER: Payload zu groß für diesen Tag-Typ!"); | ||||||
|  |     Serial.print("Tag-Typ: ");Serial.println(tagType); | ||||||
|  |     Serial.print("Benötigt: ");Serial.print(totalTlvSize);Serial.println(" Bytes"); | ||||||
|  |     Serial.print("Verfügbar: ");Serial.print(availableUserData);Serial.println(" Bytes"); | ||||||
|  |     Serial.print("Überschuss: ");Serial.print(totalTlvSize - availableUserData);Serial.println(" Bytes"); | ||||||
|  |      | ||||||
|  |     if (tagType == "NTAG213") { | ||||||
|  |       Serial.println("EMPFEHLUNG: Verwenden Sie einen NTAG215 (504 Bytes) oder NTAG216 (888 Bytes) Tag!"); | ||||||
|  |       Serial.println("Oder kürzen Sie die Payload um mindestens " + String(totalTlvSize - availableUserData) + " Bytes."); | ||||||
|  |     } | ||||||
|     Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!"); |     Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!"); | ||||||
|     Serial.println(); |     Serial.println(); | ||||||
|  |      | ||||||
|  |     oledShowMessage("Tag zu klein für Payload"); | ||||||
|  |     vTaskDelay(3000 / portTICK_PERIOD_MS); | ||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Kombiniere Header und Payload |   Serial.println("✓ Payload passt in den Tag - Schreibvorgang wird fortgesetzt"); | ||||||
|   int totalSize = sizeof(pageHeader) + len; |  | ||||||
|   uint8_t* combinedData = (uint8_t*) malloc(totalSize); |   // IMPORTANT: Use safe NDEF initialization instead of aggressive clearing | ||||||
|   if (combinedData == NULL)  |   Serial.println("Schritt 1: Sichere NDEF-Initialisierung..."); | ||||||
|   { |   if (!initializeNdefStructure()) { | ||||||
|     Serial.println("Fehler: Nicht genug Speicher vorhanden."); |     Serial.println("FEHLER: Konnte NDEF-Struktur nicht initialisieren!"); | ||||||
|     oledShowMessage("Tag too small"); |     oledShowMessage("NDEF init failed"); | ||||||
|  |     vTaskDelay(2000 / portTICK_PERIOD_MS); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   Serial.println("✓ NDEF-Struktur sicher initialisiert"); | ||||||
|  |  | ||||||
|  |   // Allocate memory for the complete TLV structure | ||||||
|  |   uint8_t* tlvData = (uint8_t*) malloc(totalTlvSize); | ||||||
|  |   if (tlvData == NULL) { | ||||||
|  |     Serial.println("Fehler: Nicht genug Speicher für TLV-Daten vorhanden."); | ||||||
|  |     oledShowMessage("Memory error"); | ||||||
|     vTaskDelay(2000 / portTICK_PERIOD_MS); |     vTaskDelay(2000 / portTICK_PERIOD_MS); | ||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Kombiniere Header und Payload |   // Build TLV structure | ||||||
|   memcpy(combinedData, pageHeader, sizeof(pageHeader)); |   uint16_t offset = 0; | ||||||
|   memcpy(&combinedData[sizeof(pageHeader)], payload, len); |  | ||||||
|    |    | ||||||
|   // Schreibe die Seiten |   // TLV Header | ||||||
|   uint8_t a = 0; |   tlvData[offset++] = 0x03; // NDEF Message TLV Tag | ||||||
|   uint8_t i = 0; |    | ||||||
|   while (totalSize > 0) { |   if (ndefRecordSize <= 254) { | ||||||
|  |     // Standard length format | ||||||
|  |     tlvData[offset++] = (uint8_t)ndefRecordSize; | ||||||
|  |   } else { | ||||||
|  |     // Extended length format | ||||||
|  |     tlvData[offset++] = 0xFF; | ||||||
|  |     tlvData[offset++] = (uint8_t)(ndefRecordSize >> 8);  // High byte | ||||||
|  |     tlvData[offset++] = (uint8_t)(ndefRecordSize & 0xFF); // Low byte | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // NDEF Record Header | ||||||
|  |   tlvData[offset++] = 0xD2; // NDEF Record Header (TNF=0x2:MIME Media + SR + ME + MB) | ||||||
|  |   tlvData[offset++] = mimeTypeLen; // Type Length | ||||||
|  |   tlvData[offset++] = (uint8_t)payloadLen; // Payload Length (short record format) | ||||||
|  |  | ||||||
|  |   // MIME Type | ||||||
|  |   memcpy(&tlvData[offset], mimeType, mimeTypeLen); | ||||||
|  |   offset += mimeTypeLen; | ||||||
|  |  | ||||||
|  |   // JSON Payload | ||||||
|  |   memcpy(&tlvData[offset], payload, payloadLen); | ||||||
|  |   offset += payloadLen; | ||||||
|  |  | ||||||
|  |   // Terminator TLV | ||||||
|  |   tlvData[offset] = 0xFE; | ||||||
|  |  | ||||||
|  |   Serial.print("Gesamt-TLV-Länge: "); | ||||||
|  |   Serial.println(offset + 1); | ||||||
|  |  | ||||||
|  |   // Debug: Print first 64 bytes of TLV data | ||||||
|  |   Serial.println("TLV Daten (erste 64 Bytes):"); | ||||||
|  |   for (int i = 0; i < min((int)(offset + 1), 64); i++) { | ||||||
|  |     if (tlvData[i] < 0x10) Serial.print("0"); | ||||||
|  |     Serial.print(tlvData[i], HEX); | ||||||
|  |     Serial.print(" "); | ||||||
|  |     if ((i + 1) % 16 == 0) Serial.println(); | ||||||
|  |   } | ||||||
|  |   Serial.println(); | ||||||
|  |  | ||||||
|  |   // Write data to tag pages (starting from page 4) | ||||||
|  |   uint16_t bytesWritten = 0; | ||||||
|  |   uint8_t pageNumber = 4; | ||||||
|  |   uint16_t totalBytes = offset + 1; | ||||||
|  |  | ||||||
|  |   Serial.println("Schritt 2: Schreibe neue NDEF-Daten..."); | ||||||
|  |   Serial.print("Schreibe "); | ||||||
|  |   Serial.print(totalBytes); | ||||||
|  |   Serial.print(" Bytes in "); | ||||||
|  |   Serial.print((totalBytes + 3) / 4); // Round up division | ||||||
|  |   Serial.println(" Seiten..."); | ||||||
|  |  | ||||||
|  |   while (bytesWritten < totalBytes && pageNumber <= maxWritablePage) { | ||||||
|  |     // Clear page buffer | ||||||
|     memset(pageBuffer, 0, 4); |     memset(pageBuffer, 0, 4); | ||||||
|     int bytesToWrite = (totalSize < 4) ? totalSize : 4; |  | ||||||
|     memcpy(pageBuffer, combinedData + a, bytesToWrite); |  | ||||||
|      |      | ||||||
|     //uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID |     // Calculate how many bytes to write to this page | ||||||
|     //uint8_t uidLength; |     uint16_t bytesToWrite = min(4, (int)(totalBytes - bytesWritten)); | ||||||
|     //nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 100); |  | ||||||
|      |      | ||||||
|     if (!(nfc.ntag2xx_WritePage(4+i, pageBuffer)))  |     // Copy data to page buffer | ||||||
|     { |     memcpy(pageBuffer, &tlvData[bytesWritten], bytesToWrite); | ||||||
|       Serial.println("Fehler beim Schreiben der Seite."); |  | ||||||
|       free(combinedData); |     // Write page to tag | ||||||
|  |     if (!nfc.ntag2xx_WritePage(pageNumber, pageBuffer)) { | ||||||
|  |       Serial.print("FEHLER beim Schreiben der Seite "); | ||||||
|  |       Serial.println(pageNumber); | ||||||
|  |       Serial.print("Möglicherweise Page-Limit erreicht für "); | ||||||
|  |       Serial.println(tagType); | ||||||
|  |       free(tlvData); | ||||||
|       return 0; |       return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     yield(); |     Serial.print("Seite "); | ||||||
|     //esp_task_wdt_reset(); |     Serial.print(pageNumber); | ||||||
|  |     Serial.print(" ✓: "); | ||||||
|  |     for (int i = 0; i < 4; i++) { | ||||||
|  |       if (pageBuffer[i] < 0x10) Serial.print("0"); | ||||||
|  |       Serial.print(pageBuffer[i], HEX); | ||||||
|  |       Serial.print(" "); | ||||||
|  |     } | ||||||
|  |     Serial.println(); | ||||||
|  |  | ||||||
|     i++; |     bytesWritten += bytesToWrite; | ||||||
|     a += 4; |     pageNumber++; | ||||||
|     totalSize -= bytesToWrite; |      | ||||||
|  |     yield(); | ||||||
|  |     vTaskDelay(5 / portTICK_PERIOD_MS); // Small delay between page writes | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Ensure the NDEF message is properly terminated |   free(tlvData); | ||||||
|   memset(pageBuffer, 0, 4); |    | ||||||
|   pageBuffer[0] = 0xFE; // NDEF record footer |   if (bytesWritten < totalBytes) { | ||||||
|   if (!(nfc.ntag2xx_WritePage(4+i, pageBuffer)))  |     Serial.println("WARNUNG: Nicht alle Daten konnten geschrieben werden!"); | ||||||
|   { |     Serial.print("Geschrieben: "); | ||||||
|     Serial.println("Fehler beim Schreiben des End-Bits."); |     Serial.print(bytesWritten); | ||||||
|     free(combinedData); |     Serial.print(" von "); | ||||||
|  |     Serial.print(totalBytes); | ||||||
|  |     Serial.println(" Bytes"); | ||||||
|  |     Serial.print("Gestoppt bei Seite: "); | ||||||
|  |     Serial.println(pageNumber - 1); | ||||||
|     return 0; |     return 0; | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   Serial.println("NDEF-Nachricht erfolgreich geschrieben."); |   Serial.println(); | ||||||
|   free(combinedData); |   Serial.println("✓ NDEF-Nachricht erfolgreich geschrieben!"); | ||||||
|  |   Serial.print("✓ Tag-Typ: ");Serial.println(tagType); | ||||||
|  |   Serial.print("✓ Insgesamt ");Serial.print(bytesWritten);Serial.println(" Bytes geschrieben"); | ||||||
|  |   Serial.print("✓ Verwendete Seiten: 4-");Serial.println(pageNumber - 1); | ||||||
|  |   Serial.print("✓ Speicher-Auslastung: "); | ||||||
|  |   Serial.print((bytesWritten * 100) / availableUserData); | ||||||
|  |   Serial.println("%"); | ||||||
|  |   Serial.println("✓ Bestehende Daten wurden überschrieben"); | ||||||
|  |   Serial.println(); | ||||||
|  |    | ||||||
|   return 1; |   return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) { | bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) { | ||||||
|   oledShowProgressBar(1, octoEnabled?5:4, "Reading", "Decoding data"); |   oledShowProgressBar(1, octoEnabled?5:4, "Reading", "Decoding data"); | ||||||
|  |  | ||||||
|   byte typeLength = encodedMessage[3]; |   // Debug: Print first 32 bytes of the raw data | ||||||
|   byte payloadLength = encodedMessage[4]; |   Serial.println("Raw NDEF data (first 32 bytes):"); | ||||||
|  |   for (int i = 0; i < 32; i++) { | ||||||
|  |     if (encodedMessage[i] < 0x10) Serial.print("0"); | ||||||
|  |     Serial.print(encodedMessage[i], HEX); | ||||||
|  |     Serial.print(" "); | ||||||
|  |     if ((i + 1) % 16 == 0) Serial.println(); | ||||||
|  |   } | ||||||
|  |   Serial.println(); | ||||||
|  |  | ||||||
|  |   // Look for the NDEF TLV structure starting from the beginning | ||||||
|  |   int tlvOffset = 0; | ||||||
|  |   bool foundNdefTlv = false; | ||||||
|  |    | ||||||
|  |   // Search for NDEF TLV (0x03) in the first few bytes | ||||||
|  |   for (int i = 0; i < 16; i++) { | ||||||
|  |     if (encodedMessage[i] == 0x03) { | ||||||
|  |       tlvOffset = i; | ||||||
|  |       foundNdefTlv = true; | ||||||
|  |       Serial.print("Found NDEF TLV at offset: "); | ||||||
|  |       Serial.println(tlvOffset); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!foundNdefTlv) { | ||||||
|  |     Serial.println("No NDEF TLV found in tag data"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Get the NDEF message length from TLV | ||||||
|  |   uint16_t ndefMessageLength = 0; | ||||||
|  |   int ndefRecordOffset = 0; | ||||||
|  |    | ||||||
|  |   if (encodedMessage[tlvOffset + 1] == 0xFF) { | ||||||
|  |     // Extended length format: next 2 bytes contain the actual length | ||||||
|  |     ndefMessageLength = (encodedMessage[tlvOffset + 2] << 8) | encodedMessage[tlvOffset + 3]; | ||||||
|  |     ndefRecordOffset = tlvOffset + 4; // Skip TLV tag + 0xFF + 2 length bytes | ||||||
|  |     Serial.print("NDEF Message Length (extended): "); | ||||||
|  |   } else { | ||||||
|  |     // Standard length format: single byte contains the length | ||||||
|  |     ndefMessageLength = encodedMessage[tlvOffset + 1]; | ||||||
|  |     ndefRecordOffset = tlvOffset + 2; // Skip TLV tag + 1 length byte | ||||||
|  |     Serial.print("NDEF Message Length (standard): "); | ||||||
|  |   } | ||||||
|  |   Serial.println(ndefMessageLength); | ||||||
|  |  | ||||||
|  |   // Get pointer to NDEF record | ||||||
|  |   const byte* ndefRecord = &encodedMessage[ndefRecordOffset]; | ||||||
|  |    | ||||||
|  |   // Parse NDEF record header | ||||||
|  |   byte recordHeader = ndefRecord[0]; | ||||||
|  |   byte typeLength = ndefRecord[1]; | ||||||
|  |    | ||||||
|  |   Serial.print("NDEF Record Header: 0x"); | ||||||
|  |   Serial.println(recordHeader, HEX); | ||||||
|  |   Serial.print("Type Length: "); | ||||||
|  |   Serial.println(typeLength); | ||||||
|  |  | ||||||
|  |   // Determine payload length (can be 1 or 4 bytes depending on SR flag) | ||||||
|  |   uint32_t payloadLength = 0; | ||||||
|  |   byte payloadLengthBytes = 1; | ||||||
|  |   byte payloadLengthOffset = 2; | ||||||
|  |    | ||||||
|  |   // Check if Short Record (SR) flag is set (bit 4) | ||||||
|  |   if (recordHeader & 0x10) { // SR flag | ||||||
|  |     payloadLength = ndefRecord[2]; | ||||||
|  |     payloadLengthBytes = 1; | ||||||
|  |     payloadLengthOffset = 2; | ||||||
|  |   } else { | ||||||
|  |     // Long record format (4 bytes for payload length) | ||||||
|  |     payloadLength = (ndefRecord[2] << 24) | (ndefRecord[3] << 16) |  | ||||||
|  |                    (ndefRecord[4] << 8) | ndefRecord[5]; | ||||||
|  |     payloadLengthBytes = 4; | ||||||
|  |     payloadLengthOffset = 2; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Serial.print("Payload Length: "); | ||||||
|  |   Serial.println(payloadLength); | ||||||
|  |   Serial.print("Payload Length Bytes: "); | ||||||
|  |   Serial.println(payloadLengthBytes); | ||||||
|  |  | ||||||
|  |   // Check for ID field (if IL flag is set) | ||||||
|  |   byte idLength = 0; | ||||||
|  |   if (recordHeader & 0x08) { // IL flag | ||||||
|  |     idLength = ndefRecord[payloadLengthOffset + payloadLengthBytes]; | ||||||
|  |     Serial.print("ID Length: "); | ||||||
|  |     Serial.println(idLength); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Calculate offset to payload | ||||||
|  |   byte payloadOffset = 1 + 1 + payloadLengthBytes + typeLength + idLength; | ||||||
|  |    | ||||||
|  |   Serial.print("Calculated payload offset: "); | ||||||
|  |   Serial.println(payloadOffset); | ||||||
|  |  | ||||||
|  |   // Verify we have enough data | ||||||
|  |   if (payloadOffset + payloadLength > ndefMessageLength) { | ||||||
|  |     Serial.println("Invalid NDEF structure - payload extends beyond message"); | ||||||
|  |     Serial.print("Payload offset + length: "); | ||||||
|  |     Serial.print(payloadOffset + payloadLength); | ||||||
|  |     Serial.print(", NDEF message length: "); | ||||||
|  |     Serial.println(ndefMessageLength); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Print the record type for debugging | ||||||
|  |   Serial.print("Record Type: "); | ||||||
|  |   for (int i = 0; i < typeLength; i++) { | ||||||
|  |     Serial.print((char)ndefRecord[1 + 1 + payloadLengthBytes + i]); | ||||||
|  |   } | ||||||
|  |   Serial.println(); | ||||||
|  |  | ||||||
|   nfcJsonData = ""; |   nfcJsonData = ""; | ||||||
|  |  | ||||||
|   for (int i = 2; i < payloadLength+2; i++)  |   // Extract JSON payload with validation | ||||||
|   { |   uint32_t actualJsonLength = 0; | ||||||
|     nfcJsonData += (char)encodedMessage[3 + typeLength + i]; |   for (uint32_t i = 0; i < payloadLength; i++) { | ||||||
|  |     byte currentByte = ndefRecord[payloadOffset + i]; | ||||||
|  |      | ||||||
|  |     // Stop at null terminator or if we find the end of JSON | ||||||
|  |     if (currentByte == 0x00) { | ||||||
|  |       Serial.print("Found null terminator at position: "); | ||||||
|  |       Serial.println(i); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Only add printable characters and common JSON characters | ||||||
|  |     if (currentByte >= 32 && currentByte <= 126) { | ||||||
|  |       nfcJsonData += (char)currentByte; | ||||||
|  |       actualJsonLength++; | ||||||
|  |     } else { | ||||||
|  |       Serial.print("Skipping non-printable byte at position "); | ||||||
|  |       Serial.print(i); | ||||||
|  |       Serial.print(": 0x"); | ||||||
|  |       Serial.println(currentByte, HEX); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check if we've reached the end of a JSON object | ||||||
|  |     if (currentByte == '}') { | ||||||
|  |       // Count opening and closing braces to detect complete JSON | ||||||
|  |       int braceCount = 0; | ||||||
|  |       for (uint32_t j = 0; j <= i; j++) { | ||||||
|  |         if (ndefRecord[payloadOffset + j] == '{') braceCount++; | ||||||
|  |         else if (ndefRecord[payloadOffset + j] == '}') braceCount--; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       if (braceCount == 0) { | ||||||
|  |         Serial.print("Found complete JSON object at position: "); | ||||||
|  |         Serial.println(i); | ||||||
|  |         actualJsonLength = i + 1; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   Serial.print("Actual JSON length extracted: "); | ||||||
|  |   Serial.println(actualJsonLength); | ||||||
|  |   Serial.print("Total nfcJsonData length: "); | ||||||
|  |   Serial.println(nfcJsonData.length()); | ||||||
|  |   Serial.println("=== DECODED JSON DATA START ==="); | ||||||
|  |   Serial.println(nfcJsonData); | ||||||
|  |   Serial.println("=== DECODED JSON DATA END ==="); | ||||||
|  |    | ||||||
|  |   // Check if JSON was truncated | ||||||
|  |   if (nfcJsonData.length() < payloadLength && !nfcJsonData.endsWith("}")) { | ||||||
|  |     Serial.println("WARNING: JSON payload appears to be truncated!"); | ||||||
|  |     Serial.print("Expected payload length: "); | ||||||
|  |     Serial.println(payloadLength); | ||||||
|  |     Serial.print("Actual extracted length: "); | ||||||
|  |     Serial.println(nfcJsonData.length()); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Trim any trailing whitespace or invalid characters | ||||||
|  |   nfcJsonData.trim(); | ||||||
|  |  | ||||||
|   // JSON-Dokument verarbeiten |   // JSON-Dokument verarbeiten | ||||||
|   JsonDocument doc; |   JsonDocument doc; | ||||||
|   DeserializationError error = deserializeJson(doc, nfcJsonData); |   DeserializationError error = deserializeJson(doc, nfcJsonData); | ||||||
| @@ -443,7 +922,9 @@ void scanRfidTask(void * parameter) { | |||||||
|  |  | ||||||
|         oledShowProgressBar(0, octoEnabled?5:4, "Reading", "Detecting tag"); |         oledShowProgressBar(0, octoEnabled?5:4, "Reading", "Detecting tag"); | ||||||
|  |  | ||||||
|         //vTaskDelay(500 / portTICK_PERIOD_MS); |         // Wait 1 second after tag detection to stabilize connection | ||||||
|  |         Serial.println("Tag detected, waiting 1 second for stabilization..."); | ||||||
|  |         vTaskDelay(1000 / portTICK_PERIOD_MS); | ||||||
|  |  | ||||||
|         // create Tag UID string |         // create Tag UID string | ||||||
|         String uidString = ""; |         String uidString = ""; | ||||||
| @@ -466,24 +947,34 @@ void scanRfidTask(void * parameter) { | |||||||
|  |  | ||||||
|             // We probably have an NTAG2xx card (though it could be Ultralight as well) |             // We probably have an NTAG2xx card (though it could be Ultralight as well) | ||||||
|             Serial.println("Seems to be an NTAG2xx tag (7 byte UID)"); |             Serial.println("Seems to be an NTAG2xx tag (7 byte UID)"); | ||||||
|  |             Serial.print("Tag size: "); | ||||||
|  |             Serial.print(tagSize); | ||||||
|  |             Serial.println(" bytes"); | ||||||
|              |              | ||||||
|             uint8_t numPages = readTagSize()/4; |             uint8_t numPages = readTagSize()/4; | ||||||
|  |              | ||||||
|             for (uint8_t i = 4; i < 4+numPages; i++) { |             for (uint8_t i = 4; i < 4+numPages; i++) { | ||||||
|  |                | ||||||
|               if (!nfc.ntag2xx_ReadPage(i, data+(i-4) * 4)) |               if (!nfc.ntag2xx_ReadPage(i, data+(i-4) * 4)) | ||||||
|               { |               { | ||||||
|                 break; // Stop if reading fails |                 break; // Stop if reading fails | ||||||
|               } |               } | ||||||
|  |               | ||||||
|               // Check for NDEF message end |               // Check for NDEF message end | ||||||
|               if (data[(i - 4) * 4] == 0xFE)  |               if (data[(i - 4) * 4] == 0xFE)  | ||||||
|               { |               { | ||||||
|  |                 Serial.println("Found NDEF message end marker"); | ||||||
|                 break; // End of NDEF message |                 break; // End of NDEF message | ||||||
|               } |               } | ||||||
|  |  | ||||||
|               yield(); |               yield(); | ||||||
|               esp_task_wdt_reset(); |               esp_task_wdt_reset(); | ||||||
|               vTaskDelay(pdMS_TO_TICKS(1)); |               // Increased delay to ensure stable reading | ||||||
|  |               vTaskDelay(pdMS_TO_TICKS(5)); // Increased from 1ms to 5ms | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |             Serial.println("Tag reading completed, starting NDEF decode..."); | ||||||
|  |              | ||||||
|             if (!decodeNdefAndReturnJson(data, uidString))  |             if (!decodeNdefAndReturnJson(data, uidString))  | ||||||
|             { |             { | ||||||
|               oledShowProgressBar(1, 1, "Failure", "Unknown tag"); |               oledShowProgressBar(1, 1, "Failure", "Unknown tag"); | ||||||
| @@ -519,6 +1010,18 @@ void scanRfidTask(void * parameter) { | |||||||
|         Serial.println("Tag entfernt"); |         Serial.println("Tag entfernt"); | ||||||
|         if (!bambuCredentials.autosend_enable) oledShowWeight(weight); |         if (!bambuCredentials.autosend_enable) oledShowWeight(weight); | ||||||
|       } |       } | ||||||
|  |       // Reset state after successful read when tag is removed | ||||||
|  |       else if (!success && nfcReaderState == NFC_READ_SUCCESS) | ||||||
|  |       { | ||||||
|  |         nfcReaderState = NFC_IDLE; | ||||||
|  |         Serial.println("Tag nach erfolgreichem Lesen entfernt - bereit für nächsten Tag"); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // Add a longer pause after successful reading to prevent immediate re-reading | ||||||
|  |       if (nfcReaderState == NFC_READ_SUCCESS) { | ||||||
|  |         Serial.println("Tag erfolgreich gelesen - warte 5 Sekunden vor nächstem Scan"); | ||||||
|  |         vTaskDelay(5000 / portTICK_PERIOD_MS); // 5 second pause | ||||||
|  |       } | ||||||
|  |  | ||||||
|       // aktualisieren der Website wenn sich der Status ändert |       // aktualisieren der Website wenn sich der Status ändert | ||||||
|       sendNfcData(); |       sendNfcData(); | ||||||
|   | |||||||
| @@ -48,7 +48,8 @@ void scale_loop(void * parameter) { | |||||||
|   Serial.println("Scale Loop started"); |   Serial.println("Scale Loop started"); | ||||||
|   Serial.println("++++++++++++++++++++++++++++++"); |   Serial.println("++++++++++++++++++++++++++++++"); | ||||||
|  |  | ||||||
|   scale.tare(); |   vTaskDelay(pdMS_TO_TICKS(500)); | ||||||
|  |   scale_tare_counter = 10; // damit beim Starten der Waage automatisch getart wird | ||||||
|    |    | ||||||
|   for(;;) { |   for(;;) { | ||||||
|     if (scale.is_ready())  |     if (scale.is_ready())  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user