From fe045804cb0ded8be8ffbacdfcdbf17ed08220d3 Mon Sep 17 00:00:00 2001 From: Patrick Balsiger Date: Fri, 29 Aug 2025 20:21:11 +0200 Subject: [PATCH] feat: set labels in NodeContext/Info --- examples/base/main.cpp | 14 ++++++-------- examples/neopixel/main.cpp | 18 ++++++++---------- examples/relay/main.cpp | 16 +++++++--------- include/NodeContext.h | 3 +++ src/ApiServer.cpp | 9 +++++++-- src/NetworkManager.cpp | 33 ++++++++++++++++++++------------- src/NodeContext.cpp | 10 ++++++++++ 7 files changed, 61 insertions(+), 42 deletions(-) diff --git a/examples/base/main.cpp b/examples/base/main.cpp index 8e6e587..942c4d3 100644 --- a/examples/base/main.cpp +++ b/examples/base/main.cpp @@ -9,23 +9,21 @@ using namespace std; -NodeContext ctx; +NodeContext ctx({ + {"app", "base"}, + {"role", "demo"} +}); NetworkManager network(ctx); TaskManager taskManager(ctx); ClusterManager cluster(ctx, taskManager); ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port); void setup() { + Serial.begin(115200); + // Setup WiFi first network.setupWiFi(); - // Add example labels for this node - auto it = ctx.memberList->find(ctx.hostname); - if (it != ctx.memberList->end()) { - it->second.labels["app"] = "base"; - it->second.labels["role"] = "demo"; - } - // Initialize and start all tasks taskManager.initialize(); diff --git a/examples/neopixel/main.cpp b/examples/neopixel/main.cpp index 2762ff3..064d721 100644 --- a/examples/neopixel/main.cpp +++ b/examples/neopixel/main.cpp @@ -339,7 +339,12 @@ private: uint8_t brightness; }; -NodeContext ctx; +NodeContext ctx({ + {"app", "neopixel"}, + {"device", "light"}, + {"pixels", String(NEOPIXEL_COUNT)}, + {"pin", String(NEOPIXEL_PIN)} +}); NetworkManager network(ctx); TaskManager taskManager(ctx); ClusterManager cluster(ctx, taskManager); @@ -347,16 +352,9 @@ ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port); NeoPixelService neoService(ctx, taskManager, NEOPIXEL_COUNT, NEOPIXEL_PIN, NEOPIXEL_TYPE); void setup() { - network.setupWiFi(); + Serial.begin(115200); - // Add example labels for this node - auto it = ctx.memberList->find(ctx.hostname); - if (it != ctx.memberList->end()) { - it->second.labels["app"] = "neopixel"; - it->second.labels["device"] = "light"; - it->second.labels["pixels"] = String(NEOPIXEL_COUNT); - it->second.labels["pin"] = String(NEOPIXEL_PIN); - } + network.setupWiFi(); taskManager.initialize(); diff --git a/examples/relay/main.cpp b/examples/relay/main.cpp index 65c2053..29e15b3 100644 --- a/examples/relay/main.cpp +++ b/examples/relay/main.cpp @@ -96,7 +96,11 @@ private: bool relayOn; }; -NodeContext ctx; +NodeContext ctx({ + {"app", "relay"}, + {"device", "actuator"}, + {"pin", String(RELAY_PIN)} +}); NetworkManager network(ctx); TaskManager taskManager(ctx); ClusterManager cluster(ctx, taskManager); @@ -104,17 +108,11 @@ ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port); RelayService relayService(ctx, taskManager, RELAY_PIN); void setup() { + Serial.begin(115200); + // Setup WiFi first network.setupWiFi(); - // Add example labels for this node - auto it = ctx.memberList->find(ctx.hostname); - if (it != ctx.memberList->end()) { - it->second.labels["app"] = "relay"; - it->second.labels["device"] = "actuator"; - it->second.labels["pin"] = String(RELAY_PIN); - } - // Initialize and start all tasks taskManager.initialize(); diff --git a/include/NodeContext.h b/include/NodeContext.h index 85e67ac..76576de 100644 --- a/include/NodeContext.h +++ b/include/NodeContext.h @@ -5,15 +5,18 @@ #include "NodeInfo.h" #include #include +#include #include "Config.h" class NodeContext { public: NodeContext(); + NodeContext(std::initializer_list> initialLabels); ~NodeContext(); WiFiUDP* udp; String hostname; IPAddress localIP; + NodeInfo self; std::map* memberList; Config config; diff --git a/src/ApiServer.cpp b/src/ApiServer.cpp index c88a35d..60acb94 100644 --- a/src/ApiServer.cpp +++ b/src/ApiServer.cpp @@ -103,6 +103,11 @@ void ApiServer::onSystemStatusRequest(AsyncWebServerRequest *request) { for (const auto& kv : it->second.labels) { labelsObj[kv.first.c_str()] = kv.second; } + } else if (!ctx.self.labels.empty()) { + JsonObject labelsObj = doc["labels"].to(); + for (const auto& kv : ctx.self.labels) { + labelsObj[kv.first.c_str()] = kv.second; + } } } String json; @@ -286,7 +291,7 @@ void ApiServer::onTaskControlRequest(AsyncWebServerRequest *request) { // Add task details to response statusDoc["taskDetails"] = JsonObject(); - JsonObject taskDetails = statusDoc["taskDetails"]; + JsonObject taskDetails = statusDoc["taskDetails"]; taskDetails["name"] = taskName; taskDetails["enabled"] = taskManager.isTaskEnabled(taskName.c_str()); taskDetails["running"] = taskManager.isTaskRunning(taskName.c_str()); @@ -294,7 +299,7 @@ void ApiServer::onTaskControlRequest(AsyncWebServerRequest *request) { // Add system context taskDetails["system"] = JsonObject(); - JsonObject systemInfo = taskDetails["system"]; + JsonObject systemInfo = taskDetails["system"]; systemInfo["freeHeap"] = ESP.getFreeHeap(); systemInfo["uptime"] = millis(); diff --git a/src/NetworkManager.cpp b/src/NetworkManager.cpp index 64d1a3a..cae4ca0 100644 --- a/src/NetworkManager.cpp +++ b/src/NetworkManager.cpp @@ -14,7 +14,6 @@ void NetworkManager::setHostnameFromMac() { } void NetworkManager::setupWiFi() { - Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ctx.config.wifi_ssid.c_str(), ctx.config.wifi_password.c_str()); Serial.println("[WiFi] Connecting to AP..."); @@ -43,18 +42,26 @@ void NetworkManager::setupWiFi() { Serial.println(ctx.hostname); Serial.printf("[WiFi] UDP listening on port %d\n", ctx.config.udp_port); - // Register this node in the memberlist via event system - NodeInfo self; - self.hostname = ctx.hostname; - if(WiFi.isConnected()) { - self.ip = WiFi.localIP(); + // Populate self NodeInfo + ctx.self.hostname = ctx.hostname; + if (WiFi.isConnected()) { + ctx.self.ip = WiFi.localIP(); } else { - // Fallback to AP IP if not connected - self.ip = WiFi.softAPIP(); + ctx.self.ip = WiFi.softAPIP(); } - self.lastSeen = millis(); - self.status = NodeInfo::ACTIVE; - // Initialize a default label for demonstration; users can modify at runtime - self.labels["hostname"] = ctx.hostname; - ctx.fire("node_discovered", &self); + ctx.self.lastSeen = millis(); + ctx.self.status = NodeInfo::ACTIVE; + ctx.self.labels["hostname"] = ctx.hostname; + + // Ensure member list has an entry for this node + auto &memberList = *ctx.memberList; + auto existing = memberList.find(ctx.hostname); + if (existing == memberList.end()) { + memberList[ctx.hostname] = ctx.self; + } else { + existing->second = ctx.self; + } + + // Notify listeners that the node is (re)discovered + ctx.fire("node_discovered", &ctx.self); } diff --git a/src/NodeContext.cpp b/src/NodeContext.cpp index 77d4a3c..e5833d3 100644 --- a/src/NodeContext.cpp +++ b/src/NodeContext.cpp @@ -4,6 +4,16 @@ NodeContext::NodeContext() { udp = new WiFiUDP(); memberList = new std::map(); hostname = ""; + self.hostname = ""; + self.ip = IPAddress(); + self.lastSeen = 0; + self.status = NodeInfo::INACTIVE; +} + +NodeContext::NodeContext(std::initializer_list> initialLabels) : NodeContext() { + for (const auto& kv : initialLabels) { + self.labels[kv.first] = kv.second; + } } NodeContext::~NodeContext() {