Formatting all c files

This commit is contained in:
Carsten Graf
2025-07-12 17:32:16 +02:00
parent 94b30ed7a3
commit 585d2d7d5d
13 changed files with 1129 additions and 1118 deletions

View File

@@ -1,52 +1,55 @@
#pragma once #pragma once
#include <Arduino.h>
#include "master.h" #include "master.h"
#include <Arduino.h>
// Aquacross Timer - ESP32 Master (Webserver + ESP-NOW + Anlernmodus) // Aquacross Timer - ESP32 Master (Webserver + ESP-NOW + Anlernmodus)
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
void handleLearningMode(const uint8_t *mac) {
void handleLearningMode(const uint8_t* mac) {
// Prüfen ob MAC bereits einem anderen Button zugewiesen ist // Prüfen ob MAC bereits einem anderen Button zugewiesen ist
if (buttonConfigs.start1.isAssigned && memcmp(buttonConfigs.start1.mac, mac, 6) == 0) { if (buttonConfigs.start1.isAssigned &&
memcmp(buttonConfigs.start1.mac, mac, 6) == 0) {
Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert"); Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert");
return; return;
} }
if (buttonConfigs.stop1.isAssigned && memcmp(buttonConfigs.stop1.mac, mac, 6) == 0) { if (buttonConfigs.stop1.isAssigned &&
memcmp(buttonConfigs.stop1.mac, mac, 6) == 0) {
Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert"); Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert");
return; return;
} }
if (buttonConfigs.start2.isAssigned && memcmp(buttonConfigs.start2.mac, mac, 6) == 0) { if (buttonConfigs.start2.isAssigned &&
memcmp(buttonConfigs.start2.mac, mac, 6) == 0) {
Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert"); Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert");
return; return;
} }
if (buttonConfigs.stop2.isAssigned && memcmp(buttonConfigs.stop2.mac, mac, 6) == 0) { if (buttonConfigs.stop2.isAssigned &&
memcmp(buttonConfigs.stop2.mac, mac, 6) == 0) {
Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert"); Serial.println("Diese MAC ist bereits zugewiesen - wird ignoriert");
return; return;
} }
// MAC ist noch nicht zugewiesen, normal fortfahren // MAC ist noch nicht zugewiesen, normal fortfahren
switch(learningStep) { switch (learningStep) {
case 0: // Start1 case 0: // Start1
memcpy(buttonConfigs.start1.mac, mac, 6); memcpy(buttonConfigs.start1.mac, mac, 6);
buttonConfigs.start1.isAssigned = true; buttonConfigs.start1.isAssigned = true;
Serial.println("Start1 Button zugewiesen"); Serial.println("Start1 Button zugewiesen");
break; break;
case 1: // Stop1 case 1: // Stop1
memcpy(buttonConfigs.stop1.mac, mac, 6); memcpy(buttonConfigs.stop1.mac, mac, 6);
buttonConfigs.stop1.isAssigned = true; buttonConfigs.stop1.isAssigned = true;
Serial.println("Stop1 Button zugewiesen"); Serial.println("Stop1 Button zugewiesen");
break; break;
case 2: // Start2 case 2: // Start2
memcpy(buttonConfigs.start2.mac, mac, 6); memcpy(buttonConfigs.start2.mac, mac, 6);
buttonConfigs.start2.isAssigned = true; buttonConfigs.start2.isAssigned = true;
Serial.println("Start2 Button zugewiesen"); Serial.println("Start2 Button zugewiesen");
break; break;
case 3: // Stop2 case 3: // Stop2
memcpy(buttonConfigs.stop2.mac, mac, 6); memcpy(buttonConfigs.stop2.mac, mac, 6);
buttonConfigs.stop2.isAssigned = true; buttonConfigs.stop2.isAssigned = true;
Serial.println("Stop2 Button zugewiesen"); Serial.println("Stop2 Button zugewiesen");
break; break;
} }
learningStep++; learningStep++;
@@ -59,19 +62,24 @@ void handleLearningMode(const uint8_t* mac) {
} }
void handleStartLearning() { void handleStartLearning() {
learningMode = true; learningMode = true;
// Count assigned buttons and set appropriate learning step // Count assigned buttons and set appropriate learning step
int assignedButtons = 0; int assignedButtons = 0;
if (buttonConfigs.start1.isAssigned) assignedButtons++; if (buttonConfigs.start1.isAssigned)
if (buttonConfigs.stop1.isAssigned) assignedButtons++; assignedButtons++;
if (buttonConfigs.start2.isAssigned) assignedButtons++; if (buttonConfigs.stop1.isAssigned)
if (buttonConfigs.stop2.isAssigned) assignedButtons++; assignedButtons++;
if (buttonConfigs.start2.isAssigned)
assignedButtons++;
if (buttonConfigs.stop2.isAssigned)
assignedButtons++;
learningStep = assignedButtons; learningStep = assignedButtons;
Serial.printf("Learning mode started - %d buttons already assigned, continuing at step %d\n", Serial.printf("Learning mode started - %d buttons already assigned, "
assignedButtons, learningStep); "continuing at step %d\n",
assignedButtons, learningStep);
} }
void handleLearningStatus() { void handleLearningStatus() {
@@ -85,15 +93,15 @@ void handleLearningStatus() {
void unlearnButton() { void unlearnButton() {
memset(buttonConfigs.start1.mac, 0, 6); memset(buttonConfigs.start1.mac, 0, 6);
buttonConfigs.start1.isAssigned = false; buttonConfigs.start1.isAssigned = false;
memset(buttonConfigs.stop1.mac, 0, 6); memset(buttonConfigs.stop1.mac, 0, 6);
buttonConfigs.stop1.isAssigned = false; buttonConfigs.stop1.isAssigned = false;
memset(buttonConfigs.start2.mac, 0, 6); memset(buttonConfigs.start2.mac, 0, 6);
buttonConfigs.start2.isAssigned = false; buttonConfigs.start2.isAssigned = false;
memset(buttonConfigs.stop2.mac, 0, 6); memset(buttonConfigs.stop2.mac, 0, 6);
buttonConfigs.stop2.isAssigned = false; buttonConfigs.stop2.isAssigned = false;
saveButtonConfig(); saveButtonConfig();
Serial.println("Buttons wurden verlernt."); Serial.println("Buttons wurden verlernt.");
} }

View File

@@ -1,30 +1,30 @@
#pragma once #pragma once
#include <Arduino.h>
#include "master.h" #include "master.h"
#include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <PicoMQTT.h> #include <PicoMQTT.h>
#include "buttonassigh.h"
#include "databasebackend.h"
#include "debug.h"
#include "helper.h"
#include "statusled.h" #include "statusled.h"
#include "timesync.h" #include "timesync.h"
#include "buttonassigh.h"
#include "helper.h"
#include "debug.h"
#include <map>
#include "databasebackend.h"
#include "webserverrouter.h" #include "webserverrouter.h"
#include <map>
struct TimestampData { struct TimestampData {
uint64_t lastMessageTimestamp; // Timestamp from the device uint64_t lastMessageTimestamp; // Timestamp from the device
uint64_t lastLocalTimestamp; // Our local timestamp when message was received uint64_t lastLocalTimestamp; // Our local timestamp when message was received
uint64_t drift; // Calculated drift uint64_t drift; // Calculated drift
}; };
// Map to store timestamp data for each MAC address // Map to store timestamp data for each MAC address
std::map<String, TimestampData> deviceTimestamps; std::map<String, TimestampData> deviceTimestamps;
// Datenstruktur für ESP-NOW Nachrichten // Datenstruktur für ESP-NOW Nachrichten
// Datenstruktur für ESP-NOW Nachrichten // Datenstruktur für ESP-NOW Nachrichten
typedef struct { typedef struct {
@@ -37,293 +37,292 @@ typedef struct {
PicoMQTT::Server mqtt; PicoMQTT::Server mqtt;
void readButtonJSON(const char * topic, const char * payload) { void readButtonJSON(const char *topic, const char *payload) {
const char* prefix = "aquacross/button/"; const char *prefix = "aquacross/button/";
size_t prefixLen = strlen(prefix); size_t prefixLen = strlen(prefix);
if (strncmp(topic, prefix, prefixLen) != 0) { if (strncmp(topic, prefix, prefixLen) != 0) {
return; return;
} }
// MAC aus dem Topic extrahieren // MAC aus dem Topic extrahieren
String buttonId = String(topic + prefixLen); String buttonId = String(topic + prefixLen);
// Create a JSON document to parse the incoming message // Create a JSON document to parse the incoming message
JsonDocument doc; JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload); DeserializationError error = deserializeJson(doc, payload);
if (error) { if (error) {
Serial.print("JSON parsing failed: "); Serial.print("JSON parsing failed: ");
Serial.println(error.c_str()); Serial.println(error.c_str());
return; return;
} }
// Extract values from JSON // Extract values from JSON
int pressType = doc["type"] | 0; int pressType = doc["type"] | 0;
uint64_t timestamp = doc["timestamp"] | 0ULL; uint64_t timestamp = doc["timestamp"] | 0ULL;
// Print received data // Print received data
Serial.printf("Button Press Received:\n"); Serial.printf("Button Press Received:\n");
Serial.printf(" Type: %d\n", pressType); Serial.printf(" Type: %d\n", pressType);
Serial.printf(" Button MAC: %s\n", buttonId.c_str()); Serial.printf(" Button MAC: %s\n", buttonId.c_str());
Serial.printf(" Timestamp: %llu\n", timestamp); Serial.printf(" Timestamp: %llu\n", timestamp);
auto macBytes = macStringToBytes(buttonId.c_str());
auto macBytes = macStringToBytes(buttonId.c_str()); if (learningMode) {
handleLearningMode(macBytes.data());
return;
}
if (learningMode) { // Button-Zuordnung prüfen und entsprechende Aktion ausführen
handleLearningMode(macBytes.data()); if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0 &&
return; (pressType == 2)) {
} handleStart1(timestamp);
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0 &&
(pressType == 1)) {
handleStop1(timestamp);
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0 &&
(pressType == 2)) {
handleStart2(timestamp);
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0 &&
(pressType == 1)) {
handleStop2(timestamp);
}
// Button-Zuordnung prüfen und entsprechende Aktion ausführen // Flash status LED to indicate received message
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0 && (pressType == 2)) { updateStatusLED(3);
handleStart1(timestamp); }
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0 && (pressType == 1)) {
handleStop1(timestamp); void handleHeartbeatTopic(const char *topic, const char *payload) {
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0 && (pressType == 2)) { // Topic-Format: heartbeat/alive/CC:DB:A7:2F:95:08
handleStart2(timestamp); String topicStr(topic);
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0 && (pressType == 1)) { int lastSlash = topicStr.lastIndexOf('/');
handleStop2(timestamp); if (lastSlash < 0)
return;
String macStr = topicStr.substring(lastSlash + 1);
auto macBytes = macStringToBytes(macStr.c_str());
String buttonType = "unknown";
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
buttonType = "start1";
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0) {
buttonType = "stop1";
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
buttonType = "start2";
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0) {
buttonType = "stop2";
}
// Parse payload for timestamp (optional, falls im Payload enthalten)
uint64_t timestamp = millis();
StaticJsonDocument<128> payloadDoc;
if (payload && strlen(payload) > 0 &&
deserializeJson(payloadDoc, payload) == DeserializationError::Ok) {
if (payloadDoc.containsKey("timestamp")) {
timestamp = payloadDoc["timestamp"];
}
}
// JSON bauen
StaticJsonDocument<128> doc;
doc["button"] = buttonType;
doc["mac"] = macStr;
doc["timestamp"] = timestamp;
String json;
serializeJson(doc, json);
pushUpdateToFrontend(
json); // Diese Funktion schickt das JSON an alle WebSocket-Clients
// Serial.printf("Published heartbeat JSON: %s\n", json.c_str());
}
void handleBatteryTopic(const char *topic, const char *payload) {
int batteryLevel = 0;
String topicStr(topic);
int lastSlash = topicStr.lastIndexOf('/');
if (lastSlash < 0)
return;
String macStr = topicStr.substring(lastSlash + 1);
auto macBytes = macStringToBytes(macStr.c_str());
String buttonType = "unknown";
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
buttonType = "start1";
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0) {
buttonType = "stop1";
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
buttonType = "start2";
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0) {
buttonType = "stop2";
}
// Parse payload for timestamp (optional, falls im Payload enthalten)
StaticJsonDocument<128> payloadDoc;
if (payload && strlen(payload) > 0 &&
deserializeJson(payloadDoc, payload) == DeserializationError::Ok) {
if (payloadDoc.containsKey("voltage")) {
batteryLevel = payloadDoc["voltage"];
}
}
// Berechne die Prozentzahl des Batteriestands für eine 1S LIPO batteryLevel
// sind Volts
// Hier wird angenommen, dass 3.7V 100% entspricht und 3.0V 0%
batteryLevel =
batteryLevel * 1000; // Umwandlung von V in mV für genauere Berechnung
if (batteryLevel < 3200) {
batteryLevel = 0; // 0% bei 3.0V
} else if (batteryLevel > 3700) {
batteryLevel = 100; // 100% bei 3.7V
} else {
batteryLevel = map(batteryLevel, 3000, 3700, 0, 100); // Linear Mapping
}
// JSON bauen
StaticJsonDocument<128> doc;
doc["button"] = buttonType;
doc["mac"] = macStr;
doc["batteryLevel"] = batteryLevel;
String json;
serializeJson(doc, json);
pushUpdateToFrontend(
json); // Diese Funktion schickt das JSON an alle WebSocket-Clients
// Serial.printf("Published heartbeat JSON: %s\n", json.c_str());
}
void readRFIDfromButton(const char *topic, const char *payload) {
// Create a JSON document to hold the button press data
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
const char *mac = doc["buttonmac"] | "unknown";
const char *uid = doc["uid"] | "unknown";
Serial.printf("RFID Read from Button:\n");
Serial.printf(" Button MAC: %s\n", mac);
Serial.printf(" UID: %s\n", uid);
// Convert buttonmac to byte array for comparison
auto macBytes = macStringToBytes(mac);
// Check if the buttonmac matches buttonConfigs.start1.mac
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
// Fetch user data
UserData userData = checkUser(uid);
if (userData.exists) {
// Log user data
Serial.printf("User found for start1: %s %s, Alter: %d\n",
userData.firstname.c_str(), userData.lastname.c_str(),
userData.alter);
// Create JSON message to send to the frontend
StaticJsonDocument<128> messageDoc;
messageDoc["firstname"] = userData.firstname;
messageDoc["lastname"] = userData.lastname;
messageDoc["lane"] = "start1"; // Add lane information
String message;
serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
Serial.printf("Pushed user data for start1 to frontend: %s\n",
message.c_str());
} else {
Serial.println("User not found for UID: " + String(uid));
} }
// Flash status LED to indicate received message
updateStatusLED(3);
}
void handleHeartbeatTopic(const char* topic, const char* payload) {
// Topic-Format: heartbeat/alive/CC:DB:A7:2F:95:08
String topicStr(topic);
int lastSlash = topicStr.lastIndexOf('/');
if (lastSlash < 0) return;
String macStr = topicStr.substring(lastSlash + 1);
auto macBytes = macStringToBytes(macStr.c_str());
String buttonType = "unknown";
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
buttonType = "start1";
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0) {
buttonType = "stop1";
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
buttonType = "start2";
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0) {
buttonType = "stop2";
} }
// Check if the buttonmac matches buttonConfigs.start2.mac
else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
// Fetch user data
UserData userData = checkUser(uid);
if (userData.exists) {
// Log user data
Serial.printf("User found for start2: %s %s, Alter: %d\n",
userData.firstname.c_str(), userData.lastname.c_str(),
userData.alter);
// Parse payload for timestamp (optional, falls im Payload enthalten) // Create JSON message to send to the frontend
uint64_t timestamp = millis(); StaticJsonDocument<128> messageDoc;
StaticJsonDocument<128> payloadDoc; messageDoc["firstname"] = userData.firstname;
if (payload && strlen(payload) > 0 && deserializeJson(payloadDoc, payload) == DeserializationError::Ok) { messageDoc["lastname"] = userData.lastname;
if (payloadDoc.containsKey("timestamp")) { messageDoc["lane"] = "start2"; // Add lane information
timestamp = payloadDoc["timestamp"];
}
}
// JSON bauen String message;
StaticJsonDocument<128> doc; serializeJson(messageDoc, message);
doc["button"] = buttonType;
doc["mac"] = macStr;
doc["timestamp"] = timestamp;
String json; // Push the message to the frontend
serializeJson(doc, json); pushUpdateToFrontend(message);
pushUpdateToFrontend(json); // Diese Funktion schickt das JSON an alle WebSocket-Clients Serial.printf("Pushed user data for start2 to frontend: %s\n",
//Serial.printf("Published heartbeat JSON: %s\n", json.c_str()); message.c_str());
} } else {
Serial.println("User not found for UID: " + String(uid));
void handleBatteryTopic(const char* topic, const char* payload) { }
int batteryLevel = 0;
String topicStr(topic);
int lastSlash = topicStr.lastIndexOf('/');
if (lastSlash < 0) return;
String macStr = topicStr.substring(lastSlash + 1);
auto macBytes = macStringToBytes(macStr.c_str());
String buttonType = "unknown";
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
buttonType = "start1";
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0) {
buttonType = "stop1";
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
buttonType = "start2";
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0) {
buttonType = "stop2";
}
// Parse payload for timestamp (optional, falls im Payload enthalten)
StaticJsonDocument<128> payloadDoc;
if (payload && strlen(payload) > 0 && deserializeJson(payloadDoc, payload) == DeserializationError::Ok) {
if (payloadDoc.containsKey("voltage")) {
batteryLevel = payloadDoc["voltage"];
}
}
//Berechne die Prozentzahl des Batteriestands für eine 1S LIPO batteryLevel sind Volts
// Hier wird angenommen, dass 3.7V 100% entspricht und 3.0V 0%
batteryLevel = batteryLevel * 1000; // Umwandlung von V in mV für genauere Berechnung
if (batteryLevel < 3200) {
batteryLevel = 0; // 0% bei 3.0V
} else if (batteryLevel > 3700) {
batteryLevel = 100; // 100% bei 3.7V
} else { } else {
batteryLevel = map(batteryLevel, 3000, 3700, 0, 100); // Linear Mapping Serial.println("Button MAC does not match start1.mac or start2.mac");
}
// JSON bauen
StaticJsonDocument<128> doc;
doc["button"] = buttonType;
doc["mac"] = macStr;
doc["batteryLevel"] = batteryLevel;
String json;
serializeJson(doc, json);
pushUpdateToFrontend(json); // Diese Funktion schickt das JSON an alle WebSocket-Clients
//Serial.printf("Published heartbeat JSON: %s\n", json.c_str());
}
void readRFIDfromButton(const char * topic, const char * payload) {
// Create a JSON document to hold the button press data
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
const char* mac = doc["buttonmac"] | "unknown";
const char* uid = doc["uid"] | "unknown";
Serial.printf("RFID Read from Button:\n");
Serial.printf(" Button MAC: %s\n", mac);
Serial.printf(" UID: %s\n", uid);
// Convert buttonmac to byte array for comparison
auto macBytes = macStringToBytes(mac);
// Check if the buttonmac matches buttonConfigs.start1.mac
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
// Fetch user data
UserData userData = checkUser(uid);
if (userData.exists) {
// Log user data
Serial.printf("User found for start1: %s %s, Alter: %d\n",
userData.firstname.c_str(),
userData.lastname.c_str(),
userData.alter);
// Create JSON message to send to the frontend
StaticJsonDocument<128> messageDoc;
messageDoc["firstname"] = userData.firstname;
messageDoc["lastname"] = userData.lastname;
messageDoc["lane"] = "start1"; // Add lane information
String message;
serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
Serial.printf("Pushed user data for start1 to frontend: %s\n", message.c_str());
} else {
Serial.println("User not found for UID: " + String(uid));
}
}
// Check if the buttonmac matches buttonConfigs.start2.mac
else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
// Fetch user data
UserData userData = checkUser(uid);
if (userData.exists) {
// Log user data
Serial.printf("User found for start2: %s %s, Alter: %d\n",
userData.firstname.c_str(),
userData.lastname.c_str(),
userData.alter);
// Create JSON message to send to the frontend
StaticJsonDocument<128> messageDoc;
messageDoc["firstname"] = userData.firstname;
messageDoc["lastname"] = userData.lastname;
messageDoc["lane"] = "start2"; // Add lane information
String message;
serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
Serial.printf("Pushed user data for start2 to frontend: %s\n", message.c_str());
} else {
Serial.println("User not found for UID: " + String(uid));
}
} else {
Serial.println("Button MAC does not match start1.mac or start2.mac");
}
} else {
Serial.println("Failed to parse RFID JSON");
} }
} else {
Serial.println("Failed to parse RFID JSON");
}
} }
void setupMqttServer() { void setupMqttServer() {
// Set up the MQTT server with the desired port // Set up the MQTT server with the desired port
// Subscribe to a topic pattern and attach a callback // Subscribe to a topic pattern and attach a callback
mqtt.subscribe("#", [](const char * topic, const char * payload) { mqtt.subscribe("#", [](const char *topic, const char *payload) {
//Message received callback // Message received callback
//Serial.printf("Received message on topic '%s': %s\n", topic, payload); // Serial.printf("Received message on topic '%s': %s\n", topic, payload);
if (strncmp(topic, "aquacross/button/", 17) == 0) { if (strncmp(topic, "aquacross/button/", 17) == 0) {
readButtonJSON(topic, payload); readButtonJSON(topic, payload);
} } else if (strncmp(topic, "aquacross/button/rfid/", 22) == 0) {
else if (strncmp(topic, "aquacross/button/rfid/", 22) == 0) { readRFIDfromButton(topic, payload);
readRFIDfromButton(topic, payload); // Handle RFID read messages
// Handle RFID read messages } else if (strncmp(topic, "aquacross/battery/", 17) == 0) {
} handleBatteryTopic(topic, payload);
else if (strncmp(topic, "aquacross/battery/", 17) == 0) { } else if (strncmp(topic, "heartbeat/alive/", 16) == 0) {
handleBatteryTopic(topic, payload); handleHeartbeatTopic(topic, payload);
} }
else if (strncmp(topic, "heartbeat/alive/", 16) == 0) { updateStatusLED(3);
handleHeartbeatTopic(topic, payload); });
}
updateStatusLED(3);
});
// Start the MQTT server // Start the MQTT server
mqtt.begin(); mqtt.begin();
Serial.println("MQTT server started on port 1883"); Serial.println("MQTT server started on port 1883");
} }
void loopMqttServer() { void loopMqttServer() {
mqtt.loop(); mqtt.loop();
static unsigned long lastPublish = 0;
if (millis() - lastPublish > 5000) {
// Convert timestamp to string before publishing
char timeStr[32];
snprintf(timeStr, sizeof(timeStr), "%llu", getCurrentTimestampMs());
mqtt.publish("sync/time", timeStr);
lastPublish = millis();
}
static unsigned long lastPublish = 0;
if (millis() - lastPublish > 5000) {
// Convert timestamp to string before publishing
char timeStr[32];
snprintf(timeStr, sizeof(timeStr), "%llu", getCurrentTimestampMs());
mqtt.publish("sync/time", timeStr);
lastPublish = millis();
}
} }
void sendMQTTMessage(const char * topic, const char * message) { void sendMQTTMessage(const char *topic, const char *message) {
// Publish a message to the specified topic // Publish a message to the specified topic
mqtt.publish(topic, message); mqtt.publish(topic, message);
Serial.printf("Published message to topic '%s': %s\n", topic, message); Serial.printf("Published message to topic '%s': %s\n", topic, message);
} }
void sendMQTTJSONMessage(const char * topic, const JsonDocument & doc) { void sendMQTTJSONMessage(const char *topic, const JsonDocument &doc) {
String jsonString; String jsonString;
serializeJson(doc, jsonString); serializeJson(doc, jsonString);
// Publish the JSON string to the specified topic // Publish the JSON string to the specified topic
auto publish = mqtt.begin_publish(topic, measureJson(doc)); auto publish = mqtt.begin_publish(topic, measureJson(doc));
serializeJson(doc, publish); serializeJson(doc, publish);
publish.send(); publish.send();
Serial.printf("Published JSON message to topic '%s': %s\n", topic, jsonString.c_str()); Serial.printf("Published JSON message to topic '%s': %s\n", topic,
jsonString.c_str());
} }

View File

@@ -1,191 +1,187 @@
#pragma once #pragma once
#include "master.h"
#include <Arduino.h> #include <Arduino.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include "master.h"
const char* BACKEND_SERVER = "http://db.reptilfpv.de:3000";
String BACKEND_TOKEN = licence; // Use the licence as the token for authentication
const char *BACKEND_SERVER = "http://db.reptilfpv.de:3000";
String BACKEND_TOKEN =
licence; // Use the licence as the token for authentication
bool backendOnline() { bool backendOnline() {
Serial.println(licence); Serial.println(licence);
if (WiFi.status() != WL_CONNECTED) { if (WiFi.status() != WL_CONNECTED) {
Serial.println("No WiFi connection."); Serial.println("No WiFi connection.");
return false; return false;
} }
HTTPClient http; HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/health"); http.begin(String(BACKEND_SERVER) + "/api/health");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN); http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
int httpCode = http.GET(); int httpCode = http.GET();
bool isOnline = (httpCode == HTTP_CODE_OK); bool isOnline = (httpCode == HTTP_CODE_OK);
if (isOnline) { if (isOnline) {
Serial.println("Database server connection successful"); Serial.println("Database server connection successful");
} else { } else {
Serial.printf("Database server connection failed, error: %d\n", httpCode); Serial.printf("Database server connection failed, error: %d\n", httpCode);
} }
http.end(); http.end();
return isOnline; return isOnline;
} }
struct UserData { struct UserData {
String uid; String uid;
String firstname; String firstname;
String lastname; String lastname;
int alter; int alter;
bool exists; bool exists;
}; };
// UserData checkUser(const String& uid) is defined only once to avoid redefinition errors. // UserData checkUser(const String& uid) is defined only once to avoid
UserData checkUser(const String& uid) { // redefinition errors.
UserData checkUser(const String &uid) {
UserData userData = {"", "", "", 0, false}; UserData userData = {"", "", "", 0, false};
if (!backendOnline()) { if (!backendOnline()) {
Serial.println("No internet connection, cannot check user."); Serial.println("No internet connection, cannot check user.");
return userData;
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/users/find");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
// Create JSON payload
StaticJsonDocument<200> requestDoc;
requestDoc["uid"] = uid;
String requestBody;
serializeJson(requestDoc, requestBody);
int httpCode = http.POST(requestBody);
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
StaticJsonDocument<512> responseDoc;
DeserializationError error = deserializeJson(responseDoc, payload);
if (!error) {
userData.uid = responseDoc["uid"].as<String>();
userData.firstname = responseDoc["firstname"].as<String>();
userData.lastname = responseDoc["lastname"].as<String>();
userData.alter = responseDoc["alter"] | 0;
userData.exists = true;
}
} else {
Serial.printf("User check failed, HTTP code: %d\n", httpCode);
}
http.end();
return userData; return userData;
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/users/find");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
// Create JSON payload
StaticJsonDocument<200> requestDoc;
requestDoc["uid"] = uid;
String requestBody;
serializeJson(requestDoc, requestBody);
int httpCode = http.POST(requestBody);
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
StaticJsonDocument<512> responseDoc;
DeserializationError error = deserializeJson(responseDoc, payload);
if (!error) {
userData.uid = responseDoc["uid"].as<String>();
userData.firstname = responseDoc["firstname"].as<String>();
userData.lastname = responseDoc["lastname"].as<String>();
userData.alter = responseDoc["alter"] | 0;
userData.exists = true;
}
} else {
Serial.printf("User check failed, HTTP code: %d\n", httpCode);
}
http.end();
return userData;
} }
//Function to enter user data into the database // Function to enter user data into the database
bool enterUserData(const String& uid, const String& firstname, const String& lastname, const String& geburtsdatum, int alter) { bool enterUserData(const String &uid, const String &firstname,
if (!backendOnline()) { const String &lastname, const String &geburtsdatum,
Serial.println("No internet connection, cannot enter user data."); int alter) {
return false; if (!backendOnline()) {
} Serial.println("No internet connection, cannot enter user data.");
return false;
}
HTTPClient http; HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/users/insert"); http.begin(String(BACKEND_SERVER) + "/api/users/insert");
http.addHeader("Content-Type", "application/json"); http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN); http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
// Create JSON payload // Create JSON payload
StaticJsonDocument<256> requestDoc; StaticJsonDocument<256> requestDoc;
requestDoc["uid"] = uid; requestDoc["uid"] = uid;
requestDoc["vorname"] = firstname; requestDoc["vorname"] = firstname;
requestDoc["nachname"] = lastname; requestDoc["nachname"] = lastname;
requestDoc["geburtsdatum"] = geburtsdatum; requestDoc["geburtsdatum"] = geburtsdatum;
requestDoc["alter"] = alter; requestDoc["alter"] = alter;
String requestBody; String requestBody;
serializeJson(requestDoc, requestBody); serializeJson(requestDoc, requestBody);
int httpCode = http.POST(requestBody); int httpCode = http.POST(requestBody);
if (httpCode == HTTP_CODE_CREATED) { if (httpCode == HTTP_CODE_CREATED) {
Serial.println("User data entered successfully."); Serial.println("User data entered successfully.");
http.end(); http.end();
return true; return true;
} else { } else {
Serial.printf("Failed to enter user data, HTTP code: %d\n", httpCode); Serial.printf("Failed to enter user data, HTTP code: %d\n", httpCode);
http.end(); http.end();
return false; return false;
} }
} }
JsonDocument getAllLocations() { JsonDocument getAllLocations() {
JsonDocument locations; // Allocate memory for the JSON document JsonDocument locations; // Allocate memory for the JSON document
if (!backendOnline()) { if (!backendOnline()) {
Serial.println("No internet connection, cannot fetch locations."); Serial.println("No internet connection, cannot fetch locations.");
return locations; // Return an empty document return locations; // Return an empty document
}
HTTPClient http;
http.begin(String(BACKEND_SERVER) + "/api/location/");
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
DeserializationError error = deserializeJson(locations, payload);
if (error) {
Serial.println("Failed to parse locations JSON.");
} }
} else {
Serial.printf("Failed to fetch locations, HTTP code: %d\n", httpCode);
}
HTTPClient http; http.end();
http.begin(String(BACKEND_SERVER) + "/api/location/"); return locations; // Return the populated JSON document
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
DeserializationError error = deserializeJson(locations, payload);
if (error) {
Serial.println("Failed to parse locations JSON.");
}
} else {
Serial.printf("Failed to fetch locations, HTTP code: %d\n", httpCode);
}
http.end();
return locations; // Return the populated JSON document
} }
// Keep this for backward compatibility // Keep this for backward compatibility
bool userExists(const String& uid) { bool userExists(const String &uid) { return checkUser(uid).exists; }
return checkUser(uid).exists;
}
// Routes from the Frontend into here and then into DB backend.
//Routes from the Frontend into here and then into DB backend. void setupBackendRoutes(AsyncWebServer &server) {
void setupBackendRoutes(AsyncWebServer& server) { server.on("/api/health", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument doc(64);
doc["status"] = backendOnline() ? "connected" : "disconnected";
String response;
serializeJson(doc, response);
request->send(200, "application/json", response);
});
server.on("/api/health", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/api/users", HTTP_GET, [](AsyncWebServerRequest *request) {
if (!backendOnline()) {
DynamicJsonDocument doc(64); request->send(503, "application/json",
doc["status"] = backendOnline() ? "connected" : "disconnected"; "{\"error\":\"Database not connected\"}");
String response; return;
serializeJson(doc, response); }
request->send(200, "application/json", response);
});
server.on("/api/users", HTTP_GET, [](AsyncWebServerRequest *request) {
if (!backendOnline()) {
request->send(503, "application/json", "{\"error\":\"Database not connected\"}");
return;
}
// Handle user retrieval logic here
});
//Location routes /api/location/
server.on("/api/location/", HTTP_GET, [](AsyncWebServerRequest *request){
// Handle user retrieval logic here
});
// Location routes /api/location/
server.on("/api/location/", HTTP_GET, [](AsyncWebServerRequest *request) {
String result; String result;
serializeJson(getAllLocations(), result); serializeJson(getAllLocations(), result);
request->send(200, "application/json", result); request->send(200, "application/json", result);
}); });
// Add more routes as needed
// Add more routes as needed
} }

View File

@@ -1,49 +1,41 @@
// Zeit-bezogene Variablen und Includes // Zeit-bezogene Variablen und Includes
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <master.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <time.h> #include <ESPAsyncWebServer.h>
#include <master.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
#include "communication.h" #include "communication.h"
void setupDebugAPI(AsyncWebServer &server);
void setupDebugAPI(AsyncWebServer &server) {
// DEBUG
void setupDebugAPI(AsyncWebServer& server); server.on("/api/debug/start1", HTTP_GET, [](AsyncWebServerRequest *request) {
void setupDebugAPI(AsyncWebServer& server) {
//DEBUG
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");
}); });
Serial.println("Debug-API initialisiert");
Serial.println("Debug-API initialisiert");
} }
// DEBUG END
//DEBUG END

View File

@@ -1,10 +1,11 @@
#pragma once #pragma once
#include <Arduino.h>
#include "master.h" #include "master.h"
#include <Arduino.h>
std::array<uint8_t, 6> macStringToBytes(const char* macStr) {
std::array<uint8_t, 6> bytes; std::array<uint8_t, 6> macStringToBytes(const char *macStr) {
sscanf(macStr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", std::array<uint8_t, 6> bytes;
&bytes[0], &bytes[1], &bytes[2], &bytes[3], &bytes[4], &bytes[5]); sscanf(macStr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &bytes[0], &bytes[1],
return bytes; &bytes[2], &bytes[3], &bytes[4], &bytes[5]);
return bytes;
} }

View File

@@ -1,102 +1,106 @@
#pragma once #pragma once
#include "mbedtls/md.h"
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <Preferences.h>
#include <esp_wifi.h> #include <esp_wifi.h>
#include <master.h> #include <master.h>
#include <Preferences.h>
#include <ArduinoJson.h>
#include "mbedtls/md.h"
const char* secret = "542ff224606c61fb3024e22f76ef9ac8";
const char *secret = "542ff224606c61fb3024e22f76ef9ac8";
// Preferences für persistente Speicherung // Preferences für persistente Speicherung
Preferences preferences; Preferences preferences;
String licence; String licence;
//Prototype für Funktionen // Prototype für Funktionen
String getUniqueDeviceID(); String getUniqueDeviceID();
String hmacSHA256(const String& key, const String& message); String hmacSHA256(const String &key, const String &message);
bool checkLicense(const String& deviceID, const String& licenseKey); bool checkLicense(const String &deviceID, const String &licenseKey);
void setupLicenceAPI(AsyncWebServer& server); void setupLicenceAPI(AsyncWebServer &server);
void saveLicenceToPrefs(); void saveLicenceToPrefs();
void loadLicenceFromPrefs(); void loadLicenceFromPrefs();
String getUniqueDeviceID() { String getUniqueDeviceID() {
uint8_t mac[6]; uint8_t mac[6];
esp_wifi_get_mac(WIFI_IF_STA, mac); // Use STA MAC for uniqueness esp_wifi_get_mac(WIFI_IF_STA, mac); // Use STA MAC for uniqueness
char id[13]; char id[13];
sprintf(id, "%02X%02X%02X%02X%02X%02X", sprintf(id, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3],
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); mac[4], mac[5]);
return String(id); return String(id);
} }
String hmacSHA256(const String& key, const String& message) { String hmacSHA256(const String &key, const String &message) {
byte hmacResult[32]; byte hmacResult[32];
mbedtls_md_context_t ctx; mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
mbedtls_md_init(&ctx); mbedtls_md_init(&ctx);
const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
mbedtls_md_setup(&ctx, md_info, 1); mbedtls_md_setup(&ctx, md_info, 1);
mbedtls_md_hmac_starts(&ctx, (const unsigned char*)key.c_str(), key.length()); mbedtls_md_hmac_starts(&ctx, (const unsigned char *)key.c_str(),
mbedtls_md_hmac_update(&ctx, (const unsigned char*)message.c_str(), message.length()); key.length());
mbedtls_md_hmac_finish(&ctx, hmacResult); mbedtls_md_hmac_update(&ctx, (const unsigned char *)message.c_str(),
mbedtls_md_free(&ctx); message.length());
mbedtls_md_hmac_finish(&ctx, hmacResult);
mbedtls_md_free(&ctx);
String result = ""; String result = "";
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
char buf[3]; char buf[3];
sprintf(buf, "%02X", hmacResult[i]); sprintf(buf, "%02X", hmacResult[i]);
result += buf; result += buf;
}
return result;
}
int getLicenseTier(const String &deviceID, const String &licenseKey) {
for (int tier = 1; tier <= 4; ++tier) {
String data = deviceID + ":" + String(tier);
String expected = hmacSHA256(secret, data);
if (licenseKey.equalsIgnoreCase(expected)) {
return tier; // Found matching tier
} }
return result; }
return 0; // No valid tier found
} }
int getLicenseTier(const String& deviceID, const String& licenseKey) { void setupLicenceAPI(AsyncWebServer &server) {
for (int tier = 1; tier <= 4; ++tier) {
String data = deviceID + ":" + String(tier);
String expected = hmacSHA256(secret, data);
if (licenseKey.equalsIgnoreCase(expected)) {
return tier; // Found matching tier
}
}
return 0; // No valid tier found
}
void setupLicenceAPI(AsyncWebServer& server) { server.on("/api/get-licence", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("Received request to get licence");
server.on("/api/get-licence", HTTP_GET, [](AsyncWebServerRequest *request){ loadLicenceFromPrefs();
Serial.println("Received request to get licence"); String deviceID = getUniqueDeviceID();
loadLicenceFromPrefs(); int tier = getLicenseTier(deviceID, licence);
String deviceID = getUniqueDeviceID(); String json = "{\"licence\":\"" + licence +
int tier = getLicenseTier(deviceID, licence); "\","
String json = "{\"licence\":\"" + licence + "\"," "\"valid\":" +
"\"valid\":" + String(tier > 0 ? "true" : "false") + String(tier > 0 ? "true" : "false") +
",\"tier\":" + String(tier) + "}"; ",\"tier\":" + String(tier) + "}";
request->send(200, "application/json", json); request->send(200, "application/json", json);
}); });
server.on("/api/set-licence", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/api/set-licence", HTTP_POST, [](AsyncWebServerRequest *request) {
Serial.println("Received request to set licence"); Serial.println("Received request to set licence");
if (request->hasParam("licence", true)) { if (request->hasParam("licence", true)) {
licence = request->getParam("licence", true)->value(); licence = request->getParam("licence", true)->value();
Serial.println("Received request to set licence " + licence); Serial.println("Received request to set licence " + licence);
saveLicenceToPrefs(); // eigene Funktion saveLicenceToPrefs(); // eigene Funktion
request->send(200, "application/json", "{\"success\":true}"); request->send(200, "application/json", "{\"success\":true}");
} else { } else {
request->send(400, "application/json", "{\"success\":false}"); request->send(400, "application/json", "{\"success\":false}");
} }
}); });
Serial.println("Licence API setup complete"); Serial.println("Licence API setup complete");
} }
void saveLicenceToPrefs() { void saveLicenceToPrefs() {
preferences.begin("key", false); preferences.begin("key", false);
preferences.putString("key", licence); preferences.putString("key", licence);
preferences.end(); preferences.end();
} }
void loadLicenceFromPrefs() { void loadLicenceFromPrefs() {

View File

@@ -1,28 +1,30 @@
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include <Arduino.h>
#include "master.h" #include "master.h"
#include <Arduino.h>
// Aquacross Timer - ESP32 Master (Webserver + ESP-NOW + Anlernmodus) // Aquacross Timer - ESP32 Master (Webserver + ESP-NOW + Anlernmodus)
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
#include <esp_now.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Preferences.h> #include <Preferences.h>
#include <PrettyOTA.h> #include <PrettyOTA.h>
#include <SPIFFS.h>
#include <esp_now.h>
#include <esp_wifi.h> #include <esp_wifi.h>
#include <AsyncTCP.h>
#include <timesync.h>
#include <licenceing.h>
#include <debug.h>
#include <wificlass.h>
#include <webserverrouter.h>
#include <communication.h> #include <communication.h>
#include <databasebackend.h> #include <databasebackend.h>
#include <debug.h>
#include <licenceing.h>
#include <rfid.h> #include <rfid.h>
#include <timesync.h>
#include <webserverrouter.h>
#include <wificlass.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) { void handleStart1(uint64_t timestamp = 0) {
if (!timerData.isRunning1 && timerData.isReady1) { if (!timerData.isRunning1 && timerData.isReady1) {
@@ -46,7 +48,8 @@ void handleStop1(uint64_t timestamp = 0) {
timerData.bestTime1 = currentTime; timerData.bestTime1 = currentTime;
saveBestTimes(); saveBestTimes();
} }
Serial.println("Bahn 1 gestoppt - Zeit: " + String(currentTime/1000.0) + "s"); Serial.println("Bahn 1 gestoppt - Zeit: " + String(currentTime / 1000.0) +
"s");
} }
} }
@@ -72,66 +75,70 @@ void handleStop2(uint64_t timestamp = 0) {
timerData.bestTime2 = currentTime; timerData.bestTime2 = currentTime;
saveBestTimes(); saveBestTimes();
} }
Serial.println("Bahn 2 gestoppt - Zeit: " + String(currentTime/1000.0) + "s"); Serial.println("Bahn 2 gestoppt - Zeit: " + String(currentTime / 1000.0) +
"s");
} }
} }
void checkAutoReset() { void checkAutoReset() {
unsigned long currentTime = millis(); unsigned long currentTime = millis();
if (timerData.isRunning1 && (currentTime - timerData.localStartTime1 > maxTimeBeforeReset)) { if (timerData.isRunning1 &&
(currentTime - timerData.localStartTime1 > maxTimeBeforeReset)) {
timerData.isRunning1 = false; timerData.isRunning1 = false;
timerData.startTime1 = 0; timerData.startTime1 = 0;
Serial.println("Bahn 1 automatisch zurückgesetzt"); Serial.println("Bahn 1 automatisch zurückgesetzt");
} }
if (timerData.isRunning2 && (currentTime - timerData.localStartTime2 > maxTimeBeforeReset)) { if (timerData.isRunning2 &&
(currentTime - timerData.localStartTime2 > maxTimeBeforeReset)) {
timerData.isRunning2 = false; timerData.isRunning2 = false;
timerData.startTime2 = 0; timerData.startTime2 = 0;
Serial.println("Bahn 2 automatisch zurückgesetzt"); Serial.println("Bahn 2 automatisch zurückgesetzt");
} }
// Automatischer Reset nach 10 Sekunden "Beendet" // Automatischer Reset nach 10 Sekunden "Beendet"
if (!timerData.isRunning1 && timerData.endTime1 > 0 && timerData.finishedSince1 > 0) { if (!timerData.isRunning1 && timerData.endTime1 > 0 &&
timerData.finishedSince1 > 0) {
if (millis() - timerData.finishedSince1 > maxTimeDisplay) { if (millis() - timerData.finishedSince1 > maxTimeDisplay) {
timerData.startTime1 = 0; timerData.startTime1 = 0;
timerData.endTime1 = 0; timerData.endTime1 = 0;
timerData.finishedSince1 = 0; timerData.finishedSince1 = 0;
timerData.isReady1 = true; // Zurücksetzen auf "Bereit" timerData.isReady1 = true; // Zurücksetzen auf "Bereit"
JsonDocument messageDoc; JsonDocument messageDoc;
messageDoc["firstname"] =""; messageDoc["firstname"] = "";
messageDoc["lastname"] = ""; messageDoc["lastname"] = "";
messageDoc["lane"] = "start1"; // Add lane information messageDoc["lane"] = "start1"; // Add lane information
String message; String message;
serializeJson(messageDoc, message); serializeJson(messageDoc, message);
// Push the message to the frontend // Push the message to the frontend
pushUpdateToFrontend(message); pushUpdateToFrontend(message);
Serial.println("Bahn 1 automatisch auf 'Bereit' zurückgesetzt"); Serial.println("Bahn 1 automatisch auf 'Bereit' zurückgesetzt");
} }
} }
if (!timerData.isRunning2 && timerData.endTime2 > 0 && timerData.finishedSince2 > 0) { if (!timerData.isRunning2 && timerData.endTime2 > 0 &&
timerData.finishedSince2 > 0) {
if (currentTime - timerData.finishedSince2 > maxTimeDisplay) { if (currentTime - timerData.finishedSince2 > maxTimeDisplay) {
timerData.startTime2 = 0; timerData.startTime2 = 0;
timerData.endTime2 = 0; timerData.endTime2 = 0;
timerData.finishedSince2 = 0; timerData.finishedSince2 = 0;
timerData.isReady2 = true; // Zurücksetzen auf "Bereit" timerData.isReady2 = true; // Zurücksetzen auf "Bereit"
JsonDocument messageDoc; JsonDocument messageDoc;
messageDoc["firstname"] = ""; messageDoc["firstname"] = "";
messageDoc["lastname"] = ""; messageDoc["lastname"] = "";
messageDoc["lane"] = "start2"; // Add lane information messageDoc["lane"] = "start2"; // Add lane information
String message; String message;
serializeJson(messageDoc, message); serializeJson(messageDoc, message);
// Push the message to the frontend
pushUpdateToFrontend(message);
// Push the message to the frontend
pushUpdateToFrontend(message);
Serial.println("Bahn 2 automatisch auf 'Bereit' zurückgesetzt"); Serial.println("Bahn 2 automatisch auf 'Bereit' zurückgesetzt");
} }
@@ -186,14 +193,14 @@ void saveWifiSettings() {
preferences.putString("ssid", ssidSTA); preferences.putString("ssid", ssidSTA);
preferences.putString("password", passwordSTA); preferences.putString("password", passwordSTA);
preferences.end(); preferences.end();
delay(500); // Warte 2 Sekunden, bevor der Neustart erfolgt delay(500); // Warte 2 Sekunden, bevor der Neustart erfolgt
ESP.restart(); // Neustart des ESP32 ESP.restart(); // Neustart des ESP32
} }
void loadLocationSettings() { void loadLocationSettings() {
preferences.begin("location", true); preferences.begin("location", true);
masterlocation = preferences.getString("location", ""); masterlocation = preferences.getString("location", "");
preferences.end(); preferences.end();
} }
void saveLocationSettings() { void saveLocationSettings() {
@@ -203,18 +210,14 @@ void saveLocationSettings() {
} }
void loadWifiSettings() { void loadWifiSettings() {
preferences.begin("wifi", true); preferences.begin("wifi", true);
String ssid = preferences.getString("ssid", ""); String ssid = preferences.getString("ssid", "");
String password = preferences.getString("password", ""); String password = preferences.getString("password", "");
ssidSTA = strdup(ssid.c_str()); ssidSTA = strdup(ssid.c_str());
passwordSTA = strdup(password.c_str()); passwordSTA = strdup(password.c_str());
preferences.end(); preferences.end();
} }
int checkLicence() { int checkLicence() {
loadLicenceFromPrefs(); loadLicenceFromPrefs();
String id = getUniqueDeviceID(); String id = getUniqueDeviceID();
@@ -257,7 +260,8 @@ String getTimerDataJSON() {
// Lernmodus // Lernmodus
doc["learningMode"] = learningMode; doc["learningMode"] = learningMode;
if (learningMode) { if (learningMode) {
String buttons[] = {"Start Bahn 1", "Stop Bahn 1", "Start Bahn 2", "Stop Bahn 2"}; String buttons[] = {"Start Bahn 1", "Stop Bahn 1", "Start Bahn 2",
"Stop Bahn 2"};
doc["learningButton"] = buttons[learningStep]; doc["learningButton"] = buttons[learningStep];
} }
@@ -266,24 +270,21 @@ String getTimerDataJSON() {
return result; return result;
} }
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
if (!SPIFFS.begin(true)) { if (!SPIFFS.begin(true)) {
Serial.println("SPIFFS Mount Failed"); Serial.println("SPIFFS Mount Failed");
return; return;
} }
//setup API libararies // setup API libararies
setupTimeAPI(server); setupTimeAPI(server);
setupLicenceAPI(server); setupLicenceAPI(server);
setupDebugAPI(server); setupDebugAPI(server);
setupBackendRoutes(server); setupBackendRoutes(server);
setupRFIDRoute(server); setupRFIDRoute(server);
// Gespeicherte Daten laden // Gespeicherte Daten laden
loadButtonConfig(); loadButtonConfig();
loadBestTimes(); loadBestTimes();
@@ -299,8 +300,6 @@ void setup() {
setupLED(); setupLED();
setupMqttServer(); // MQTT Server initialisieren setupMqttServer(); // MQTT Server initialisieren
setupRFID(); setupRFID();
} }
void loop() { void loop() {

View File

@@ -1,15 +1,16 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <time.h> #include <ESPAsyncWebServer.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
const char* ssidAP;
const char* passwordAP = nullptr;
char* ssidSTA = nullptr; const char *ssidAP;
char* passwordSTA = nullptr; const char *passwordAP = nullptr;
char *ssidSTA = nullptr;
char *passwordSTA = nullptr;
// Timer Struktur // Timer Struktur
struct TimerData { struct TimerData {
@@ -42,7 +43,7 @@ struct ButtonConfigs {
ButtonConfig stop2; ButtonConfig stop2;
}; };
extern const char* firmwareversion; extern const char *firmwareversion;
// Globale Variablen // Globale Variablen
TimerData timerData; TimerData timerData;
@@ -50,13 +51,13 @@ ButtonConfigs buttonConfigs;
bool learningMode = false; bool learningMode = false;
int learningStep = 0; // 0=Start1, 1=Stop1, 2=Start2, 3=Stop2 int learningStep = 0; // 0=Start1, 1=Stop1, 2=Start2, 3=Stop2
unsigned long maxTimeBeforeReset = 300000; // 5 Minuten default 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;
//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 handleStart1(uint64_t timestamp);
void handleStop1(uint64_t timestamp); void handleStop1(uint64_t timestamp);

View File

@@ -1,16 +1,17 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <SPI.h>
#include <MFRC522.h> #include <MFRC522.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
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
std::map<String, unsigned long> blockedUIDs; // Map to store blocked UIDs and their timestamps std::map<String, unsigned long>
blockedUIDs; // Map to store blocked UIDs and their timestamps
const unsigned long BLOCK_DURATION = 10 * 1000; // 10 Seconds in milliseconds const unsigned long BLOCK_DURATION = 10 * 1000; // 10 Seconds in milliseconds
// Neue Variablen für API-basiertes Lesen // Neue Variablen für API-basiertes Lesen
@@ -18,20 +19,19 @@ bool rfidReadRequested = false;
String lastReadUID = ""; String lastReadUID = "";
bool rfidReadSuccess = false; bool rfidReadSuccess = false;
unsigned long rfidReadStartTime = 0; unsigned long rfidReadStartTime = 0;
const unsigned long RFID_READ_TIMEOUT = 10000; // 10 Sekunden Timeout für API Requests const unsigned long RFID_READ_TIMEOUT =
10000; // 10 Sekunden Timeout für API Requests
void setupRFID() { void setupRFID() {
// SPI und RFID initialisieren // SPI und RFID initialisieren
SPI.begin(); // Init SPI bus SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 mfrc522.PCD_Init(); // Init MFRC522
delay(4); // Optional delay. Some boards need more time after init to be ready delay(4); // Optional delay. Some boards need more time after init to be ready
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card
// Reader details
} }
void handleAutomaticRFID() { void handleAutomaticRFID() {
if (!mfrc522.PICC_IsNewCardPresent()) { if (!mfrc522.PICC_IsNewCardPresent()) {
return; return;
@@ -73,7 +73,7 @@ void handleAutomaticRFID() {
// Block the UID for 10 seconds // Block the UID for 10 seconds
blockedUIDs[uid] = currentTime; blockedUIDs[uid] = currentTime;
//show the remaining time for the block // show the remaining time for the block
Serial.print(F("UID blocked for 10 seconds. Remaining time: ")); Serial.print(F("UID blocked for 10 seconds. Remaining time: "));
Serial.print((BLOCK_DURATION - (currentTime - blockedUIDs[uid])) / 1000); Serial.print((BLOCK_DURATION - (currentTime - blockedUIDs[uid])) / 1000);
Serial.println(F(" seconds.")); Serial.println(F(" seconds."));
@@ -139,76 +139,79 @@ void startRFIDRead() {
} }
// API Funktion: Prüfen ob Lesevorgang abgeschlossen // API Funktion: Prüfen ob Lesevorgang abgeschlossen
bool isRFIDReadComplete() { bool isRFIDReadComplete() { return !rfidReadRequested; }
return !rfidReadRequested;
}
// API Funktion: Ergebnis des Lesevorgangs abrufen // API Funktion: Ergebnis des Lesevorgangs abrufen
String getRFIDReadResult(bool& success) { String getRFIDReadResult(bool &success) {
success = rfidReadSuccess; success = rfidReadSuccess;
return lastReadUID; return lastReadUID;
} }
void setupRFIDRoute(AsyncWebServer& server) { void setupRFIDRoute(AsyncWebServer &server) {
server.on("/api/rfid/read", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/api/rfid/read", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("api/rfid/read"); Serial.println("api/rfid/read");
// Start RFID-Lesevorgang // Start RFID-Lesevorgang
startRFIDRead(); startRFIDRead();
unsigned long startTime = millis(); unsigned long startTime = millis();
// Warten, bis eine UID gelesen wird oder Timeout eintritt // Warten, bis eine UID gelesen wird oder Timeout eintritt
while (!isRFIDReadComplete()) { while (!isRFIDReadComplete()) {
if (millis() - startTime > RFID_READ_TIMEOUT) { if (millis() - startTime > RFID_READ_TIMEOUT) {
break; break;
} }
delay(10); // Kurze Pause, um die CPU nicht zu blockieren delay(10); // Kurze Pause, um die CPU nicht zu blockieren
} }
DynamicJsonDocument response(200);
if (rfidReadSuccess && lastReadUID.length() > 0) {
response["success"] = true;
response["uid"] = lastReadUID;
response["message"] = "UID erfolgreich gelesen";
} else {
response["success"] = false;
response["error"] = "Keine RFID Karte erkannt oder Timeout";
response["uid"] = "";
}
String jsonString;
serializeJson(response, jsonString);
request->send(200, "application/json", jsonString);
});
server.on("/api/users/insert", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
Serial.println("/api/users/insert");
// Parse the incoming JSON payload
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, data, len);
DynamicJsonDocument response(200); DynamicJsonDocument response(200);
if (error) { if (rfidReadSuccess && lastReadUID.length() > 0) {
Serial.println("Fehler beim Parsen der JSON-Daten"); response["success"] = true;
response["success"] = false; response["uid"] = lastReadUID;
response["error"] = "Ungültige JSON-Daten"; response["message"] = "UID erfolgreich gelesen";
} else { } else {
// Extract user data from the JSON payload response["success"] = false;
String uid = doc["uid"] | ""; response["error"] = "Keine RFID Karte erkannt oder Timeout";
String vorname = doc["vorname"] | ""; response["uid"] = "";
String nachname = doc["nachname"] | ""; }
String geburtsdatum = doc["geburtsdatum"] | "";
int alter = doc["alter"] | 0;
// Validate the data String jsonString;
if (uid.isEmpty() || vorname.isEmpty() || nachname.isEmpty() || geburtsdatum.isEmpty() || alter <= 0) { serializeJson(response, jsonString);
request->send(200, "application/json", jsonString);
});
server.on(
"/api/users/insert", HTTP_POST, [](AsyncWebServerRequest *request) {},
NULL,
[](AsyncWebServerRequest *request, uint8_t *data, size_t len,
size_t index, size_t total) {
Serial.println("/api/users/insert");
// Parse the incoming JSON payload
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, data, len);
DynamicJsonDocument response(200);
if (error) {
Serial.println("Fehler beim Parsen der JSON-Daten");
response["success"] = false;
response["error"] = "Ungültige JSON-Daten";
} else {
// Extract user data from the JSON payload
String uid = doc["uid"] | "";
String vorname = doc["vorname"] | "";
String nachname = doc["nachname"] | "";
String geburtsdatum = doc["geburtsdatum"] | "";
int alter = doc["alter"] | 0;
// Validate the data
if (uid.isEmpty() || vorname.isEmpty() || nachname.isEmpty() ||
geburtsdatum.isEmpty() || alter <= 0) {
Serial.println("Ungültige Eingabedaten"); Serial.println("Ungültige Eingabedaten");
response["success"] = false; response["success"] = false;
response["error"] = "Ungültige Eingabedaten"; response["error"] = "Ungültige Eingabedaten";
} else { } else {
// Process the data using the enterUserData function // Process the data using the enterUserData function
Serial.println("Benutzerdaten empfangen:"); Serial.println("Benutzerdaten empfangen:");
Serial.println("UID: " + uid); Serial.println("UID: " + uid);
@@ -216,27 +219,26 @@ server.on("/api/users/insert", HTTP_POST, [](AsyncWebServerRequest *request) {},
Serial.println("Nachname: " + nachname); Serial.println("Nachname: " + nachname);
Serial.println("Alter: " + String(alter)); Serial.println("Alter: " + String(alter));
bool dbSuccess = enterUserData(uid, vorname, nachname, geburtsdatum, alter); bool dbSuccess =
enterUserData(uid, vorname, nachname, geburtsdatum, alter);
if (dbSuccess) { if (dbSuccess) {
response["success"] = true; response["success"] = true;
response["message"] = "Benutzer erfolgreich gespeichert"; response["message"] = "Benutzer erfolgreich gespeichert";
} else { } else {
response["success"] = false; response["success"] = false;
response["error"] = "Fehler beim Speichern in der Datenbank"; response["error"] = "Fehler beim Speichern in der Datenbank";
} }
}
} }
}
// Send the response back to the client
String jsonString;
serializeJson(response, jsonString);
request->send(200, "application/json", jsonString);
});
// Send the response back to the client
String jsonString;
serializeJson(response, jsonString);
request->send(200, "application/json", jsonString);
});
} }
// API Funktion: RFID Reader Status prüfen // API Funktion: RFID Reader Status prüfen
bool checkRFIDReaderStatus() { bool checkRFIDReaderStatus() {
byte version = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); byte version = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
@@ -246,7 +248,8 @@ bool checkRFIDReaderStatus() {
Serial.println("RFID Reader OK (Version: 0x" + String(version, HEX) + ")"); Serial.println("RFID Reader OK (Version: 0x" + String(version, HEX) + ")");
return true; return true;
} else { } else {
Serial.println("RFID Reader Fehler (Version: 0x" + String(version, HEX) + ")"); Serial.println("RFID Reader Fehler (Version: 0x" + String(version, HEX) +
")");
return false; return false;
} }
} }
@@ -265,7 +268,7 @@ void cleanupBlockedUIDs() {
} }
} }
void loopRFID(){ void loopRFID() {
// Originale Funktionalität für automatisches Lesen // Originale Funktionalität für automatisches Lesen
if (!rfidReadRequested) { if (!rfidReadRequested) {
handleAutomaticRFID(); handleAutomaticRFID();
@@ -276,5 +279,3 @@ void loopRFID(){
handleAPIRFIDRead(); handleAPIRFIDRead();
} }
} }

View File

@@ -1,6 +1,5 @@
#include <Arduino.h> #include <Arduino.h>
#define LED_PIN 13 #define LED_PIN 13
// Status LED // Status LED
@@ -16,43 +15,42 @@ void updateStatusLED(int blinkPattern) {
unsigned long currentTime = millis(); unsigned long currentTime = millis();
switch (blinkPattern) { switch (blinkPattern) {
case 0: // Suche Master - Langsames Blinken case 0: // Suche Master - Langsames Blinken
if (currentTime - lastLedBlink > 1000) { if (currentTime - lastLedBlink > 1000) {
ledState = !ledState; ledState = !ledState;
digitalWrite(LED_PIN, ledState); digitalWrite(LED_PIN, ledState);
lastLedBlink = currentTime; lastLedBlink = currentTime;
} }
break; break;
case 1: // Verbunden - Kurzes Blinken alle 3 Sekunden case 1: // Verbunden - Kurzes Blinken alle 3 Sekunden
if (currentTime - lastLedBlink > 3000) { if (currentTime - lastLedBlink > 3000) {
digitalWrite(LED_PIN, HIGH); digitalWrite(LED_PIN, HIGH);
delay(100); delay(100);
digitalWrite(LED_PIN, LOW); digitalWrite(LED_PIN, LOW);
lastLedBlink = currentTime; lastLedBlink = currentTime;
} }
break; break;
case 2: // Button gedrückt - Schnelles Blinken 3x case 2: // Button gedrückt - Schnelles Blinken 3x
static int blinkCount = 0; static int blinkCount = 0;
if (currentTime - lastLedBlink > 100) { if (currentTime - lastLedBlink > 100) {
ledState = !ledState; ledState = !ledState;
digitalWrite(LED_PIN, ledState); digitalWrite(LED_PIN, ledState);
lastLedBlink = currentTime; lastLedBlink = currentTime;
blinkCount++; blinkCount++;
if (blinkCount >= 6) { // 3 komplette Blinks if (blinkCount >= 6) { // 3 komplette Blinks
blinkCount = 0; blinkCount = 0;
blinkPattern = 1; // Zurück zu verbunden blinkPattern = 1; // Zurück zu verbunden
}
} }
}
case 3: // Flash bei Empfang - Einmaliges kurzes Blinken case 3: // Flash bei Empfang - Einmaliges kurzes Blinken
{ {
digitalWrite(LED_PIN, HIGH); digitalWrite(LED_PIN, HIGH);
delay(100); delay(100);
digitalWrite(LED_PIN, LOW); digitalWrite(LED_PIN, LOW);
} } break;
break;
} }
} }

View File

@@ -1,12 +1,13 @@
// Zeit-bezogene Variablen und Includes // Zeit-bezogene Variablen und Includes
#pragma once #pragma once
#include <Arduino.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <time.h>
#include <sys/time.h>
#include <Wire.h>
#include "RTClib.h" #include "RTClib.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h>
#include <Wire.h>
#include <sys/time.h>
#include <time.h>
RTC_PCF8523 rtc; RTC_PCF8523 rtc;
@@ -16,8 +17,8 @@ struct timezone tz;
time_t now; time_t now;
struct tm timeinfo; struct tm timeinfo;
//Prototypen für Zeit-Management-Funktionen // Prototypen für Zeit-Management-Funktionen
void setupTimeAPI(AsyncWebServer& server); void setupTimeAPI(AsyncWebServer &server);
String getCurrentTimeJSON(); String getCurrentTimeJSON();
bool setSystemTime(long timestamp); bool setSystemTime(long timestamp);
@@ -61,137 +62,143 @@ bool setSystemTime(long timestamp) {
} }
} }
void setupTimeAPI(AsyncWebServer& server) { void setupTimeAPI(AsyncWebServer &server) {
//setupRTC(); // setupRTC();
// API-Endpunkt: Aktuelle Zeit abrufen // API-Endpunkt: Aktuelle Zeit abrufen
server.on("/api/time", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/time", HTTP_GET, [](AsyncWebServerRequest *request) {
String response = getCurrentTimeJSON(); String response = getCurrentTimeJSON();
request->send(200, "application/json", response); request->send(200, "application/json", response);
}); });
// API-Endpunkt: Zeit setzen // API-Endpunkt: Zeit setzen
server.on("/api/set-time", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/api/set-time", HTTP_POST, [](AsyncWebServerRequest *request) {
StaticJsonDocument<100> doc; StaticJsonDocument<100> doc;
if (request->hasParam("timestamp", true)) { if (request->hasParam("timestamp", true)) {
String timestampStr = request->getParam("timestamp", true)->value(); String timestampStr = request->getParam("timestamp", true)->value();
long timestamp = timestampStr.toInt(); long timestamp = timestampStr.toInt();
if (timestamp > 0) { if (timestamp > 0) {
bool success = setSystemTime(timestamp); bool success = setSystemTime(timestamp);
doc["success"] = success; doc["success"] = success;
if (success) { if (success) {
doc["message"] = "Zeit erfolgreich gesetzt"; doc["message"] = "Zeit erfolgreich gesetzt";
doc["timestamp"] = timestamp; doc["timestamp"] = timestamp;
} else {
doc["message"] = "Fehler beim Setzen der Zeit";
}
} else { } else {
doc["message"] = "Fehler beim Setzen der Zeit"; doc["success"] = false;
doc["message"] = "Ungültiger Timestamp";
} }
} else { } else {
doc["success"] = false; doc["success"] = false;
doc["message"] = "Ungültiger Timestamp"; doc["message"] = "Timestamp-Parameter fehlt";
} }
} else {
doc["success"] = false;
doc["message"] = "Timestamp-Parameter fehlt";
}
String response; String response;
serializeJson(doc, response); serializeJson(doc, response);
request->send(200, "application/json", response); request->send(200, "application/json", response);
}); });
// Alternative Implementierung für manuelle Datum/Zeit-Eingabe // Alternative Implementierung für manuelle Datum/Zeit-Eingabe
server.on("/api/set-datetime", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/api/set-datetime", HTTP_POST, [](AsyncWebServerRequest *request) {
StaticJsonDocument<150> doc; StaticJsonDocument<150> doc;
if (request->hasParam("year", true) && if (request->hasParam("year", true) && request->hasParam("month", true) &&
request->hasParam("month", true) && request->hasParam("day", true) && request->hasParam("hour", true) &&
request->hasParam("day", true) && request->hasParam("minute", true) &&
request->hasParam("hour", true) && request->hasParam("second", true)) {
request->hasParam("minute", true) &&
request->hasParam("second", true)) {
struct tm timeinfo; struct tm timeinfo;
timeinfo.tm_year = request->getParam("year", true)->value().toInt() - 1900; timeinfo.tm_year =
timeinfo.tm_mon = request->getParam("month", true)->value().toInt() - 1; request->getParam("year", true)->value().toInt() - 1900;
timeinfo.tm_mday = request->getParam("day", true)->value().toInt(); timeinfo.tm_mon = request->getParam("month", true)->value().toInt() - 1;
timeinfo.tm_hour = request->getParam("hour", true)->value().toInt(); timeinfo.tm_mday = request->getParam("day", true)->value().toInt();
timeinfo.tm_min = request->getParam("minute", true)->value().toInt(); timeinfo.tm_hour = request->getParam("hour", true)->value().toInt();
timeinfo.tm_sec = request->getParam("second", true)->value().toInt(); timeinfo.tm_min = request->getParam("minute", true)->value().toInt();
timeinfo.tm_sec = request->getParam("second", true)->value().toInt();
time_t timestamp = mktime(&timeinfo); time_t timestamp = mktime(&timeinfo);
if (timestamp != -1) { if (timestamp != -1) {
bool success = setSystemTime(timestamp); bool success = setSystemTime(timestamp);
doc["success"] = success; doc["success"] = success;
if (success) { if (success) {
doc["message"] = "Zeit erfolgreich gesetzt"; doc["message"] = "Zeit erfolgreich gesetzt";
doc["timestamp"] = (long)timestamp; doc["timestamp"] = (long)timestamp;
} else {
doc["message"] = "Fehler beim Setzen der Zeit";
}
} else { } else {
doc["message"] = "Fehler beim Setzen der Zeit"; doc["success"] = false;
doc["message"] = "Ungültiges Datum/Zeit";
} }
} else { } else {
doc["success"] = false; doc["success"] = false;
doc["message"] = "Ungültiges Datum/Zeit"; doc["message"] = "Datum/Zeit-Parameter fehlen";
} }
} else {
doc["success"] = false;
doc["message"] = "Datum/Zeit-Parameter fehlen";
}
String response; String response;
serializeJson(doc, response); serializeJson(doc, response);
request->send(200, "application/json", response); request->send(200, "application/json", response);
}); });
// Erweiterte Zeit-Informationen (optional) // Erweiterte Zeit-Informationen (optional)
server.on("/api/time/info", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/time/info", HTTP_GET, [](AsyncWebServerRequest *request) {
gettimeofday(&tv, &tz); gettimeofday(&tv, &tz);
now = tv.tv_sec; now = tv.tv_sec;
gmtime_r(&now, &timeinfo); gmtime_r(&now, &timeinfo);
StaticJsonDocument<400> doc; StaticJsonDocument<400> doc;
doc["timestamp"] = (long)now; doc["timestamp"] = (long)now;
doc["uptime"] = millis(); doc["uptime"] = millis();
// Formatierte Zeitstrings // Formatierte Zeitstrings
char buffer[64]; char buffer[64];
strftime(buffer, sizeof(buffer), "%Y-%m-%d", &timeinfo); strftime(buffer, sizeof(buffer), "%Y-%m-%d", &timeinfo);
doc["date"] = String(buffer); doc["date"] = String(buffer);
strftime(buffer, sizeof(buffer), "%H:%M:%S", &timeinfo); strftime(buffer, sizeof(buffer), "%H:%M:%S", &timeinfo);
doc["time"] = String(buffer); doc["time"] = String(buffer);
strftime(buffer, sizeof(buffer), "%A", &timeinfo); strftime(buffer, sizeof(buffer), "%A", &timeinfo);
doc["weekday"] = String(buffer); doc["weekday"] = String(buffer);
strftime(buffer, sizeof(buffer), "%B", &timeinfo); strftime(buffer, sizeof(buffer), "%B", &timeinfo);
doc["month_name"] = String(buffer); doc["month_name"] = String(buffer);
// Zusätzliche Infos // Zusätzliche Infos
doc["day_of_year"] = timeinfo.tm_yday + 1; doc["day_of_year"] = timeinfo.tm_yday + 1;
doc["week_of_year"] = (timeinfo.tm_yday + 7 - timeinfo.tm_wday) / 7; doc["week_of_year"] = (timeinfo.tm_yday + 7 - timeinfo.tm_wday) / 7;
doc["is_dst"] = timeinfo.tm_isdst; doc["is_dst"] = timeinfo.tm_isdst;
String response; String response;
serializeJson(doc, response); serializeJson(doc, response);
request->send(200, "application/json", response); request->send(200, "application/json", response);
}); });
Serial.println("Zeit-API initialisiert"); Serial.println("Zeit-API initialisiert");
} }
// Hilfsfunktion: Zeit-Validierung // Hilfsfunktion: Zeit-Validierung
bool isValidDateTime(int year, int month, int day, int hour, int minute, int second) { bool isValidDateTime(int year, int month, int day, int hour, int minute,
if (year < 2020 || year > 2099) return false; int second) {
if (month < 1 || month > 12) return false; if (year < 2020 || year > 2099)
if (day < 1 || day > 31) return false; return false;
if (hour < 0 || hour > 23) return false; if (month < 1 || month > 12)
if (minute < 0 || minute > 59) return false; return false;
if (second < 0 || second > 59) return false; if (day < 1 || day > 31)
return false;
if (hour < 0 || hour > 23)
return false;
if (minute < 0 || minute > 59)
return false;
if (second < 0 || second > 59)
return false;
// Erweiterte Validierung für Monatstage // Erweiterte Validierung für Monatstage
int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
@@ -205,7 +212,7 @@ bool isValidDateTime(int year, int month, int day, int hour, int minute, int sec
} }
uint64_t getCurrentTimestampMs() { uint64_t getCurrentTimestampMs() {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000LL + (uint64_t)tv.tv_usec / 1000LL; return (uint64_t)tv.tv_sec * 1000LL + (uint64_t)tv.tv_usec / 1000LL;
} }

View File

@@ -1,55 +1,57 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
void sendMQTTMessage(const char * topic, const char * message); void sendMQTTMessage(const char *topic, const char *message);
#include "master.h" #include "master.h"
#include <ESPAsyncWebServer.h>
#include <AsyncWebSocket.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <AsyncWebSocket.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h> #include <SPIFFS.h>
#include <esp_wifi.h> #include <esp_wifi.h>
#include "communication.h"
#include <buttonassigh.h> #include <buttonassigh.h>
#include <wificlass.h> #include <wificlass.h>
#include "communication.h"
AsyncWebServer server(80); AsyncWebServer server(80);
AsyncWebSocket ws("/ws"); AsyncWebSocket ws("/ws");
void setupRoutes(){ void setupRoutes() {
// Web Server Routes // Web Server Routes
// Attach WebSocket to the server // Attach WebSocket to the server
server.addHandler(&ws); server.addHandler(&ws);
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", "text/html"); request->send(SPIFFS, "/index.html", "text/html");
}); });
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SPIFFS, "/settings.html", "text/html"); request->send(SPIFFS, "/settings.html", "text/html");
}); });
server.on("/rfid", HTTP_GET, [](AsyncWebServerRequest *request) { server.on("/rfid", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SPIFFS, "/rfid.html", "text/html"); request->send(SPIFFS, "/rfid.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");
Serial.println("Firmware file served: /firmware.bin"); Serial.println("Firmware file served: /firmware.bin");
} else { } else {
request->send(404, "application/json", "{\"error\":\"File not found\"}"); request->send(404, "application/json", "{\"error\":\"File not found\"}");
Serial.println("Firmware file not found: /firmware.bin"); Serial.println("Firmware file not found: /firmware.bin");
} }
}); });
server.on("/api/data", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/data", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "application/json", getTimerDataJSON()); request->send(200, "application/json", getTimerDataJSON());
}); });
server.on("/api/reset-best", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/api/reset-best", HTTP_POST, [](AsyncWebServerRequest *request) {
Serial.println("/api/reset-best called"); Serial.println("/api/reset-best called");
timerData.bestTime1 = 0; timerData.bestTime1 = 0;
timerData.bestTime2 = 0; timerData.bestTime2 = 0;
@@ -61,38 +63,39 @@ void setupRoutes(){
request->send(200, "application/json", result); request->send(200, "application/json", result);
}); });
server.on("/api/unlearn-button", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/api/unlearn-button", HTTP_POST,
Serial.println("/api/unlearn-button called"); [](AsyncWebServerRequest *request) {
unlearnButton(); Serial.println("/api/unlearn-button called");
request->send(200, "application/json", "{\"success\":true}"); unlearnButton();
request->send(200, "application/json", "{\"success\":true}");
});
}); server.on("/api/set-max-time", HTTP_POST, [](AsyncWebServerRequest *request) {
server.on("/api/set-max-time", HTTP_POST, [](AsyncWebServerRequest *request){
Serial.println("/api/set-max-time called"); Serial.println("/api/set-max-time called");
bool changed = false; bool changed = false;
if (request->hasParam("maxTime", true)) { if (request->hasParam("maxTime", true)) {
maxTimeBeforeReset = request->getParam("maxTime", true)->value().toInt() * 1000; maxTimeBeforeReset =
changed = true; request->getParam("maxTime", true)->value().toInt() * 1000;
changed = true;
} }
if (request->hasParam("maxTimeDisplay", true)) { if (request->hasParam("maxTimeDisplay", true)) {
maxTimeDisplay = request->getParam("maxTimeDisplay", true)->value().toInt() * 1000; maxTimeDisplay =
changed = true; request->getParam("maxTimeDisplay", true)->value().toInt() * 1000;
changed = true;
} }
if (changed) { if (changed) {
saveSettings(); saveSettings();
DynamicJsonDocument doc(32); DynamicJsonDocument doc(32);
doc["success"] = true; doc["success"] = true;
String result; String result;
serializeJson(doc, result); serializeJson(doc, result);
request->send(200, "application/json", result); request->send(200, "application/json", result);
} else { } else {
request->send(400, "application/json", "{\"success\":false}"); request->send(400, "application/json", "{\"success\":false}");
} }
}); });
server.on("/api/get-settings", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/get-settings", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("/api/get-settings called"); Serial.println("/api/get-settings called");
DynamicJsonDocument doc(256); DynamicJsonDocument doc(256);
doc["maxTime"] = maxTimeBeforeReset / 1000; doc["maxTime"] = maxTimeBeforeReset / 1000;
@@ -102,31 +105,33 @@ void setupRoutes(){
request->send(200, "application/json", result); request->send(200, "application/json", result);
}); });
server.on("/api/start-learning", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/api/start-learning", HTTP_POST,
Serial.println("/api/start-learning called"); [](AsyncWebServerRequest *request) {
learningMode = true; Serial.println("/api/start-learning called");
learningStep = 0; learningMode = true;
DynamicJsonDocument doc(64); learningStep = 0;
doc["success"] = true; DynamicJsonDocument doc(64);
String result; doc["success"] = true;
serializeJson(doc, result); String result;
Serial.println("Learning mode started"); serializeJson(doc, result);
request->send(200, "application/json", result); Serial.println("Learning mode started");
}); request->send(200, "application/json", result);
});
server.on("/api/stop-learning", HTTP_POST, [](AsyncWebServerRequest *request){ server.on("/api/stop-learning", HTTP_POST,
Serial.println("/api/stop-learning called"); [](AsyncWebServerRequest *request) {
learningMode = false; Serial.println("/api/stop-learning called");
learningStep = 0; learningMode = false;
DynamicJsonDocument doc(64); learningStep = 0;
doc["success"] = true; DynamicJsonDocument doc(64);
String result; doc["success"] = true;
serializeJson(doc, result); String result;
Serial.println("Learning mode stopped"); serializeJson(doc, result);
request->send(200, "application/json", result); Serial.println("Learning mode stopped");
}); request->send(200, "application/json", result);
});
server.on("/api/learn/status", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/learn/status", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument doc(256); DynamicJsonDocument doc(256);
doc["active"] = learningMode; doc["active"] = learningMode;
doc["step"] = learningStep; doc["step"] = learningStep;
@@ -135,18 +140,19 @@ void setupRoutes(){
request->send(200, "application/json", response); request->send(200, "application/json", response);
}); });
server.on("/api/buttons/status", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/buttons/status", HTTP_GET,
DynamicJsonDocument doc(128); [](AsyncWebServerRequest *request) {
doc["lane1Start"] = buttonConfigs.start1.isAssigned; DynamicJsonDocument doc(128);
doc["lane1Stop"] = buttonConfigs.stop1.isAssigned; doc["lane1Start"] = buttonConfigs.start1.isAssigned;
doc["lane2Start"] = buttonConfigs.start2.isAssigned; doc["lane1Stop"] = buttonConfigs.stop1.isAssigned;
doc["lane2Stop"] = buttonConfigs.stop2.isAssigned; doc["lane2Start"] = buttonConfigs.start2.isAssigned;
String result; doc["lane2Stop"] = buttonConfigs.stop2.isAssigned;
serializeJson(doc, result); String result;
request->send(200, "application/json", result); serializeJson(doc, result);
}); request->send(200, "application/json", result);
});
server.on("/api/info", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/info", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument doc(256); DynamicJsonDocument doc(256);
// IP address // IP address
@@ -158,7 +164,8 @@ void setupRoutes(){
uint8_t mac[6]; uint8_t mac[6];
esp_wifi_get_mac(WIFI_IF_STA, mac); esp_wifi_get_mac(WIFI_IF_STA, mac);
char macStr[18]; char macStr[18];
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
doc["mac"] = macStr; doc["mac"] = macStr;
// Free memory // Free memory
@@ -166,55 +173,59 @@ void setupRoutes(){
// Connected buttons (count assigned) // Connected buttons (count assigned)
int connected = 0; int connected = 0;
if (buttonConfigs.start1.isAssigned) connected++; if (buttonConfigs.start1.isAssigned)
if (buttonConfigs.stop1.isAssigned) connected++; connected++;
if (buttonConfigs.start2.isAssigned) connected++; if (buttonConfigs.stop1.isAssigned)
if (buttonConfigs.stop2.isAssigned) connected++; connected++;
if (buttonConfigs.start2.isAssigned)
connected++;
if (buttonConfigs.stop2.isAssigned)
connected++;
doc["connectedButtons"] = connected; doc["connectedButtons"] = connected;
doc["valid"] = checkLicence() > 0 ? "Ja" : "Nein"; doc["valid"] = checkLicence() > 0 ? "Ja" : "Nein";
doc["tier"] = checkLicence() ; doc["tier"] = checkLicence();
String result; String result;
serializeJson(doc, result); serializeJson(doc, result);
request->send(200, "application/json", result); request->send(200, "application/json", result);
}); });
// Setze WLAN-Name und Passwort (POST) // Setze WLAN-Name und Passwort (POST)
server.on("/api/set-wifi", HTTP_POST, [](AsyncWebServerRequest *request) { server.on("/api/set-wifi", HTTP_POST, [](AsyncWebServerRequest *request) {
Serial.println("/api/set-wifi called"); Serial.println("/api/set-wifi called");
String ssid, password; String ssid, password;
if (request->hasParam("ssid", true)) { if (request->hasParam("ssid", true)) {
ssid = request->getParam("ssid", true)->value(); ssid = request->getParam("ssid", true)->value();
} }
if (request->hasParam("password", true)) { if (request->hasParam("password", true)) {
password = request->getParam("password", true)->value(); password = request->getParam("password", true)->value();
} }
if (ssid.length() > 0) { if (ssid.length() > 0) {
// Speicher freigeben, bevor neue Werte zugewiesen werden // Speicher freigeben, bevor neue Werte zugewiesen werden
free(ssidSTA); free(ssidSTA);
free(passwordSTA); free(passwordSTA);
// Neue Werte zuweisen // Neue Werte zuweisen
ssidSTA = strdup(ssid.c_str()); ssidSTA = strdup(ssid.c_str());
passwordSTA = strdup(password.c_str()); passwordSTA = strdup(password.c_str());
saveWifiSettings(); saveWifiSettings();
// Rückmeldung // Rückmeldung
DynamicJsonDocument doc(64); DynamicJsonDocument doc(64);
doc["success"] = true; doc["success"] = true;
String result; String result;
serializeJson(doc, result); serializeJson(doc, result);
request->send(200, "application/json", result); request->send(200, "application/json", result);
} else { } else {
request->send(400, "application/json", "{\"success\":false,\"error\":\"SSID fehlt\"}"); request->send(400, "application/json",
"{\"success\":false,\"error\":\"SSID fehlt\"}");
} }
}); });
// Liefert aktuelle WLAN-Einstellungen (GET) // Liefert aktuelle WLAN-Einstellungen (GET)
server.on("/api/get-wifi", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/get-wifi", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument doc(128); DynamicJsonDocument doc(128);
doc["ssid"] = ssidSTA ? ssidSTA : ""; doc["ssid"] = ssidSTA ? ssidSTA : "";
doc["password"] = passwordSTA ? passwordSTA : ""; doc["password"] = passwordSTA ? passwordSTA : "";
@@ -223,31 +234,30 @@ void setupRoutes(){
request->send(200, "application/json", result); request->send(200, "application/json", result);
}); });
server.on("/api/set-location", HTTP_POST, [](AsyncWebServerRequest *request) { server.on("/api/set-location", HTTP_POST, [](AsyncWebServerRequest *request) {
Serial.println("/api/set-location called"); Serial.println("/api/set-location called");
String id, name; String id, name;
if (request->hasParam("id", true)) { if (request->hasParam("id", true)) {
id = request->getParam("id", true)->value(); id = request->getParam("id", true)->value();
} }
if (request->hasParam("name", true)) { if (request->hasParam("name", true)) {
name = request->getParam("name", true)->value(); name = request->getParam("name", true)->value();
} }
masterlocation = name; masterlocation = name;
saveLocationSettings(); saveLocationSettings();
// Rückmeldung // Rückmeldung
DynamicJsonDocument doc(64); DynamicJsonDocument doc(64);
doc["success"] = true; doc["success"] = true;
String result; String result;
serializeJson(doc, result); serializeJson(doc, result);
request->send(200, "application/json", result); request->send(200, "application/json", result);
});
}); server.on("/api/get-location", HTTP_GET, [](AsyncWebServerRequest *request) {
server.on("/api/get-location", HTTP_GET, [](AsyncWebServerRequest *request){
DynamicJsonDocument doc(128); DynamicJsonDocument doc(128);
loadLocationSettings(); loadLocationSettings();
doc["locationid"] = masterlocation ? masterlocation : ""; doc["locationid"] = masterlocation ? masterlocation : "";
@@ -256,41 +266,39 @@ server.on("/api/set-location", HTTP_POST, [](AsyncWebServerRequest *request) {
request->send(200, "application/json", result); request->send(200, "application/json", result);
}); });
server.on("/api/updateButtons", HTTP_GET, [](AsyncWebServerRequest *request) {
server.on("/api/updateButtons", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("/api/updateButtons called"); Serial.println("/api/updateButtons called");
// MQTT publish on aquacross/update/flag with raw payload "1" // MQTT publish on aquacross/update/flag with raw payload "1"
sendMQTTMessage("aquacross/update/flag", "1"); sendMQTTMessage("aquacross/update/flag", "1");
Serial.println("MQTT published: aquacross/update/flag -> 1"); Serial.println("MQTT published: aquacross/update/flag -> 1");
request->send(200, "application/json", "{\"success\":true}"); request->send(200, "application/json", "{\"success\":true}");
}); });
// Statische Dateien
// Statische Dateien
server.serveStatic("/", SPIFFS, "/"); server.serveStatic("/", SPIFFS, "/");
server.begin(); server.begin();
Serial.println("Web Server gestartet"); Serial.println("Web Server gestartet");
} }
void setupWebSocket() { void setupWebSocket() {
ws.onEvent([](AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { ws.onEvent([](AsyncWebSocket *server, AsyncWebSocketClient *client,
if (type == WS_EVT_CONNECT) { AwsEventType type, void *arg, uint8_t *data, size_t len) {
Serial.printf("WebSocket client connected: %u\n", client->id()); if (type == WS_EVT_CONNECT) {
} else if (type == WS_EVT_DISCONNECT) { Serial.printf("WebSocket client connected: %u\n", client->id());
Serial.printf("WebSocket client disconnected: %u\n", client->id()); } else if (type == WS_EVT_DISCONNECT) {
} else if (type == WS_EVT_DATA) { Serial.printf("WebSocket client disconnected: %u\n", client->id());
// Handle incoming WebSocket messages if needed } else if (type == WS_EVT_DATA) {
Serial.printf("WebSocket message received: %s\n", (char *)data); // Handle incoming WebSocket messages if needed
} Serial.printf("WebSocket message received: %s\n", (char *)data);
}); }
});
} }
void pushUpdateToFrontend(const String &message) { void pushUpdateToFrontend(const String &message) {
ws.textAll(message); // Send the message to all connected clients ws.textAll(message); // Send the message to all connected clients
} }
void loopWebSocket() { void loopWebSocket() {
ws.cleanupClients(); // Clean up disconnected clients ws.cleanupClients(); // Clean up disconnected clients
} }

View File

@@ -1,13 +1,15 @@
#pragma once #pragma once
#include <Arduino.h> #include <Arduino.h>
#include <esp_wifi.h>
#include <PrettyOTA.h>
#include <esp_now.h>
#include <WiFi.h>
#include <ESPmDNS.h> // <-- mDNS hinzufügen #include <ESPmDNS.h> // <-- mDNS hinzufügen
#include <PrettyOTA.h>
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include "master.h"
#include "licenceing.h" #include "licenceing.h"
#include "master.h"
String uniqueSSID; String uniqueSSID;
@@ -17,84 +19,79 @@ String getUniqueSSID();
void setupWifi() { void setupWifi() {
uniqueSSID = getUniqueSSID(); uniqueSSID = getUniqueSSID();
ssidAP = uniqueSSID.c_str(); ssidAP = uniqueSSID.c_str();
if (ssidSTA == nullptr || passwordSTA == nullptr || String(ssidSTA).isEmpty() || String(passwordSTA).isEmpty() ) { if (ssidSTA == nullptr || passwordSTA == nullptr ||
Serial.println("Fehler: ssidSTA oder passwordSTA ist null!"); String(ssidSTA).isEmpty() || String(passwordSTA).isEmpty()) {
WiFi.mode(WIFI_MODE_AP); Serial.println("Fehler: ssidSTA oder passwordSTA ist null!");
WiFi.softAP(ssidAP, passwordAP); WiFi.mode(WIFI_MODE_AP);
WiFi.softAP(ssidAP, passwordAP);
} else {
WiFi.mode(WIFI_MODE_APSTA);
WiFi.begin(ssidSTA, passwordSTA);
WiFi.softAP(ssidAP, passwordAP);
// Add timeout for WiFi connection
unsigned long startAttemptTime = millis();
while (WiFi.status() != WL_CONNECTED &&
millis() - startAttemptTime < 10000) { // 10 seconds timeout
delay(500);
Serial.print(".");
} }
else if (WiFi.status() != WL_CONNECTED) {
{ Serial.println("Fehler: Verbindung zum WLAN fehlgeschlagen!");
Serial.println("Starte Access Point...");
WiFi.mode(WIFI_MODE_APSTA); WiFi.mode(WIFI_MODE_AP);
WiFi.begin(ssidSTA, passwordSTA); WiFi.softAP(ssidAP, passwordAP);
WiFi.softAP(ssidAP, passwordAP); } else {
Serial.println("Erfolgreich mit WLAN verbunden!");
// Add timeout for WiFi connection Serial.print("IP Adresse: ");
unsigned long startAttemptTime = millis(); Serial.println(WiFi.localIP());
while (WiFi.status() != WL_CONNECTED &&
millis() - startAttemptTime < 10000) { // 10 seconds timeout
delay(500);
Serial.print(".");
}
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Fehler: Verbindung zum WLAN fehlgeschlagen!");
Serial.println("Starte Access Point...");
WiFi.mode(WIFI_MODE_AP);
WiFi.softAP(ssidAP, passwordAP);
}
else {
Serial.println("Erfolgreich mit WLAN verbunden!");
Serial.print("IP Adresse: ");
Serial.println(WiFi.localIP());
} }
// Only wait for connection if ssidSTA and passwordSTA are set
//Only wait for connection if ssidSTA and passwordSTA are set
Serial.println("WiFi AP gestartet"); Serial.println("WiFi AP gestartet");
Serial.print("SSID: "); Serial.print("SSID: ");
Serial.println(WiFi.softAPSSID()); Serial.println(WiFi.softAPSSID());
Serial.print("IP Adresse: "); Serial.print("IP Adresse: ");
Serial.println(WiFi.softAPIP()); Serial.println(WiFi.softAPIP());
Serial.println("PrettyOTA can be accessed at: http://" + WiFi.softAPIP().toString() + "/update"); Serial.println("PrettyOTA can be accessed at: http://" +
WiFi.softAPIP().toString() + "/update");
// mDNS starten // mDNS starten
if (MDNS.begin("aquacross-timer")) { // z.B. http://aquacross-timer.local/ if (MDNS.begin("aquacross-timer")) { // z.B. http://aquacross-timer.local/
Serial.println("mDNS responder gestartet: http://aquacross-timer.local/"); Serial.println("mDNS responder gestartet: http://aquacross-timer.local/");
} else { } else {
Serial.println("Fehler beim Starten von mDNS!"); Serial.println("Fehler beim Starten von mDNS!");
}
} }
}
} }
void setupOTA(AsyncWebServer *server) { void setupOTA(AsyncWebServer *server) {
// Initialize PrettyOTA // Initialize PrettyOTA
OTAUpdates.Begin(server); OTAUpdates.Begin(server);
// Set unique Hardware-ID for your hardware/board // Set unique Hardware-ID for your hardware/board
OTAUpdates.SetHardwareID("AquaCross-Master"); OTAUpdates.SetHardwareID("AquaCross-Master");
// Set firmware version to 1.0.0 // Set firmware version to 1.0.0
OTAUpdates.SetAppVersion(firmwareversion); OTAUpdates.SetAppVersion(firmwareversion);
// Set current build time and date // Set current build time and date
PRETTY_OTA_SET_CURRENT_BUILD_TIME_AND_DATE(); PRETTY_OTA_SET_CURRENT_BUILD_TIME_AND_DATE();
} }
String getUniqueSSID() { String getUniqueSSID() {
uint8_t mac[6]; uint8_t mac[6];
esp_wifi_get_mac(WIFI_IF_STA, mac); esp_wifi_get_mac(WIFI_IF_STA, mac);
// Create a 5-character string from last 3 bytes of MAC // Create a 5-character string from last 3 bytes of MAC
char uniqueId[6]; char uniqueId[6];
snprintf(uniqueId, sizeof(uniqueId), "%02X%03X", mac[4], mac[5]); snprintf(uniqueId, sizeof(uniqueId), "%02X%03X", mac[4], mac[5]);
return String("AquaCross-") + String(uniqueId); return String("AquaCross-") + String(uniqueId);
} }
// WiFi als Access Point // WiFi als Access Point