Reworks graphics of tag reading and some api fixes

Reworks the graphics of the NFC-Tag reading process of spool and location tags. Introduces progress bar for reading process. Also first re-work of the spoolman availability (not fixed completly yet). Also fixes an issue where the API request to spoolman and octoprint was sent in parallel. This now happens sequentially to reduce heap load.
This commit is contained in:
Jan Philipp Ecker
2025-08-03 16:51:09 +02:00
parent 85a9bcf8bd
commit 97a1368747
8 changed files with 147 additions and 76 deletions

View File

@@ -9,8 +9,11 @@ volatile spoolmanApiStateType spoolmanApiState = API_INIT;
//bool spoolman_connected = false; //bool spoolman_connected = false;
String spoolmanUrl = ""; String spoolmanUrl = "";
bool octoEnabled = false; bool octoEnabled = false;
bool sendOctoUpdate = false;
String octoUrl = ""; String octoUrl = "";
String octoToken = ""; String octoToken = "";
uint16_t remainingWeight = 0;
bool spoolmanConnected = false;
struct SendToApiParams { struct SendToApiParams {
SpoolmanApiRequestType requestType; SpoolmanApiRequestType requestType;
@@ -124,23 +127,58 @@ void sendToApi(void *parameter) {
Serial.print("Fehler beim Parsen der JSON-Antwort: "); Serial.print("Fehler beim Parsen der JSON-Antwort: ");
Serial.println(error.c_str()); Serial.println(error.c_str());
} else { } else {
if (requestType == API_REQUEST_SPOOL_WEIGHT_UPDATE) { switch(requestType){
uint16_t remaining_weight = doc["remaining_weight"].as<float>(); case API_REQUEST_SPOOL_WEIGHT_UPDATE:
remainingWeight = doc["remaining_weight"].as<uint16_t>();
Serial.print("Aktuelles Gewicht: "); Serial.print("Aktuelles Gewicht: ");
Serial.println(remaining_weight); Serial.println(remainingWeight);
oledShowMessage("Remaining: " + String(remaining_weight) + "g"); //oledShowMessage("Remaining: " + String(remaining_weight) + "g");
} if(!octoEnabled){
else if ( requestType == API_REQUEST_SPOOL_LOCATION_UPDATE) { // TBD: Do not use Strings...
oledShowMessage("Location updated!"); oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Spool Tag", ("Done: " + String(remainingWeight) + " g remain").c_str());
remainingWeight = 0;
}else{
// ocoto is enabled, trigger octo update
sendOctoUpdate = true;
}
break;
case API_REQUEST_SPOOL_LOCATION_UPDATE:
oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Loc. Tag", "Done!");
break;
case API_REQUEST_OCTO_SPOOL_UPDATE:
// TBD: Do not use Strings...
oledShowProgressBar(5, 5, "Spool Tag", ("Done: " + String(remainingWeight) + " g remain").c_str());
remainingWeight = 0;
break;
} }
// TBD: really required?
vTaskDelay(3000 / portTICK_PERIOD_MS); vTaskDelay(3000 / portTICK_PERIOD_MS);
} }
doc.clear(); doc.clear();
} else { } else {
switch(requestType){
case API_REQUEST_SPOOL_WEIGHT_UPDATE:
oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Failure!", "Spoolman update");
break;
case API_REQUEST_SPOOL_LOCATION_UPDATE:
oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Failure!", "Spoolman update");
break;
case API_REQUEST_OCTO_SPOOL_UPDATE:
oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Failure!", "Octoprint update");
break;
case API_REQUEST_BAMBU_UPDATE:
// TBD: rework error
oledShowMessage("Spoolman update failed");
break;
case API_REQUEST_SPOOL_TAG_ID_UPDATE:
// TBD: rework error
oledShowMessage("Spoolman update failed");
break;
}
Serial.println("Fehler beim Senden an Spoolman! HTTP Code: " + String(httpCode)); Serial.println("Fehler beim Senden an Spoolman! HTTP Code: " + String(httpCode));
oledShowMessage("Spoolman update failed");
// TBD: really required?
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
} }
@@ -215,6 +253,7 @@ bool updateSpoolTagId(String uidString, const char* payload) {
uint8_t updateSpoolWeight(String spoolId, uint16_t weight) { uint8_t updateSpoolWeight(String spoolId, uint16_t weight) {
HEAP_DEBUG_MESSAGE("updateSpoolWeight begin"); HEAP_DEBUG_MESSAGE("updateSpoolWeight begin");
oledShowProgressBar(3, octoEnabled?5:4, "Spool Tag", "Spoolman update");
String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId + "/measure"; String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId + "/measure";
Serial.print("Update Spule mit URL: "); Serial.print("Update Spule mit URL: ");
Serial.println(spoolsUrl); Serial.println(spoolsUrl);
@@ -230,6 +269,7 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) {
SendToApiParams* params = new SendToApiParams(); SendToApiParams* params = new SendToApiParams();
if (params == nullptr) { if (params == nullptr) {
// TBD: reset ESP instead of showing a message
Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren.");
return 0; return 0;
} }
@@ -257,6 +297,8 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) {
uint8_t updateSpoolLocation(String spoolId, String location){ uint8_t updateSpoolLocation(String spoolId, String location){
HEAP_DEBUG_MESSAGE("updateSpoolLocation begin"); HEAP_DEBUG_MESSAGE("updateSpoolLocation begin");
oledShowProgressBar(3, octoEnabled?5:4, "Loc. Tag", "Spoolman update");
String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId; String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId;
Serial.print("Update Spule mit URL: "); Serial.print("Update Spule mit URL: ");
Serial.println(spoolsUrl); Serial.println(spoolsUrl);
@@ -280,6 +322,7 @@ uint8_t updateSpoolLocation(String spoolId, String location){
params->spoolsUrl = spoolsUrl; params->spoolsUrl = spoolsUrl;
params->updatePayload = updatePayload; params->updatePayload = updatePayload;
if(spoolmanApiState == API_IDLE){
// Erstelle die Task // Erstelle die Task
BaseType_t result = xTaskCreate( BaseType_t result = xTaskCreate(
sendToApi, // Task-Funktion sendToApi, // Task-Funktion
@@ -290,6 +333,10 @@ uint8_t updateSpoolLocation(String spoolId, String location){
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
}else{
Serial.println("Not spawning new task, API still active!");
}
updateDoc.clear(); updateDoc.clear();
HEAP_DEBUG_MESSAGE("updateSpoolLocation end"); HEAP_DEBUG_MESSAGE("updateSpoolLocation end");
@@ -297,6 +344,8 @@ uint8_t updateSpoolLocation(String spoolId, String location){
} }
bool updateSpoolOcto(int spoolId) { bool updateSpoolOcto(int spoolId) {
oledShowProgressBar(4, octoEnabled?5:4, "Spool Tag", "Octoprint update");
String spoolsUrl = octoUrl + "/plugin/Spoolman/selectSpool"; String spoolsUrl = octoUrl + "/plugin/Spoolman/selectSpool";
Serial.print("Update Spule in Octoprint mit URL: "); Serial.print("Update Spule in Octoprint mit URL: ");
Serial.println(spoolsUrl); Serial.println(spoolsUrl);
@@ -561,6 +610,7 @@ bool checkSpoolmanInstance(const String& url) {
if (!checkSpoolmanExtraFields()) { if (!checkSpoolmanExtraFields()) {
Serial.println("Fehler beim Überprüfen der Extrafelder."); Serial.println("Fehler beim Überprüfen der Extrafelder.");
// TBD
oledShowMessage("Spoolman Error creating Extrafields"); oledShowMessage("Spoolman Error creating Extrafields");
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
@@ -569,6 +619,7 @@ bool checkSpoolmanInstance(const String& url) {
spoolmanApiState = API_IDLE; spoolmanApiState = API_IDLE;
oledShowTopRow(); oledShowTopRow();
spoolmanConnected = true;
return strcmp(status, "healthy") == 0; return strcmp(status, "healthy") == 0;
} }

View File

@@ -24,8 +24,10 @@ extern volatile spoolmanApiStateType spoolmanApiState;
extern bool spoolman_connected; extern bool spoolman_connected;
extern String spoolmanUrl; extern String spoolmanUrl;
extern bool octoEnabled; extern bool octoEnabled;
extern bool sendOctoUpdate;
extern String octoUrl; extern String octoUrl;
extern String octoToken; extern String octoToken;
extern bool spoolmanConnected;
bool checkSpoolmanInstance(const String& url); bool checkSpoolmanInstance(const String& url);
bool saveSpoolmanUrl(const String& url, bool octoOn, const String& octoWh, const String& octoTk); bool saveSpoolmanUrl(const String& url, bool octoOn, const String& octoWh, const String& octoTk);

View File

@@ -171,17 +171,19 @@ void oledShowTopRow() {
iconToggle = !iconToggle; iconToggle = !iconToggle;
if (bambu_connected == 1) { if(bambuDisabled == false) {
display.drawBitmap(50, 0, bitmap_bambu_on , 16, 16, WHITE); if (bambu_connected == 1) {
} else {
if(iconToggle){
display.drawBitmap(50, 0, bitmap_bambu_on , 16, 16, WHITE); display.drawBitmap(50, 0, bitmap_bambu_on , 16, 16, WHITE);
display.drawLine(50, 15, 66, 0, WHITE); } else {
display.drawLine(51, 15, 67, 0, WHITE); if(iconToggle){
display.drawBitmap(50, 0, bitmap_bambu_on , 16, 16, WHITE);
display.drawLine(50, 15, 66, 0, WHITE);
display.drawLine(51, 15, 67, 0, WHITE);
}
} }
} }
if (spoolmanApiState != API_INIT) { if (spoolmanConnected) {
display.drawBitmap(80, 0, bitmap_spoolman_on , 16, 16, WHITE); display.drawBitmap(80, 0, bitmap_spoolman_on , 16, 16, WHITE);
} else { } else {
if(iconToggle){ if(iconToggle){

View File

@@ -218,19 +218,14 @@ void loop() {
lastWeight = weight; lastWeight = weight;
// Wenn ein Tag mit SM id erkannte wurde und der Waage Counter anspricht an SM Senden // Wenn ein Tag mit SM id erkannte wurde und der Waage Counter anspricht an SM Senden
if (activeSpoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && nfcReaderState == NFC_READ_SUCCESS) { if (activeSpoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && nfcReaderState == NFC_READ_SUCCESS && tagProcessed == false && spoolmanApiState == API_IDLE) {
oledShowIcon("loading"); // set the current tag as processed to prevent it beeing processed again
tagProcessed = true;
if (updateSpoolWeight(activeSpoolId, weight)) if (updateSpoolWeight(activeSpoolId, weight))
{ {
oledShowIcon("success");
vTaskDelay(2000 / portTICK_PERIOD_MS);
weightSend = 1; weightSend = 1;
autoSetToBambuSpoolId = activeSpoolId.toInt();
if (octoEnabled)
{
updateSpoolOcto(autoSetToBambuSpoolId);
}
} }
else else
{ {
@@ -239,5 +234,15 @@ void loop() {
} }
} }
if(sendOctoUpdate && spoolmanApiState == API_IDLE){
autoSetToBambuSpoolId = activeSpoolId.toInt();
if(octoEnabled)
{
updateSpoolOcto(autoSetToBambuSpoolId);
}
sendOctoUpdate = false;
}
esp_task_wdt_reset(); esp_task_wdt_reset();
} }

View File

@@ -18,6 +18,7 @@ JsonDocument rfidData;
String activeSpoolId = ""; String activeSpoolId = "";
String lastSpoolId = ""; String lastSpoolId = "";
String nfcJsonData = ""; String nfcJsonData = "";
bool tagProcessed = false;
volatile bool pauseBambuMqttTask = false; volatile bool pauseBambuMqttTask = false;
volatile nfcReaderStateType nfcReaderState = NFC_IDLE; volatile nfcReaderStateType nfcReaderState = NFC_IDLE;
@@ -196,6 +197,8 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
} }
bool decodeNdefAndReturnJson(const byte* encodedMessage) { bool decodeNdefAndReturnJson(const byte* encodedMessage) {
oledShowProgressBar(1, octoEnabled?5:4, "Reading", "Decoding data");
byte typeLength = encodedMessage[3]; byte typeLength = encodedMessage[3];
byte payloadLength = encodedMessage[4]; byte payloadLength = encodedMessage[4];
@@ -219,35 +222,43 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage) {
} }
else else
{ {
// Sende die aktualisierten AMS-Daten an alle WebSocket-Clients // If spoolman is unavailable, there is no point in continuing
Serial.println("JSON-Dokument erfolgreich verarbeitet"); if(spoolmanConnected){
Serial.println(doc.as<String>()); // Sende die aktualisierten AMS-Daten an alle WebSocket-Clients
if (doc["sm_id"].is<String>() && doc["sm_id"] != "") Serial.println("JSON-Dokument erfolgreich verarbeitet");
{ Serial.println(doc.as<String>());
Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as<String>()); if (doc["sm_id"].is<String>() && doc["sm_id"] != "")
activeSpoolId = doc["sm_id"].as<String>(); {
lastSpoolId = activeSpoolId; oledShowProgressBar(2, octoEnabled?5:4, "Spool Tag", "Weighing");
} Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as<String>());
else if(doc["location"].is<String>() && doc["location"] != "") activeSpoolId = doc["sm_id"].as<String>();
{ lastSpoolId = activeSpoolId;
Serial.println("Location Tag found!");
String location = doc["location"].as<String>(); Serial.println("Api state: " + String(spoolmanApiState));
if(lastSpoolId != ""){ }
updateSpoolLocation(lastSpoolId, location); else if(doc["location"].is<String>() && doc["location"] != "")
{
Serial.println("Location Tag found!");
String location = doc["location"].as<String>();
if(lastSpoolId != ""){
updateSpoolLocation(lastSpoolId, location);
}
else
{
Serial.println("Location update tag scanned without scanning spool before!");
oledShowProgressBar(1, 1, "Failure", "Scan spool first");
}
} }
else else
{ {
Serial.println("Location update tag scanned without scanning spool before!"); Serial.println("Keine SPOOL-ID gefunden.");
oledShowMessage("No spool scanned before!"); activeSpoolId = "";
// TBD: this path has not been tested!
oledShowMessage("Unknown Spool");
vTaskDelay(2000 / portTICK_PERIOD_MS);
} }
}else{
} oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Failure!", "Spoolman unavailable");
else
{
Serial.println("Keine SPOOL-ID gefunden.");
activeSpoolId = "";
oledShowMessage("Unknown Spool");
vTaskDelay(2000 / portTICK_PERIOD_MS);
} }
} }
@@ -384,14 +395,19 @@ void scanRfidTask(void * parameter) {
foundNfcTag(nullptr, success); foundNfcTag(nullptr, success);
if (success && nfcReaderState != NFC_READ_SUCCESS) // As long as there is still a tag on the reader, do not try to read it again
if (success && nfcReaderState != NFC_READ_SUCCESS && nfcReaderState != NFC_READ_ERROR)
{ {
// Set the current tag as not processed
tagProcessed = false;
// Display some basic information about the card // Display some basic information about the card
Serial.println("Found an ISO14443A card"); Serial.println("Found an ISO14443A card");
nfcReaderState = NFC_READING; nfcReaderState = NFC_READING;
oledShowIcon("transfer"); oledShowProgressBar(0, octoEnabled?5:4, "Reading", "Detecting tag");
vTaskDelay(500 / portTICK_PERIOD_MS); vTaskDelay(500 / portTICK_PERIOD_MS);
if (uidLength == 7) if (uidLength == 7)
@@ -425,8 +441,7 @@ void scanRfidTask(void * parameter) {
if (!decodeNdefAndReturnJson(data)) if (!decodeNdefAndReturnJson(data))
{ {
oledShowMessage("NFC-Tag unknown"); oledShowProgressBar(1, 1, "Failure", "Unkown Tag");
vTaskDelay(2000 / portTICK_PERIOD_MS);
nfcReaderState = NFC_READ_ERROR; nfcReaderState = NFC_READ_ERROR;
} }
else else
@@ -438,12 +453,13 @@ void scanRfidTask(void * parameter) {
} }
else else
{ {
oledShowMessage("NFC-Tag read error"); oledShowProgressBar(1, 1, "Failure", "Tag Read Error");
nfcReaderState = NFC_READ_ERROR; nfcReaderState = NFC_READ_ERROR;
} }
} }
else else
{ {
//TBD: Show error here?!
Serial.println("This doesn't seem to be an NTAG2xx tag (UUID length != 7 bytes)!"); Serial.println("This doesn't seem to be an NTAG2xx tag (UUID length != 7 bytes)!");
} }
} }
@@ -474,6 +490,7 @@ void startNfc() {
Serial.println("Kann kein RFID Board finden !"); // Sende Text "Kann kein..." an seriellen Monitor Serial.println("Kann kein RFID Board finden !"); // Sende Text "Kann kein..." an seriellen Monitor
//delay(5000); //delay(5000);
//ESP.restart(); //ESP.restart();
//TBD: rework this
oledShowMessage("No RFID Board found"); oledShowMessage("No RFID Board found");
delay(2000); delay(2000);
} }

View File

@@ -23,6 +23,7 @@ extern String activeSpoolId;
extern String lastSpoolId; extern String lastSpoolId;
extern volatile nfcReaderStateType nfcReaderState; extern volatile nfcReaderStateType nfcReaderState;
extern volatile bool pauseBambuMqttTask; extern volatile bool pauseBambuMqttTask;
extern bool tagProcessed;

View File

@@ -162,7 +162,7 @@ uint8_t calibrate_scale() {
{ {
scale.set_scale(); scale.set_scale();
oledShowMessage("Step 1 empty Scale"); oledShowProgressBar(0, 3, "Scale Cal.", "Empty Scale");
for (uint16_t i = 0; i < 5000; i++) { for (uint16_t i = 0; i < 5000; i++) {
yield(); yield();
@@ -174,7 +174,7 @@ uint8_t calibrate_scale() {
Serial.println("Tare done..."); Serial.println("Tare done...");
Serial.print("Place a known weight on the scale..."); Serial.print("Place a known weight on the scale...");
oledShowMessage("Step 2 Place the weight"); oledShowProgressBar(1, 3, "Scale Cal.", "Place the weight");
for (uint16_t i = 0; i < 5000; i++) { for (uint16_t i = 0; i < 5000; i++) {
yield(); yield();
@@ -207,9 +207,7 @@ uint8_t calibrate_scale() {
Serial.print("Verified stored value: "); Serial.print("Verified stored value: ");
Serial.println(verifyValue); Serial.println(verifyValue);
Serial.println("End calibration, remove weight"); oledShowProgressBar(2, 3, "Scale Cal.", "Remove weight");
oledShowMessage("Remove weight");
scale.set_scale(newCalibrationValue); scale.set_scale(newCalibrationValue);
for (uint16_t i = 0; i < 2000; i++) { for (uint16_t i = 0; i < 2000; i++) {
@@ -218,7 +216,7 @@ uint8_t calibrate_scale() {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
oledShowMessage("Scale calibrated"); oledShowProgressBar(3, 3, "Scale Cal.", "Completed");
// For some reason it is not possible to re-tare the scale here, it will result in a wdt timeout. Instead let the scale loop do the taring // For some reason it is not possible to re-tare the scale here, it will result in a wdt timeout. Instead let the scale loop do the taring
//scale.tare(); //scale.tare();
@@ -232,21 +230,18 @@ uint8_t calibrate_scale() {
returnState = 1; returnState = 1;
} }
else else
{ {
{ Serial.println("Calibration value is invalid. Please recalibrate.");
Serial.println("Calibration value is invalid. Please recalibrate.");
oledShowMessage("Calibration ERROR Try again"); oledShowMessage("Calibration ERROR Try again");
for (uint16_t i = 0; i < 50000; i++) { for (uint16_t i = 0; i < 50000; i++) {
yield(); yield();
vTaskDelay(pdMS_TO_TICKS(1)); vTaskDelay(pdMS_TO_TICKS(1));
esp_task_wdt_reset(); esp_task_wdt_reset();
}
returnState = 0;
} }
returnState = 0;
} }
} }
else else

View File

@@ -52,8 +52,6 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, message); deserializeJson(doc, message);
bool spoolmanConnected = (spoolmanApiState != API_INIT);
if (doc["type"] == "heartbeat") { if (doc["type"] == "heartbeat") {
// Sende Heartbeat-Antwort // Sende Heartbeat-Antwort
ws.text(client->id(), "{" ws.text(client->id(), "{"