diff --git a/LICENCE.md b/LICENCE.md new file mode 100644 index 0000000..ba34ec5 --- /dev/null +++ b/LICENCE.md @@ -0,0 +1,26 @@ +# Lizenzvereinbarung (License Agreement) + +Dieses Softwareprojekt ("Ninjacross Timer") sowie sämtliche zugehörigen Quellcodes, Dokumentationen und Ressourcen sind urheberrechtlich geschützt und stehen ausschließlich unter folgender Lizenz: + +## Exklusive Lizenz + +Die Nutzung, Vervielfältigung, Veränderung, Verbreitung oder Veröffentlichung dieses Projekts ist ausschließlich Carsten Graf (@reptil1990) vorbehalten. Jede Weitergabe, Nutzung oder Bearbeitung durch Dritte ist ohne ausdrückliche, schriftliche Genehmigung von Carsten Graf untersagt. + +## Rechte des Lizenznehmers + +- Exklusives, zeitlich und räumlich uneingeschränktes Nutzungsrecht für alle privaten, gewerblichen und wissenschaftlichen Zwecke +- Recht zur Modifikation, Erweiterung und Integration in eigene Projekte +- Recht zur Weitergabe an Dritte nur mit ausdrücklicher, schriftlicher Zustimmung des Rechteinhabers + +## Pflichten und Einschränkungen + +- Die Software darf nicht ohne Genehmigung veröffentlicht, verkauft oder anderweitig Dritten zugänglich gemacht werden +- Der Urheberrechtshinweis und diese Lizenzvereinbarung müssen in allen Kopien und abgeleiteten Werken enthalten bleiben + +## Haftungsausschluss + +Die Software wird ohne jegliche Gewährleistung bereitgestellt. Der Rechteinhaber übernimmt keine Haftung für Schäden, die aus der Nutzung der Software entstehen. + +--- + +© 2025 Carsten Graf (@reptil1990). Alle Rechte vorbehalten. diff --git a/TODO.md b/TODO.md index 87f3261..7a6c691 100644 --- a/TODO.md +++ b/TODO.md @@ -1,19 +1,17 @@ - KOMPLETTES Messageing System auf MQTT Server und Broker umstellen. DONE - Testen wie zuverlässig das ist - - -- message system überarbeiten. Sehr unzuverlässig mit dem peering DONE jetzt MQTT -- Uhrzeit abfragen (Eingabe der Zeitzone) DONE -- Sync der Buttons mit echtzeit +- message system überarbeiten. Sehr unzuverlässig mit dem peering DONE jetzt MQTT +- Uhrzeit abfragen (Eingabe der Zeitzone) DONE +- Sync der Buttons mit echtzeit DONE - implementierung einer RTC v2.0 -- ADD Hotspot Manager to connect to a Wifi + +- ADD Hotspot Manager to connect to a Wifi DONE - ADD Licence Management (generate a programm where i can generate keys that get checked agains a private seed in the firmware) -enables the Wifimanager to connect DONE - -- ADD option point for location (read from online table and select the location via dropdown) -- ADD option to enter a name, age DONE -- ADD upload to a Online Database () DONE + enables the Wifimanager to connect DONE +- ADD option point for location (read from online table and select the location via dropdown) DONE +- ADD option to enter a name, age DONE +- ADD upload to a Online Database () DONE diff --git a/src/buttonassigh.h b/src/buttonassigh.h index 0041be5..2172153 100644 --- a/src/buttonassigh.h +++ b/src/buttonassigh.h @@ -5,6 +5,8 @@ // Aquacross Timer - ESP32 Master (Webserver + ESP-NOW + Anlernmodus) #include +// Weist im Lernmodus eine MAC-Adresse dem nächsten freien Button zu, sofern sie +// noch nicht vergeben ist void handleLearningMode(const uint8_t *mac) { // Prüfen ob MAC bereits einem anderen Button zugewiesen ist if (buttonConfigs.start1.isAssigned && @@ -61,6 +63,8 @@ void handleLearningMode(const uint8_t *mac) { } } +// Startet den Lernmodus und setzt den Lernschritt entsprechend der bereits +// zugewiesenen Buttons void handleStartLearning() { learningMode = true; @@ -82,6 +86,7 @@ void handleStartLearning() { assignedButtons, learningStep); } +// Erstellt ein JSON mit Status und aktuellem Lernschritt des Lernmodus void handleLearningStatus() { DynamicJsonDocument doc(256); doc["active"] = learningMode; @@ -91,6 +96,7 @@ void handleLearningStatus() { serializeJson(doc, response); } +// Setzt alle Button-Zuweisungen zurück und speichert die Konfiguration void unlearnButton() { memset(buttonConfigs.start1.mac, 0, 6); diff --git a/src/communication.h b/src/communication.h index b507104..2632b93 100644 --- a/src/communication.h +++ b/src/communication.h @@ -3,7 +3,6 @@ #include #include - #include #include "buttonassigh.h" @@ -15,18 +14,24 @@ #include "webserverrouter.h" #include - +/** + * Struktur zur Speicherung von Zeitdaten für jedes Gerät/MAC. + * lastMessageTimestamp: Timestamp vom Gerät (z.B. Button) + * lastLocalTimestamp: Lokaler Timestamp beim Empfang der Nachricht + * drift: Berechneter Drift zwischen Gerät und Master + */ struct TimestampData { - uint64_t lastMessageTimestamp; // Timestamp from the device - uint64_t lastLocalTimestamp; // Our local timestamp when message was received - uint64_t drift; // Calculated drift + uint64_t lastMessageTimestamp; + uint64_t lastLocalTimestamp; + uint64_t drift; }; -// Map to store timestamp data for each MAC address +// Map zur Speicherung der Zeitdaten für jede MAC-Adresse std::map deviceTimestamps; -// Datenstruktur für ESP-NOW Nachrichten -// Datenstruktur für ESP-NOW Nachrichten +/** + * Datenstruktur für eine Button-Nachricht (optional, falls benötigt) + */ typedef struct { uint8_t messageType; uint8_t buttonId; @@ -35,8 +40,13 @@ typedef struct { char messageId[33]; // 32 hex chars + null terminator for 128-bit ID } ButtonMessage; +// MQTT-Server-Instanz PicoMQTT::Server mqtt; +/** + * Liest eine Button-JSON-Nachricht, extrahiert Typ, MAC und Timestamp, + * prüft die Button-Zuordnung und ruft die entsprechende Handler-Funktion auf. + */ void readButtonJSON(const char *topic, const char *payload) { const char *prefix = "aquacross/button/"; @@ -94,6 +104,10 @@ void readButtonJSON(const char *topic, const char *payload) { updateStatusLED(3); } +/** + * Verarbeitet Heartbeat-Nachrichten von Buttons, erkennt den Button-Typ, + * extrahiert MAC und Timestamp und sendet ein JSON an das Frontend. + */ void handleHeartbeatTopic(const char *topic, const char *payload) { // Topic-Format: heartbeat/alive/CC:DB:A7:2F:95:08 String topicStr(topic); @@ -138,6 +152,10 @@ void handleHeartbeatTopic(const char *topic, const char *payload) { // Serial.printf("Published heartbeat JSON: %s\n", json.c_str()); } +/** + * Verarbeitet Batteriestands-Nachrichten von Buttons, erkennt den Button-Typ, + * berechnet den Ladezustand und sendet ein JSON an das Frontend. + */ void handleBatteryTopic(const char *topic, const char *payload) { int batteryLevel = 0; String topicStr(topic); @@ -194,6 +212,10 @@ void handleBatteryTopic(const char *topic, const char *payload) { // Serial.printf("Published heartbeat JSON: %s\n", json.c_str()); } +/** + * Verarbeitet RFID-Lese-Nachrichten von Buttons, prüft Userdaten, + * sendet diese ggf. als JSON an das Frontend. + */ void readRFIDfromButton(const char *topic, const char *payload) { // Create a JSON document to hold the button press data StaticJsonDocument<256> doc; @@ -270,6 +292,10 @@ void readRFIDfromButton(const char *topic, const char *payload) { } } +/** + * Initialisiert den MQTT-Server, richtet Subscriptions und Callback-Handler + * ein. + */ void setupMqttServer() { // Set up the MQTT server with the desired port @@ -296,6 +322,10 @@ void setupMqttServer() { Serial.println("MQTT server started on port 1883"); } +/** + * Muss regelmäßig im Loop aufgerufen werden, damit der MQTT-Server arbeitet. + * Sendet außerdem alle 5 Sekunden einen Zeit-Sync. + */ void loopMqttServer() { mqtt.loop(); @@ -309,12 +339,18 @@ void loopMqttServer() { } } +/** + * Sendet eine einfache Textnachricht an ein MQTT-Topic. + */ void sendMQTTMessage(const char *topic, const char *message) { // Publish a message to the specified topic mqtt.publish(topic, message); Serial.printf("Published message to topic '%s': %s\n", topic, message); } +/** + * Sendet ein JSON-Dokument als Nachricht an ein MQTT-Topic. + */ void sendMQTTJSONMessage(const char *topic, const JsonDocument &doc) { String jsonString; serializeJson(doc, jsonString); diff --git a/src/databasebackend.h b/src/databasebackend.h index 7c18467..1025ed6 100644 --- a/src/databasebackend.h +++ b/src/databasebackend.h @@ -41,8 +41,8 @@ struct UserData { bool exists; }; -// UserData checkUser(const String& uid) is defined only once to avoid -// redefinition errors. +// Prüft, ob ein Benutzer mit der angegebenen UID in der Datenbank existiert und +// gibt dessen Daten zurück. UserData checkUser(const String &uid) { UserData userData = {"", "", "", 0, false}; @@ -85,7 +85,7 @@ UserData checkUser(const String &uid) { return userData; } -// Function to enter user data into the database +// Fügt einen neuen Benutzer mit den angegebenen Daten in die Datenbank ein. bool enterUserData(const String &uid, const String &firstname, const String &lastname, const String &geburtsdatum, int alter) { @@ -123,6 +123,7 @@ bool enterUserData(const String &uid, const String &firstname, } } +// Holt alle Standorte aus der Datenbank und gibt sie als JSON-Dokument zurück. JsonDocument getAllLocations() { JsonDocument locations; // Allocate memory for the JSON document @@ -152,11 +153,12 @@ JsonDocument getAllLocations() { return locations; // Return the populated JSON document } -// Keep this for backward compatibility +// Prüft, ob ein Benutzer mit der angegebenen UID existiert +// (Kompatibilitätsfunktion). bool userExists(const String &uid) { return checkUser(uid).exists; } -// Routes from the Frontend into here and then into DB backend. - +// Richtet die HTTP-Routen für die Backend-API ein (z.B. Health-Check, User- und +// Location-Abfragen). void setupBackendRoutes(AsyncWebServer &server) { server.on("/api/health", HTTP_GET, [](AsyncWebServerRequest *request) { diff --git a/src/master.h b/src/master.h index 9bf33a9..39c0c6c 100644 --- a/src/master.h +++ b/src/master.h @@ -5,7 +5,6 @@ #include #include - const char *ssidAP; const char *passwordAP = nullptr; diff --git a/src/rfid.h b/src/rfid.h index 682b7ab..84c1c18 100644 --- a/src/rfid.h +++ b/src/rfid.h @@ -4,7 +4,6 @@ #include #include - // RFID Konfiguration #define RST_PIN 21 // Configurable, see typical pin layout above #define SS_PIN 5 // Configurable, see typical pin layout above @@ -22,6 +21,7 @@ unsigned long rfidReadStartTime = 0; const unsigned long RFID_READ_TIMEOUT = 10000; // 10 Sekunden Timeout für API Requests +// Initialisiert den RFID-Reader und das SPI-Interface. void setupRFID() { // SPI und RFID initialisieren @@ -32,6 +32,8 @@ void setupRFID() { // Reader details } +// Liest automatisch eine RFID-Karte ein und blockiert die UID für eine +// bestimmte Zeit. void handleAutomaticRFID() { if (!mfrc522.PICC_IsNewCardPresent()) { return; @@ -83,6 +85,8 @@ void handleAutomaticRFID() { } // Neue Funktion für API-basiertes RFID Lesen + +// Liest eine RFID-Karte im API-Modus ein (für Web-Requests). void handleAPIRFIDRead() { unsigned long currentTime = millis(); @@ -130,6 +134,8 @@ void handleAPIRFIDRead() { } // API Funktion: RFID Lesevorgang starten + +// Startet einen neuen RFID-Lesevorgang über die API. void startRFIDRead() { Serial.println("RFID API Lesevorgang gestartet..."); rfidReadRequested = true; @@ -139,14 +145,18 @@ void startRFIDRead() { } // API Funktion: Prüfen ob Lesevorgang abgeschlossen + +// Prüft, ob der aktuelle RFID-Lesevorgang abgeschlossen ist. bool isRFIDReadComplete() { return !rfidReadRequested; } // API Funktion: Ergebnis des Lesevorgangs abrufen +// Gibt das Ergebnis des letzten RFID-Lesevorgangs zurück. String getRFIDReadResult(bool &success) { success = rfidReadSuccess; return lastReadUID; } +// Richtet die HTTP-API-Routen für RFID-Operationen ein. void setupRFIDRoute(AsyncWebServer &server) { server.on("/api/rfid/read", HTTP_GET, [](AsyncWebServerRequest *request) { Serial.println("api/rfid/read"); @@ -240,6 +250,8 @@ void setupRFIDRoute(AsyncWebServer &server) { } // API Funktion: RFID Reader Status prüfen + +// Prüft, ob der RFID-Reader korrekt funktioniert und gibt den Status zurück. bool checkRFIDReaderStatus() { byte version = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); @@ -255,6 +267,8 @@ bool checkRFIDReaderStatus() { } // Hilfsfunktion: Blockierte UIDs aufräumen + +// Entfernt UIDs aus der Blockliste, deren Blockdauer abgelaufen ist. void cleanupBlockedUIDs() { unsigned long currentTime = millis(); @@ -268,6 +282,7 @@ void cleanupBlockedUIDs() { } } +// Hauptschleife für das RFID-Handling (automatisch und API-basiert). void loopRFID() { // Originale Funktionalität für automatisches Lesen if (!rfidReadRequested) { diff --git a/src/statusled.h b/src/statusled.h index e42bb13..6c7d3ff 100644 --- a/src/statusled.h +++ b/src/statusled.h @@ -6,11 +6,13 @@ unsigned long lastLedBlink = 0; bool ledState = false; +// Initialisiert die Status-LED (setzt Pin-Modus und schaltet sie aus). void setupLED() { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); // LED aus } +// Steuert die Status-LED je nach übergebenem Blinkmuster (Statusanzeige). void updateStatusLED(int blinkPattern) { unsigned long currentTime = millis(); diff --git a/src/timesync.h b/src/timesync.h index 32fe768..ca37863 100644 --- a/src/timesync.h +++ b/src/timesync.h @@ -8,7 +8,6 @@ #include #include - RTC_PCF8523 rtc; // Globale Zeitvariablen @@ -17,12 +16,14 @@ struct timezone tz; time_t now; struct tm timeinfo; -// Prototypen für Zeit-Management-Funktionen +// Initialisiert die Zeit-API und richtet die HTTP-Endpunkte ein. void setupTimeAPI(AsyncWebServer &server); +// Gibt die aktuelle Zeit als JSON-String zurück. String getCurrentTimeJSON(); +// Setzt die Systemzeit auf den angegebenen Zeitstempel (Sekunden seit 1970). bool setSystemTime(long timestamp); -// Hilfsfunktionen für Zeit-Management +// Hilfsfunktion: Gibt die aktuelle Zeit als JSON-String zurück. String getCurrentTimeJSON() { gettimeofday(&tv, &tz); now = tv.tv_sec; @@ -48,6 +49,7 @@ String getCurrentTimeJSON() { return response; } +// Hilfsfunktion: Setzt die Systemzeit auf den angegebenen Zeitstempel. bool setSystemTime(long timestamp) { struct timeval tv; tv.tv_sec = timestamp; @@ -62,6 +64,7 @@ bool setSystemTime(long timestamp) { } } +// Initialisiert die Zeit-API und richtet die HTTP-Endpunkte ein. void setupTimeAPI(AsyncWebServer &server) { // setupRTC(); @@ -185,6 +188,7 @@ void setupTimeAPI(AsyncWebServer &server) { } // Hilfsfunktion: Zeit-Validierung +// Prüft, ob die übergebenen Datums- und Zeitwerte gültig sind. bool isValidDateTime(int year, int month, int day, int hour, int minute, int second) { if (year < 2020 || year > 2099) @@ -211,6 +215,7 @@ bool isValidDateTime(int year, int month, int day, int hour, int minute, return day <= daysInMonth[month - 1]; } +// Gibt den aktuellen Zeitstempel in Millisekunden seit 1970 zurück. uint64_t getCurrentTimestampMs() { struct timeval tv; gettimeofday(&tv, NULL); diff --git a/src/webserverrouter.h b/src/webserverrouter.h index 1132d5f..9737c5a 100644 --- a/src/webserverrouter.h +++ b/src/webserverrouter.h @@ -10,15 +10,14 @@ void sendMQTTMessage(const char *topic, const char *message); #include #include - #include "communication.h" #include #include - AsyncWebServer server(80); AsyncWebSocket ws("/ws"); +// Richtet alle HTTP-Routen für den Webserver ein (API und statische Dateien). void setupRoutes() { // Web Server Routes @@ -281,6 +280,7 @@ void setupRoutes() { Serial.println("Web Server gestartet"); } +// Initialisiert den WebSocket-Server und definiert die Event-Handler. void setupWebSocket() { ws.onEvent([](AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { @@ -295,10 +295,12 @@ void setupWebSocket() { }); } +// Sendet eine Nachricht an alle verbundenen WebSocket-Clients (Frontend). void pushUpdateToFrontend(const String &message) { ws.textAll(message); // Send the message to all connected clients } +// Bereinigt getrennte WebSocket-Clients (sollte regelmäßig aufgerufen werden). void loopWebSocket() { ws.cleanupClients(); // Clean up disconnected clients } diff --git a/src/wificlass.h b/src/wificlass.h index 36d0b77..7be0e60 100644 --- a/src/wificlass.h +++ b/src/wificlass.h @@ -6,17 +6,16 @@ #include #include - #include "licenceing.h" #include "master.h" - String uniqueSSID; PrettyOTA OTAUpdates; String getUniqueSSID(); +// Initialisiert das WLAN als Access Point oder Station und startet mDNS/OTA. void setupWifi() { uniqueSSID = getUniqueSSID(); @@ -69,6 +68,7 @@ void setupWifi() { } } +// Initialisiert das OTA-Update-System (PrettyOTA) für Firmware-Updates. void setupOTA(AsyncWebServer *server) { // Initialize PrettyOTA OTAUpdates.Begin(server); @@ -83,6 +83,7 @@ void setupOTA(AsyncWebServer *server) { PRETTY_OTA_SET_CURRENT_BUILD_TIME_AND_DATE(); } +// Generiert eine eindeutige SSID auf Basis der MAC-Adresse. String getUniqueSSID() { uint8_t mac[6]; esp_wifi_get_mac(WIFI_IF_STA, mac);