Bug fixed, Wettkampfmodus Done. TODO: Zeitstempel der Statusampel im Master verwenden
This commit is contained in:
@@ -355,18 +355,24 @@ body {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status.ready {
|
||||
.status.finished {
|
||||
background-color: rgba(52, 152, 219, 0.3);
|
||||
border: 2px solid #3498db;
|
||||
}
|
||||
|
||||
.status.running {
|
||||
.status.ready {
|
||||
background-color: rgba(46, 204, 113, 0.3);
|
||||
border: 2px solid #2ecc71;
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
|
||||
.status.finished {
|
||||
.status.armed {
|
||||
background-color: rgb(197, 194, 0);
|
||||
border: 2px solid #fbff00;
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
|
||||
.status.running {
|
||||
background-color: rgba(231, 76, 60, 0.3);
|
||||
border: 2px solid #e74c3c;
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@
|
||||
s1.textContent = "Beendet";
|
||||
break;
|
||||
case "armed":
|
||||
s1.textContent = "Armiert"; // Neuer Status für armiert
|
||||
s1.textContent = "Armiert";
|
||||
break;
|
||||
default:
|
||||
s1.textContent = "Unbekannter Status";
|
||||
@@ -391,7 +391,7 @@
|
||||
|
||||
if (!lane2Connected) {
|
||||
s2.className = "status standby";
|
||||
s2.textContent = "Standby: Bitte beide 1x betätigen";
|
||||
s2.textContent = "Standby: Bitte beide Buttons 1x betätigen";
|
||||
} else {
|
||||
s2.className = `status ${status2}`;
|
||||
|
||||
|
||||
@@ -344,6 +344,11 @@ void setupMqttServer() {
|
||||
handleBatteryTopic(topic, payload);
|
||||
} else if (strncmp(topic, "heartbeat/alive/", 16) == 0) {
|
||||
handleHeartbeatTopic(topic, payload);
|
||||
} else if (strncmp(topic, "aquacross/competition/toMaster", 30) == 0) {
|
||||
// Handle competition lane messages
|
||||
// payload ist sendMQTTMessage("aquacross/competition/toMaster", "start");
|
||||
startCompetition = (payload != nullptr && strcmp(payload, "start") == 0);
|
||||
runCompetition();
|
||||
}
|
||||
updateStatusLED(3);
|
||||
});
|
||||
|
||||
104
src/gamemodes.h
104
src/gamemodes.h
@@ -14,10 +14,6 @@ void IndividualMode(const char *action, int press, int lane,
|
||||
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 triggerAction(const char *action, int press, int lane,
|
||||
uint64_t _timestamp) {
|
||||
@@ -41,6 +37,7 @@ void IndividualMode(const char *action, int press, int lane,
|
||||
timerData.localStartTime1 = millis(); // Set local start time
|
||||
timerData.isRunning1 = true;
|
||||
timerData.endTime1 = 0;
|
||||
timerData.isArmed1 = false; // Reset armed status
|
||||
publishLaneStatus(1, "running");
|
||||
Serial.println("Bahn 1 gestartet");
|
||||
}
|
||||
@@ -68,6 +65,7 @@ void IndividualMode(const char *action, int press, int lane,
|
||||
timerData.localStartTime2 = millis(); // Set local start time
|
||||
timerData.isRunning2 = true;
|
||||
timerData.endTime2 = 0;
|
||||
timerData.isArmed2 = false; // Reset armed status
|
||||
publishLaneStatus(2, "running");
|
||||
Serial.println("Bahn 2 gestartet");
|
||||
}
|
||||
@@ -137,26 +135,11 @@ void CompetitionMode(const char *action, int press, int lane,
|
||||
}
|
||||
|
||||
if (timerData.isArmed1 && timerData.isArmed2) {
|
||||
timerData.isReady1 = 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
|
||||
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
|
||||
publishLaneStatus(2, "running");
|
||||
Serial.println("Bahn 2 gestartet");
|
||||
sendMQTTMessage("aquacross/competition/toSignal", "armed");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((action == "stop" && press == 1 && lane == 1)) {
|
||||
if (timerData.isRunning1) {
|
||||
timerData.endTime1 = (timestamp > 0) ? timestamp : millis();
|
||||
@@ -191,6 +174,32 @@ void CompetitionMode(const char *action, int press, int lane,
|
||||
}
|
||||
}
|
||||
|
||||
void runCompetition() {
|
||||
if (timerData.isArmed1 && timerData.isArmed2 && startCompetition) {
|
||||
timerData.isReady1 = 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
|
||||
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
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
void checkAutoReset() {
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
@@ -273,3 +282,54 @@ void checkAutoReset() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getTimerDataJSON() {
|
||||
DynamicJsonDocument doc(1024);
|
||||
|
||||
unsigned long currentTime = millis();
|
||||
// Bahn 1
|
||||
if (timerData.isRunning1) {
|
||||
doc["time1"] = (currentTime - timerData.localStartTime1) / 1000.0;
|
||||
doc["status1"] = "running";
|
||||
} else if (timerData.endTime1 > 0) {
|
||||
doc["time1"] = (timerData.endTime1 - timerData.startTime1) / 1000.0;
|
||||
doc["status1"] = "finished";
|
||||
} else if (timerData.isArmed1) {
|
||||
doc["time1"] = 0;
|
||||
doc["status1"] = "armed"; // Status für Bahn 1, wenn sie armiert ist
|
||||
} else {
|
||||
doc["time1"] = 0;
|
||||
doc["status1"] = "ready";
|
||||
}
|
||||
|
||||
// Bahn 2
|
||||
if (timerData.isRunning2) {
|
||||
doc["time2"] = (currentTime - timerData.localStartTime2) / 1000.0;
|
||||
doc["status2"] = "running";
|
||||
} else if (timerData.endTime2 > 0) {
|
||||
doc["time2"] = (timerData.endTime2 - timerData.startTime2) / 1000.0;
|
||||
doc["status2"] = "finished";
|
||||
} else if (timerData.isArmed2) {
|
||||
doc["time2"] = 0;
|
||||
doc["status2"] = "armed"; // Status für Bahn 2, wenn sie armiert ist
|
||||
} else {
|
||||
doc["time2"] = 0;
|
||||
doc["status2"] = "ready";
|
||||
}
|
||||
|
||||
// Beste Zeiten
|
||||
doc["best1"] = timerData.bestTime1 / 1000.0;
|
||||
doc["best2"] = timerData.bestTime2 / 1000.0;
|
||||
|
||||
// Lernmodus
|
||||
doc["learningMode"] = learningMode;
|
||||
if (learningMode) {
|
||||
String buttons[] = {"Start Bahn 1", "Stop Bahn 1", "Start Bahn 2",
|
||||
"Stop Bahn 2"};
|
||||
doc["learningButton"] = buttons[learningStep];
|
||||
}
|
||||
|
||||
String result;
|
||||
serializeJson(doc, result);
|
||||
return result;
|
||||
}
|
||||
@@ -107,56 +107,7 @@ int checkLicence() {
|
||||
return tier;
|
||||
}
|
||||
|
||||
String getTimerDataJSON() {
|
||||
DynamicJsonDocument doc(1024);
|
||||
|
||||
unsigned long currentTime = millis();
|
||||
// Bahn 1
|
||||
if (timerData.isRunning1) {
|
||||
doc["time1"] = (currentTime - timerData.localStartTime1) / 1000.0;
|
||||
doc["status1"] = "running";
|
||||
} else if (timerData.endTime1 > 0) {
|
||||
doc["time1"] = (timerData.endTime1 - timerData.startTime1) / 1000.0;
|
||||
doc["status1"] = "finished";
|
||||
} else if (timerData.isArmed1) {
|
||||
doc["time1"] = 0;
|
||||
doc["status1"] = "armed"; // Status für Bahn 1, wenn sie armiert ist
|
||||
} else {
|
||||
doc["time1"] = 0;
|
||||
doc["status1"] = "ready";
|
||||
}
|
||||
|
||||
// Bahn 2
|
||||
if (timerData.isRunning2) {
|
||||
doc["time2"] = (currentTime - timerData.localStartTime2) / 1000.0;
|
||||
doc["status2"] = "running";
|
||||
} else if (timerData.endTime2 > 0) {
|
||||
doc["time2"] = (timerData.endTime2 - timerData.startTime2) / 1000.0;
|
||||
doc["status2"] = "finished";
|
||||
} else if (timerData.isArmed2) {
|
||||
doc["time2"] = 0;
|
||||
doc["status2"] = "armed"; // Status für Bahn 2, wenn sie armiert ist
|
||||
} else {
|
||||
doc["time2"] = 0;
|
||||
doc["status2"] = "ready";
|
||||
}
|
||||
|
||||
// Beste Zeiten
|
||||
doc["best1"] = timerData.bestTime1 / 1000.0;
|
||||
doc["best2"] = timerData.bestTime2 / 1000.0;
|
||||
|
||||
// Lernmodus
|
||||
doc["learningMode"] = learningMode;
|
||||
if (learningMode) {
|
||||
String buttons[] = {"Start Bahn 1", "Stop Bahn 1", "Start Bahn 2",
|
||||
"Stop Bahn 2"};
|
||||
doc["learningButton"] = buttons[learningStep];
|
||||
}
|
||||
|
||||
String result;
|
||||
serializeJson(doc, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
@@ -180,6 +131,7 @@ void setup() {
|
||||
loadWifiSettings();
|
||||
loadLocationSettings();
|
||||
|
||||
|
||||
setupWifi(); // WiFi initialisieren
|
||||
setupOTA(&server);
|
||||
|
||||
|
||||
@@ -58,7 +58,8 @@ unsigned long maxTimeBeforeReset = 300000; // 5 Minuten default
|
||||
unsigned long maxTimeDisplay = 20000; // 20 Sekunden Standard (in ms)
|
||||
bool wifimodeAP = false; // AP-Modus deaktiviert
|
||||
String masterlocation;
|
||||
int gamemode; // 0=Individual, 1=Wettkampf
|
||||
int gamemode; // 0=Individual, 1=Wettkampf
|
||||
bool startCompetition = false; // Flag, ob der Timer gestartet wurde
|
||||
|
||||
// Function Declarations
|
||||
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len);
|
||||
|
||||
@@ -300,6 +300,7 @@ void setupRoutes() {
|
||||
String result;
|
||||
serializeJson(doc, result);
|
||||
request->send(200, "application/json", result);
|
||||
saveSettings();
|
||||
} else {
|
||||
request->send(400, "application/json",
|
||||
"{\"success\":false,\"error\":\"Modus fehlt\"}");
|
||||
@@ -314,16 +315,6 @@ void setupRoutes() {
|
||||
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
|
||||
server.serveStatic("/", SPIFFS, "/");
|
||||
server.begin();
|
||||
|
||||
Reference in New Issue
Block a user