NTP, send Voltage to Frontend
This commit is contained in:
@@ -157,59 +157,64 @@ void handleHeartbeatTopic(const char *topic, const char *payload) {
|
||||
* berechnet den Ladezustand und sendet ein JSON an das Frontend.
|
||||
*/
|
||||
void handleBatteryTopic(const char *topic, const char *payload) {
|
||||
int batteryLevel = 0;
|
||||
float batteryLevelV = 0;
|
||||
int batteryLevelP = 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"];
|
||||
batteryLevelV = 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
|
||||
|
||||
if (batteryLevelV < 3200) {
|
||||
batteryLevelP = 0; // 0% bei 3.2V
|
||||
} else if (batteryLevelV > 3700) {
|
||||
batteryLevelP = 100; // 100% bei 3.7V
|
||||
} else {
|
||||
batteryLevel = map(batteryLevel, 3000, 3700, 0, 100); // Linear Mapping
|
||||
batteryLevelP = map(batteryLevelV, 3200, 3700, 0, 100); // Linear Mapping
|
||||
}
|
||||
|
||||
auto macBytes = macStringToBytes(macStr.c_str());
|
||||
String buttonType = "unknown";
|
||||
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
|
||||
buttonType = "start1";
|
||||
buttonConfigs.start1.voltage = batteryLevelP;
|
||||
} else if (memcmp(macBytes.data(), buttonConfigs.stop1.mac, 6) == 0) {
|
||||
buttonType = "stop1";
|
||||
buttonConfigs.stop1.voltage = batteryLevelP;
|
||||
} else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
|
||||
buttonType = "start2";
|
||||
buttonConfigs.start2.voltage = batteryLevelP;
|
||||
} else if (memcmp(macBytes.data(), buttonConfigs.stop2.mac, 6) == 0) {
|
||||
buttonType = "stop2";
|
||||
buttonConfigs.stop2.voltage = batteryLevelP;
|
||||
}
|
||||
|
||||
// JSON bauen
|
||||
StaticJsonDocument<128> doc;
|
||||
doc["button"] = buttonType;
|
||||
doc["mac"] = macStr;
|
||||
doc["batteryLevel"] = batteryLevel;
|
||||
doc["batteryLevel"] = batteryLevelP;
|
||||
|
||||
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());
|
||||
|
||||
// Serial.printf("Battery level for %s (%s): %d%%\n", buttonType.c_str(),
|
||||
macStr.c_str(), batteryLevelP);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <HTTPClient.h>
|
||||
|
||||
const char *BACKEND_SERVER = "http://db.reptilfpv.de:3000";
|
||||
String BACKEND_TOKEN =
|
||||
licence; // Use the licence as the token for authentication
|
||||
extern String licence; // Declare licence as an external variable defined elsewhere
|
||||
String BACKEND_TOKEN = licence; // Use the licence as the token for authentication
|
||||
|
||||
bool backendOnline() {
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
|
||||
std::array<uint8_t, 6> macStringToBytes(const char *macStr) {
|
||||
std::array<uint8_t, 6> bytes;
|
||||
sscanf(macStr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &bytes[0], &bytes[1],
|
||||
|
||||
@@ -33,6 +33,7 @@ struct TimerData {
|
||||
struct ButtonConfig {
|
||||
uint8_t mac[6];
|
||||
bool isAssigned = false;
|
||||
float voltage = 0.0;
|
||||
};
|
||||
|
||||
struct ButtonConfigs {
|
||||
|
||||
@@ -49,6 +49,29 @@ String getCurrentTimeJSON() {
|
||||
return response;
|
||||
}
|
||||
|
||||
void syncTimeWithNTP(const char *ntpServer = "pool.ntp.org",
|
||||
long gmtOffset_sec = 3600, int daylightOffset_sec = 0) {
|
||||
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
||||
Serial.println("Warte auf NTP-Zeit (max 5s)...");
|
||||
struct tm timeinfo;
|
||||
unsigned long start = millis();
|
||||
bool synced = false;
|
||||
while (millis() - start < 5000) {
|
||||
if (getLocalTime(&timeinfo, 10)) { // 10ms Timeout pro Versuch
|
||||
synced = true;
|
||||
break;
|
||||
}
|
||||
delay(10); // Kurze Pause, damit der Loop nicht blockiert
|
||||
}
|
||||
if (synced) {
|
||||
Serial.println("\nNTP-Zeit synchronisiert!");
|
||||
Serial.printf("Aktuelle Zeit: %02d:%02d:%02d\n", timeinfo.tm_hour,
|
||||
timeinfo.tm_min, timeinfo.tm_sec);
|
||||
} else {
|
||||
Serial.println("\nNTP-Sync fehlgeschlagen (Timeout nach 5s)");
|
||||
}
|
||||
}
|
||||
|
||||
// Hilfsfunktion: Setzt die Systemzeit auf den angegebenen Zeitstempel.
|
||||
bool setSystemTime(long timestamp) {
|
||||
struct timeval tv;
|
||||
|
||||
@@ -143,9 +143,13 @@ void setupRoutes() {
|
||||
[](AsyncWebServerRequest *request) {
|
||||
DynamicJsonDocument doc(128);
|
||||
doc["lane1Start"] = buttonConfigs.start1.isAssigned;
|
||||
doc["lane1StartVoltage"] = buttonConfigs.start1.voltage;
|
||||
doc["lane1Stop"] = buttonConfigs.stop1.isAssigned;
|
||||
doc["lane1StopVoltage"] = buttonConfigs.stop1.voltage;
|
||||
doc["lane2Start"] = buttonConfigs.start2.isAssigned;
|
||||
doc["lane2StartVoltage"] = buttonConfigs.start2.voltage;
|
||||
doc["lane2Stop"] = buttonConfigs.stop2.isAssigned;
|
||||
doc["lane2StopVoltage"] = buttonConfigs.stop2.voltage;
|
||||
String result;
|
||||
serializeJson(doc, result);
|
||||
request->send(200, "application/json", result);
|
||||
@@ -181,7 +185,7 @@ void setupRoutes() {
|
||||
if (buttonConfigs.stop2.isAssigned)
|
||||
connected++;
|
||||
doc["connectedButtons"] = connected;
|
||||
|
||||
doc["isOnline"] = isInternetAvailable() ? true : false;
|
||||
doc["valid"] = checkLicence() > 0 ? "Ja" : "Nein";
|
||||
doc["tier"] = checkLicence();
|
||||
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
|
||||
#include "licenceing.h"
|
||||
#include "master.h"
|
||||
#include "timesync.h"
|
||||
|
||||
String uniqueSSID;
|
||||
|
||||
PrettyOTA OTAUpdates;
|
||||
|
||||
String getUniqueSSID();
|
||||
bool isInternetAvailable();
|
||||
|
||||
// Initialisiert das WLAN als Access Point oder Station und startet mDNS/OTA.
|
||||
void setupWifi() {
|
||||
@@ -48,6 +50,9 @@ void setupWifi() {
|
||||
Serial.println("Erfolgreich mit WLAN verbunden!");
|
||||
Serial.print("IP Adresse: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
if (isInternetAvailable) {
|
||||
syncTimeWithNTP();
|
||||
} // Synchronisiere Zeit mit NTP
|
||||
}
|
||||
|
||||
// Only wait for connection if ssidSTA and passwordSTA are set
|
||||
@@ -95,4 +100,9 @@ String getUniqueSSID() {
|
||||
return String("AquaCross-") + String(uniqueId);
|
||||
}
|
||||
|
||||
// WiFi als Access Point
|
||||
// Prüft, ob das Internet erreichbar ist (z.B. durch Ping auf 8.8.8.8)
|
||||
bool isInternetAvailable() {
|
||||
WiFiClient client;
|
||||
// Versuche, eine Verbindung zu Googles DNS auf Port 53 herzustellen
|
||||
return client.connect("8.8.8.8", 53);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user