From 168d7405957f90abb63255c5313ac962653669db Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Sun, 14 Jun 2026 18:50:09 +0200 Subject: [PATCH] MVP --- platformio.ini | 4 +- src/main.cpp | 303 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 225 insertions(+), 82 deletions(-) diff --git a/platformio.ini b/platformio.ini index 576e39a..62ad05c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,4 +13,6 @@ platform = espressif32 board = esp32-s3-devkitc-1 framework = arduino monitor_speed = 115200 -lib_deps = tzapu/WiFiManager@^2.0.17 +lib_deps = + tzapu/WiFiManager@^2.0.17 + bblanchon/ArduinoJson@^7.0.0 diff --git a/src/main.cpp b/src/main.cpp index 67c674e..cde37af 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,37 +3,97 @@ #include #include #include +#include #define HOSTNAME_DEFAULT "m1730" +#define MAX_METERS 10 +#define PWM_FREQ 5000 +#define PWM_RES 10 + +struct MeterConfig { + int pin; + float maxDuty; + float currentValue; +}; static char hostname[32] = HOSTNAME_DEFAULT; +static int meterCount = 0; +static MeterConfig meters[MAX_METERS] = {}; static WiFiManagerParameter hostnameParam("hostname", "Device hostname", hostname, 32); static WebServer server(80); -static void saveParams() { - strlcpy(hostname, hostnameParam.getValue(), sizeof(hostname)); +// --------------------------------------------------------------------------- +// Config persistence (JSON via LittleFS) +// --------------------------------------------------------------------------- - File f = LittleFS.open("/hostname.txt", "w"); +static void loadConfig() { + if (!LittleFS.exists("/config.json")) return; + File f = LittleFS.open("/config.json", "r"); + if (!f) return; + + JsonDocument doc; + DeserializationError err = deserializeJson(doc, f); + f.close(); + if (err) return; + + if (doc["hostname"].is()) + strlcpy(hostname, doc["hostname"], sizeof(hostname)); + + JsonArray arr = doc["meters"].as(); + meterCount = min((int)arr.size(), MAX_METERS); + for (int i = 0; i < meterCount; i++) { + JsonObject m = arr[i]; + meters[i].pin = m["pin"] | 0; + meters[i].maxDuty = m["maxD"] | 0.0f; + meters[i].currentValue = m["current"] | 0.0f; + } +} + +static void saveConfig() { + JsonDocument doc; + doc["hostname"] = hostname; + + JsonArray arr = doc["meters"].to(); + for (int i = 0; i < meterCount; i++) { + JsonObject m = arr.add(); + m["pin"] = meters[i].pin; + m["maxD"] = meters[i].maxDuty; + m["current"] = meters[i].currentValue; + } + + File f = LittleFS.open("/config.json", "w"); if (f) { - f.print(hostname); + serializeJson(doc, f); f.close(); } } -static void loadParams() { - if (!LittleFS.exists("/hostname.txt")) return; +// --------------------------------------------------------------------------- +// PWM helpers +// --------------------------------------------------------------------------- - File f = LittleFS.open("/hostname.txt", "r"); - if (!f) return; - - String val = f.readString(); - val.trim(); - if (val.length() > 0) { - val.toCharArray(hostname, sizeof(hostname)); +static void attachMeters() { + for (int i = 0; i < meterCount && i < 8; i++) { + if (meters[i].pin > 0) { + ledcSetup(i, PWM_FREQ, PWM_RES); + ledcAttachPin(meters[i].pin, i); + } } - f.close(); } +static void applyMeters() { + for (int i = 0; i < meterCount && i < 8; i++) { + if (meters[i].pin <= 0 || meters[i].maxDuty <= 0) continue; + float pct = meters[i].currentValue / 100.0f * meters[i].maxDuty / 100.0f; + int duty = constrain((int)(pct * 1023), 0, 1023); + ledcWrite(i, duty); + } +} + +// --------------------------------------------------------------------------- +// mDNS +// --------------------------------------------------------------------------- + static void startMDNS() { if (MDNS.begin(hostname)) { Serial.printf("mDNS: %s.local\n", hostname); @@ -43,7 +103,34 @@ static void startMDNS() { } } +// --------------------------------------------------------------------------- +// Web handlers +// --------------------------------------------------------------------------- + static void handleRoot() { + String meterRows; + for (int i = 0; i < meterCount; i++) { + char maxStr[8], curStr[8]; + dtostrf(meters[i].maxDuty, 1, 1, maxStr); + dtostrf(meters[i].currentValue, 1, 1, curStr); + + meterRows += "
Meter " + String(i) + ""; + meterRows += "
"; + meterRows += "
"; + meterRows += "
"; + meterRows += ""; + meterRows += ""; + meterRows += "" + String(curStr) + "%"; + meterRows += "
"; + } + + String countOpts; + for (int i = 1; i <= MAX_METERS; i++) { + countOpts += "