Refactor for Gamemodes

This commit is contained in:
Carsten Graf
2025-08-05 21:21:22 +02:00
parent 60d4393bd2
commit 6793a54103
7 changed files with 213 additions and 149 deletions

View File

@@ -344,6 +344,7 @@
loadCurrentTime(); loadCurrentTime();
updateCurrentTimeDisplay(); updateCurrentTimeDisplay();
loadWifiSettings(); loadWifiSettings();
loadMode();
}; };
// Aktuelle Zeit anzeigen (Live-Update) // Aktuelle Zeit anzeigen (Live-Update)
@@ -525,6 +526,23 @@
.catch(error => showMessage('Verbindungsfehler', 'error')); .catch(error => showMessage('Verbindungsfehler', 'error'));
}); });
function loadMode() {
fetch("/api/get-mode")
.then((response) => response.json())
.then((data) => {
const mode = data.mode || "individual";
document.querySelectorAll('.mode-button').forEach(button => {
button.classList.remove('active');
});
const btn = document.querySelector(`.mode-button[data-mode="${mode}"]`);
if (btn) btn.classList.add('active');
})
.catch((error) => {
showMessage("Fehler beim Laden des Modus", "error");
});
}
// Einstellungen laden // Einstellungen laden
function loadSettings() { function loadSettings() {
fetch("/api/get-settings") fetch("/api/get-settings")

View File

@@ -12,6 +12,7 @@
#include "statusled.h" #include "statusled.h"
#include "timesync.h" #include "timesync.h"
#include "webserverrouter.h" #include "webserverrouter.h"
#include <gamemodes.h>
#include <map> #include <map>
/** /**
@@ -88,16 +89,20 @@ void readButtonJSON(const char *topic, const char *payload) {
// Button-Zuordnung prüfen und entsprechende Aktion ausführen // Button-Zuordnung prüfen und entsprechende Aktion ausführen
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0 && if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0 &&
(pressType == 2)) { (pressType == 2)) {
handleStart1(timestamp); // handleStart1(timestamp);
triggerAction("start", 2, 1, timestamp);
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0 && } else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0 &&
(pressType == 1)) { (pressType == 1)) {
handleStop1(timestamp); // handleStop1(timestamp);
triggerAction("stop", 1, 1, timestamp);
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0 && } else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0 &&
(pressType == 2)) { (pressType == 2)) {
handleStart2(timestamp); // handleStart2(timestamp);
triggerAction("start", 2, 2, timestamp);
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0 && } else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0 &&
(pressType == 1)) { (pressType == 1)) {
handleStop2(timestamp); // handleStop2(timestamp);
triggerAction("stop", 1, 2, timestamp);
} }
// Flash status LED to indicate received message // Flash status LED to indicate received message

View File

@@ -7,8 +7,8 @@
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include "communication.h" #include "communication.h"
#include "gamemodes.h"
void setupDebugAPI(AsyncWebServer &server); void setupDebugAPI(AsyncWebServer &server);
@@ -16,22 +16,22 @@ void setupDebugAPI(AsyncWebServer &server) {
// DEBUG // DEBUG
server.on("/api/debug/start1", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/api/debug/start1", HTTP_GET, [](AsyncWebServerRequest *request) {
handleStart1(0); // handleStart1(0);
request->send(200, "text/plain", "handleStart1() called"); request->send(200, "text/plain", "handleStart1() called");
}); });
server.on("/api/debug/stop1", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/api/debug/stop1", HTTP_GET, [](AsyncWebServerRequest *request) {
handleStop1(0); // handleStop1(0);
request->send(200, "text/plain", "handleStop1() called"); request->send(200, "text/plain", "handleStop1() called");
}); });
server.on("/api/debug/start2", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/api/debug/start2", HTTP_GET, [](AsyncWebServerRequest *request) {
handleStart2(0); // handleStart2(0);
request->send(200, "text/plain", "handleStart2() called"); request->send(200, "text/plain", "handleStart2() called");
}); });
server.on("/api/debug/stop2", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/api/debug/stop2", HTTP_GET, [](AsyncWebServerRequest *request) {
handleStop2(0); // handleStop2(0);
request->send(200, "text/plain", "handleStop2() called"); request->send(200, "text/plain", "handleStop2() called");
}); });

View File

@@ -1,20 +1,171 @@
void publishLaneStatus(int lane, String status);
void pushUpdateToFrontend(const String &message);
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <master.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <communication.h>
#include <webserverrouter.h>
void IndividualMode(); void IndividualMode(const char *action, int press, int lane,
void CompetitionMode(); uint64_t timestamp = 0);
void CompetitionMode(const char *action, int press, int lane,
uint64_t timestamp = 0);
void handleStart1(uint64_t timestamp);
void handleStop1(uint64_t timestamp);
void handleStart2(uint64_t timestamp);
void handleStop2(uint64_t timestamp);
void IndividualMode(const char *action, int lane, int timestamp = 0) { void triggerAction(const char *action, int press, int lane,
Serial.printf("Individual Mode Action: %s on Lane %d at %d\n", action, lane, uint64_t _timestamp = 0) {
if (gamemode == 0) {
Serial.println("Individual Mode aktiv");
IndividualMode(action, press, lane, _timestamp);
} else if (gamemode == 1) {
Serial.println("Wettkampf Mode aktiv");
CompetitionMode(action, press, lane, _timestamp);
} else {
Serial.println("Unbekannter Modus, bitte überprüfen");
}
}
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;
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;
unsigned long currentTime = timerData.endTime1 - timerData.startTime1;
if (timerData.bestTime1 == 0 || currentTime < timerData.bestTime1) {
timerData.bestTime1 = currentTime;
saveBestTimes();
}
publishLaneStatus(1, "stopped");
Serial.println("Bahn 1 gestoppt - Zeit: " + String(currentTime / 1000.0) +
"s");
}
}
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;
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;
unsigned long currentTime = timerData.endTime2 - timerData.startTime2;
if (timerData.bestTime2 == 0 || currentTime < timerData.bestTime2) {
timerData.bestTime2 = currentTime;
saveBestTimes();
}
publishLaneStatus(2, "stopped");
Serial.println("Bahn 2 gestoppt - Zeit: " + String(currentTime / 1000.0) +
"s");
}
}
Serial.printf("Individual Mode Action: %s on Lane %d at %llu\n", action, lane,
timestamp); timestamp);
// Implement individual mode logic here // Implement individual mode logic here
} }
void CompetitionMode(const char *action, int lane, int timestamp = 0) { void CompetitionMode(const char *action, int press, int lane,
Serial.printf("Competition Mode Action: %s on Lane %d at %d\n", action, lane, uint64_t timestamp) {
timestamp); Serial.printf("Competition Mode Action: %s on Lane %d at %llu\n", action,
lane, timestamp);
// Implement competition mode logic here // Implement competition mode logic here
}
void checkAutoReset() {
unsigned long currentTime = millis();
if (timerData.isRunning1 &&
(currentTime - timerData.localStartTime1 > maxTimeBeforeReset)) {
timerData.isRunning1 = false;
timerData.startTime1 = 0;
publishLaneStatus(1, "ready");
Serial.println("Bahn 1 automatisch zurückgesetzt");
}
if (timerData.isRunning2 &&
(currentTime - timerData.localStartTime2 > maxTimeBeforeReset)) {
timerData.isRunning2 = false;
timerData.startTime2 = 0;
publishLaneStatus(2, "ready");
Serial.println("Bahn 2 automatisch zurückgesetzt");
}
// Automatischer Reset nach 10 Sekunden "Beendet"
if (!timerData.isRunning1 && timerData.endTime1 > 0 &&
timerData.finishedSince1 > 0) {
if (millis() - timerData.finishedSince1 > maxTimeDisplay) {
timerData.startTime1 = 0;
timerData.endTime1 = 0;
timerData.finishedSince1 = 0;
timerData.isReady1 = true; // Zurücksetzen auf "Bereit"
JsonDocument messageDoc;
messageDoc["firstname"] = "";
messageDoc["lastname"] = "";
messageDoc["lane"] = "start1"; // Add lane information
String message;
serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
publishLaneStatus(1, "ready");
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; // Zurücksetzen auf "Bereit"
JsonDocument messageDoc;
messageDoc["firstname"] = "";
messageDoc["lastname"] = "";
messageDoc["lane"] = "start2"; // Add lane information
String message;
serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
publishLaneStatus(2, "ready");
Serial.println("Bahn 2 automatisch auf 'Bereit' zurückgesetzt");
}
}
} }

View File

@@ -21,135 +21,10 @@
#include <timesync.h> #include <timesync.h>
#include <webserverrouter.h> #include <webserverrouter.h>
#include <wificlass.h> #include <wificlass.h>
#include <gamemodes.h>
const char *firmwareversion = "1.0.0"; // Version der Firmware const char *firmwareversion = "1.0.0"; // Version der Firmware
void handleStart1(uint64_t timestamp = 0) {
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;
publishLaneStatus(1, "running");
Serial.println("Bahn 1 gestartet");
}
}
void handleStop1(uint64_t timestamp = 0) {
if (timerData.isRunning1) {
timerData.endTime1 = (timestamp > 0) ? timestamp : millis();
timerData.finishedSince1 = millis(); // Set finished time
timerData.isRunning1 = false;
unsigned long currentTime = timerData.endTime1 - timerData.startTime1;
if (timerData.bestTime1 == 0 || currentTime < timerData.bestTime1) {
timerData.bestTime1 = currentTime;
saveBestTimes();
}
publishLaneStatus(1, "stopped");
Serial.println("Bahn 1 gestoppt - Zeit: " + String(currentTime / 1000.0) +
"s");
}
}
void handleStart2(uint64_t timestamp = 0) {
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;
publishLaneStatus(2, "running");
Serial.println("Bahn 2 gestartet");
}
}
void handleStop2(uint64_t timestamp = 0) {
if (timerData.isRunning2) {
timerData.endTime2 = (timestamp > 0) ? timestamp : millis();
timerData.finishedSince2 = millis(); // Set finished time
timerData.isRunning2 = false;
unsigned long currentTime = timerData.endTime2 - timerData.startTime2;
if (timerData.bestTime2 == 0 || currentTime < timerData.bestTime2) {
timerData.bestTime2 = currentTime;
saveBestTimes();
}
publishLaneStatus(2, "stopped");
Serial.println("Bahn 2 gestoppt - Zeit: " + String(currentTime / 1000.0) +
"s");
}
}
void checkAutoReset() {
unsigned long currentTime = millis();
if (timerData.isRunning1 &&
(currentTime - timerData.localStartTime1 > maxTimeBeforeReset)) {
timerData.isRunning1 = false;
timerData.startTime1 = 0;
publishLaneStatus(1, "ready");
Serial.println("Bahn 1 automatisch zurückgesetzt");
}
if (timerData.isRunning2 &&
(currentTime - timerData.localStartTime2 > maxTimeBeforeReset)) {
timerData.isRunning2 = false;
timerData.startTime2 = 0;
publishLaneStatus(2, "ready");
Serial.println("Bahn 2 automatisch zurückgesetzt");
}
// Automatischer Reset nach 10 Sekunden "Beendet"
if (!timerData.isRunning1 && timerData.endTime1 > 0 &&
timerData.finishedSince1 > 0) {
if (millis() - timerData.finishedSince1 > maxTimeDisplay) {
timerData.startTime1 = 0;
timerData.endTime1 = 0;
timerData.finishedSince1 = 0;
timerData.isReady1 = true; // Zurücksetzen auf "Bereit"
JsonDocument messageDoc;
messageDoc["firstname"] = "";
messageDoc["lastname"] = "";
messageDoc["lane"] = "start1"; // Add lane information
String message;
serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
publishLaneStatus(1, "ready");
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; // Zurücksetzen auf "Bereit"
JsonDocument messageDoc;
messageDoc["firstname"] = "";
messageDoc["lastname"] = "";
messageDoc["lane"] = "start2"; // Add lane information
String message;
serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
publishLaneStatus(2, "ready");
Serial.println("Bahn 2 automatisch auf 'Bereit' zurückgesetzt");
}
}
}
void saveButtonConfig() { void saveButtonConfig() {
preferences.begin("buttons", false); preferences.begin("buttons", false);

View File

@@ -56,16 +56,12 @@ unsigned long maxTimeBeforeReset = 300000; // 5 Minuten default
unsigned long maxTimeDisplay = 20000; // 20 Sekunden Standard (in ms) unsigned long maxTimeDisplay = 20000; // 20 Sekunden Standard (in ms)
bool wifimodeAP = false; // AP-Modus deaktiviert bool wifimodeAP = false; // AP-Modus deaktiviert
String masterlocation; String masterlocation;
int operationalMode = 0; // 0=Individual, 1=Wettkampf int gamemode; // 0=Individual, 1=Wettkampf
// 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);
void handleLearningMode(const uint8_t *mac); void handleLearningMode(const uint8_t *mac);
void handleStartLearning(); void handleStartLearning();
void handleStart1(uint64_t timestamp);
void handleStop1(uint64_t timestamp);
void handleStart2(uint64_t timestamp);
void handleStop2(uint64_t timestamp);
void checkAutoReset(); void checkAutoReset();
void saveButtonConfig(); void saveButtonConfig();
void loadButtonConfig(); void loadButtonConfig();

View File

@@ -12,6 +12,7 @@ void sendMQTTMessage(const char *topic, const char *message);
#include "communication.h" #include "communication.h"
#include <buttonassigh.h> #include <buttonassigh.h>
#include <gamemodes.h>
#include <wificlass.h> #include <wificlass.h>
AsyncWebServer server(80); AsyncWebServer server(80);
@@ -290,9 +291,9 @@ void setupRoutes() {
if (mode.length() > 0) { if (mode.length() > 0) {
// Speichere den Modus // Speichere den Modus
operationalMode = mode == "individual" ? 1 : 0; gamemode = mode == "individual" ? 0 : 1;
Serial.printf("Operational mode set to: %s\n", Serial.printf("Operational mode set to: %s\n",
operationalMode == 1 ? "Individual" : "Wettkampf"); gamemode == 0 ? "Individual" : "Wettkampf");
// Rückmeldung // Rückmeldung
DynamicJsonDocument doc(64); DynamicJsonDocument doc(64);
doc["success"] = true; doc["success"] = true;
@@ -305,6 +306,24 @@ void setupRoutes() {
} }
}); });
server.on("/api/get-mode", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument doc(32);
doc["mode"] = gamemode == 0 ? "individual" : "wettkampf";
String result;
serializeJson(doc, result);
request->send(200, "application/json", result);
});
server.on("/api/get-mode", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument doc(32);
doc["mode"] = gamemode == 0 ? "individual" : "wettkampf";
String result;
serializeJson(doc, result);
request->send(200, "application/json", result);
});
// ...existing code...
// Statische Dateien // Statische Dateien
server.serveStatic("/", SPIFFS, "/"); server.serveStatic("/", SPIFFS, "/");
server.begin(); server.begin();