feat: services (#2)

This commit is contained in:
2025-09-13 13:45:24 +02:00
parent fe045804cb
commit 12caeb0be6
33 changed files with 3293 additions and 785 deletions

View File

@@ -0,0 +1,89 @@
#include "RelayService.h"
#include "ApiServer.h"
RelayService::RelayService(TaskManager& taskMgr, int pin)
: taskManager(taskMgr), relayPin(pin), relayOn(false) {
pinMode(relayPin, OUTPUT);
// Many relay modules are active LOW. Start in OFF state (relay de-energized).
digitalWrite(relayPin, HIGH);
registerTasks();
}
void RelayService::registerEndpoints(ApiServer& api) {
api.addEndpoint("/api/relay/status", HTTP_GET,
[this](AsyncWebServerRequest* request) { handleStatusRequest(request); },
std::vector<ParamSpec>{});
api.addEndpoint("/api/relay", HTTP_POST,
[this](AsyncWebServerRequest* request) { handleControlRequest(request); },
std::vector<ParamSpec>{
ParamSpec{String("state"), true, String("body"), String("string"),
{String("on"), String("off"), String("toggle")}}
});
}
void RelayService::handleStatusRequest(AsyncWebServerRequest* request) {
JsonDocument doc;
doc["pin"] = relayPin;
doc["state"] = relayOn ? "on" : "off";
doc["uptime"] = millis();
String json;
serializeJson(doc, json);
request->send(200, "application/json", json);
}
void RelayService::handleControlRequest(AsyncWebServerRequest* request) {
String state = request->hasParam("state", true) ? request->getParam("state", true)->value() : "";
bool ok = false;
if (state.equalsIgnoreCase("on")) {
turnOn();
ok = true;
} else if (state.equalsIgnoreCase("off")) {
turnOff();
ok = true;
} else if (state.equalsIgnoreCase("toggle")) {
toggle();
ok = true;
}
JsonDocument resp;
resp["success"] = ok;
resp["state"] = relayOn ? "on" : "off";
if (!ok) {
resp["message"] = "Invalid state. Use: on, off, or toggle";
}
String json;
serializeJson(resp, json);
request->send(ok ? 200 : 400, "application/json", json);
}
void RelayService::turnOn() {
relayOn = true;
// Active LOW relay
digitalWrite(relayPin, LOW);
Serial.println("[RelayService] Relay ON");
}
void RelayService::turnOff() {
relayOn = false;
digitalWrite(relayPin, HIGH);
Serial.println("[RelayService] Relay OFF");
}
void RelayService::toggle() {
if (relayOn) {
turnOff();
} else {
turnOn();
}
}
void RelayService::registerTasks() {
taskManager.registerTask("relay_status_print", 5000, [this]() {
Serial.printf("[RelayService] Status - pin: %d, state: %s\n",
relayPin, relayOn ? "ON" : "OFF");
});
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "services/Service.h"
#include "TaskManager.h"
#include <ArduinoJson.h>
class RelayService : public Service {
public:
RelayService(TaskManager& taskMgr, int pin);
void registerEndpoints(ApiServer& api) override;
const char* getName() const override { return "Relay"; }
void turnOn();
void turnOff();
void toggle();
private:
void registerTasks();
TaskManager& taskManager;
int relayPin;
bool relayOn;
void handleStatusRequest(AsyncWebServerRequest* request);
void handleControlRequest(AsyncWebServerRequest* request);
};

View File

@@ -7,6 +7,13 @@
#include "ApiServer.h"
#include "TaskManager.h"
// Services
#include "services/NodeService.h"
#include "services/NetworkService.h"
#include "services/ClusterService.h"
#include "services/TaskService.h"
#include "RelayService.h"
using namespace std;
// Choose a default relay pin. For ESP-01 this is GPIO0. Adjust as needed for your board.
@@ -14,88 +21,6 @@ using namespace std;
#define RELAY_PIN 0
#endif
class RelayService {
public:
RelayService(NodeContext& ctx, TaskManager& taskMgr, int pin)
: ctx(ctx), taskManager(taskMgr), relayPin(pin), relayOn(false) {
pinMode(relayPin, OUTPUT);
// Many relay modules are active LOW. Start in OFF state (relay de-energized).
digitalWrite(relayPin, HIGH);
registerTasks();
}
void registerApi(ApiServer& api) {
api.addEndpoint("/api/relay/status", HTTP_GET, [this](AsyncWebServerRequest* request) {
JsonDocument doc;
doc["pin"] = relayPin;
doc["state"] = relayOn ? "on" : "off";
doc["uptime"] = millis();
String json;
serializeJson(doc, json);
request->send(200, "application/json", json);
});
api.addEndpoint("/api/relay", HTTP_POST, [this](AsyncWebServerRequest* request) {
String state = request->hasParam("state", true) ? request->getParam("state", true)->value() : "";
bool ok = false;
if (state.equalsIgnoreCase("on")) {
turnOn();
ok = true;
} else if (state.equalsIgnoreCase("off")) {
turnOff();
ok = true;
} else if (state.equalsIgnoreCase("toggle")) {
toggle();
ok = true;
}
JsonDocument resp;
resp["success"] = ok;
resp["state"] = relayOn ? "on" : "off";
if (!ok) {
resp["message"] = "Invalid state. Use: on, off, or toggle";
}
String json;
serializeJson(resp, json);
request->send(ok ? 200 : 400, "application/json", json);
}, std::vector<ApiServer::ParamSpec>{ ApiServer::ParamSpec{ String("state"), true, String("body"), String("string"), { String("on"), String("off"), String("toggle") } } });
}
void turnOn() {
relayOn = true;
// Active LOW relay
digitalWrite(relayPin, LOW);
Serial.println("[RelayService] Relay ON");
}
void turnOff() {
relayOn = false;
digitalWrite(relayPin, HIGH);
Serial.println("[RelayService] Relay OFF");
}
void toggle() {
if (relayOn) {
turnOff();
} else {
turnOn();
}
}
private:
void registerTasks() {
taskManager.registerTask("relay_status_print", 5000, [this]() {
Serial.printf("[RelayService] Status - pin: %d, state: %s\n", relayPin, relayOn ? "ON" : "OFF");
});
}
NodeContext& ctx;
TaskManager& taskManager;
int relayPin;
bool relayOn;
};
NodeContext ctx({
{"app", "relay"},
{"device", "actuator"},
@@ -105,7 +30,13 @@ NetworkManager network(ctx);
TaskManager taskManager(ctx);
ClusterManager cluster(ctx, taskManager);
ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port);
RelayService relayService(ctx, taskManager, RELAY_PIN);
// Create services
NodeService nodeService(ctx);
NetworkService networkService(network);
ClusterService clusterService(ctx);
TaskService taskService(taskManager);
RelayService relayService(taskManager, RELAY_PIN);
void setup() {
Serial.begin(115200);
@@ -116,9 +47,13 @@ void setup() {
// Initialize and start all tasks
taskManager.initialize();
// Start the API server and expose relay endpoints
// Register services and start API server
apiServer.addService(nodeService);
apiServer.addService(networkService);
apiServer.addService(clusterService);
apiServer.addService(taskService);
apiServer.addService(relayService);
apiServer.begin();
relayService.registerApi(apiServer);
// Print initial task status
taskManager.printTaskStatus();
@@ -127,4 +62,4 @@ void setup() {
void loop() {
taskManager.execute();
yield();
}
}