Sonoff4ChPro/src/http.cpp

180 lines
5.2 KiB
C++

#include "http.h"
#include "io.h"
#include <ArduinoJson.h>
#include <LittleFS.h>
#include "wifi.h"
#ifdef ESP8266
#include <ESP8266WebServer.h>
ESP8266WebServer server(80);
#endif
#ifdef ESP32
#include <WebServer.h>
WebServer server(80);
#endif
bool httpRunning = false;
File httpUploadFile;
void httpString(const String &key, const std::function<void(const String &)> &modifier) {
if (server.hasArg(key)) {
const auto name = server.arg(key);
modifier(name);
}
}
void httpBool(const String &key, const std::function<void(const bool &)> &modifier) {
if (server.hasArg(key)) {
const auto state = server.arg(key);
if (state == "true") {
modifier(true);
} else if (state == "false") {
modifier(false);
}
}
}
void httpLong(const String &key, const std::function<void(const long &)> &modifier) {
if (server.hasArg(key)) {
modifier(server.arg(key).toInt());
}
}
void httpInitial(const String &key, const std::function<void(const Initial &)> &modifier) {
httpString(key, [&modifier](const String &value) {
if (value == "OFF") {
modifier(INITIAL_OFF);
} else if (value == "ON") {
modifier(INITIAL_ON);
} else if (value == "CYCLE") {
modifier(INITIAL_CYCLE);
}
});
}
void httpRelay(const int index, Relay &relay) {
const String suffix(index);
httpString("name" + suffix, [&relay](const String &value) { relay.setName(value); });
httpInitial("initial" + suffix, [&relay](const Initial &value) { relay.setInitial(value); });
httpLong("onCount" + suffix, [&relay](const long &value) { relay.setOnCount(value); });
httpLong("onMillis" + suffix, [&relay](const long &value) { relay.setOnMillis(value); });
httpLong("offMillis" + suffix, [&relay](const long &value) { relay.setOffMillis(value); });
httpString("topic" + suffix, [&relay](const String &value) { relay.setTopic(value); });
httpBool("gridPowerDeltaOnEnabled" + suffix, [&relay](const long &value) { relay.setGridPowerDeltaOnEnabled(value); });
httpLong("gridPowerDeltaOnThreshold" + suffix, [&relay](const long &value) { relay.setGridPowerDeltaOnThreshold(value); });
httpLong("gridPowerDeltaOnDelay" + suffix, [&relay](const long &value) { relay.setGridPowerDeltaOnDelay(value); });
httpBool("gridPowerDeltaOffEnabled" + suffix, [&relay](const long &value) { relay.setGridPowerDeltaOffEnabled(value); });
httpLong("gridPowerDeltaOffThreshold" + suffix, [&relay](const long &value) { relay.setGridPowerDeltaOffThreshold(value); });
httpLong("gridPowerDeltaOffDelay" + suffix, [&relay](const long &value) { relay.setGridPowerDeltaOffDelay(value); });
httpBool("state" + suffix, [&relay](const bool &value) { relay.set(value); });
}
void httpStatus() {
JsonDocument json;
const auto wifi = json["wifi"].to<JsonObject>();
wifi["hostname"] = WiFi.getHostname();
wifi["ssid"] = WiFi.SSID();
const auto mqtt = json["mqtt"].to<JsonObject>();
mqtt["user"] = getMqttUser();
mqtt["host"] = getMqttHost();
mqtt["port"] = getMqttPort();
json["gridPowerDeltaValue"] = gridPowerDeltaValue;
json["gridPowerDeltaAge"] = millis() - gridPowerDeltaMillis;
const auto relays = json["relays"].to<JsonArray>();
relay0.json(relays.add<JsonObject>());
#ifdef Ch4Pro
relay1.json(relays.add<JsonObject>());
relay2.json(relays.add<JsonObject>());
relay3.json(relays.add<JsonObject>());
#endif
String response;
serializeJson(json, response);
server.send(200, "application/json", response);
}
void httpSet() {
httpString("wifiHostname", wifiSetHostname);
httpString("wifiSSID", wifiSetSSID);
httpString("wifiPassword", wifiSetPassword);
httpString("mqttHost", mqttSetHost);
httpLong("mqttPort", mqttSetPort);
httpString("mqttUser", mqttSetUser);
httpString("mqttPassword", mqttSetPassword);
httpRelay(0, relay0);
#ifdef Ch4Pro
httpRelay(1, relay1);
httpRelay(2, relay2);
httpRelay(3, relay3);
#endif
httpStatus();
}
void httpUpload(const char *name) {
yield();
const auto upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
char path[64];
snprintf(path, sizeof(path), "/%s", name);
httpUploadFile = LittleFS.open(path, "w");
Serial.printf("[HTTP] Uploading: %s\n", name);
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (httpUploadFile) {
httpUploadFile.write(upload.buf, upload.currentSize);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (httpUploadFile) {
httpUploadFile.close();
Serial.printf("[HTTP] Upload complete: %s (%d bytes)\n", name, upload.currentSize);
server.send(200);
}
}
}
void httpSetup() {
server.enableCORS(true);
server.serveStatic("", LittleFS, "/index.html");
server.serveStatic("/", LittleFS, "/index.html");
server.serveStatic("/icon.svg", LittleFS, "/icon.svg");
server.on("/status", httpSet);
server.on("/status/", httpSet);
server.on("/upload/index", HTTP_POST, [] { server.send(200); }, [] { httpUpload("index.html"); });
server.on("/upload/icon", HTTP_POST, [] { server.send(200); }, [] { httpUpload("icon.svg"); });
server.begin();
Serial.println("[HTTP] Server started");
httpRunning = true;
}
void httpLoop() {
server.handleClient();
}
void httpStop() {
if (httpRunning) {
httpRunning = false;
server.stop();
Serial.println("[HTTP] Server stopped");
}
}