Compare commits

..

35 Commits

Author SHA1 Message Date
e537c6ec07 docs: update changelog and header for version v2.0.0-beta14
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m4s
2025-08-30 16:47:24 +02:00
bec769e95a docs: update platformio.ini for beta version v2.0.0-beta14 2025-08-30 16:47:24 +02:00
5cc58927a6 feat: implement retry mechanism and timeout handling for API requests 2025-08-30 16:47:18 +02:00
afde3f5f81 fix: add timeout handling and error states for vendor and filament operations 2025-08-30 16:40:01 +02:00
6800c88bb2 docs: update changelog and header for version v2.0.0-beta13
All checks were successful
Release Workflow / detect-provider (push) Successful in 4s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m8s
2025-08-30 15:52:46 +02:00
6172242f24 docs: update platformio.ini for beta version v2.0.0-beta13 2025-08-30 15:52:46 +02:00
7f4b3b8d90 refactor: optimize weight stabilization parameters for improved responsiveness 2025-08-30 15:52:38 +02:00
7a15424bc7 docs: update changelog and header for version v2.0.0-beta12
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m59s
2025-08-30 15:43:59 +02:00
039a29fa3c docs: update platformio.ini for beta version v2.0.0-beta12 2025-08-30 15:43:59 +02:00
6cccf3d603 feat: enhance weight processing with filtered display and API stability checks 2025-08-30 15:43:51 +02:00
693ee839e5 docs: update changelog and header for version v2.0.0-beta11
All checks were successful
Release Workflow / detect-provider (push) Successful in 4s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m21s
2025-08-30 14:56:09 +02:00
0bf383ecd9 docs: update changelog and header for version v2.0.0-beta11 2025-08-30 14:55:54 +02:00
6451d91c59 docs: update platformio.ini for beta version v2.0.0-beta11 2025-08-30 14:55:53 +02:00
8d82e221b5 feat: implement weight stabilization functions and improve tare handling 2025-08-30 14:55:42 +02:00
bf63ecd594 docs: update changelog and header for version v2.0.0-beta10
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m55s
2025-08-30 11:27:29 +02:00
0daa3a148b docs: update platformio.ini for beta version v2.0.0-beta10 2025-08-30 11:27:29 +02:00
602642c203 feat: add fast-path JSON reading for web interface display 2025-08-30 11:27:22 +02:00
458bd2e67b docs: update changelog and header for version v2.0.0-beta9
All checks were successful
Release Workflow / detect-provider (push) Successful in 4s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m11s
2025-08-30 11:09:04 +02:00
e6a5cb29a9 docs: update platformio.ini for beta version v2.0.0-beta9 2025-08-30 11:09:04 +02:00
6502bb7185 feat: add handling for successful NFC tag writes to send weight to Spoolman without auto-sending to Bambu 2025-08-30 11:08:56 +02:00
63fafa2463 docs: update changelog and header for version v2.0.0-beta8
All checks were successful
Release Workflow / detect-provider (push) Successful in 5s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m4s
2025-08-30 10:17:37 +02:00
f664e85933 docs: update platformio.ini for beta version v2.0.0-beta8 2025-08-30 10:17:37 +02:00
7bf9868d79 feat: implement robust page reading with error recovery for NFC tags 2025-08-30 10:17:30 +02:00
b9e488d675 docs: update changelog and header for version v2.0.0-beta7
Some checks failed
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Failing after 2m13s
2025-08-30 10:09:28 +02:00
2e3fc19741 docs: update platformio.ini for beta version v2.0.0-beta7 2025-08-30 10:09:28 +02:00
4d84169b29 feat: enhance NFC tag reading with robust error recovery and JSON optimization for fast-path detection 2025-08-30 10:09:22 +02:00
10aeb9bc52 docs: update changelog and header for version v2.0.0-beta6
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m52s
2025-08-30 09:28:33 +02:00
00b9bc08af docs: update changelog and header for version v2.0.0-beta6 2025-08-30 09:28:10 +02:00
dfe9e4dbe9 docs: update platformio.ini for beta version v2.0.0-beta6 2025-08-30 09:28:09 +02:00
79eacae225 feat: implement robust page reading and safe tag detection with error recovery 2025-08-30 09:27:57 +02:00
d5d7358f58 fix: enhance commit categorization for breaking changes 2025-08-30 08:54:40 +02:00
9b362b3c73 BREAKING CHANGE: Handling of Spools with Tags from Vendors.
fix: improve get_last_tag function to handle non-beta tags and fallback to newest tag
2025-08-30 08:52:45 +02:00
bc51956793 docs: update changelog and header for version v2.0.0-beta5
All checks were successful
Release Workflow / detect-provider (push) Successful in 4s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m18s
2025-08-30 08:25:58 +02:00
5666a58da2 docs: update platformio.ini for beta version v2.0.0-beta5 2025-08-30 08:25:58 +02:00
a35f15eca5 fix: call scale.tare() in setup after starting scale 2025-08-30 08:25:52 +02:00
9 changed files with 1531 additions and 74 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html
[common]
version = "2.0.0-beta4"
version = "2.0.0-beta14"
to_old_version = "1.5.10"
##

View File

@@ -14,17 +14,39 @@ def get_version():
return version_match.group(1) if version_match else None
def get_last_tag():
"""Get the last non-beta tag for changelog generation"""
try:
result = subprocess.run(['git', 'describe', '--tags', '--abbrev=0'],
# Get all tags sorted by version
result = subprocess.run(['git', 'tag', '-l', '--sort=-version:refname'],
capture_output=True, text=True)
return result.stdout.strip()
if result.returncode != 0:
return None
tags = result.stdout.strip().split('\n')
# Find the first (newest) non-beta tag
for tag in tags:
if tag and not '-beta' in tag.lower():
print(f"Using last stable tag for changelog: {tag}")
return tag
# Fallback: if no non-beta tags found, use the newest tag
print("No stable tags found, using newest tag")
if tags and tags[0]:
return tags[0]
return None
except subprocess.CalledProcessError:
return None
def categorize_commit(commit_msg):
"""Categorize commit messages based on conventional commits"""
lower_msg = commit_msg.lower()
if any(x in lower_msg for x in ['feat', 'add', 'new']):
# Check for breaking changes first
if ('!' in commit_msg and any(x in lower_msg for x in ['feat!', 'fix!', 'chore!', 'refactor!'])) or \
'breaking change' in lower_msg or 'breaking:' in lower_msg:
return 'Breaking Changes'
elif any(x in lower_msg for x in ['feat', 'add', 'new']):
return 'Added'
elif any(x in lower_msg for x in ['fix', 'bug']):
return 'Fixed'
@@ -34,6 +56,7 @@ def categorize_commit(commit_msg):
def get_changes_from_git():
"""Get changes from git commits since last tag"""
changes = {
'Breaking Changes': [],
'Added': [],
'Changed': [],
'Fixed': []
@@ -55,7 +78,9 @@ def get_changes_from_git():
if commit:
category = categorize_commit(commit)
# Clean up commit message
clean_msg = re.sub(r'^(feat|fix|chore|docs|style|refactor|perf|test)(\(.*\))?:', '', commit).strip()
clean_msg = re.sub(r'^(feat|fix|chore|docs|style|refactor|perf|test)(\(.*\))?!?:', '', commit).strip()
# Remove BREAKING CHANGE prefix if present
clean_msg = re.sub(r'^breaking change:\s*', '', clean_msg, flags=re.IGNORECASE).strip()
changes[category].append(clean_msg)
except subprocess.CalledProcessError:

View File

@@ -124,28 +124,69 @@ void sendToApi(void *parameter) {
String octoToken = params->octoToken;
bool triggerWeightUpdate = params->triggerWeightUpdate;
String spoolIdForWeight = params->spoolIdForWeight;
uint16_t weightValue = params->weightValue;
uint16_t weightValue = params->weightValue;
HTTPClient http;
http.setReuse(false);
// Retry mechanism with configurable parameters
const uint8_t MAX_RETRIES = 3;
const uint16_t RETRY_DELAY_MS = 1000; // 1 second between retries
const uint16_t HTTP_TIMEOUT_MS = 10000; // 10 second HTTP timeout
bool success = false;
int httpCode = -1;
String responsePayload = "";
// Try request with retries
for (uint8_t attempt = 1; attempt <= MAX_RETRIES && !success; attempt++) {
Serial.printf("API Request attempt %d/%d to: %s\n", attempt, MAX_RETRIES, spoolsUrl.c_str());
HTTPClient http;
http.setReuse(false);
http.setTimeout(HTTP_TIMEOUT_MS); // Set HTTP timeout
http.begin(spoolsUrl);
http.addHeader("Content-Type", "application/json");
if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken);
http.begin(spoolsUrl);
http.addHeader("Content-Type", "application/json");
if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken);
// Execute HTTP request based on type
if (httpType == "PATCH") httpCode = http.PATCH(updatePayload);
else if (httpType == "POST") httpCode = http.POST(updatePayload);
else if (httpType == "GET") httpCode = http.GET();
else httpCode = http.PUT(updatePayload);
int httpCode;
if (httpType == "PATCH") httpCode = http.PATCH(updatePayload);
else if (httpType == "POST") httpCode = http.POST(updatePayload);
else if (httpType == "GET") httpCode = http.GET();
else httpCode = http.PUT(updatePayload);
// Check if request was successful
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_CREATED) {
responsePayload = http.getString();
success = true;
Serial.printf("API Request successful on attempt %d, HTTP Code: %d\n", attempt, httpCode);
} else {
Serial.printf("API Request failed on attempt %d, HTTP Code: %d (%s)\n",
attempt, httpCode, http.errorToString(httpCode).c_str());
// Don't retry on certain error codes (client errors)
if (httpCode >= 400 && httpCode < 500 && httpCode != 408 && httpCode != 429) {
Serial.println("Client error detected, stopping retries");
break;
}
// Wait before retry (except on last attempt)
if (attempt < MAX_RETRIES) {
Serial.printf("Waiting %dms before retry...\n", RETRY_DELAY_MS);
http.end();
vTaskDelay(RETRY_DELAY_MS / portTICK_PERIOD_MS);
continue;
}
}
http.end();
}
if (httpCode == HTTP_CODE_OK) {
// Process successful response
if (success) {
Serial.println("Spoolman Abfrage erfolgreich");
// Restgewicht der Spule auslesen
String payload = http.getString();
JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload);
DeserializationError error = deserializeJson(doc, responsePayload);
if (error) {
Serial.print("Fehler beim Parsen der JSON-Antwort: ");
Serial.println(error.c_str());
@@ -225,10 +266,9 @@ void sendToApi(void *parameter) {
} else if (httpCode == HTTP_CODE_CREATED) {
Serial.println("Spoolman erfolgreich erstellt");
// Parse response for created resources
String payload = http.getString();
// Parse response for created resources
JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload);
DeserializationError error = deserializeJson(doc, responsePayload);
if (error) {
Serial.print("Fehler beim Parsen der JSON-Antwort: ");
Serial.println(error.c_str());
@@ -280,14 +320,17 @@ void sendToApi(void *parameter) {
Serial.println(weightPayload);
// Execute weight update
http.begin(weightUrl);
http.addHeader("Content-Type", "application/json");
HTTPClient weightHttp;
weightHttp.setReuse(false);
weightHttp.setTimeout(HTTP_TIMEOUT_MS);
weightHttp.begin(weightUrl);
weightHttp.addHeader("Content-Type", "application/json");
int weightHttpCode = http.PUT(weightPayload);
int weightHttpCode = weightHttp.PUT(weightPayload);
if (weightHttpCode == HTTP_CODE_OK) {
Serial.println("Weight update successful");
String weightResponse = http.getString();
String weightResponse = weightHttp.getString();
JsonDocument weightResponseDoc;
DeserializationError weightError = deserializeJson(weightResponseDoc, weightResponse);
@@ -310,6 +353,7 @@ void sendToApi(void *parameter) {
oledShowProgressBar(1, 1, "Failure!", "Weight update");
}
weightHttp.end();
weightDoc.clear();
}
} else {
@@ -325,14 +369,25 @@ void sendToApi(void *parameter) {
case API_REQUEST_BAMBU_UPDATE:
oledShowProgressBar(1, 1, "Failure!", "Bambu update");
break;
case API_REQUEST_VENDOR_CHECK:
oledShowProgressBar(1, 1, "Failure!", "Vendor check");
foundVendorId = 0; // Set to 0 to indicate error/not found
break;
case API_REQUEST_VENDOR_CREATE:
oledShowProgressBar(1, 1, "Failure!", "Vendor create");
createdVendorId = 0; // Set to 0 to indicate error
break;
case API_REQUEST_FILAMENT_CHECK:
oledShowProgressBar(1, 1, "Failure!", "Filament check");
foundFilamentId = 0; // Set to 0 to indicate error/not found
break;
case API_REQUEST_FILAMENT_CREATE:
oledShowProgressBar(1, 1, "Failure!", "Filament create");
createdFilamentId = 0; // Set to 0 to indicate error
break;
case API_REQUEST_SPOOL_CREATE:
oledShowProgressBar(1, 1, "Failure!", "Spool create");
createdSpoolId = 0; // Set to 0 to indicate error instead of hanging
break;
}
Serial.println("Fehler beim Senden an Spoolman! HTTP Code: " + String(httpCode));
@@ -340,7 +395,6 @@ void sendToApi(void *parameter) {
nfcReaderState = NFC_IDLE; // Reset NFC state to allow retry
}
http.end();
vTaskDelay(50 / portTICK_PERIOD_MS);
// Speicher freigeben
@@ -952,6 +1006,13 @@ uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& paylo
while(createdSpoolId == 65535) {
vTaskDelay(50 / portTICK_PERIOD_MS);
}
// Check if spool creation was successful
if (createdSpoolId == 0) {
Serial.println("ERROR: Spool creation failed");
nfcReaderState = NFC_IDLE; // Reset NFC state
return 0;
}
// Write data to tag with startWriteJsonToTag
// void startWriteJsonToTag(const bool isSpoolTag, const char* payload);

View File

@@ -59,6 +59,7 @@ void setup() {
// Scale
start_scale(touchSensorConnected);
scale.tare();
// WDT initialisieren mit 10 Sekunden Timeout
bool panic = true; // Wenn true, löst ein WDT-Timeout einen System-Panik aus
@@ -177,9 +178,11 @@ void loop() {
// Ausgabe der Waage auf Display
if(pauseMainTask == 0)
{
// Use filtered weight for smooth display, but still check API weight for significant changes
int16_t displayWeight = getFilteredDisplayWeight();
if (mainTaskWasPaused || (weight != lastWeight && nfcReaderState == NFC_IDLE && (!bambuCredentials.autosend_enable || autoSetToBambuSpoolId == 0)))
{
(weight < 2) ? ((weight < -2) ? oledShowMessage("!! -0") : oledShowWeight(0)) : oledShowWeight(weight);
(displayWeight < 2) ? ((displayWeight < -2) ? oledShowMessage("!! -0") : oledShowWeight(0)) : oledShowWeight(displayWeight);
}
mainTaskWasPaused = false;
}
@@ -249,6 +252,25 @@ void loop() {
}
}
// Handle successful tag write: Send weight to Spoolman but NEVER auto-send to Bambu
if (activeSpoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && nfcReaderState == NFC_WRITE_SUCCESS && tagProcessed == false && spoolmanApiState == API_IDLE)
{
// set the current tag as processed to prevent it beeing processed again
tagProcessed = true;
if (updateSpoolWeight(activeSpoolId, weight))
{
weightSend = 1;
Serial.println("Tag written: Weight sent to Spoolman, but NO auto-send to Bambu");
// INTENTIONALLY do NOT set autoSetToBambuSpoolId here to prevent Bambu auto-send
}
else
{
oledShowIcon("failed");
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
if(octoEnabled && sendOctoUpdate && spoolmanApiState == API_IDLE)
{
updateSpoolOcto(autoSetToBambuSpoolId);

View File

@@ -108,6 +108,37 @@ bool formatNdefTag() {
return buffer[2]*8;
}
// Robust page reading with error recovery
bool robustPageRead(uint8_t page, uint8_t* buffer) {
const int MAX_READ_ATTEMPTS = 3;
for (int attempt = 0; attempt < MAX_READ_ATTEMPTS; attempt++) {
esp_task_wdt_reset();
yield();
if (nfc.ntag2xx_ReadPage(page, buffer)) {
return true;
}
Serial.printf("Page %d read failed, attempt %d/%d\n", page, attempt + 1, MAX_READ_ATTEMPTS);
// Try to stabilize connection between attempts
if (attempt < MAX_READ_ATTEMPTS - 1) {
vTaskDelay(pdMS_TO_TICKS(25));
// Re-verify tag presence with quick check
uint8_t uid[7];
uint8_t uidLength;
if (!nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 100)) {
Serial.println("Tag lost during read operation");
return false;
}
}
}
return false;
}
String detectNtagType()
{
// Read capability container from page 3 to determine exact NTAG type
@@ -1268,6 +1299,61 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) {
return true;
}
// Read complete JSON data for fast-path to enable web interface display
bool readCompleteJsonForFastPath() {
Serial.println("=== FAST-PATH: Reading complete JSON for web interface ===");
// Read tag size first
uint16_t tagSize = readTagSize();
if (tagSize == 0) {
Serial.println("FAST-PATH: Could not determine tag size");
return false;
}
// Create buffer for complete data
uint8_t* data = (uint8_t*)malloc(tagSize);
if (!data) {
Serial.println("FAST-PATH: Could not allocate memory for complete read");
return false;
}
memset(data, 0, tagSize);
// Read all pages
uint8_t numPages = tagSize / 4;
for (uint8_t i = 4; i < 4 + numPages; i++) {
if (!robustPageRead(i, data + (i - 4) * 4)) {
Serial.printf("FAST-PATH: Failed to read page %d\n", i);
free(data);
return false;
}
// Check for NDEF message end
if (data[(i - 4) * 4] == 0xFE) {
Serial.println("FAST-PATH: Found NDEF message end marker");
break;
}
yield();
esp_task_wdt_reset();
vTaskDelay(pdMS_TO_TICKS(2));
}
// Decode NDEF and extract JSON
bool success = decodeNdefAndReturnJson(data, ""); // Empty UID string for fast-path
free(data);
if (success) {
Serial.println("✓ FAST-PATH: Complete JSON data successfully loaded");
Serial.print("nfcJsonData length: ");
Serial.println(nfcJsonData.length());
} else {
Serial.println("✗ FAST-PATH: Failed to decode complete JSON data");
}
return success;
}
bool quickSpoolIdCheck(String uidString) {
// Fast-path: Read NDEF structure to quickly locate and check JSON payload
// This dramatically speeds up known spool recognition
@@ -1285,10 +1371,11 @@ bool quickSpoolIdCheck(String uidString) {
memset(ndefData, 0, 20);
for (uint8_t page = 4; page < 9; page++) {
if (!nfc.ntag2xx_ReadPage(page, ndefData + (page - 4) * 4)) {
Serial.print("Failed to read page ");
Serial.println(page);
return false; // Fall back to full read
if (!robustPageRead(page, ndefData + (page - 4) * 4)) {
Serial.print("FAST-PATH: Failed to read page ");
Serial.print(page);
Serial.println(" - falling back to full read");
return false; // Fall back to full read if any page read fails
}
}
@@ -1358,10 +1445,11 @@ bool quickSpoolIdCheck(String uidString) {
memset(extraData, 0, 16);
for (uint8_t page = 9; page < 13; page++) {
if (!nfc.ntag2xx_ReadPage(page, extraData + (page - 9) * 4)) {
Serial.print("Failed to read additional page ");
Serial.println(page);
return false;
if (!robustPageRead(page, extraData + (page - 9) * 4)) {
Serial.print("FAST-PATH: Failed to read additional page ");
Serial.print(page);
Serial.println(" - falling back to full read");
return false; // Fall back to full read if extended read fails
}
}
@@ -1403,6 +1491,14 @@ bool quickSpoolIdCheck(String uidString) {
activeSpoolId = quickSpoolId;
lastSpoolId = activeSpoolId;
// Read complete JSON data for web interface display
Serial.println("FAST-PATH: Reading complete JSON data for web interface...");
if (readCompleteJsonForFastPath()) {
Serial.println("✓ FAST-PATH: Complete JSON data loaded for web interface");
} else {
Serial.println("⚠ FAST-PATH: Could not read complete JSON, web interface may show limited data");
}
oledShowProgressBar(2, octoEnabled?5:4, "Known Spool", "Quick mode");
Serial.println("✓ FAST-PATH SUCCESS: Known spool processed quickly");
return true;
@@ -1450,6 +1546,14 @@ bool quickSpoolIdCheck(String uidString) {
activeSpoolId = quickSpoolId;
lastSpoolId = activeSpoolId;
// Read complete JSON data for web interface display
Serial.println("FAST-PATH: Reading complete JSON data for web interface...");
if (readCompleteJsonForFastPath()) {
Serial.println("✓ FAST-PATH: Complete JSON data loaded for web interface");
} else {
Serial.println("⚠ FAST-PATH: Could not read complete JSON, web interface may show limited data");
}
oledShowProgressBar(2, octoEnabled?5:4, "Known Spool", "Quick mode");
Serial.println("✓ FAST-PATH SUCCESS: Known spool processed quickly");
return true;
@@ -1496,6 +1600,10 @@ void writeJsonToTag(void *parameter) {
// aktualisieren der Website wenn sich der Status ändert
sendNfcData();
vTaskDelay(100 / portTICK_PERIOD_MS);
// Show waiting message for tag detection
oledShowProgressBar(0, 1, "Write Tag", "Warte auf Tag");
// Wait 10sec for tag
uint8_t success = 0;
String uidString = "";
@@ -1655,10 +1763,60 @@ void writeJsonToTag(void *parameter) {
vTaskDelete(NULL);
}
// Ensures sm_id is always the first key in JSON for fast-path detection
String optimizeJsonForFastPath(const char* payload) {
JsonDocument inputDoc;
DeserializationError error = deserializeJson(inputDoc, payload);
if (error) {
Serial.print("JSON optimization failed: ");
Serial.println(error.c_str());
return String(payload); // Return original if parsing fails
}
// Create optimized JSON with sm_id first
JsonDocument optimizedDoc;
// Always add sm_id first (even if it's "0" for brand filaments)
if (inputDoc["sm_id"].is<String>()) {
optimizedDoc["sm_id"] = inputDoc["sm_id"].as<String>();
Serial.print("Optimizing JSON: sm_id found = ");
Serial.println(inputDoc["sm_id"].as<String>());
} else {
optimizedDoc["sm_id"] = "0"; // Default for brand filaments
Serial.println("Optimizing JSON: No sm_id found, setting to '0'");
}
// Add all other keys in original order
for (JsonPair kv : inputDoc.as<JsonObject>()) {
String key = kv.key().c_str();
if (key != "sm_id") { // Skip sm_id as it's already added first
optimizedDoc[key] = kv.value();
}
}
String optimizedJson;
serializeJson(optimizedDoc, optimizedJson);
Serial.println("JSON optimized for fast-path detection:");
Serial.print("Original: ");
Serial.println(payload);
Serial.print("Optimized: ");
Serial.println(optimizedJson);
inputDoc.clear();
optimizedDoc.clear();
return optimizedJson;
}
void startWriteJsonToTag(const bool isSpoolTag, const char* payload) {
// Optimize JSON to ensure sm_id is first key for fast-path detection
String optimizedPayload = optimizeJsonForFastPath(payload);
NfcWriteParameterType* parameters = new NfcWriteParameterType();
parameters->tagType = isSpoolTag;
parameters->payload = strdup(payload);
parameters->payload = strdup(optimizedPayload.c_str()); // Use optimized payload
// Task nicht mehrfach starten
if (nfcReaderState == NFC_IDLE || nfcReaderState == NFC_READ_ERROR || nfcReaderState == NFC_READ_SUCCESS) {
@@ -1678,9 +1836,44 @@ void startWriteJsonToTag(const bool isSpoolTag, const char* payload) {
}
}
// Safe tag detection with manual retry logic and short timeouts
bool safeTagDetection(uint8_t* uid, uint8_t* uidLength) {
const int MAX_ATTEMPTS = 3;
const int SHORT_TIMEOUT = 100; // Very short timeout to prevent hanging
for (int attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
// Watchdog reset on each attempt
esp_task_wdt_reset();
yield();
// Use short timeout to avoid blocking
bool success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, uidLength, SHORT_TIMEOUT);
if (success) {
Serial.printf("✓ Tag detected on attempt %d with %dms timeout\n", attempt + 1, SHORT_TIMEOUT);
return true;
}
// Short pause between attempts
vTaskDelay(pdMS_TO_TICKS(25));
// Refresh RF field after failed attempt (but not on last attempt)
if (attempt < MAX_ATTEMPTS - 1) {
nfc.SAMConfig();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
return false;
}
void scanRfidTask(void * parameter) {
Serial.println("RFID Task gestartet");
for(;;) {
// Regular watchdog reset
esp_task_wdt_reset();
yield();
// Skip scanning during write operations, but keep NFC interface active
if (nfcReaderState != NFC_WRITING && !nfcWriteInProgress && !nfcReadingTaskSuspendRequest && !booting)
{
@@ -1691,10 +1884,16 @@ void scanRfidTask(void * parameter) {
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength;
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500);
// Use safe tag detection instead of blocking readPassiveTargetID
success = safeTagDetection(uid, &uidLength);
foundNfcTag(nullptr, success);
// Reset activeSpoolId immediately when no tag is detected to prevent stale autoSet
if (!success) {
activeSpoolId = "";
}
// As long as there is still a tag on the reader, do not try to read it again
if (success && nfcReaderState == NFC_IDLE)
{
@@ -1708,9 +1907,9 @@ void scanRfidTask(void * parameter) {
oledShowProgressBar(0, octoEnabled?5:4, "Reading", "Detecting tag");
// Wait 1 second after tag detection to stabilize connection
Serial.println("Tag detected, waiting 1 second for stabilization...");
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Reduced stabilization time for better responsiveness
Serial.println("Tag detected, minimal stabilization...");
vTaskDelay(200 / portTICK_PERIOD_MS); // Reduced from 1000ms to 200ms
// create Tag UID string
String uidString = "";
@@ -1753,9 +1952,10 @@ void scanRfidTask(void * parameter) {
for (uint8_t i = 4; i < 4+numPages; i++) {
if (!nfc.ntag2xx_ReadPage(i, data+(i-4) * 4))
if (!robustPageRead(i, data+(i-4) * 4))
{
break; // Stop if reading fails
Serial.printf("Failed to read page %d after retries, stopping\n", i);
break; // Stop if reading fails after retries
}
// Check for NDEF message end
@@ -1767,8 +1967,8 @@ void scanRfidTask(void * parameter) {
yield();
esp_task_wdt_reset();
// Increased delay to ensure stable reading
vTaskDelay(pdMS_TO_TICKS(5)); // Increased from 1ms to 5ms
// Reduced delay for faster reading
vTaskDelay(pdMS_TO_TICKS(2)); // Reduced from 5ms to 2ms
}
Serial.println("Tag reading completed, starting NDEF decode...");
@@ -1789,6 +1989,9 @@ void scanRfidTask(void * parameter) {
{
oledShowProgressBar(1, 1, "Failure", "Tag read error");
nfcReaderState = NFC_READ_ERROR;
// Reset activeSpoolId when tag reading fails to prevent autoSet
activeSpoolId = "";
Serial.println("Tag read failed - activeSpoolId reset to prevent autoSet");
}
}
else
@@ -1796,6 +1999,9 @@ void scanRfidTask(void * parameter) {
//TBD: Show error here?!
oledShowProgressBar(1, 1, "Failure", "Unkown tag type");
Serial.println("This doesn't seem to be an NTAG2xx tag (UUID length != 7 bytes)!");
// Reset activeSpoolId when tag type is unknown to prevent autoSet
activeSpoolId = "";
Serial.println("Unknown tag type - activeSpoolId reset to prevent autoSet");
}
}
@@ -1815,10 +2021,13 @@ void scanRfidTask(void * parameter) {
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
// Add a 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
Serial.println("Tag erfolgreich gelesen - warte 3 Sekunden vor nächstem Scan");
vTaskDelay(3000 / portTICK_PERIOD_MS); // Reduced from 5 seconds to 3 seconds
} else {
// Faster scanning when no tag or idle state
vTaskDelay(150 / portTICK_PERIOD_MS); // Faster scan interval
}
// aktualisieren der Website wenn sich der Status ändert

View File

@@ -17,6 +17,7 @@ void startNfc();
void scanRfidTask(void * parameter);
void startWriteJsonToTag(const bool isSpoolTag, const char* payload);
bool quickSpoolIdCheck(String uidString);
bool readCompleteJsonForFastPath(); // Read complete JSON data for fast-path web interface display
extern TaskHandle_t RfidReaderTask;
extern String nfcJsonData;

View File

@@ -13,6 +13,21 @@ TaskHandle_t ScaleTask;
int16_t weight = 0;
// Weight stabilization variables
#define MOVING_AVERAGE_SIZE 8 // Reduced from 20 to 8 for faster response
#define LOW_PASS_ALPHA 0.3f // Increased from 0.15 to 0.3 for faster tracking
#define DISPLAY_THRESHOLD 0.3f // Reduced from 0.5 to 0.3g for more responsive display
#define API_THRESHOLD 1.5f // Reduced from 2.0 to 1.5g for faster API actions
#define MEASUREMENT_INTERVAL_MS 30 // Reduced from 50ms to 30ms for faster updates
float weightBuffer[MOVING_AVERAGE_SIZE];
uint8_t bufferIndex = 0;
bool bufferFilled = false;
float filteredWeight = 0.0f;
int16_t lastDisplayedWeight = 0;
int16_t lastStableWeight = 0; // For API/action triggering
unsigned long lastMeasurementTime = 0;
uint8_t weigthCouterToApi = 0;
uint8_t scale_tare_counter = 0;
bool scaleTareRequest = false;
@@ -21,6 +36,93 @@ bool scaleCalibrated;
bool autoTare = true;
bool scaleCalibrationActive = false;
// ##### Weight stabilization functions #####
/**
* Reset weight filter buffer - call after tare or calibration
*/
void resetWeightFilter() {
bufferIndex = 0;
bufferFilled = false;
filteredWeight = 0.0f;
lastDisplayedWeight = 0;
lastStableWeight = 0; // Reset stable weight for API actions
// Initialize buffer with zeros
for (int i = 0; i < MOVING_AVERAGE_SIZE; i++) {
weightBuffer[i] = 0.0f;
}
}
/**
* Calculate moving average from weight buffer
*/
float calculateMovingAverage() {
float sum = 0.0f;
int count = bufferFilled ? MOVING_AVERAGE_SIZE : bufferIndex;
for (int i = 0; i < count; i++) {
sum += weightBuffer[i];
}
return (count > 0) ? sum / count : 0.0f;
}
/**
* Apply low-pass filter to smooth weight readings
* Uses exponential smoothing: y_new = alpha * x_new + (1-alpha) * y_old
*/
float applyLowPassFilter(float newValue) {
filteredWeight = LOW_PASS_ALPHA * newValue + (1.0f - LOW_PASS_ALPHA) * filteredWeight;
return filteredWeight;
}
/**
* Process new weight reading with stabilization
* Returns stabilized weight value
*/
int16_t processWeightReading(float rawWeight) {
// Add to moving average buffer
weightBuffer[bufferIndex] = rawWeight;
bufferIndex = (bufferIndex + 1) % MOVING_AVERAGE_SIZE;
if (bufferIndex == 0) {
bufferFilled = true;
}
// Calculate moving average
float avgWeight = calculateMovingAverage();
// Apply low-pass filter
float smoothedWeight = applyLowPassFilter(avgWeight);
// Round to nearest gram
int16_t newWeight = round(smoothedWeight);
// Update displayed weight if display threshold is reached
if (abs(newWeight - lastDisplayedWeight) >= DISPLAY_THRESHOLD) {
lastDisplayedWeight = newWeight;
}
// Update global weight for API actions only if stable threshold is reached
int16_t weightToReturn = weight; // Default: keep current weight
if (abs(newWeight - lastStableWeight) >= API_THRESHOLD) {
lastStableWeight = newWeight;
weightToReturn = newWeight;
}
return weightToReturn;
}
/**
* Get current filtered weight for display purposes
* This returns the smoothed weight even if it hasn't triggered API actions
*/
int16_t getFilteredDisplayWeight() {
return lastDisplayedWeight;
}
// ##### Funktionen für Waage #####
uint8_t setAutoTare(bool autoTareValue) {
Serial.print("Set AutoTare to ");
@@ -39,6 +141,7 @@ uint8_t setAutoTare(bool autoTareValue) {
uint8_t tareScale() {
Serial.println("Tare scale");
scale.tare();
resetWeightFilter(); // Reset stabilization filter after tare
return 1;
}
@@ -48,37 +151,61 @@ void scale_loop(void * parameter) {
Serial.println("Scale Loop started");
Serial.println("++++++++++++++++++++++++++++++");
// Initialize weight filter
resetWeightFilter();
lastMeasurementTime = millis();
for(;;) {
if (scale.is_ready())
{
// Waage automatisch Taren, wenn zu lange Abweichung
if (autoTare && scale_tare_counter >= 5)
unsigned long currentTime = millis();
// Only measure at defined intervals to reduce noise
if (currentTime - lastMeasurementTime >= MEASUREMENT_INTERVAL_MS) {
if (scale.is_ready())
{
Serial.println("Auto Tare scale");
scale.tare();
scale_tare_counter = 0;
}
// Waage automatisch Taren, wenn zu lange Abweichung
if (autoTare && scale_tare_counter >= 5)
{
Serial.println("Auto Tare scale");
scale.tare();
resetWeightFilter(); // Reset filter after auto tare
scale_tare_counter = 0;
}
// Waage manuell Taren
if (scaleTareRequest == true)
{
Serial.println("Re-Tare scale");
oledShowMessage("TARE Scale");
vTaskDelay(pdMS_TO_TICKS(1000));
scale.tare();
vTaskDelay(pdMS_TO_TICKS(1000));
oledShowWeight(0);
scaleTareRequest = false;
}
// Waage manuell Taren
if (scaleTareRequest == true)
{
Serial.println("Re-Tare scale");
oledShowMessage("TARE Scale");
vTaskDelay(pdMS_TO_TICKS(1000));
scale.tare();
resetWeightFilter(); // Reset filter after manual tare
vTaskDelay(pdMS_TO_TICKS(1000));
oledShowWeight(0);
scaleTareRequest = false;
}
// Only update weight if median changed more than 1
int16_t newWeight = round(scale.get_units());
if(abs(weight-newWeight) > 1){
weight = newWeight;
// Get raw weight reading
float rawWeight = scale.get_units();
// Process weight with stabilization
int16_t stabilizedWeight = processWeightReading(rawWeight);
// Update global weight variable only if it changed significantly (for API actions)
if (stabilizedWeight != weight) {
weight = stabilizedWeight;
}
// Debug output for monitoring (can be removed in production)
static unsigned long lastDebugTime = 0;
if (currentTime - lastDebugTime > 2000) { // Print every 2 seconds
lastDebugTime = currentTime;
}
lastMeasurementTime = currentTime;
}
}
vTaskDelay(pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(10)); // Shorter delay for more responsive loop
}
}
@@ -122,8 +249,11 @@ void start_scale(bool touchSensorConnected) {
}
scale.set_scale(calibrationValue);
vTaskDelay(pdMS_TO_TICKS(5000));
scale.tare();
//vTaskDelay(pdMS_TO_TICKS(5000));
//scale.tare();
// Initialize weight stabilization filter
resetWeightFilter();
// Display Gewicht
oledShowWeight(0);
@@ -209,6 +339,7 @@ uint8_t calibrate_scale() {
oledShowProgressBar(2, 3, "Scale Cal.", "Remove weight");
scale.set_scale(newCalibrationValue);
resetWeightFilter(); // Reset filter after calibration
for (uint16_t i = 0; i < 2000; i++) {
yield();
vTaskDelay(pdMS_TO_TICKS(1));

View File

@@ -9,6 +9,13 @@ uint8_t start_scale(bool touchSensorConnected);
uint8_t calibrate_scale();
uint8_t tareScale();
// Weight stabilization functions
void resetWeightFilter();
float calculateMovingAverage();
float applyLowPassFilter(float newValue);
int16_t processWeightReading(float rawWeight);
int16_t getFilteredDisplayWeight();
extern HX711 scale;
extern int16_t weight;
extern uint8_t weigthCouterToApi;