MAJOR update. More like a Backup before things get Crazy

Added Websocket Support
Added Universal Message Handling for both MQTT and WS
Added Timekeeper Class, that handles Physical Clock and Scheduling
Added Bell Assignment Settings, Note to Bell mapping
This commit is contained in:
2025-09-05 19:27:13 +03:00
parent c1fa1d5e57
commit 101f9e7135
20 changed files with 10746 additions and 9766 deletions

View File

@@ -1,27 +1,13 @@
#pragma once
extern uint16_t relayDurations[16];
extern uint16_t bellDurations[16];
void loadRelayTimings();
void saveRelayTimings();
// - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Sets Incoming Relay Durations to RAM and then call funtion to save them to file.
void updateRelayTimings(JsonVariant doc) {
// Iterate through the relays in the JSON payload
for (uint8_t i = 0; i < 16; i++) {
String key = String("b") + (i + 1); // Generate "b1", "b2", ...
if (doc.containsKey(key)) {
relayDurations[i] = doc[key].as<uint16_t>();
LOG_DEBUG("Relay %d duration s1et to %d ms\n", i + 1, relayDurations[i]);
} else {
LOG_DEBUG("Relay %d not found in JSON payload. Keeping previous duration: %d ms\n", i + 1, relayDurations[i]);
}
}
saveRelayTimings();
LOG_INFO("Updated Relay Timings.")
}
// Save file "filename" with data: "data" to the "dirPath" directory of the SD card
void saveFileToSD(const char* dirPath, const char* filename, const char* data) {
@@ -59,7 +45,7 @@ void saveRelayTimings() {
// Populate the JSON object with relay durations
for (uint8_t i = 0; i < 16; i++) {
String key = String("b") + (i + 1);
doc[key] = relayDurations[i];
doc[key] = bellDurations[i];
}
char buffer[512];
@@ -100,14 +86,14 @@ void loadRelayTimings() {
for (uint8_t i = 0; i < 16; i++) {
String key = String("b") + (i + 1);
if (doc.containsKey(key)) {
relayDurations[i] = doc[key].as<uint16_t>();
LOG_DEBUG("Loaded relay %d duration: %d ms\n", i + 1, relayDurations[i]);
bellDurations[i] = doc[key].as<uint16_t>();
LOG_DEBUG("Loaded relay %d duration: %d ms", i + 1, bellDurations[i]);
}
}
}
// Function to sync time with NTP server and update RTC
/* Function to sync time with NTP server and update RTC
void syncTimeWithNTP() {
// Connect to Wi-Fi if not already connected
if (WiFi.status() != WL_CONNECTED) {
@@ -142,6 +128,8 @@ void syncTimeWithNTP() {
timeInfo.tm_mday, timeInfo.tm_mon + 1, timeInfo.tm_year + 1900);
}
*/
// Call this function with the Firebase URL and desired local filename
bool downloadFileToSD(const String& url, const String& directory, const String& filename) {
LOG_INFO("HTTP Starting download...");
@@ -192,7 +180,6 @@ bool downloadFileToSD(const String& url, const String& directory, const String&
return true;
}
// Returns the list of melodies (the filenames) currently inside the SD Card.
String listFilesAsJson(const char* dirPath) {
if (!SD.begin(SD_CS)) {
@@ -280,14 +267,14 @@ void printFileAsText(const String& path, const String& filename) {
}
// Downloads a new melody from HTTP
void addMelody(JsonVariant doc) {
LOG_INFO("Trying Saving...");
const char* url = doc["url"];
const char* filename = doc["filename"];
downloadFileToSD(url, "/melodies", filename);
bool addMelody(JsonVariant doc) {
LOG_INFO("Trying Download of Melody...");
const char* url = doc["download_url"];
const char* filename = doc["melodys_uid"];
if (downloadFileToSD(url, "/melodies", filename)) {
return true;
}
return false;
}
// Checks the onboard SD Card for new firmware
@@ -340,6 +327,59 @@ void checkFirmwareUpdate() {
updateBin.close();
}
// call this in setup() after WiFi is up
void setupUdpDiscovery() {
if (udp.listen(DISCOVERY_PORT)) {
Serial.printf("UDP discovery listening on %u\n", DISCOVERY_PORT);
udp.onPacket([](AsyncUDPPacket packet) {
// Parse request
String msg = String((const char*)packet.data(), packet.length());
Serial.printf("UDP from %s:%u -> %s\n",
packet.remoteIP().toString().c_str(),
packet.remotePort(),
msg.c_str());
// Minimal: accept plain text or JSON
bool shouldReply = false;
if (msg.indexOf("discover") >= 0) {
shouldReply = true;
} else {
// Try JSON
StaticJsonDocument<128> req;
DeserializationError err = deserializeJson(req, msg);
if (!err) {
shouldReply = (req["op"] == "discover" && req["svc"] == "vesper");
}
}
if (!shouldReply) return;
// Build reply JSON
StaticJsonDocument<256> doc;
doc["op"] = "discover_reply";
doc["svc"] = "vesper";
doc["ver"] = 1;
doc["name"] = "Proj. Vesper v0.5"; // your device name
doc["id"] = DEV_ID; // stable unique ID if you have one
doc["ip"] = WiFi.localIP().toString();
doc["ws"] = String("ws://") + WiFi.localIP().toString() + "/ws";
doc["port"] = 80; // your WS server port
doc["fw"] = "1.2.3"; // firmware version
String out;
serializeJson(doc, out);
// Reply directly to the senders IP/port
udp.writeTo((const uint8_t*)out.c_str(), out.length(),
packet.remoteIP(), packet.remotePort());
});
} else {
Serial.println("Failed to start UDP discovery.");
}
}
// UNSUSED FUNCTIONS.