Comments und add licence

This commit is contained in:
Carsten Graf
2025-07-12 17:39:45 +02:00
parent 585d2d7d5d
commit d10a8fef6d
11 changed files with 126 additions and 34 deletions

26
LICENCE.md Normal file
View File

@@ -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.

20
TODO.md
View File

@@ -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

View File

@@ -5,6 +5,8 @@
// Aquacross Timer - ESP32 Master (Webserver + ESP-NOW + Anlernmodus)
#include <ESPAsyncWebServer.h>
// 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);

View File

@@ -3,7 +3,6 @@
#include <Arduino.h>
#include <ArduinoJson.h>
#include <PicoMQTT.h>
#include "buttonassigh.h"
@@ -15,18 +14,24 @@
#include "webserverrouter.h"
#include <map>
/**
* 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<String, TimestampData> 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);

View File

@@ -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) {

View File

@@ -5,7 +5,6 @@
#include <sys/time.h>
#include <time.h>
const char *ssidAP;
const char *passwordAP = nullptr;

View File

@@ -4,7 +4,6 @@
#include <MFRC522.h>
#include <SPI.h>
// 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) {

View File

@@ -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();

View File

@@ -8,7 +8,6 @@
#include <sys/time.h>
#include <time.h>
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);

View File

@@ -10,15 +10,14 @@ void sendMQTTMessage(const char *topic, const char *message);
#include <SPIFFS.h>
#include <esp_wifi.h>
#include "communication.h"
#include <buttonassigh.h>
#include <wificlass.h>
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
}

View File

@@ -6,17 +6,16 @@
#include <esp_now.h>
#include <esp_wifi.h>
#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);