Compare commits

...

24 Commits

Author SHA1 Message Date
fad84e12c8 docs: update changelog and header for version v1.4.10
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 3m6s
2025-03-30 12:19:25 +02:00
696efc4d79 docs: update platformio.ini for version v1.4.10 2025-03-30 12:19:25 +02:00
29868e7101 fix: update TTP223 pin configuration and adjust touch sensor logic 2025-03-30 12:19:07 +02:00
823db6157c fix: add manual tare functionality for scale 2025-03-29 14:44:33 +01:00
83d14b32d1 fix: add debounce handling for TTP223 touch sensor 2025-03-29 14:23:55 +01:00
2bf7c9fb7d feat: add TTP223 touch sensor support and wiring configuration 2025-03-29 14:18:58 +01:00
07a919b6ba docs: update changelog and header for version v1.4.9
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 2m48s
2025-03-29 10:11:25 +01:00
8618b90e33 docs: update platformio.ini for version v1.4.9 2025-03-29 10:11:25 +01:00
57723b5354 fix: enhance HTTP method handling in sendToApi function 2025-03-29 10:03:17 +01:00
d2be752175 docs: update changelog and header for version v1.4.8
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 2m46s
2025-03-29 07:58:12 +01:00
97a050ace8 docs: update platformio.ini for version v1.4.8 2025-03-29 07:58:12 +01:00
367e692c74 Merge pull request #30 from janecker/main
Fix memory leak issue in HTTPClient
2025-03-29 07:55:45 +01:00
926a21249b Merge branch 'testing' into main 2025-03-29 07:55:33 +01:00
2635c19667 fix: improve HTTP client configuration and clear update documents after API calls 2025-03-29 07:52:49 +01:00
6cc4efca0a Fixes memory leak in HTTPClient by disabling connection reuse 2025-03-28 22:40:50 +01:00
1484a6b0da fix: update reload logic after removing and saving Bambu credentials for better cache handling 2025-03-27 19:13:57 +01:00
b5f0472af4 docs: update changelog and header for version v1.4.7
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 3m10s
2025-03-27 18:54:33 +01:00
95c1bc823c docs: update platformio.ini for version v1.4.7 2025-03-27 18:54:33 +01:00
491ba7f526 Merge branch 'testing' 2025-03-27 18:54:15 +01:00
56d7d8596c style: update remove button for Bambu credentials with red background 2025-03-27 18:07:33 +01:00
1044e91a0a feat: add forced cache refresh after removing and saving Bambu credentials 2025-03-27 18:03:40 +01:00
e459b53472 feat: add functionality to remove Bambu credentials and update API handling 2025-03-27 18:01:15 +01:00
190e952ec4 docs: update changelog and header for version v1.4.6
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 2m57s
2025-03-26 11:52:46 +01:00
89620a7f00 docs: update platformio.ini for version v1.4.6 2025-03-26 11:52:46 +01:00
15 changed files with 210 additions and 43 deletions

View File

@ -1,5 +1,63 @@
# Changelog # Changelog
## [1.4.10] - 2025-03-30
### Added
- add manual tare functionality for scale
- add debounce handling for TTP223 touch sensor
- add TTP223 touch sensor support and wiring configuration
### Changed
- update platformio.ini for version v1.4.10
### Fixed
- update TTP223 pin configuration and adjust touch sensor logic
## [1.4.9] - 2025-03-29
### Changed
- update platformio.ini for version v1.4.9
### Fixed
- enhance HTTP method handling in sendToApi function
## [1.4.8] - 2025-03-29
### Changed
- update platformio.ini for version v1.4.8
- Merge pull request #30 from janecker/main
- Merge branch 'testing' into main
### Fixed
- improve HTTP client configuration and clear update documents after API calls
- Fixes memory leak in HTTPClient by disabling connection reuse
- update reload logic after removing and saving Bambu credentials for better cache handling
## [1.4.7] - 2025-03-27
### Added
- add forced cache refresh after removing and saving Bambu credentials
- add functionality to remove Bambu credentials and update API handling
- add rfid_bambu.html and update bambu connection handling
### Changed
- update platformio.ini for version v1.4.7
- Merge branch 'testing'
- update remove button for Bambu credentials with red background
- Merge pull request #28 from tugsi/main
### Fixed
- handle Bambu connection state by introducing bambuDisabled flag
- Fix rfid.js-Failure with X1-Series, if you wanna send a Spool to AMS: - Uncaught TypeError: Cannot read properties of undefined (reading 'replace') at handleSpoolIn (rfid.js:493:67) at HTMLButtonElement.onclick ((Index):1:1) handleSpoolIn @ rfid.js:493 onclick @ (Index):1
## [1.4.6] - 2025-03-26
### Changed
- update platformio.ini for version v1.4.6
### Fixed
- handle potential undefined value for tray_info_idx in handleSpoolIn function, by @tugsi
## [1.4.5] - 2025-03-25 ## [1.4.5] - 2025-03-25
### Changed ### Changed
- update platformio.ini for version v1.4.5 - update platformio.ini for version v1.4.5

View File

@ -55,19 +55,22 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
## Hardware-Anforderungen ## Hardware-Anforderungen
### Komponenten ### Komponenten
- **ESP32 Entwicklungsboard:** Jede ESP32-Variante. - **ESP32 Development Board:** Any ESP32 variant.
[Amazon Link](https://amzn.eu/d/aXThslf) [Amazon Link](https://amzn.to/3FHea6D)
- **HX711 5kg Wägezellen-Verstärker:** Für Gewichtsmessung. - **HX711 5kg Load Cell Amplifier:** For weight measurement.
[Amazon Link](https://amzn.eu/d/06A0DLb) [Amazon Link](https://amzn.to/4ja1KTe)
- **OLED 0.96 Zoll I2C weiß/gelb Display:** 128x64 SSD1306. - **OLED 0.96 Zoll I2C white/yellow Display:** 128x64 SSD1306.
[Amazon Link](https://amzn.eu/d/0AuBp2c) [Amazon Link](https://amzn.to/445aaa9)
- **PN532 NFC NXP RFID-Modul V3:** Für NFC-Tag-Operationen. - **PN532 NFC NXP RFID-Modul V3:** For NFC tag operations.
[Amazon Link](https://amzn.eu/d/jfIuQXb) [Amazon Link](https://amzn.to/4iO6CO4)
- **NFC Tags NTAG213 NTA215:** RFID Tag - **NFC Tags NTAG213 NTAG215:** RFID Tag
[Amazon Link](https://amzn.eu/d/9Z6mXc1) [Amazon Link](https://amzn.to/3E071xO)
- **TTP223 Touch Sensor (optional):** For reTARE per Button/Touch
[Amazon Link](https://amzn.to/4hTChMK)
### Pin-Konfiguration
| Komponente | ESP32 Pin | ### Pin Konfiguration
| Component | ESP32 Pin |
|-------------------|-----------| |-------------------|-----------|
| HX711 DOUT | 16 | | HX711 DOUT | 16 |
| HX711 SCK | 17 | | HX711 SCK | 17 |
@ -77,8 +80,10 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
| PN532 RESET | 33 | | PN532 RESET | 33 |
| PN532 SDA | 21 | | PN532 SDA | 21 |
| PN532 SCL | 22 | | PN532 SCL | 22 |
| TTP223 I/O | 25 |
**Achte darauf, dass am PN532 die DIP-Schalter auf I2C gestellt sind** **!! Achte darauf, dass am PN532 die DIP-Schalter auf I2C gestellt sind**
**Nutze den 3V Pin vom ESP für den Touch Sensor**
![Wiring](./img/Schaltplan.png) ![Wiring](./img/Schaltplan.png)

View File

@ -60,15 +60,17 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
### Components ### Components
- **ESP32 Development Board:** Any ESP32 variant. - **ESP32 Development Board:** Any ESP32 variant.
[Amazon Link](https://amzn.eu/d/aXThslf) [Amazon Link](https://amzn.to/3FHea6D)
- **HX711 5kg Load Cell Amplifier:** For weight measurement. - **HX711 5kg Load Cell Amplifier:** For weight measurement.
[Amazon Link](https://amzn.eu/d/06A0DLb) [Amazon Link](https://amzn.to/4ja1KTe)
- **OLED 0.96 Zoll I2C white/yellow Display:** 128x64 SSD1306. - **OLED 0.96 Zoll I2C white/yellow Display:** 128x64 SSD1306.
[Amazon Link](https://amzn.eu/d/0AuBp2c) [Amazon Link](https://amzn.to/445aaa9)
- **PN532 NFC NXP RFID-Modul V3:** For NFC tag operations. - **PN532 NFC NXP RFID-Modul V3:** For NFC tag operations.
[Amazon Link](https://amzn.eu/d/jfIuQXb) [Amazon Link](https://amzn.to/4iO6CO4)
- **NFC Tags NTAG213 NTAG215:** RFID Tag - **NFC Tags NTAG213 NTAG215:** RFID Tag
[Amazon Link](https://amzn.eu/d/9Z6mXc1) [Amazon Link](https://amzn.to/3E071xO)
- **TTP223 Touch Sensor (optional):** For reTARE per Button/Touch
[Amazon Link](https://amzn.to/4hTChMK)
### Pin Configuration ### Pin Configuration
@ -82,8 +84,10 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
| PN532 RESET | 33 | | PN532 RESET | 33 |
| PN532 SDA | 21 | | PN532 SDA | 21 |
| PN532 SCL | 22 | | PN532 SCL | 22 |
| TTP223 I/O | 25 |
**Make sure that the DIP switches on the PN532 are set to I2C** **!! Make sure that the DIP switches on the PN532 are set to I2C**
**Use the 3V pin from the ESP for the touch sensor**
![Wiring](./img/Schaltplan.png) ![Wiring](./img/Schaltplan.png)

View File

@ -57,6 +57,31 @@
toggleOctoFields(); toggleOctoFields();
}; };
function removeBambuCredentials() {
fetch('/api/bambu?remove=true')
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('bambuIp').value = '';
document.getElementById('bambuSerial').value = '';
document.getElementById('bambuCode').value = '';
document.getElementById('autoSend').checked = false;
document.getElementById('autoSendTime').value = '';
document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials removed!';
// Reload with forced cache refresh after short delay
setTimeout(() => {
window.location.reload(true);
window.location.href = '/';
}, 1500);
} else {
document.getElementById('bambuStatusMessage').innerText = 'Error while removing Bambu Credentials.';
}
})
.catch(error => {
document.getElementById('bambuStatusMessage').innerText = 'Error while removing: ' + error.message;
});
}
function checkSpoolmanInstance() { function checkSpoolmanInstance() {
const url = document.getElementById('spoolmanUrl').value; const url = document.getElementById('spoolmanUrl').value;
const spoolmanOctoEnabled = document.getElementById('spoolmanOctoEnabled').checked; const spoolmanOctoEnabled = document.getElementById('spoolmanOctoEnabled').checked;
@ -89,6 +114,11 @@
.then(data => { .then(data => {
if (data.healthy) { if (data.healthy) {
document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials saved!'; document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials saved!';
// Reload with forced cache refresh after short delay
setTimeout(() => {
window.location.reload(true);
window.location.href = '/';
}, 1500);
} else { } else {
document.getElementById('bambuStatusMessage').innerText = 'Error while saving Bambu Credentials.'; document.getElementById('bambuStatusMessage').innerText = 'Error while saving Bambu Credentials.';
} }
@ -162,6 +192,7 @@
</div> </div>
<button style="margin: 0;" onclick="saveBambuCredentials()">Save Bambu Credentials</button> <button style="margin: 0;" onclick="saveBambuCredentials()">Save Bambu Credentials</button>
<button style="margin: 0; background-color: red;" onclick="removeBambuCredentials()">Remove Credentials</button>
<p id="bambuStatusMessage"></p> <p id="bambuStatusMessage"></p>
</div> </div>
</div> </div>

View File

@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[common] [common]
version = "1.4.5" version = "1.4.10"
to_old_version = "1.4.0" to_old_version = "1.4.0"
## ##

View File

@ -94,13 +94,16 @@ void sendToApi(void *parameter) {
String octoToken = params->octoToken; String octoToken = params->octoToken;
HTTPClient http; HTTPClient http;
http.setReuse(false);
http.begin(spoolsUrl); http.begin(spoolsUrl);
http.addHeader("Content-Type", "application/json"); http.addHeader("Content-Type", "application/json");
if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken); if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken);
int httpCode = http.PUT(updatePayload); int httpCode;
if (httpType == "PATCH") httpCode = http.PATCH(updatePayload); if (httpType == "PATCH") httpCode = http.PATCH(updatePayload);
if (httpType == "POST") httpCode = http.POST(updatePayload); else if (httpType == "POST") httpCode = http.POST(updatePayload);
else httpCode = http.PUT(updatePayload);
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
Serial.println("Spoolman erfolgreich aktualisiert"); Serial.println("Spoolman erfolgreich aktualisiert");
@ -111,6 +114,7 @@ void sendToApi(void *parameter) {
} }
http.end(); http.end();
vTaskDelay(50 / portTICK_PERIOD_MS);
// Speicher freigeben // Speicher freigeben
delete params; delete params;
@ -165,6 +169,8 @@ bool updateSpoolTagId(String uidString, const char* payload) {
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return true; return true;
} }
@ -201,6 +207,8 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) {
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return 1; return 1;
} }
@ -238,6 +246,8 @@ bool updateSpoolOcto(int spoolId) {
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return true; return true;
} }

View File

@ -38,6 +38,32 @@ int ams_count = 0;
String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients
AMSData ams_data[MAX_AMS]; // Definition des Arrays; AMSData ams_data[MAX_AMS]; // Definition des Arrays;
bool removeBambuCredentials() {
if (BambuMqttTask) {
vTaskDelete(BambuMqttTask);
}
if (!removeJsonValue("/bambu_credentials.json")) {
Serial.println("Fehler beim Löschen der Bambu-Credentials.");
return false;
}
// Löschen der globalen Variablen
g_bambu_ip = "";
g_bambu_accesscode = "";
g_bambu_serialnr = "";
bambu_ip = nullptr;
bambu_accesscode = nullptr;
bambu_serialnr = nullptr;
autoSendToBambu = false;
autoSetToBambuSpoolId = 0;
ams_count = 0;
amsJsonData = "";
bambuDisabled = true;
return true;
}
bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend, const String& autoSendTime) { bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend, const String& autoSendTime) {
if (BambuMqttTask) { if (BambuMqttTask) {
vTaskDelete(BambuMqttTask); vTaskDelete(BambuMqttTask);

View File

@ -32,6 +32,7 @@ extern bool autoSendToBambu;
extern int autoSetToBambuSpoolId; extern int autoSetToBambuSpoolId;
extern bool bambuDisabled; extern bool bambuDisabled;
bool removeBambuCredentials();
bool loadBambuCredentials(); bool loadBambuCredentials();
bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend, const String& autoSendTime); bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend, const String& autoSendTime);
bool setupMqtt(); bool setupMqtt();

View File

@ -1,6 +1,20 @@
#include "commonFS.h" #include "commonFS.h"
#include <LittleFS.h> #include <LittleFS.h>
bool removeJsonValue(const char* filename) {
File file = LittleFS.open(filename, "r");
if (!file) {
return true;
}
file.close();
if (!LittleFS.remove(filename)) {
Serial.print("Fehler beim Löschen der Datei: ");
Serial.println(filename);
return false;
}
return true;
}
bool saveJsonValue(const char* filename, const JsonDocument& doc) { bool saveJsonValue(const char* filename, const JsonDocument& doc) {
File file = LittleFS.open(filename, "w"); File file = LittleFS.open(filename, "w");
if (!file) { if (!file) {

View File

@ -5,6 +5,7 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <LittleFS.h> #include <LittleFS.h>
bool removeJsonValue(const char* filename);
bool saveJsonValue(const char* filename, const JsonDocument& doc); bool saveJsonValue(const char* filename, const JsonDocument& doc);
bool loadJsonValue(const char* filename, JsonDocument& doc); bool loadJsonValue(const char* filename, JsonDocument& doc);
void initializeFileSystem(); void initializeFileSystem();

View File

@ -19,6 +19,12 @@ const uint16_t SCALE_LEVEL_WEIGHT = 500;
uint16_t defaultScaleCalibrationValue = 430; uint16_t defaultScaleCalibrationValue = 430;
// ***** HX711 // ***** HX711
// ***** TTP223 (Touch Sensor)
// TTP223 circuit wiring
const uint8_t TTP223_PIN = 25;
// ***** TTP223
// ***** Display // ***** Display
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// On an ESP32: 21(SDA), 22(SCL) // On an ESP32: 21(SDA), 22(SCL)

View File

@ -11,6 +11,8 @@ extern const uint8_t LOADCELL_SCK_PIN;
extern const uint8_t calVal_eepromAdress; extern const uint8_t calVal_eepromAdress;
extern const uint16_t SCALE_LEVEL_WEIGHT; extern const uint16_t SCALE_LEVEL_WEIGHT;
extern const uint8_t TTP223_PIN;
extern const int8_t OLED_RESET; extern const int8_t OLED_RESET;
extern const uint8_t SCREEN_ADDRESS; extern const uint8_t SCREEN_ADDRESS;
extern const uint8_t SCREEN_WIDTH; extern const uint8_t SCREEN_WIDTH;

View File

@ -39,7 +39,6 @@ void setup() {
setupWebserver(server); setupWebserver(server);
// Spoolman API // Spoolman API
// api.cpp
initSpoolman(); initSpoolman();
// Bambu MQTT // Bambu MQTT
@ -48,6 +47,7 @@ void setup() {
// NFC Reader // NFC Reader
startNfc(); startNfc();
// Scale
start_scale(); start_scale();
// WDT initialisieren mit 10 Sekunden Timeout // WDT initialisieren mit 10 Sekunden Timeout
@ -56,6 +56,9 @@ void setup() {
// Aktuellen Task (loopTask) zum Watchdog hinzufügen // Aktuellen Task (loopTask) zum Watchdog hinzufügen
esp_task_wdt_add(NULL); esp_task_wdt_add(NULL);
// Touch Sensor
pinMode(TTP223_PIN, INPUT_PULLUP);
} }
@ -84,13 +87,25 @@ uint8_t autoAmsCounter = 0;
uint8_t weightSend = 0; uint8_t weightSend = 0;
int16_t lastWeight = 0; int16_t lastWeight = 0;
// WIFI check variables
unsigned long lastWifiCheckTime = 0; unsigned long lastWifiCheckTime = 0;
const unsigned long wifiCheckInterval = 60000; // Überprüfe alle 60 Sekunden (60000 ms) const unsigned long wifiCheckInterval = 60000; // Überprüfe alle 60 Sekunden (60000 ms)
// Button debounce variables
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 500; // 500 ms debounce delay
// ##### PROGRAM START ##### // ##### PROGRAM START #####
void loop() { void loop() {
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
// Überprüfe den Status des Touch Sensors
if (digitalRead(TTP223_PIN) == HIGH && currentMillis - lastButtonPress > debounceDelay)
{
lastButtonPress = currentMillis;
scaleTareRequest = true;
}
// Überprüfe regelmäßig die WLAN-Verbindung // Überprüfe regelmäßig die WLAN-Verbindung
if (intervalElapsed(currentMillis, lastWifiCheckTime, wifiCheckInterval)) if (intervalElapsed(currentMillis, lastWifiCheckTime, wifiCheckInterval))
{ {
@ -158,25 +173,6 @@ void loop() {
{ {
lastWeightReadTime = currentMillis; lastWeightReadTime = currentMillis;
// Prüfen ob die Waage korrekt genullt ist
if ((weight > 0 && weight < 5) || weight < -1)
{
if(scaleTareCounter < 5)
{
scaleTareCounter++;
}
else
{
scaleTareRequest = true;
scaleTareCounter = 0;
}
}
else
{
scaleTareCounter = 0;
}
// Prüfen ob das Gewicht gleich bleibt und dann senden // Prüfen ob das Gewicht gleich bleibt und dann senden
if (weight == lastWeight && weight > 5) if (weight == lastWeight && weight > 5)
{ {

View File

@ -38,11 +38,15 @@ void scale_loop(void * parameter) {
for(;;) { for(;;) {
if (scale.is_ready()) if (scale.is_ready())
{ {
// Waage nochmal Taren, wenn zu lange Abweichung // Waage manuell Taren
if (scaleTareRequest == true) if (scaleTareRequest == true)
{ {
Serial.println("Re-Tare scale"); Serial.println("Re-Tare scale");
oledShowMessage("TARE Scale");
vTaskDelay(pdMS_TO_TICKS(1000));
scale.tare(); scale.tare();
vTaskDelay(pdMS_TO_TICKS(1000));
oledShowWeight(0);
scaleTareRequest = false; scaleTareRequest = false;
} }

View File

@ -313,6 +313,15 @@ void setupWebserver(AsyncWebServer &server) {
// Route für das Überprüfen der Bambu-Instanz // Route für das Überprüfen der Bambu-Instanz
server.on("/api/bambu", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/bambu", HTTP_GET, [](AsyncWebServerRequest *request){
if (request->hasParam("remove")) {
if (removeBambuCredentials()) {
request->send(200, "application/json", "{\"success\": true}");
} else {
request->send(500, "application/json", "{\"success\": false, \"error\": \"Fehler beim Löschen der Bambu-Credentials\"}");
}
return;
}
if (!request->hasParam("bambu_ip") || !request->hasParam("bambu_serialnr") || !request->hasParam("bambu_accesscode")) { if (!request->hasParam("bambu_ip") || !request->hasParam("bambu_serialnr") || !request->hasParam("bambu_accesscode")) {
request->send(400, "application/json", "{\"success\": false, \"error\": \"Missing parameter\"}"); request->send(400, "application/json", "{\"success\": false, \"error\": \"Missing parameter\"}");
return; return;