This commit is contained in:
Carsten Graf
2025-09-18 23:21:14 +02:00
parent 4f0fc68d41
commit 02a60d84cf
7 changed files with 123 additions and 101 deletions

View File

@@ -12,7 +12,7 @@ html {
body { body {
font-family: "Segoe UI", Arial, sans-serif; font-family: "Segoe UI", Arial, sans-serif;
background: linear-gradient(135deg, #49bae4 0%, #223c83 100%); background: linear-gradient(0deg, #0d1733 0%, #223c83 100%);
height: 100vh; height: 100vh;
width: 100vw; width: 100vw;
display: flex; display: flex;
@@ -38,8 +38,8 @@ body {
text-decoration: none; text-decoration: none;
display: block; display: block;
cursor: pointer; cursor: pointer;
padding-left: 5px; padding: 5px;
padding-right: 5px; background:rgba(255, 255, 255, 0.6);
} }
.logo:hover { .logo:hover {
@@ -367,8 +367,8 @@ body {
} }
.status.ready { .status.ready {
background-color: rgba(34, 60, 131, 0.3); background-color: rgb(0 165 3 / 54%);
border: 2px solid #223c83; border: 2px solid #06ff00;
animation: pulse 1s infinite; animation: pulse 1s infinite;
} }
@@ -379,7 +379,7 @@ body {
} }
.status.running { .status.running {
background-color: rgba(245, 157, 15, 0.3); background-color: rgb(255 91 0 / 65%);
border: 2px solid #f59d0f; border: 2px solid #f59d0f;
} }

View File

@@ -6,7 +6,7 @@
body { body {
font-family: "Segoe UI", Arial, sans-serif; font-family: "Segoe UI", Arial, sans-serif;
background: linear-gradient(135deg, #49bae4 0%, #223c83 100%); background: linear-gradient(0deg, #0d1733 0%, #223c83 100%);
min-height: 100vh; min-height: 100vh;
padding: 20px; padding: 20px;
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "master.h"
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include <preferencemanager.h> #include <preferencemanager.h>
@@ -78,7 +79,7 @@ UserData checkUser(const String &uid) {
userData.firstname = responseDoc["firstname"].as<String>(); userData.firstname = responseDoc["firstname"].as<String>();
userData.lastname = responseDoc["lastname"].as<String>(); userData.lastname = responseDoc["lastname"].as<String>();
userData.alter = responseDoc["alter"] | 0; userData.alter = responseDoc["alter"] | 0;
userData.exists = responseDoc["exists"] | true; userData.exists = responseDoc["exists"] | false;
} }
} else { } else {
Serial.printf("User check failed, HTTP code: %d\n", httpCode); Serial.printf("User check failed, HTTP code: %d\n", httpCode);
@@ -88,43 +89,6 @@ UserData checkUser(const String &uid) {
return userData; return userData;
} }
// Fügt einen neuen Benutzer mit den angegebenen Daten in die Datenbank ein.
bool enterUserData(const String &uid, const String &firstname,
const String &lastname, const String &geburtsdatum,
int alter) {
if (!backendOnline()) {
Serial.println("No internet connection, cannot enter user data.");
return false;
}
HTTPClient http;
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["rfiduid"] = uid;
requestDoc["firstname"] = firstname;
requestDoc["lastname"] = lastname;
requestDoc["birthdate"] = geburtsdatum;
String requestBody;
serializeJson(requestDoc, requestBody);
int httpCode = http.POST(requestBody);
if (httpCode == HTTP_CODE_CREATED) {
Serial.println("User data entered successfully.");
http.end();
return true;
} else {
Serial.printf("Failed to enter user data, HTTP code: %d\n", httpCode);
http.end();
return false;
}
}
// Holt alle Standorte aus der Datenbank und gibt sie als JSON-Dokument zurück. // Holt alle Standorte aus der Datenbank und gibt sie als JSON-Dokument zurück.
JsonDocument getAllLocations() { JsonDocument getAllLocations() {
JsonDocument locations; // Allocate memory for the JSON document JsonDocument locations; // Allocate memory for the JSON document
@@ -159,6 +123,45 @@ JsonDocument getAllLocations() {
// (Kompatibilitätsfunktion). // (Kompatibilitätsfunktion).
bool userExists(const String &uid) { return checkUser(uid).exists; } bool userExists(const String &uid) { return checkUser(uid).exists; }
// Fügt einen neuen Benutzer in die Datenbank ein
bool enterUserData(const String &uid, const String &vorname,
const String &nachname, const String &geburtsdatum,
int alter) {
if (!backendOnline()) {
Serial.println("No internet connection, cannot enter user data.");
return false;
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/v1/private/users/insert");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
// Create JSON payload
StaticJsonDocument<512> requestDoc;
requestDoc["uid"] = uid;
requestDoc["firstname"] = vorname;
requestDoc["lastname"] = nachname;
requestDoc["geburtsdatum"] = geburtsdatum;
requestDoc["alter"] = alter;
String requestBody;
serializeJson(requestDoc, requestBody);
int httpCode = http.POST(requestBody);
bool success = (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_CREATED);
if (success) {
Serial.println("User data successfully entered into database");
} else {
Serial.printf("Failed to enter user data, HTTP code: %d\n", httpCode);
}
http.end();
return success;
}
// Richtet die HTTP-Routen für die Backend-API ein (z.B. Health-Check, User- und // Richtet die HTTP-Routen für die Backend-API ein (z.B. Health-Check, User- und
// Location-Abfragen). // Location-Abfragen).
void setupBackendRoutes(AsyncWebServer &server) { void setupBackendRoutes(AsyncWebServer &server) {

View File

@@ -21,7 +21,7 @@ struct TimerData1 {
bool isRunning = false; bool isRunning = false;
bool isReady = true; // Status für Bahn 1 bool isReady = true; // Status für Bahn 1
bool isArmed = false; // Status für Bahn 1 (armiert/nicht armiert) bool isArmed = false; // Status für Bahn 1 (armiert/nicht armiert)
char RFIDUID = ""; char RFIDUID[32] = "";
}; };
// Timer Struktur für Bahn 2 // Timer Struktur für Bahn 2
@@ -34,7 +34,7 @@ struct TimerData2 {
bool isRunning = false; bool isRunning = false;
bool isReady = true; // Status für Bahn 2 bool isReady = true; // Status für Bahn 2
bool isArmed = false; // Status für Bahn 2 (armiert/nicht armiert) bool isArmed = false; // Status für Bahn 2 (armiert/nicht armiert)
char RFIDUID = ""; char RFIDUID[32] = "";
}; };
// Button Konfiguration // Button Konfiguration
@@ -69,9 +69,9 @@ int gamemode; // 0=Individual, 1=Wettkampf
bool startCompetition = false; // Flag, ob der Timer gestartet wurde bool startCompetition = false; // Flag, ob der Timer gestartet wurde
// Lane Configuration // Lane Configuration
int laneConfigType = 0; // 0=Identical, 1=Different int laneConfigType = 0; // 0=Identical, 1=Different
int lane1DifficultyType = 0; // 0=Light, 1=Heavy (difficulty) int lane1DifficultyType = 0; // 0=Light, 1=Heavy (difficulty)
int lane2DifficultyType = 0; // 0=Light, 1=Heavy (difficulty) int lane2DifficultyType = 0; // 0=Light, 1=Heavy (difficulty)
// Function Declarations // Function Declarations
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len); void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len);

View File

@@ -2,8 +2,8 @@
#include <Arduino.h> #include <Arduino.h>
#include <Preferences.h> #include <Preferences.h>
#include <master.h>
#include <licenceing.h> #include <licenceing.h>
#include <master.h>
// Persist and load button configuration // Persist and load button configuration
void saveButtonConfig() { void saveButtonConfig() {
@@ -43,8 +43,8 @@ void saveSettings() {
preferences.putULong("maxTimeDisplay", maxTimeDisplay); preferences.putULong("maxTimeDisplay", maxTimeDisplay);
preferences.putUInt("gamemode", gamemode); preferences.putUInt("gamemode", gamemode);
preferences.putUInt("laneConfigType", laneConfigType); preferences.putUInt("laneConfigType", laneConfigType);
preferences.putUInt("lane1DifficultyType", lane1DifficultyType); preferences.putUInt("lane1Diff", lane1DifficultyType);
preferences.putUInt("lane2DifficultyType", lane2DifficultyType); preferences.putUInt("lane2Diff", lane2DifficultyType);
preferences.end(); preferences.end();
} }
@@ -54,8 +54,8 @@ void loadSettings() {
maxTimeDisplay = preferences.getULong("maxTimeDisplay", 20000); maxTimeDisplay = preferences.getULong("maxTimeDisplay", 20000);
gamemode = preferences.getUInt("gamemode", 0); gamemode = preferences.getUInt("gamemode", 0);
laneConfigType = preferences.getUInt("laneConfigType", 0); laneConfigType = preferences.getUInt("laneConfigType", 0);
lane1DifficultyType = preferences.getUInt("lane1DifficultyType", 0); lane1DifficultyType = preferences.getUInt("lane1Diff", 0);
lane2DifficultyType = preferences.getUInt("lane2DifficultyType", 0); lane2DifficultyType = preferences.getUInt("lane2Diff", 0);
preferences.end(); preferences.end();
} }

View File

@@ -1,9 +1,11 @@
#pragma once #pragma once
#include "databasebackend.h"
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <MFRC522.h> #include <MFRC522.h>
#include <SPI.h> #include <SPI.h>
// RFID Konfiguration // RFID Konfiguration
#define RST_PIN 21 // Configurable, see typical pin layout above #define RST_PIN 21 // Configurable, see typical pin layout above
#define SS_PIN 5 // Configurable, see typical pin layout above #define SS_PIN 5 // Configurable, see typical pin layout above

View File

@@ -33,7 +33,6 @@ void setupRoutes() {
request->send(SPIFFS, "/settings.html", "text/html"); request->send(SPIFFS, "/settings.html", "text/html");
}); });
server.on("/firmware.bin", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/firmware.bin", HTTP_GET, [](AsyncWebServerRequest *request) {
if (SPIFFS.exists("/firmware.bin")) { if (SPIFFS.exists("/firmware.bin")) {
request->send(SPIFFS, "/firmware.bin", "application/octet-stream"); request->send(SPIFFS, "/firmware.bin", "application/octet-stream");
@@ -313,51 +312,69 @@ void setupRoutes() {
}); });
// Lane Configuration API Routes // Lane Configuration API Routes
server.on("/api/set-lane-config", HTTP_POST, [](AsyncWebServerRequest *request) { server.on(
Serial.println("/api/set-lane-config called"); "/api/set-lane-config", HTTP_POST, [](AsyncWebServerRequest *request) {},
NULL,
[](AsyncWebServerRequest *request, uint8_t *data, size_t len,
size_t index, size_t total) {
Serial.println("/api/set-lane-config called");
String body = request->getBody(); DynamicJsonDocument doc(256);
DynamicJsonDocument doc(256); DeserializationError error = deserializeJson(doc, data, len);
deserializeJson(doc, body);
if (doc.containsKey("type")) { if (error) {
String laneType = doc["type"]; Serial.println("JSON parsing error");
laneConfigType = (laneType == "identical") ? 0 : 1; request->send(400, "application/json",
"{\"success\":false,\"error\":\"Invalid JSON\"}");
return;
}
if (laneConfigType == 1 && doc.containsKey("lane1Difficulty") && doc.containsKey("lane2Difficulty")) { if (doc.containsKey("type")) {
String lane1Difficulty = doc["lane1Difficulty"]; String laneType = doc["type"];
String lane2Difficulty = doc["lane2Difficulty"]; laneConfigType = (laneType == "identical") ? 0 : 1;
lane1DifficultyType = (lane1Difficulty == "light") ? 0 : 1;
lane2DifficultyType = (lane2Difficulty == "light") ? 0 : 1;
}
Serial.printf("Lane configuration set - Type: %s, Lane1: %s, Lane2: %s\n", if (laneConfigType == 1 && doc.containsKey("lane1Difficulty") &&
laneType.c_str(), doc.containsKey("lane2Difficulty")) {
(laneConfigType == 1) ? ((lane1DifficultyType == 0) ? "light" : "heavy") : "identical", String lane1Difficulty = doc["lane1Difficulty"];
(laneConfigType == 1) ? ((lane2DifficultyType == 0) ? "light" : "heavy") : "identical"); String lane2Difficulty = doc["lane2Difficulty"];
lane1DifficultyType = (lane1Difficulty == "light") ? 0 : 1;
lane2DifficultyType = (lane2Difficulty == "light") ? 0 : 1;
}
DynamicJsonDocument response(64); Serial.printf(
response["success"] = true; "Lane configuration set - Type: %s, Lane1: %s, Lane2: %s\n",
String result; laneType.c_str(),
serializeJson(response, result); (laneConfigType == 1)
request->send(200, "application/json", result); ? ((lane1DifficultyType == 0) ? "light" : "heavy")
saveSettings(); : "identical",
} else { (laneConfigType == 1)
request->send(400, "application/json", "{\"success\":false,\"error\":\"Lane type missing\"}"); ? ((lane2DifficultyType == 0) ? "light" : "heavy")
} : "identical");
});
server.on("/api/get-lane-config", HTTP_GET, [](AsyncWebServerRequest *request) { DynamicJsonDocument response(64);
DynamicJsonDocument doc(128); response["success"] = true;
doc["type"] = laneConfigType == 0 ? "identical" : "different"; String result;
if (laneConfigType == 1) { serializeJson(response, result);
doc["lane1Difficulty"] = lane1DifficultyType == 0 ? "light" : "heavy"; request->send(200, "application/json", result);
doc["lane2Difficulty"] = lane2DifficultyType == 0 ? "light" : "heavy"; saveSettings();
} } else {
String result; request->send(400, "application/json",
serializeJson(doc, result); "{\"success\":false,\"error\":\"Lane type missing\"}");
request->send(200, "application/json", result); }
}); });
server.on(
"/api/get-lane-config", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument doc(128);
doc["type"] = laneConfigType == 0 ? "identical" : "different";
if (laneConfigType == 1) {
doc["lane1Difficulty"] = lane1DifficultyType == 0 ? "light" : "heavy";
doc["lane2Difficulty"] = lane2DifficultyType == 0 ? "light" : "heavy";
}
String result;
serializeJson(doc, result);
request->send(200, "application/json", result);
});
// Statische Dateien // Statische Dateien
server.serveStatic("/", SPIFFS, "/"); server.serveStatic("/", SPIFFS, "/");