add settings locations
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
Carsten Graf
2025-09-08 22:30:15 +02:00
parent 55eb062d2c
commit 173b13fcfc
13 changed files with 940 additions and 247 deletions

View File

@@ -2,10 +2,13 @@
#include "master.h"
#include <Arduino.h>
#include <HTTPClient.h>
#include <preferencemanager.h>
const char *BACKEND_SERVER = "http://db.reptilfpv.de:3000";
extern String licence; // Declare licence as an external variable defined elsewhere
String BACKEND_TOKEN = licence; // Use the licence as the token for authentication
const char *BACKEND_SERVER = "https://ninja.reptilfpv.de";
extern String
licence; // Declare licence as an external variable defined elsewhere
String BACKEND_TOKEN =
licence; // Use the licence as the token for authentication
bool backendOnline() {
@@ -17,7 +20,7 @@ bool backendOnline() {
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/health");
http.begin(String(BACKEND_SERVER) + "/v1/private/health");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
int httpCode = http.GET();
@@ -53,7 +56,7 @@ UserData checkUser(const String &uid) {
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/users/find");
http.begin(String(BACKEND_SERVER) + "/v1/private/users/find");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
@@ -95,17 +98,16 @@ bool enterUserData(const String &uid, const String &firstname,
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/users/insert");
http.begin(String(BACKEND_SERVER) + "/v1/private/create-player");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
// Create JSON payload
StaticJsonDocument<256> requestDoc;
requestDoc["uid"] = uid;
requestDoc["vorname"] = firstname;
requestDoc["nachname"] = lastname;
requestDoc["geburtsdatum"] = geburtsdatum;
requestDoc["alter"] = alter;
requestDoc["rfiduid"] = uid;
requestDoc["firstname"] = firstname;
requestDoc["lastname"] = lastname;
requestDoc["birthdate"] = geburtsdatum;
String requestBody;
serializeJson(requestDoc, requestBody);
@@ -133,7 +135,7 @@ JsonDocument getAllLocations() {
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/location/");
http.begin(String(BACKEND_SERVER) + "/v1/private/locations");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
int httpCode = http.GET();
@@ -185,5 +187,36 @@ void setupBackendRoutes(AsyncWebServer &server) {
request->send(200, "application/json", result);
});
server.on("/api/set-local-location", HTTP_POST,
[](AsyncWebServerRequest *request) {
Serial.println("/api/set-local-location called");
String locationId;
if (request->hasParam("locationId", true)) {
locationId = request->getParam("locationId", true)->value();
}
if (locationId.length() > 0) {
saveLocationIdToPrefs(locationId);
DynamicJsonDocument doc(64);
doc["success"] = true;
String result;
serializeJson(doc, result);
request->send(200, "application/json", result);
} else {
request->send(400, "application/json", "{\"success\":false}");
}
});
server.on("/api/get-local-location", HTTP_GET,
[](AsyncWebServerRequest *request) {
String locationId = getLocationIdFromPrefs();
DynamicJsonDocument doc(64);
doc["locationId"] = locationId;
String result;
serializeJson(doc, result);
request->send(200, "application/json", result);
// Andere Logik wie in getBestLocs
});
// Add more routes as needed
}

View File

@@ -31,26 +31,26 @@ void triggerAction(const char *action, int press, int lane,
void IndividualMode(const char *action, int press, int lane,
uint64_t timestamp) {
if (action == "start" && press == 2 && lane == 1) {
if (!timerData.isRunning1 && timerData.isReady1) {
timerData.isReady1 = false;
timerData.startTime1 = (timestamp > 0) ? timestamp : millis();
timerData.localStartTime1 = millis(); // Set local start time
timerData.isRunning1 = true;
timerData.endTime1 = 0;
timerData.isArmed1 = false; // Reset armed status
if (!timerData1.isRunning && timerData1.isReady) {
timerData1.isReady = false;
timerData1.startTime = (timestamp > 0) ? timestamp : millis();
timerData1.localStartTime = millis(); // Set local start time
timerData1.isRunning = true;
timerData1.endTime = 0;
timerData1.isArmed = false; // Reset armed status
publishLaneStatus(1, "running");
Serial.println("Bahn 1 gestartet");
}
}
if (action == "stop" && press == 1 && lane == 1) {
if (timerData.isRunning1) {
timerData.endTime1 = (timestamp > 0) ? timestamp : millis();
timerData.finishedSince1 = millis(); // Set finished time
timerData.isRunning1 = false;
uint64_t currentTime = timerData.endTime1 - timerData.startTime1;
if (timerData1.isRunning) {
timerData1.endTime = (timestamp > 0) ? timestamp : millis();
timerData1.finishedSince = millis(); // Set finished time
timerData1.isRunning = false;
uint64_t currentTime = timerData1.endTime - timerData1.startTime;
if (timerData.bestTime1 == 0 || currentTime < timerData.bestTime1) {
timerData.bestTime1 = currentTime;
if (timerData1.bestTime == 0 || currentTime < timerData1.bestTime) {
timerData1.bestTime = currentTime;
saveBestTimes();
}
publishLaneStatus(1, "stopped");
@@ -59,26 +59,26 @@ void IndividualMode(const char *action, int press, int lane,
}
}
if (action == "start" && press == 2 && lane == 2) {
if (!timerData.isRunning2 && timerData.isReady2) {
timerData.isReady2 = false;
timerData.startTime2 = (timestamp > 0) ? timestamp : millis();
timerData.localStartTime2 = millis(); // Set local start time
timerData.isRunning2 = true;
timerData.endTime2 = 0;
timerData.isArmed2 = false; // Reset armed status
if (!timerData2.isRunning && timerData2.isReady) {
timerData2.isReady = false;
timerData2.startTime = (timestamp > 0) ? timestamp : millis();
timerData2.localStartTime = millis(); // Set local start time
timerData2.isRunning = true;
timerData2.endTime = 0;
timerData2.isArmed = false; // Reset armed status
publishLaneStatus(2, "running");
Serial.println("Bahn 2 gestartet");
}
}
if (action == "stop" && press == 1 && lane == 2) {
if (timerData.isRunning2) {
timerData.endTime2 = (timestamp > 0) ? timestamp : millis();
timerData.finishedSince2 = millis(); // Set finished time
timerData.isRunning2 = false;
uint64_t currentTime = timerData.endTime2 - timerData.startTime2;
if (timerData2.isRunning) {
timerData2.endTime = (timestamp > 0) ? timestamp : millis();
timerData2.finishedSince = millis(); // Set finished time
timerData2.isRunning = false;
uint64_t currentTime = timerData2.endTime - timerData2.startTime;
if (timerData.bestTime2 == 0 || currentTime < timerData.bestTime2) {
timerData.bestTime2 = currentTime;
if (timerData2.bestTime == 0 || currentTime < timerData2.bestTime) {
timerData2.bestTime = currentTime;
saveBestTimes();
}
publishLaneStatus(2, "stopped");
@@ -102,18 +102,18 @@ void CompetitionMode(const char *action, int press, int lane,
int armTimeout = 10000; // Zeit in Millisekunden, die die Bahn armiert bleibt
if (action == "start" && press == 2 && lane == 1) {
if (!timerData.isRunning1 && timerData.isReady1) {
timerData.isReady1 = false;
timerData.isArmed1 = true; // Set Bahn 1 as armed
if (!timerData1.isRunning && timerData1.isReady) {
timerData1.isReady = false;
timerData1.isArmed = true; // Set Bahn 1 as armed
publishLaneStatus(1, "armed");
Serial.println("Bahn 1 armiert");
armedAtTime1 = millis(); // Set armed time for Bahn 1
}
}
if (action == "start" && press == 2 && lane == 2) {
if (!timerData.isRunning2 && timerData.isReady2) {
timerData.isReady2 = false;
timerData.isArmed2 = true; // Set Bahn 2 as armed
if (!timerData2.isRunning && timerData2.isReady) {
timerData2.isReady = false;
timerData2.isArmed = true; // Set Bahn 2 as armed
publishLaneStatus(2, "armed");
Serial.println("Bahn 2 armiert");
armedAtTime2 = millis(); // Set armed time for Bahn 2
@@ -121,34 +121,32 @@ void CompetitionMode(const char *action, int press, int lane,
}
if (armedAtTime1 > armedAtTime1 + armTimeout) {
timerData.isArmed1 = false; // Reset Bahn 1 if armed time exceeded
timerData.isReady1 = true; // Set Bahn 1 back to ready
timerData1.isArmed = false; // Reset Bahn 1 if armed time exceeded
timerData1.isReady = true; // Set Bahn 1 back to ready
Serial.println("Bahn 1 automatisch zurückgesetzt (armiert)");
publishLaneStatus(1, "ready");
}
if (armedAtTime2 > armedAtTime2 + armTimeout) {
timerData.isArmed2 = false; // Reset Bahn 2 if armed time exceeded
timerData.isReady2 = true; // Set Bahn 2 back to ready
timerData2.isArmed = false; // Reset Bahn 2 if armed time exceeded
timerData2.isReady = true; // Set Bahn 2 back to ready
Serial.println("Bahn 2 automatisch zurückgesetzt (armiert)");
publishLaneStatus(2, "ready");
}
if (timerData.isArmed1 && timerData.isArmed2) {
if (timerData1.isArmed && timerData2.isArmed) {
sendMQTTMessage("aquacross/competition/toSignal", "armed");
}
if ((action == "stop" && press == 1 && lane == 1)) {
if (timerData.isRunning1) {
timerData.endTime1 = (timestamp > 0) ? timestamp : millis();
timerData.finishedSince1 = millis(); // Set finished time
timerData.isRunning1 = false;
uint64_t currentTime1 = timerData.endTime1 - timerData.startTime1;
if (timerData1.isRunning) {
timerData1.endTime = (timestamp > 0) ? timestamp : millis();
timerData1.finishedSince = millis(); // Set finished time
timerData1.isRunning = false;
uint64_t currentTime1 = timerData1.endTime - timerData1.startTime;
if (timerData.bestTime1 == 0 || currentTime1 < timerData.bestTime1) {
timerData.bestTime1 = currentTime1;
if (timerData1.bestTime == 0 || currentTime1 < timerData1.bestTime) {
timerData1.bestTime = currentTime1;
saveBestTimes();
}
publishLaneStatus(1, "stopped");
@@ -157,14 +155,14 @@ void CompetitionMode(const char *action, int press, int lane,
}
}
if (action == "stop" && press == 1 && lane == 2) {
if (timerData.isRunning2) {
timerData.endTime2 = (timestamp > 0) ? timestamp : millis();
timerData.finishedSince2 = millis(); // Set finished time
timerData.isRunning2 = false;
uint64_t currentTime2 = timerData.endTime2 - timerData.startTime2;
if (timerData2.isRunning) {
timerData2.endTime = (timestamp > 0) ? timestamp : millis();
timerData2.finishedSince = millis(); // Set finished time
timerData2.isRunning = false;
uint64_t currentTime2 = timerData2.endTime - timerData2.startTime;
if (timerData.bestTime2 == 0 || currentTime2 < timerData.bestTime2) {
timerData.bestTime2 = currentTime2;
if (timerData2.bestTime == 0 || currentTime2 < timerData2.bestTime) {
timerData2.bestTime = currentTime2;
saveBestTimes();
}
publishLaneStatus(2, "stopped");
@@ -175,28 +173,28 @@ void CompetitionMode(const char *action, int press, int lane,
}
void runCompetition() {
if (timerData.isArmed1 && timerData.isArmed2 && startCompetition) {
timerData.isReady1 = false;
if (timerData1.isArmed && timerData2.isArmed && startCompetition) {
timerData1.isReady = false;
uint64_t startNow = getCurrentTimestampMs();
timerData.startTime1 = startNow;
timerData.localStartTime1 = millis(); // Set local start time
timerData.isRunning1 = true;
timerData.endTime1 = 0; // Reset end time for Bahn 1
timerData.isArmed1 = false; // Reset Bahn 1 armed status
timerData1.startTime = startNow;
timerData1.localStartTime = millis(); // Set local start time
timerData1.isRunning = true;
timerData1.endTime = 0; // Reset end time for Bahn 1
timerData1.isArmed = false; // Reset Bahn 1 armed status
publishLaneStatus(1, "running");
Serial.println("Bahn 1 gestartet");
timerData.isReady2 = false;
timerData.startTime2 = startNow;
timerData.localStartTime2 = millis(); // Set local start time
timerData.isRunning2 = true;
timerData.endTime2 = 0; // Reset end time for Bahn 2
timerData.isArmed2 = false; // Reset Bahn 2 armed status
timerData2.isReady = false;
timerData2.startTime = startNow;
timerData2.localStartTime = millis(); // Set local start time
timerData2.isRunning = true;
timerData2.endTime = 0; // Reset end time for Bahn 2
timerData2.isArmed = false; // Reset Bahn 2 armed status
publishLaneStatus(2, "running");
Serial.println("Bahn 2 gestartet");
}
else {
Serial.println("Bahn 1 und Bahn 2 müssen armiert sein, um den Wettkampf zu starten.");
} else {
Serial.println(
"Bahn 1 und Bahn 2 müssen armiert sein, um den Wettkampf zu starten.");
}
}
@@ -204,13 +202,13 @@ void checkAutoReset() {
unsigned long currentTime = millis();
if (gamemode == 0) { // Individual Mode: Bahnen unabhängig zurücksetzen
if (!timerData.isRunning1 && timerData.endTime1 > 0 &&
timerData.finishedSince1 > 0) {
if (currentTime - timerData.finishedSince1 > maxTimeDisplay) {
timerData.startTime1 = 0;
timerData.endTime1 = 0;
timerData.finishedSince1 = 0;
timerData.isReady1 = true;
if (!timerData1.isRunning && timerData1.endTime > 0 &&
timerData1.finishedSince > 0) {
if (currentTime - timerData1.finishedSince > maxTimeDisplay) {
timerData1.startTime = 0;
timerData1.endTime = 0;
timerData1.finishedSince = 0;
timerData1.isReady = true;
JsonDocument messageDoc;
messageDoc["firstname"] = "";
messageDoc["lastname"] = "";
@@ -222,13 +220,13 @@ void checkAutoReset() {
Serial.println("Bahn 1 automatisch auf 'Bereit' zurückgesetzt");
}
}
if (!timerData.isRunning2 && timerData.endTime2 > 0 &&
timerData.finishedSince2 > 0) {
if (currentTime - timerData.finishedSince2 > maxTimeDisplay) {
timerData.startTime2 = 0;
timerData.endTime2 = 0;
timerData.finishedSince2 = 0;
timerData.isReady2 = true;
if (!timerData2.isRunning && timerData2.endTime > 0 &&
timerData2.finishedSince > 0) {
if (currentTime - timerData2.finishedSince > maxTimeDisplay) {
timerData2.startTime = 0;
timerData2.endTime = 0;
timerData2.finishedSince = 0;
timerData2.isReady = true;
JsonDocument messageDoc;
messageDoc["firstname"] = "";
messageDoc["lastname"] = "";
@@ -242,30 +240,30 @@ void checkAutoReset() {
}
} else if (gamemode ==
1) { // Competition Mode: Beide Bahnen gemeinsam zurücksetzen
bool bothStopped = !timerData.isRunning1 && !timerData.isRunning2 &&
timerData.endTime1 > 0 && timerData.endTime2 > 0 &&
timerData.finishedSince1 > 0 &&
timerData.finishedSince2 > 0;
bool bothStopped = !timerData1.isRunning && !timerData2.isRunning &&
timerData1.endTime > 0 && timerData2.endTime > 0 &&
timerData1.finishedSince > 0 &&
timerData2.finishedSince > 0;
unsigned long latestFinish =
timerData.finishedSince1 > timerData.finishedSince2
? timerData.finishedSince1
: timerData.finishedSince2;
timerData1.finishedSince > timerData2.finishedSince
? timerData1.finishedSince
: timerData2.finishedSince;
if (bothStopped && (currentTime - latestFinish > maxTimeDisplay)) {
// Bahn 1 zurücksetzen
timerData.startTime1 = 0;
timerData.endTime1 = 0;
timerData.finishedSince1 = 0;
timerData.isReady1 = true;
timerData1.startTime = 0;
timerData1.endTime = 0;
timerData1.finishedSince = 0;
timerData1.isReady = true;
publishLaneStatus(1, "ready");
Serial.println("Bahn 1 automatisch auf 'Bereit' zurückgesetzt");
// Bahn 2 zurücksetzen
timerData.startTime2 = 0;
timerData.endTime2 = 0;
timerData.finishedSince2 = 0;
timerData.isReady2 = true;
timerData2.startTime = 0;
timerData2.endTime = 0;
timerData2.finishedSince = 0;
timerData2.isReady = true;
publishLaneStatus(2, "ready");
Serial.println("Bahn 2 automatisch auf 'Bereit' zurückgesetzt");
@@ -288,13 +286,13 @@ String getTimerDataJSON() {
unsigned long currentTime = millis();
// Bahn 1
if (timerData.isRunning1) {
doc["time1"] = (currentTime - timerData.localStartTime1) / 1000.0;
if (timerData1.isRunning) {
doc["time1"] = (currentTime - timerData1.localStartTime) / 1000.0;
doc["status1"] = "running";
} else if (timerData.endTime1 > 0) {
doc["time1"] = (timerData.endTime1 - timerData.startTime1) / 1000.0;
} else if (timerData1.endTime > 0) {
doc["time1"] = (timerData1.endTime - timerData1.startTime) / 1000.0;
doc["status1"] = "finished";
} else if (timerData.isArmed1) {
} else if (timerData1.isArmed) {
doc["time1"] = 0;
doc["status1"] = "armed"; // Status für Bahn 1, wenn sie armiert ist
} else {
@@ -303,13 +301,13 @@ String getTimerDataJSON() {
}
// Bahn 2
if (timerData.isRunning2) {
doc["time2"] = (currentTime - timerData.localStartTime2) / 1000.0;
if (timerData2.isRunning) {
doc["time2"] = (currentTime - timerData2.localStartTime) / 1000.0;
doc["status2"] = "running";
} else if (timerData.endTime2 > 0) {
doc["time2"] = (timerData.endTime2 - timerData.startTime2) / 1000.0;
} else if (timerData2.endTime > 0) {
doc["time2"] = (timerData2.endTime - timerData2.startTime) / 1000.0;
doc["status2"] = "finished";
} else if (timerData.isArmed2) {
} else if (timerData2.isArmed) {
doc["time2"] = 0;
doc["status2"] = "armed"; // Status für Bahn 2, wenn sie armiert ist
} else {
@@ -318,8 +316,8 @@ String getTimerDataJSON() {
}
// Beste Zeiten
doc["best1"] = timerData.bestTime1 / 1000.0;
doc["best2"] = timerData.bestTime2 / 1000.0;
doc["best1"] = timerData1.bestTime / 1000.0;
doc["best2"] = timerData2.bestTime / 1000.0;
// Lernmodus
doc["learningMode"] = learningMode;

View File

@@ -11,24 +11,28 @@ const char *passwordAP = nullptr;
char *ssidSTA = nullptr;
char *passwordSTA = nullptr;
// Timer Struktur
struct TimerData {
unsigned long startTime1 = 0;
unsigned long startTime2 = 0;
unsigned long localStartTime1 = 0;
unsigned long localStartTime2 = 0;
unsigned long finishedSince1 = 0;
unsigned long finishedSince2 = 0;
unsigned long endTime1 = 0;
unsigned long endTime2 = 0;
unsigned long bestTime1 = 0;
unsigned long bestTime2 = 0;
bool isRunning1 = false;
bool isRunning2 = false;
bool isReady1 = true; // Status für Bahn 1
bool isReady2 = true; // Status für Bahn 2
bool isArmed1 = false; // Status für Bahn 1 (armiert/nicht armiert)
bool isArmed2 = false; // Status für Bahn 2 (armiert/nicht armiert)
// Timer Struktur für Bahn 1
struct TimerData1 {
unsigned long startTime = 0;
unsigned long localStartTime = 0;
unsigned long finishedSince = 0;
unsigned long endTime = 0;
unsigned long bestTime = 0;
bool isRunning = false;
bool isReady = true; // Status für Bahn 1
bool isArmed = false; // Status für Bahn 1 (armiert/nicht armiert)
};
// Timer Struktur für Bahn 2
struct TimerData2 {
unsigned long startTime = 0;
unsigned long localStartTime = 0;
unsigned long finishedSince = 0;
unsigned long endTime = 0;
unsigned long bestTime = 0;
bool isRunning = false;
bool isReady = true; // Status für Bahn 2
bool isArmed = false; // Status für Bahn 2 (armiert/nicht armiert)
};
// Button Konfiguration
@@ -50,7 +54,8 @@ struct ButtonConfigs {
extern const char *firmwareversion;
// Globale Variablen
TimerData timerData;
TimerData1 timerData1;
TimerData2 timerData2;
ButtonConfigs buttonConfigs;
bool learningMode = false;
int learningStep = 0; // 0=Start1, 1=Stop1, 2=Start2, 3=Stop2

View File

@@ -24,15 +24,15 @@ void loadButtonConfig() {
// Persist and load best times
void saveBestTimes() {
preferences.begin("times", false);
preferences.putULong("best1", timerData.bestTime1);
preferences.putULong("best2", timerData.bestTime2);
preferences.putULong("best1", timerData1.bestTime);
preferences.putULong("best2", timerData2.bestTime);
preferences.end();
}
void loadBestTimes() {
preferences.begin("times", true);
timerData.bestTime1 = preferences.getULong("best1", 0);
timerData.bestTime2 = preferences.getULong("best2", 0);
timerData1.bestTime = preferences.getULong("best1", 0);
timerData2.bestTime = preferences.getULong("best2", 0);
preferences.end();
}
@@ -93,4 +93,15 @@ int checkLicence() {
return tier;
}
void saveLocationIdToPrefs(const String &locationId) {
preferences.begin("locationid", false);
preferences.putString("locationid", locationId);
preferences.end();
}
String getLocationIdFromPrefs() {
preferences.begin("locationid", true);
String locationId = preferences.getString("locationid", "");
preferences.end();
return locationId;
}

View File

@@ -53,8 +53,8 @@ void setupRoutes() {
server.on("/api/reset-best", HTTP_POST, [](AsyncWebServerRequest *request) {
Serial.println("/api/reset-best called");
timerData.bestTime1 = 0;
timerData.bestTime2 = 0;
timerData1.bestTime = 0;
timerData2.bestTime = 0;
saveBestTimes();
DynamicJsonDocument doc(64);
doc["success"] = true;