From fd89c8e7eb2cb545da2951d69f4e4646f0daa301 Mon Sep 17 00:00:00 2001 From: Patrick Balsiger Date: Thu, 21 Aug 2025 21:33:54 +0200 Subject: [PATCH] feat: config class --- include/Config.h | 37 +++++++++++++++++++++++++++++++++++++ src/ClusterManager.cpp | 10 +++++----- src/Config.cpp | 31 +++++++++++++++++++++++++++++++ src/NetworkManager.cpp | 15 +++++++-------- src/NodeContext.h | 2 ++ src/NodeInfo.cpp | 13 +++++++++---- src/NodeInfo.h | 3 ++- src/main.cpp | 24 +++++++++++++++++------- 8 files changed, 110 insertions(+), 25 deletions(-) create mode 100644 include/Config.h create mode 100644 src/Config.cpp diff --git a/include/Config.h b/include/Config.h new file mode 100644 index 0000000..95740eb --- /dev/null +++ b/include/Config.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +class Config { +public: + // WiFi Configuration + String wifi_ssid; + String wifi_password; + + // Network Configuration + uint16_t udp_port; + uint16_t api_server_port; + + // Cluster Configuration + unsigned long discovery_interval_ms; + unsigned long heartbeat_interval_ms; + unsigned long status_update_interval_ms; + unsigned long member_info_update_interval_ms; + unsigned long print_interval_ms; + + // Node Status Thresholds + unsigned long node_active_threshold_ms; + unsigned long node_inactive_threshold_ms; + unsigned long node_dead_threshold_ms; + + // WiFi Connection + unsigned long wifi_connect_timeout_ms; + unsigned long wifi_retry_delay_ms; + + // System Configuration + unsigned long restart_delay_ms; + uint16_t json_doc_size; + + // Constructor + Config(); +}; \ No newline at end of file diff --git a/src/ClusterManager.cpp b/src/ClusterManager.cpp index 23814cf..8792e39 100644 --- a/src/ClusterManager.cpp +++ b/src/ClusterManager.cpp @@ -10,7 +10,7 @@ ClusterManager::ClusterManager(NodeContext& ctx) : ctx(ctx) { void ClusterManager::sendDiscovery() { //Serial.println("[Cluster] Sending discovery packet..."); - ctx.udp->beginPacket("255.255.255.255", ClusterProtocol::UDP_PORT); + ctx.udp->beginPacket("255.255.255.255", ctx.config.udp_port); ctx.udp->write(ClusterProtocol::DISCOVERY_MSG); ctx.udp->endPacket(); } @@ -26,7 +26,7 @@ void ClusterManager::listenForDiscovery() { //Serial.printf("[UDP] Packet received: %s\n", incoming); if (strcmp(incoming, ClusterProtocol::DISCOVERY_MSG) == 0) { //Serial.printf("[UDP] Discovery request from: %s\n", ctx.udp->remoteIP().toString().c_str()); - ctx.udp->beginPacket(ctx.udp->remoteIP(), ClusterProtocol::UDP_PORT); + ctx.udp->beginPacket(ctx.udp->remoteIP(), ctx.config.udp_port); String response = String(ClusterProtocol::RESPONSE_MSG) + ":" + ctx.hostname; ctx.udp->write(response.c_str()); ctx.udp->endPacket(); @@ -57,7 +57,7 @@ void ClusterManager::addOrUpdateNode(const String& nodeHost, IPAddress nodeIP) { newNode.hostname = nodeHost; newNode.ip = nodeIP; newNode.lastSeen = millis(); - updateNodeStatus(newNode, newNode.lastSeen); + updateNodeStatus(newNode, newNode.lastSeen, ctx.config.node_inactive_threshold_ms, ctx.config.node_dead_threshold_ms); memberList[nodeHost] = newNode; Serial.printf("[Cluster] Added node: %s @ %s | Status: %s | last update: 0\n", nodeHost.c_str(), @@ -140,7 +140,7 @@ void ClusterManager::updateAllNodeStatuses() { unsigned long now = millis(); for (auto& pair : memberList) { NodeInfo& node = pair.second; - updateNodeStatus(node, now); + updateNodeStatus(node, now, ctx.config.node_inactive_threshold_ms, ctx.config.node_dead_threshold_ms); node.latency = now - node.lastSeen; } } @@ -152,7 +152,7 @@ void ClusterManager::removeDeadNodes() { // Use iterator to safely remove elements from map for (auto it = memberList.begin(); it != memberList.end(); ) { unsigned long diff = now - it->second.lastSeen; - if (it->second.status == NodeInfo::DEAD && diff > NODE_DEAD_THRESHOLD) { + if (it->second.status == NodeInfo::DEAD && diff > ctx.config.node_dead_threshold_ms) { Serial.printf("[Cluster] Removing node: %s\n", it->second.hostname.c_str()); it = memberList.erase(it); } else { diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..6700557 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,31 @@ +#include "Config.h" + +Config::Config() { + // WiFi Configuration + wifi_ssid = "shroud"; + wifi_password = "th3r31sn0sp00n"; + + // Network Configuration + udp_port = 4210; + api_server_port = 80; + + // Cluster Configuration + discovery_interval_ms = 1000; + heartbeat_interval_ms = 2000; + status_update_interval_ms = 1000; + member_info_update_interval_ms = 10000; + print_interval_ms = 5000; + + // Node Status Thresholds + node_active_threshold_ms = 10000; + node_inactive_threshold_ms = 60000; + node_dead_threshold_ms = 120000; + + // WiFi Connection + wifi_connect_timeout_ms = 15000; + wifi_retry_delay_ms = 500; + + // System Configuration + restart_delay_ms = 10; + json_doc_size = 1024; +} \ No newline at end of file diff --git a/src/NetworkManager.cpp b/src/NetworkManager.cpp index be25db0..be13f60 100644 --- a/src/NetworkManager.cpp +++ b/src/NetworkManager.cpp @@ -1,7 +1,6 @@ #include "NetworkManager.h" -const char* STA_SSID = "shroud"; -const char* STA_PASS = "th3r31sn0sp00n"; +// SSID and password are now configured via Config class NetworkManager::NetworkManager(NodeContext& ctx) : ctx(ctx) {} @@ -17,11 +16,11 @@ void NetworkManager::setHostnameFromMac() { void NetworkManager::setupWiFi() { Serial.begin(115200); WiFi.mode(WIFI_STA); - WiFi.begin(STA_SSID, STA_PASS); + WiFi.begin(ctx.config.wifi_ssid.c_str(), ctx.config.wifi_password.c_str()); Serial.println("[WiFi] Connecting to AP..."); unsigned long startAttemptTime = millis(); - while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < 15000) { - delay(500); + while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < ctx.config.wifi_connect_timeout_ms) { + delay(ctx.config.wifi_retry_delay_ms); Serial.print("."); } if (WiFi.status() == WL_CONNECTED) { @@ -32,17 +31,17 @@ void NetworkManager::setupWiFi() { Serial.println(); Serial.println("[WiFi] Failed to connect to AP. Creating AP..."); WiFi.mode(WIFI_AP); - WiFi.softAP(STA_SSID, STA_PASS); + WiFi.softAP(ctx.config.wifi_ssid.c_str(), ctx.config.wifi_password.c_str()); Serial.print("[WiFi] AP created, IP: "); Serial.println(WiFi.softAPIP()); } setHostnameFromMac(); - ctx.udp->begin(4210); + ctx.udp->begin(ctx.config.udp_port); ctx.localIP = WiFi.localIP(); ctx.hostname = WiFi.hostname(); Serial.print("[WiFi] Hostname set to: "); Serial.println(ctx.hostname); - Serial.print("[WiFi] UDP listening on port 4210\n"); + Serial.printf("[WiFi] UDP listening on port %d\n", ctx.config.udp_port); // Register this node in the memberlist via event system NodeInfo self; diff --git a/src/NodeContext.h b/src/NodeContext.h index d179b49..f5f4bef 100644 --- a/src/NodeContext.h +++ b/src/NodeContext.h @@ -5,6 +5,7 @@ #include "NodeInfo.h" #include #include +#include "Config.h" class NodeContext { public: @@ -15,6 +16,7 @@ public: String hostname; IPAddress localIP; std::map* memberList; + Config config; using EventCallback = std::function; std::map> eventRegistry; diff --git a/src/NodeInfo.cpp b/src/NodeInfo.cpp index 25fd67f..3bfaab5 100644 --- a/src/NodeInfo.cpp +++ b/src/NodeInfo.cpp @@ -9,13 +9,18 @@ const char* statusToStr(NodeInfo::Status status) { } } -void updateNodeStatus(NodeInfo &node, unsigned long now) { +void updateNodeStatus(NodeInfo &node, unsigned long now, unsigned long inactive_threshold, unsigned long dead_threshold) { unsigned long diff = now - node.lastSeen; - if (diff < NODE_INACTIVE_THRESHOLD) { + if (diff < inactive_threshold) { node.status = NodeInfo::ACTIVE; - } else if (diff < NODE_INACTIVE_THRESHOLD) { - node.status = NodeInfo::INACTIVE; + } else if (diff < dead_threshold) { + node.status = NodeInfo::DEAD; } else { node.status = NodeInfo::DEAD; } } + +void updateNodeStatus(NodeInfo &node, unsigned long now) { + // Legacy implementation using hardcoded values + updateNodeStatus(node, now, NODE_INACTIVE_THRESHOLD, NODE_DEAD_THRESHOLD); +} diff --git a/src/NodeInfo.h b/src/NodeInfo.h index 37a3ed0..bda152d 100644 --- a/src/NodeInfo.h +++ b/src/NodeInfo.h @@ -21,4 +21,5 @@ struct NodeInfo { }; const char* statusToStr(NodeInfo::Status status); -void updateNodeStatus(NodeInfo &node, unsigned long now = millis()); +void updateNodeStatus(NodeInfo &node, unsigned long now, unsigned long inactive_threshold, unsigned long dead_threshold); +void updateNodeStatus(NodeInfo &node, unsigned long now = millis()); // Legacy overload for backward compatibility diff --git a/src/main.cpp b/src/main.cpp index 17532e0..6a0c2f1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,18 +8,27 @@ NodeContext ctx; NetworkManager network(ctx); ClusterManager cluster(ctx); -ApiServer apiServer(ctx); +ApiServer apiServer(ctx, ctx.config.api_server_port); -Task tSendDiscovery(TaskIntervals::SEND_DISCOVERY, TASK_FOREVER, [](){ cluster.sendDiscovery(); }); -Task tListenForDiscovery(TaskIntervals::LISTEN_FOR_DISCOVERY, TASK_FOREVER, [](){ cluster.listenForDiscovery(); }); -Task tUpdateStatus(TaskIntervals::UPDATE_STATUS, TASK_FOREVER, [](){ cluster.updateAllNodeStatuses(); cluster.removeDeadNodes(); }); -Task tPrintMemberList(TaskIntervals::PRINT_MEMBER_LIST, TASK_FOREVER, [](){ cluster.printMemberList(); }); -Task tHeartbeat(TaskIntervals::HEARTBEAT, TASK_FOREVER, [](){ cluster.heartbeatTaskCallback(); }); -Task tUpdateAllMembersInfo(TaskIntervals::UPDATE_ALL_MEMBERS_INFO, TASK_FOREVER, [](){ cluster.updateAllMembersInfoTaskCallback(); }); +Task tSendDiscovery(0, TASK_FOREVER, [](){ cluster.sendDiscovery(); }); +Task tListenForDiscovery(0, TASK_FOREVER, [](){ cluster.listenForDiscovery(); }); +Task tUpdateStatus(0, TASK_FOREVER, [](){ cluster.updateAllNodeStatuses(); cluster.removeDeadNodes(); }); +Task tPrintMemberList(0, TASK_FOREVER, [](){ cluster.printMemberList(); }); +Task tHeartbeat(0, TASK_FOREVER, [](){ cluster.heartbeatTaskCallback(); }); +Task tUpdateAllMembersInfo(0, TASK_FOREVER, [](){ cluster.updateAllMembersInfoTaskCallback(); }); void setup() { network.setupWiFi(); ctx.scheduler->init(); + + // Set task intervals from config + tSendDiscovery.setInterval(ctx.config.discovery_interval_ms); + tListenForDiscovery.setInterval(ctx.config.discovery_interval_ms / 10); // Listen more frequently + tUpdateStatus.setInterval(ctx.config.status_update_interval_ms); + tPrintMemberList.setInterval(ctx.config.print_interval_ms); + tHeartbeat.setInterval(ctx.config.heartbeat_interval_ms); + tUpdateAllMembersInfo.setInterval(ctx.config.member_info_update_interval_ms); + ctx.scheduler->addTask(tSendDiscovery); ctx.scheduler->addTask(tListenForDiscovery); ctx.scheduler->addTask(tUpdateStatus); @@ -37,4 +46,5 @@ void setup() { void loop() { ctx.scheduler->execute(); + yield(); }