From e91ef1a98c7302b6aba1a3ed3ab902fcdd30412a Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Fri, 20 Mar 2026 11:27:50 +0100 Subject: [PATCH] WIP --- .../include/AmsJsonGenerator.h | 2 + lib/AmsJsonGenerator/src/AmsJsonGenerator.cpp | 267 ++++++ lib/JsonMqttHandler/include/JsonMqttHandler.h | 2 + lib/JsonMqttHandler/src/JsonMqttHandler.cpp | 876 ++++++++++-------- lib/SvelteUi/json/conf_cloud.json | 7 - lib/SvelteUi/json/conf_debug.json | 5 - lib/SvelteUi/json/conf_domoticz.json | 7 - lib/SvelteUi/json/conf_general.json | 8 - lib/SvelteUi/json/conf_gpio.json | 37 - lib/SvelteUi/json/conf_ha.json | 5 - lib/SvelteUi/json/conf_meter.json | 23 - lib/SvelteUi/json/conf_mqtt.json | 21 - lib/SvelteUi/json/conf_net.json | 13 - lib/SvelteUi/json/conf_price.json | 7 - lib/SvelteUi/json/conf_price_row.json | 10 - lib/SvelteUi/json/conf_thresholds.json | 15 - lib/SvelteUi/json/conf_ui.json | 18 - lib/SvelteUi/json/conf_wifi.json | 7 - lib/SvelteUi/src/AmsWebServer.cpp | 250 +---- 19 files changed, 749 insertions(+), 831 deletions(-) delete mode 100644 lib/SvelteUi/json/conf_cloud.json delete mode 100644 lib/SvelteUi/json/conf_debug.json delete mode 100644 lib/SvelteUi/json/conf_domoticz.json delete mode 100644 lib/SvelteUi/json/conf_general.json delete mode 100644 lib/SvelteUi/json/conf_gpio.json delete mode 100644 lib/SvelteUi/json/conf_ha.json delete mode 100644 lib/SvelteUi/json/conf_meter.json delete mode 100644 lib/SvelteUi/json/conf_mqtt.json delete mode 100644 lib/SvelteUi/json/conf_net.json delete mode 100644 lib/SvelteUi/json/conf_price.json delete mode 100644 lib/SvelteUi/json/conf_price_row.json delete mode 100644 lib/SvelteUi/json/conf_thresholds.json delete mode 100644 lib/SvelteUi/json/conf_ui.json delete mode 100644 lib/SvelteUi/json/conf_wifi.json diff --git a/lib/AmsJsonGenerator/include/AmsJsonGenerator.h b/lib/AmsJsonGenerator/include/AmsJsonGenerator.h index 70d32a13..cc06ec0a 100644 --- a/lib/AmsJsonGenerator/include/AmsJsonGenerator.h +++ b/lib/AmsJsonGenerator/include/AmsJsonGenerator.h @@ -1,9 +1,11 @@ #pragma once #include "AmsDataStorage.h" +#include "AmsConfiguration.h" class AmsJsonGenerator { public: static void generateDayPlotJson(AmsDataStorage* ds, char* buf, size_t bufSize); static void generateMonthPlotJson(AmsDataStorage* ds, char* buf, size_t bufSize); + static void generateConfigurationJson(AmsConfiguration* config, char* buf, size_t bufSize); }; \ No newline at end of file diff --git a/lib/AmsJsonGenerator/src/AmsJsonGenerator.cpp b/lib/AmsJsonGenerator/src/AmsJsonGenerator.cpp index 81239405..257a96f8 100644 --- a/lib/AmsJsonGenerator/src/AmsJsonGenerator.cpp +++ b/lib/AmsJsonGenerator/src/AmsJsonGenerator.cpp @@ -1,4 +1,8 @@ #include "AmsJsonGenerator.h" +#include "hexutils.h" +#include "AmsStorage.h" +#include "LittleFS.h" +#include "FirmwareVersion.h" void AmsJsonGenerator::generateDayPlotJson(AmsDataStorage* ds, char* buf, size_t bufSize) { uint16_t pos = snprintf_P(buf, bufSize, PSTR("{\"unit\":\"kwh\"")); @@ -15,3 +19,266 @@ void AmsJsonGenerator::generateMonthPlotJson(AmsDataStorage* ds, char* buf, size } snprintf_P(buf+pos, bufSize-pos, PSTR("}")); } + +void AmsJsonGenerator::generateConfigurationJson(AmsConfiguration* config, char* buf, size_t bufSize) { + uint16_t pos = snprintf_P(buf, bufSize, PSTR("{\"version\":\"%s\""), FirmwareVersion::VersionString); + + SystemConfig sysConfig; + config->getSystemConfig(sysConfig); + + WebConfig webConfig; + config->getWebConfig(webConfig); + + MeterConfig meterConfig; + config->getMeterConfig(meterConfig); + + NetworkConfig networkConfig; + config->getNetworkConfig(networkConfig); + + NtpConfig ntpConfig; + config->getNtpConfig(ntpConfig); + + EnergyAccountingConfig eac; + config->getEnergyAccountingConfig(eac); + + MqttConfig mqttConfig; + config->getMqttConfig(mqttConfig); + + PriceServiceConfig price; + config->getPriceServiceConfig(price); + + DebugConfig debugConfig; + config->getDebugConfig(debugConfig); + + GpioConfig gpioConfig; + config->getGpioConfig(gpioConfig); + + UiConfig ui; + config->getUiConfig(ui); + + DomoticzConfig domo; + config->getDomoticzConfig(domo); + + HomeAssistantConfig haconf; + config->getHomeAssistantConfig(haconf); + + CloudConfig cloud; + config->getCloudConfig(cloud); + + ZmartChargeConfig zcc; + config->getZmartChargeConfig(zcc); + + // General + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"g\":{\"t\":\"%s\",\"h\":\"%s\",\"s\":%d,\"u\":\"%s\",\"p\":\"%s\",\"c\":\"%s\"}"), + ntpConfig.timezone, + networkConfig.hostname, + webConfig.security, + webConfig.username, + strlen(webConfig.password) > 0 ? "***" : "", + webConfig.context + ); + + // Meter + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"m\":{\"o\":%d,\"a\":%d,\"b\":%d,\"p\":%d,\"i\":%s,\"s\":%d,\"d\":%d,\"f\":%d,\"r\":%d"), + meterConfig.source, + meterConfig.parser, + meterConfig.baud, + meterConfig.parity, + meterConfig.invert ? "true" : "false", + meterConfig.bufferSize * 64, + meterConfig.distributionSystem, + meterConfig.mainFuse, + meterConfig.productionCapacity + ); + + bool encen = false; + for(uint8_t i = 0; i < 16; i++) { + if(meterConfig.encryptionKey[i] > 0) { + encen = true; + } + } + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"e\":{\"e\":%s,\"k\":\"%s\",\"a\":\"%s\"}"), + encen ? "true" : "false", + toHex(meterConfig.encryptionKey, 16).c_str(), + toHex(meterConfig.authenticationKey, 16).c_str() + ); + + bool multEnable = false; + if(meterConfig.wattageMultiplier != 1.0 && meterConfig.wattageMultiplier != 0.0) + multEnable = true; + if(meterConfig.voltageMultiplier != 1.0 && meterConfig.voltageMultiplier != 0.0) + multEnable = true; + if(meterConfig.amperageMultiplier != 1.0 && meterConfig.amperageMultiplier != 0.0) + multEnable = true; + if(meterConfig.accumulatedMultiplier != 1.0 && meterConfig.accumulatedMultiplier != 0.0) + multEnable = true; + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"m\":{\"e\":%s,\"w\":%.3f,\"v\":%.3f,\"a\":%.3f,\"c\":%.3f}"), + multEnable ? "true" : "false", + meterConfig.wattageMultiplier == 0.0 ? 1.0 : meterConfig.wattageMultiplier / 1000.0, + meterConfig.voltageMultiplier == 0.0 ? 1.0 : meterConfig.voltageMultiplier / 1000.0, + meterConfig.amperageMultiplier == 0.0 ? 1.0 : meterConfig.amperageMultiplier / 1000.0, + meterConfig.accumulatedMultiplier == 0.0 ? 1.0 : meterConfig.accumulatedMultiplier / 1000.0 + ); + + pos += snprintf_P(buf+pos, bufSize-pos, PSTR("}")); // End of meter + + // Thresholds + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"t\":{\"t\":[%d,%d,%d,%d,%d,%d,%d,%d,%d,%d],\"h\":%d}"), + eac.thresholds[0], + eac.thresholds[1], + eac.thresholds[2], + eac.thresholds[3], + eac.thresholds[4], + eac.thresholds[5], + eac.thresholds[6], + eac.thresholds[7], + eac.thresholds[8], + eac.thresholds[9], + eac.hours + ); + + // WiFi + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"w\":{\"s\":\"%s\",\"p\":\"%s\",\"w\":%.1f,\"z\":%d,\"b\":%s}"), + networkConfig.ssid, + strlen(networkConfig.psk) > 0 ? "***" : "", + networkConfig.power / 10.0, + networkConfig.sleep, + networkConfig.use11b ? "true" : "false" + ); + + // Network + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"n\":{\"c\":%d,\"m\":\"%s\",\"i\":\"%s\",\"s\":\"%s\",\"g\":\"%s\",\"d1\":\"%s\",\"d2\":\"%s\",\"d\":%s,\"n1\":\"%s\",\"h\":%s,\"x\":%s}"), + networkConfig.mode, + strlen(networkConfig.ip) > 0 ? "static" : "dhcp", + networkConfig.ip, + networkConfig.subnet, + networkConfig.gateway, + networkConfig.dns1, + networkConfig.dns2, + networkConfig.mdns ? "true" : "false", + ntpConfig.server, + ntpConfig.dhcp ? "true" : "false", + networkConfig.ipv6 ? "true" : "false" + ); + + // MQTT + bool qsc = false; + bool qsr = false; + bool qsk = false; + if(LittleFS.begin()) { + qsc = LittleFS.exists(FILE_MQTT_CA); + qsr = LittleFS.exists(FILE_MQTT_CERT); + qsk = LittleFS.exists(FILE_MQTT_KEY); + } + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"q\":{\"h\":\"%s\",\"p\":%d,\"u\":\"%s\",\"a\":\"%s\",\"c\":\"%s\",\"b\":\"%s\",\"r\":\"%s\",\"m\":%d,\"s\":{\"e\":%s,\"c\":%s,\"r\":%s,\"k\":%s},\"t\":%d,\"d\":%d,\"i\":%d,\"k\":%d,\"e\":%d}"), + mqttConfig.host, + mqttConfig.port, + mqttConfig.username, + strlen(mqttConfig.password) > 0 ? "***" : "", + mqttConfig.clientId, + mqttConfig.publishTopic, + mqttConfig.subscribeTopic, + mqttConfig.payloadFormat, + mqttConfig.ssl ? "true" : "false", + qsc ? "true" : "false", + qsr ? "true" : "false", + qsk ? "true" : "false", + mqttConfig.stateUpdate, + mqttConfig.stateUpdateInterval, + mqttConfig.timeout, + mqttConfig.keepalive, + mqttConfig.rebootMinutes == 0 ? "null" : String(mqttConfig.rebootMinutes, 10).c_str() + ); + + // Price + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"p\":{\"e\":%s,\"t\":\"%s\",\"r\":\"%s\",\"c\":\"%s\",\"m\":%d}"), + price.enabled ? "true" : "false", + price.entsoeToken, + price.area, + price.currency, + price.resolutionInMinutes + ); + + // Debug + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"d\":{\"s\":%s,\"t\":%s,\"l\":%d}"), + debugConfig.serial ? "true" : "false", + debugConfig.telnet ? "true" : "false", + debugConfig.level + ); + + // GPIO + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"i\":{\"h\":{\"p\":%s,\"u\":%s,\"t\":%s},\"a\":%s,\"l\":{\"p\":%s,\"i\":%s},\"r\":{\"r\":%s,\"g\":%s,\"b\":%s,\"i\":%s},\"d\":{\"d\":%s,\"b\":%d},\"t\":{\"d\":%s,\"a\":%s},\"v\":{\"p\":%s,\"o\":%.2f,\"m\":%.3f,\"d\":{\"v\":%d,\"g\":%d},\"b\":%.1f},\"p\":%d}"), + meterConfig.rxPin == 0xff ? "null" : String(meterConfig.rxPin, 10).c_str(), + meterConfig.rxPinPullup ? "true" : "false", + meterConfig.txPin == 0xff ? "null" : String(meterConfig.txPin, 10).c_str(), + gpioConfig.apPin == 0xff ? "null" : String(gpioConfig.apPin, 10).c_str(), + gpioConfig.ledPin == 0xff ? "null" : String(gpioConfig.ledPin, 10).c_str(), + gpioConfig.ledInverted ? "true" : "false", + gpioConfig.ledPinRed == 0xff ? "null" : String(gpioConfig.ledPinRed, 10).c_str(), + gpioConfig.ledPinGreen == 0xff ? "null" : String(gpioConfig.ledPinGreen, 10).c_str(), + gpioConfig.ledPinBlue == 0xff ? "null" : String(gpioConfig.ledPinBlue, 10).c_str(), + gpioConfig.ledRgbInverted ? "true" : "false", + gpioConfig.ledDisablePin == 0xff ? "null" : String(gpioConfig.ledDisablePin, 10).c_str(), + gpioConfig.ledBehaviour, + gpioConfig.tempSensorPin == 0xff ? "null" : String(gpioConfig.tempSensorPin, 10).c_str(), + gpioConfig.tempAnalogSensorPin == 0xff ? "null" : String(gpioConfig.tempAnalogSensorPin, 10).c_str(), + gpioConfig.vccPin == 0xff ? "null" : String(gpioConfig.vccPin, 10).c_str(), + gpioConfig.vccOffset / 100.0, + gpioConfig.vccMultiplier / 1000.0, + gpioConfig.vccResistorVcc, + gpioConfig.vccResistorGnd, + gpioConfig.vccBootLimit / 10.0, + gpioConfig.powersaving + ); + + // UI + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"u\":{\"i\":%d,\"e\":%d,\"v\":%d,\"a\":%d,\"r\":%d,\"c\":%d,\"t\":%d,\"p\":%d,\"d\":%d,\"m\":%d,\"s\":%d,\"l\":%d,\"h\":%d,\"f\":%d,\"k\":%d,\"lang\":\"%s\"}"), + ui.showImport, + ui.showExport, + ui.showVoltage, + ui.showAmperage, + ui.showReactive, + ui.showRealtime, + ui.showPeaks, + ui.showPricePlot, + ui.showDayPlot, + ui.showMonthPlot, + ui.showTemperaturePlot, + ui.showRealtimePlot, + ui.showPerPhasePower, + ui.showPowerFactor, + ui.darkMode, + ui.language + ); + + // Domoticz + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"o\":{\"e\":%d,\"c\":%d,\"u1\":%d,\"u2\":%d,\"u3\":%d}"), + domo.elidx, + domo.cl1idx, + domo.vl1idx, + domo.vl2idx, + domo.vl3idx + ); + + // Home-Assistant + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"h\":{\"t\":\"%s\",\"h\":\"%s\",\"n\":\"%s\"}"), + haconf.discoveryPrefix, + haconf.discoveryHostname, + haconf.discoveryNameTag + ); + + // Cloud + pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"c\":{\"e\":%s,\"p\":%d,\"es\":%s,\"ze\":%s,\"zt\":\"%s\"}"), + cloud.enabled ? "true" : "false", + cloud.proto, + #if defined(ESP32) && defined(ENERGY_SPEEDOMETER_PASS) + sysConfig.energyspeedometer == 7 ? "true" : "false", + #else + "null", + #endif + zcc.enabled ? "true" : "false", + zcc.token + ); + + pos += snprintf_P(buf+pos, bufSize-pos, PSTR("}")); // End of config +} \ No newline at end of file diff --git a/lib/JsonMqttHandler/include/JsonMqttHandler.h b/lib/JsonMqttHandler/include/JsonMqttHandler.h index ae99fc00..08f3d533 100644 --- a/lib/JsonMqttHandler/include/JsonMqttHandler.h +++ b/lib/JsonMqttHandler/include/JsonMqttHandler.h @@ -8,6 +8,7 @@ #define _JSONMQTTHANDLER_H #include "AmsMqttHandler.h" +#include "ArduinoJson.h" class JsonMqttHandler : public AmsMqttHandler { public: @@ -51,5 +52,6 @@ private: bool publishList4(AmsData* data, EnergyAccounting* ea); String getMeterModel(AmsData* data); void toJsonIsoTimestamp(time_t t, char* buf, size_t buflen); + void handleConfigMessage(JsonObject& configObj); }; #endif diff --git a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp index d9463e56..724945a4 100644 --- a/lib/JsonMqttHandler/src/JsonMqttHandler.cpp +++ b/lib/JsonMqttHandler/src/JsonMqttHandler.cpp @@ -9,7 +9,6 @@ #include "hexutils.h" #include "Uptime.h" #include "AmsJsonGenerator.h" -#include "ArduinoJson.h" bool JsonMqttHandler::publish(AmsData* update, AmsData* previousState, EnergyAccounting* ea, PriceService* ps) { if(strlen(mqttConfig.publishTopic) == 0) { @@ -528,7 +527,7 @@ void JsonMqttHandler::onMessage(String &topic, String &payload) { debugger->printf_P(PSTR(" - this is our subscribed topic\n")); if(payload.startsWith("{")) { - DynamicJsonDocument doc(BufferSize); + DynamicJsonDocument doc(512); DeserializationError error = deserializeJson(doc, payload); if(error) { #if defined(AMS_REMOTE_DEBUG) @@ -538,429 +537,41 @@ void JsonMqttHandler::onMessage(String &topic, String &payload) { return; } else { JsonObject obj = doc.as(); - if(obj.containsKey("action")) { - const char* action = obj["action"]; - if(strcmp(action, "fwupgrade") == 0) { + if(obj.containsKey(F("action"))) { + const char* action = obj[F("action")]; + if(strcmp_P(action, PSTR("fwupgrade")) == 0) { if(strcmp(updater->getNextVersion(), FirmwareVersion::VersionString) != 0) { updater->setTargetVersion(updater->getNextVersion()); } - } else if(strcmp(action, "dayplot") == 0) { + } else if(strcmp_P(action, PSTR("dayplot")) == 0) { char pubTopic[192]; snprintf_P(pubTopic, 192, PSTR("%s/dayplot"), mqttConfig.publishTopic); AmsJsonGenerator::generateDayPlotJson(ds, json, BufferSize); bool ret = mqtt.publish(pubTopic, json); loop(); - } else if(strcmp(action, "monthplot") == 0) { + } else if(strcmp_P(action, PSTR("monthplot")) == 0) { char pubTopic[192]; snprintf_P(pubTopic, 192, PSTR("%s/monthplot"), mqttConfig.publishTopic); AmsJsonGenerator::generateMonthPlotJson(ds, json, BufferSize); bool ret = mqtt.publish(pubTopic, json); loop(); - } else if(strcmp(action, "config") == 0 && obj.containsKey("config")) { - JsonObject configObj = obj["config"]; - - if(configObj.containsKey("system")) { - SystemConfig newConfig; - config->getSystemConfig(newConfig); - - JsonObject systemObj = configObj["system"]; - if(systemObj.containsKey("country")) { - strlcpy(newConfig.country, systemObj["country"], sizeof(newConfig.country)); - } - if(systemObj.containsKey("firmwareChannel")) { - newConfig.firmwareChannel = systemObj["firmwareChannel"]; - } - config->setSystemConfig(newConfig); - } - - if(configObj.containsKey("network")) { - NetworkConfig newConfig; - config->getNetworkConfig(newConfig); - - JsonObject networkObj = configObj["network"]; - if(networkObj.containsKey("mode")) { - newConfig.mode = networkObj["mode"]; - } - if(newConfig.mode == 1 || newConfig.mode == 2) { - if(networkObj.containsKey("ssid")) { - strlcpy(newConfig.ssid, networkObj["ssid"], sizeof(newConfig.ssid)); - } - if(networkObj.containsKey("psk")) { - strlcpy(newConfig.psk, networkObj["psk"], sizeof(newConfig.psk)); - } - if(networkObj.containsKey("power")) { - newConfig.power = networkObj["power"]; - } - if(networkObj.containsKey("sleep")) { - newConfig.sleep = networkObj["sleep"]; - } - if(networkObj.containsKey("use11b")) { - newConfig.use11b = networkObj["use11b"]; - } - } - if(networkObj.containsKey("ip")) { - strlcpy(newConfig.ip, networkObj["ip"], sizeof(newConfig.ip)); - } - if(networkObj.containsKey("gateway")) { - strlcpy(newConfig.gateway, networkObj["gateway"], sizeof(newConfig.gateway)); - } - if(networkObj.containsKey("subnet")) { - strlcpy(newConfig.subnet, networkObj["subnet"], sizeof(newConfig.subnet)); - } - if(networkObj.containsKey("dns1")) { - strlcpy(newConfig.dns1, networkObj["dns1"], sizeof(newConfig.dns1)); - } - if(networkObj.containsKey("dns2")) { - strlcpy(newConfig.dns2, networkObj["dns2"], sizeof(newConfig.dns2)); - } - if(networkObj.containsKey("hostname")) { - strlcpy(newConfig.hostname, networkObj["hostname"], sizeof(newConfig.hostname)); - } - if(networkObj.containsKey("mdns")) { - newConfig.mdns = networkObj["mdns"]; - } - if(networkObj.containsKey("ipv6")) { - newConfig.ipv6 = networkObj["ipv6"]; - } - config->setNetworkConfig(newConfig); - } - - if(configObj.containsKey("web")) { - WebConfig newConfig; - config->getWebConfig(newConfig); - - JsonObject webObj = configObj["web"]; - if(webObj.containsKey("security")) { - newConfig.security = webObj["security"]; - } - if(newConfig.security > 0) { - if(webObj.containsKey("username")) { - strlcpy(newConfig.username, webObj["username"], sizeof(newConfig.username)); - } - if(webObj.containsKey("password")) { - strlcpy(newConfig.password, webObj["password"], sizeof(newConfig.password)); - } - } - if(webObj.containsKey("context")) { - strlcpy(newConfig.context, webObj["context"], sizeof(newConfig.context)); - } - config->setWebConfig(newConfig); - } - - if(configObj.containsKey("meter")) { - MeterConfig newConfig; - config->getMeterConfig(newConfig); - - JsonObject meterObj = configObj["meter"]; - if(meterObj.containsKey("baud")) { - newConfig.baud = meterObj["baud"]; - } - if(meterObj.containsKey("parity")) { - newConfig.parity = meterObj["parity"]; - } - if(meterObj.containsKey("invert")) { - newConfig.invert = meterObj["invert"]; - } - if(meterObj.containsKey("distributionSystem")) { - newConfig.distributionSystem = meterObj["distributionSystem"]; - } - if(meterObj.containsKey("mainFuse")) { - newConfig.mainFuse = meterObj["mainFuse"]; - } - if(meterObj.containsKey("productionCapacity")) { - newConfig.productionCapacity = meterObj["productionCapacity"]; - } - if(meterObj.containsKey("wattageMultiplier")) { - newConfig.wattageMultiplier = meterObj["wattageMultiplier"]; - } - if(meterObj.containsKey("voltageMultiplier")) { - newConfig.voltageMultiplier = meterObj["voltageMultiplier"]; - } - if(meterObj.containsKey("amperageMultiplier")) { - newConfig.amperageMultiplier = meterObj["amperageMultiplier"]; - } - if(meterObj.containsKey("accumulatedMultiplier")) { - newConfig.accumulatedMultiplier = meterObj["accumulatedMultiplier"]; - } - if(meterObj.containsKey("parser")) { - newConfig.parser = meterObj["parser"]; - } - if(meterObj.containsKey("bufferSize")) { - newConfig.bufferSize = meterObj["bufferSize"]; - } - if(meterObj.containsKey("rxPin")) { - newConfig.rxPin = meterObj["rxPin"]; - } - if(meterObj.containsKey("rxPinPullup")) { - newConfig.rxPinPullup = meterObj["rxPinPullup"]; - } - if(meterObj.containsKey("txPin")) { - newConfig.txPin = meterObj["txPin"]; - } - } - - if(configObj.containsKey("mqtt")) { - MqttConfig newConfig; - config->getMqttConfig(newConfig); - - JsonObject mqttObj = configObj["mqtt"]; - if(mqttObj.containsKey("host")) { - strlcpy(newConfig.host, mqttObj["host"], sizeof(newConfig.host)); - } - if(mqttObj.containsKey("port")) { - newConfig.port = mqttObj["port"]; - } - if(mqttObj.containsKey("clientId")) { - strlcpy(newConfig.clientId, mqttObj["clientId"], sizeof(newConfig.clientId)); - } - if(mqttObj.containsKey("publishTopic")) { - strlcpy(newConfig.publishTopic, mqttObj["publishTopic"], sizeof(newConfig.publishTopic)); - } - if(mqttObj.containsKey("subscribeTopic")) { - strlcpy(newConfig.subscribeTopic, mqttObj["subscribeTopic"], sizeof(newConfig.subscribeTopic)); - } - if(mqttObj.containsKey("username")) { - strlcpy(newConfig.username, mqttObj["username"], sizeof(newConfig.username)); - } - if(mqttObj.containsKey("password")) { - strlcpy(newConfig.password, mqttObj["password"], sizeof(newConfig.password)); - } - if(mqttObj.containsKey("payloadFormat")) { - newConfig.payloadFormat = mqttObj["payloadFormat"]; - } - if(mqttObj.containsKey("ssl")) { - newConfig.ssl = mqttObj["ssl"]; - } - if(mqttObj.containsKey("stateUpdate")) { - newConfig.stateUpdate = mqttObj["stateUpdate"]; - } - if(mqttObj.containsKey("stateUpdateInterval")) { - newConfig.stateUpdateInterval = mqttObj["stateUpdateInterval"]; - } - if(mqttObj.containsKey("timeout")) { - newConfig.timeout = mqttObj["timeout"]; - } - if(mqttObj.containsKey("keepalive")) { - newConfig.keepalive = mqttObj["keepalive"]; - } - if(mqttObj.containsKey("rebootMinutes")) { - newConfig.rebootMinutes = mqttObj["rebootMinutes"]; - } - config->setMqttConfig(newConfig); - - if(mqttObj.containsKey("domoticz")) { - DomoticzConfig newConfig; - config->getDomoticzConfig(newConfig); - JsonObject domoticzObj = mqttObj["domoticz"]; - if(domoticzObj.containsKey("elidx")) { - newConfig.elidx = domoticzObj["elidx"]; - } - if(domoticzObj.containsKey("vl1idx")) { - newConfig.vl1idx = domoticzObj["vl1idx"]; - } - if(domoticzObj.containsKey("vl2idx")) { - newConfig.vl2idx = domoticzObj["vl2idx"]; - } - if(domoticzObj.containsKey("vl3idx")) { - newConfig.vl3idx = domoticzObj["vl3idx"]; - } - if(domoticzObj.containsKey("cl1idx")) { - newConfig.cl1idx = domoticzObj["cl1idx"]; - } - config->setDomoticzConfig(newConfig); - } - - if(mqttObj.containsKey("homeAssistant")) { - HomeAssistantConfig newConfig; - config->getHomeAssistantConfig(newConfig); - JsonObject haObj = mqttObj["homeAssistant"]; - if(haObj.containsKey("discoveryPrefix")) { - strlcpy(newConfig.discoveryPrefix, haObj["discoveryPrefix"], sizeof(newConfig.discoveryPrefix)); - } - if(haObj.containsKey("discoveryHostname")) { - strlcpy(newConfig.discoveryHostname, haObj["discoveryHostname"], sizeof(newConfig.discoveryHostname)); - } - if(haObj.containsKey("discoveryNameTag")) { - strlcpy(newConfig.discoveryNameTag, haObj["discoveryNameTag"], sizeof(newConfig.discoveryNameTag)); - } - config->setHomeAssistantConfig(newConfig); - } - } - - if(configObj.containsKey("debug")) { - DebugConfig newConfig; - config->getDebugConfig(newConfig); - - JsonObject debugObj = configObj["debug"]; - if(debugObj.containsKey("telnet")) { - newConfig.telnet = debugObj["telnet"]; - } - if(debugObj.containsKey("serial")) { - newConfig.serial = debugObj["serial"]; - } - if(debugObj.containsKey("level")) { - newConfig.level = debugObj["level"]; - } - config->setDebugConfig(newConfig); - } - - if(configObj.containsKey("gpio")) { - GpioConfig newConfig; - config->getGpioConfig(newConfig); - - JsonObject gpioObj = configObj["gpio"]; - if(gpioObj.containsKey("apPin")) { - newConfig.apPin = gpioObj["apPin"]; - } - if(gpioObj.containsKey("ledPin")) { - newConfig.ledPin = gpioObj["ledPin"]; - } - if(gpioObj.containsKey("ledInverted")) { - newConfig.ledInverted = gpioObj["ledInverted"]; - } - if(gpioObj.containsKey("ledPinRed")) { - newConfig.ledPinRed = gpioObj["ledPinRed"]; - } - if(gpioObj.containsKey("ledPinGreen")) { - newConfig.ledPinGreen = gpioObj["ledPinGreen"]; - } - if(gpioObj.containsKey("ledPinBlue")) { - newConfig.ledPinBlue = gpioObj["ledPinBlue"]; - } - if(gpioObj.containsKey("ledRgbInverted")) { - newConfig.ledRgbInverted = gpioObj["ledRgbInverted"]; - } - if(gpioObj.containsKey("tempSensorPin")) { - newConfig.tempSensorPin = gpioObj["tempSensorPin"]; - } - if(gpioObj.containsKey("tempAnalogSensorPin")) { - newConfig.tempAnalogSensorPin = gpioObj["tempAnalogSensorPin"]; - } - if(gpioObj.containsKey("vccPin")) { - newConfig.vccPin = gpioObj["vccPin"]; - } - if(gpioObj.containsKey("vccOffset")) { - newConfig.vccOffset = gpioObj["vccOffset"]; - } - if(gpioObj.containsKey("vccMultiplier")) { - newConfig.vccMultiplier = gpioObj["vccMultiplier"]; - } - if(gpioObj.containsKey("vccBootLimit")) { - newConfig.vccBootLimit = gpioObj["vccBootLimit"]; - } - if(gpioObj.containsKey("vccResistorGnd")) { - newConfig.vccResistorGnd = gpioObj["vccResistorGnd"]; - } - if(gpioObj.containsKey("vccResistorVcc")) { - newConfig.vccResistorVcc = gpioObj["vccResistorVcc"]; - } - if(gpioObj.containsKey("ledDisablePin")) { - newConfig.ledDisablePin = gpioObj["ledDisablePin"]; - } - if(gpioObj.containsKey("ledBehaviour")) { - newConfig.ledBehaviour = gpioObj["ledBehaviour"]; - } - config->setGpioConfig(newConfig); - } - - if(configObj.containsKey("ntp")) { - NtpConfig newConfig; - config->getNtpConfig(newConfig); - - JsonObject ntpObj = configObj["ntp"]; - if(ntpObj.containsKey("enable")) { - newConfig.enable = ntpObj["enable"]; - } - if(ntpObj.containsKey("dhcp")) { - newConfig.dhcp = ntpObj["dhcp"]; - } - if(ntpObj.containsKey("server")) { - strlcpy(newConfig.server, ntpObj["server"], sizeof(newConfig.server)); - } - if(ntpObj.containsKey("timezone")) { - strlcpy(newConfig.timezone, ntpObj["timezone"], sizeof(newConfig.timezone)); - } - config->setNtpConfig(newConfig); - } - - if(configObj.containsKey("priceService")) { - PriceServiceConfig newConfig; - config->getPriceServiceConfig(newConfig); - JsonObject priceServiceObj = configObj["priceService"]; - if(priceServiceObj.containsKey("area")) { - strlcpy(newConfig.area, priceServiceObj["area"], sizeof(newConfig.area)); - } - if(priceServiceObj.containsKey("currency")) { - strlcpy(newConfig.currency, priceServiceObj["currency"], sizeof(newConfig.currency)); - } - if(priceServiceObj.containsKey("resolutionInMinutes")) { - newConfig.resolutionInMinutes = priceServiceObj["resolutionInMinutes"]; - } - if(priceServiceObj.containsKey("enabled")) { - newConfig.enabled = priceServiceObj["enabled"]; - } - config->setPriceServiceConfig(newConfig); - } - - if(configObj.containsKey("cloud")) { - JsonObject cloudObj = configObj["cloud"]; - - if(cloudObj.containsKey("amsleser")) { - CloudConfig newConfig; - config->getCloudConfig(newConfig); - - JsonObject amsCloudObj = cloudObj["amsleser"]; - if(amsCloudObj.containsKey("enabled")) { - newConfig.enabled = amsCloudObj["enabled"]; - } - if(amsCloudObj.containsKey("interval")) { - newConfig.interval = amsCloudObj["interval"]; - } - if(amsCloudObj.containsKey("hostname")) { - strlcpy(newConfig.hostname, amsCloudObj["hostname"], sizeof(newConfig.hostname)); - } - if(amsCloudObj.containsKey("port")) { - newConfig.port = amsCloudObj["port"]; - } - if(amsCloudObj.containsKey("clientId")) { - strlcpy((char*)newConfig.clientId, amsCloudObj["clientId"], sizeof(newConfig.clientId)); - } - if(amsCloudObj.containsKey("proto")) { - newConfig.proto = amsCloudObj["proto"]; - } - config->setCloudConfig(newConfig); - } - - if(cloudObj.containsKey("zmartCharge")) { - ZmartChargeConfig newConfig; - config->getZmartChargeConfig(newConfig); - JsonObject zmartChargeObj = cloudObj["zmartCharge"]; - if(zmartChargeObj.containsKey("enabled")) { - newConfig.enabled = zmartChargeObj["enabled"]; - } - if(zmartChargeObj.containsKey("token")) { - strlcpy(newConfig.token, zmartChargeObj["token"], sizeof(newConfig.token)); - } - if(zmartChargeObj.containsKey("baseUrl")) { - strlcpy(newConfig.baseUrl, zmartChargeObj["baseUrl"], sizeof(newConfig.baseUrl)); - } - config->setZmartChargeConfig(newConfig); - } - } + } else if(strcmp_P(action, PSTR("config")) == 0 && obj.containsKey(F("config"))) { + JsonObject configObj = obj[F("config")]; + handleConfigMessage(configObj); } } } - } else if(payload.equals("fwupgrade")) { + } else if(payload.equals(F("fwupgrade"))) { if(strcmp(updater->getNextVersion(), FirmwareVersion::VersionString) != 0) { updater->setTargetVersion(updater->getNextVersion()); } - } else if(payload.equals("dayplot")) { + } else if(payload.equals(F("dayplot"))) { char pubTopic[192]; snprintf_P(pubTopic, 192, PSTR("%s/dayplot"), mqttConfig.publishTopic); AmsJsonGenerator::generateDayPlotJson(ds, json, BufferSize); bool ret = mqtt.publish(pubTopic, json); loop(); - } else if(payload.equals("monthplot")) { + } else if(payload.equals(F("monthplot"))) { char pubTopic[192]; snprintf_P(pubTopic, 192, PSTR("%s/monthplot"), mqttConfig.publishTopic); AmsJsonGenerator::generateMonthPlotJson(ds, json, BufferSize); @@ -970,6 +581,469 @@ void JsonMqttHandler::onMessage(String &topic, String &payload) { } } +void JsonMqttHandler::handleConfigMessage(JsonObject& configObj) { + // General + if(configObj.containsKey(F("g"))) { + JsonObject generalObj = configObj[F("g")]; + if(generalObj.containsKey(F("t"))) { + NtpConfig ntpConfig; + config->getNtpConfig(ntpConfig); + strlcpy(ntpConfig.timezone, generalObj[F("t")], sizeof(ntpConfig.timezone)); + config->setNtpConfig(ntpConfig); + } + if(generalObj.containsKey(F("h"))) { + NetworkConfig networkConfig; + config->getNetworkConfig(networkConfig); + strlcpy(networkConfig.hostname, generalObj[F("h")], sizeof(networkConfig.hostname)); + config->setNetworkConfig(networkConfig); + } + + WebConfig webConfig; + config->getWebConfig(webConfig); + if(generalObj.containsKey(F("s"))) { + webConfig.security = generalObj[F("s")]; + } + if(webConfig.security > 0) { + if(generalObj.containsKey(F("u"))) { + strlcpy(webConfig.username, generalObj[F("u")], sizeof(webConfig.username)); + } + if(generalObj.containsKey(F("p"))) { + strlcpy(webConfig.password, generalObj[F("p")], sizeof(webConfig.password)); + } + } + if(generalObj.containsKey(F("c"))) { + strlcpy(webConfig.context, generalObj[F("c")], sizeof(webConfig.context)); + } + config->setWebConfig(webConfig); + } + + // Meter + if(configObj.containsKey(F("m"))) { + JsonObject meterObj = configObj[F("m")]; + MeterConfig newConfig; + config->getMeterConfig(newConfig); + + if(meterObj.containsKey(F("o"))) { + newConfig.source = meterObj[F("o")]; + } + if(meterObj.containsKey(F("a"))) { + newConfig.parser = meterObj[F("a")]; + } + if(meterObj.containsKey(F("b"))) { + newConfig.baud = meterObj[F("b")]; + } + if(meterObj.containsKey(F("p"))) { + // TODO, string to enum + newConfig.parity = meterObj[F("p")]; + } + if(meterObj.containsKey(F("i"))) { + newConfig.invert = meterObj[F("i")]; + } + if(meterObj.containsKey(F("s"))) { + newConfig.bufferSize = meterObj[F("s")] / 64; // convert from bytes to 64 byte blocks + } + if(meterObj.containsKey(F("d"))) { + newConfig.distributionSystem = meterObj[F("d")]; + } + if(meterObj.containsKey(F("f"))) { + newConfig.mainFuse = meterObj[F("f")]; + } + if(meterObj.containsKey(F("r"))) { + newConfig.productionCapacity = meterObj[F("r")]; + } + if(meterObj.containsKey(F("e"))) { + JsonObject encryptionObj = meterObj[F("e")]; + if(encryptionObj.containsKey(F("e"))) { + bool enabled = encryptionObj[F("e")]; + if(enabled) { + if(encryptionObj.containsKey(F("k"))) { + // TODO + } + if(encryptionObj.containsKey(F("a"))) { + // TODO + } + } else { + memset(newConfig.encryptionKey, 0, sizeof(newConfig.encryptionKey)); + memset(newConfig.authenticationKey, 0, sizeof(newConfig.authenticationKey)); + } + } + } + + config->setMeterConfig(newConfig); + } + + if(configObj.containsKey(F("system"))) { + SystemConfig newConfig; + config->getSystemConfig(newConfig); + + JsonObject systemObj = configObj[F("system")]; + if(systemObj.containsKey(F("country"))) { + strlcpy(newConfig.country, systemObj[F("country")], sizeof(newConfig.country)); + } + if(systemObj.containsKey(F("firmwareChannel"))) { + newConfig.firmwareChannel = systemObj[F("firmwareChannel")]; + } + config->setSystemConfig(newConfig); + } + + if(configObj.containsKey(F("network"))) { + NetworkConfig newConfig; + config->getNetworkConfig(newConfig); + + JsonObject networkObj = configObj[F("network")]; + if(networkObj.containsKey(F("mode"))) { + newConfig.mode = networkObj[F("mode")]; + } + if(newConfig.mode == 1 || newConfig.mode == 2) { + if(networkObj.containsKey(F("ssid"))) { + strlcpy(newConfig.ssid, networkObj[F("ssid")], sizeof(newConfig.ssid)); + } + if(networkObj.containsKey(F("psk"))) { + strlcpy(newConfig.psk, networkObj[F("psk")], sizeof(newConfig.psk)); + } + if(networkObj.containsKey(F("power"))) { + newConfig.power = networkObj[F("power")]; + } + if(networkObj.containsKey(F("sleep"))) { + newConfig.sleep = networkObj[F("sleep")]; + } + if(networkObj.containsKey(F("use11b"))) { + newConfig.use11b = networkObj[F("use11b")]; + } + } + if(networkObj.containsKey(F("ip"))) { + strlcpy(newConfig.ip, networkObj[F("ip")], sizeof(newConfig.ip)); + } + if(networkObj.containsKey(F("gateway"))) { + strlcpy(newConfig.gateway, networkObj[F("gateway")], sizeof(newConfig.gateway)); + } + if(networkObj.containsKey(F("subnet"))) { + strlcpy(newConfig.subnet, networkObj[F("subnet")], sizeof(newConfig.subnet)); + } + if(networkObj.containsKey(F("dns1"))) { + strlcpy(newConfig.dns1, networkObj[F("dns1")], sizeof(newConfig.dns1)); + } + if(networkObj.containsKey(F("dns2"))) { + strlcpy(newConfig.dns2, networkObj[F("dns2")], sizeof(newConfig.dns2)); + } + if(networkObj.containsKey(F("mdns"))) { + newConfig.mdns = networkObj[F("mdns")]; + } + if(networkObj.containsKey(F("ipv6"))) { + newConfig.ipv6 = networkObj[F("ipv6")]; + } + config->setNetworkConfig(newConfig); + } + + if(configObj.containsKey(F("meter"))) { + MeterConfig newConfig; + config->getMeterConfig(newConfig); + + JsonObject meterObj = configObj[F("meter")]; + if(meterObj.containsKey(F("baud"))) { + newConfig.baud = meterObj[F("baud")]; + } + if(meterObj.containsKey(F("parity"))) { + newConfig.parity = meterObj[F("parity")]; + } + if(meterObj.containsKey(F("invert"))) { + newConfig.invert = meterObj[F("invert")]; + } + if(meterObj.containsKey(F("distributionSystem"))) { + newConfig.distributionSystem = meterObj[F("distributionSystem")]; + } + if(meterObj.containsKey(F("mainFuse"))) { + newConfig.mainFuse = meterObj[F("mainFuse")]; + } + if(meterObj.containsKey(F("productionCapacity"))) { + newConfig.productionCapacity = meterObj[F("productionCapacity")]; + } + if(meterObj.containsKey(F("wattageMultiplier"))) { + newConfig.wattageMultiplier = meterObj[F("wattageMultiplier")]; + } + if(meterObj.containsKey(F("voltageMultiplier"))) { + newConfig.voltageMultiplier = meterObj[F("voltageMultiplier")]; + } + if(meterObj.containsKey(F("amperageMultiplier"))) { + newConfig.amperageMultiplier = meterObj[F("amperageMultiplier")]; + } + if(meterObj.containsKey(F("accumulatedMultiplier"))) { + newConfig.accumulatedMultiplier = meterObj[F("accumulatedMultiplier")]; + } + if(meterObj.containsKey(F("parser"))) { + newConfig.parser = meterObj[F("parser")]; + } + if(meterObj.containsKey(F("bufferSize"))) { + newConfig.bufferSize = meterObj[F("bufferSize")]; + } + if(meterObj.containsKey(F("rxPin"))) { + newConfig.rxPin = meterObj[F("rxPin")]; + } + if(meterObj.containsKey(F("rxPinPullup"))) { + newConfig.rxPinPullup = meterObj[F("rxPinPullup")]; + } + if(meterObj.containsKey(F("txPin"))) { + newConfig.txPin = meterObj[F("txPin")]; + } + } + + if(configObj.containsKey(F("mqtt"))) { + MqttConfig newConfig; + config->getMqttConfig(newConfig); + + JsonObject mqttObj = configObj[F("mqtt")]; + if(mqttObj.containsKey(F("host"))) { + strlcpy(newConfig.host, mqttObj[F("host")], sizeof(newConfig.host)); + } + if(mqttObj.containsKey(F("port"))) { + newConfig.port = mqttObj[F("port")]; + } + if(mqttObj.containsKey(F("clientId"))) { + strlcpy(newConfig.clientId, mqttObj[F("clientId")], sizeof(newConfig.clientId)); + } + if(mqttObj.containsKey(F("publishTopic"))) { + strlcpy(newConfig.publishTopic, mqttObj[F("publishTopic")], sizeof(newConfig.publishTopic)); + } + if(mqttObj.containsKey(F("subscribeTopic"))) { + strlcpy(newConfig.subscribeTopic, mqttObj[F("subscribeTopic")], sizeof(newConfig.subscribeTopic)); + } + if(mqttObj.containsKey(F("username"))) { + strlcpy(newConfig.username, mqttObj[F("username")], sizeof(newConfig.username)); + } + if(mqttObj.containsKey(F("password"))) { + strlcpy(newConfig.password, mqttObj[F("password")], sizeof(newConfig.password)); + } + if(mqttObj.containsKey(F("payloadFormat"))) { + newConfig.payloadFormat = mqttObj[F("payloadFormat")]; + } + if(mqttObj.containsKey(F("ssl"))) { + newConfig.ssl = mqttObj[F("ssl")]; + } + if(mqttObj.containsKey(F("stateUpdate"))) { + newConfig.stateUpdate = mqttObj[F("stateUpdate")]; + } + if(mqttObj.containsKey(F("stateUpdateInterval"))) { + newConfig.stateUpdateInterval = mqttObj[F("stateUpdateInterval")]; + } + if(mqttObj.containsKey(F("timeout"))) { + newConfig.timeout = mqttObj[F("timeout")]; + } + if(mqttObj.containsKey(F("keepalive"))) { + newConfig.keepalive = mqttObj[F("keepalive")]; + } + if(mqttObj.containsKey(F("rebootMinutes"))) { + newConfig.rebootMinutes = mqttObj[F("rebootMinutes")]; + } + config->setMqttConfig(newConfig); + + if(mqttObj.containsKey(F("domoticz"))) { + DomoticzConfig newConfig; + config->getDomoticzConfig(newConfig); + JsonObject domoticzObj = mqttObj[F("domoticz")]; + if(domoticzObj.containsKey(F("elidx"))) { + newConfig.elidx = domoticzObj[F("elidx")]; + } + if(domoticzObj.containsKey(F("vl1idx"))) { + newConfig.vl1idx = domoticzObj[F("vl1idx")]; + } + if(domoticzObj.containsKey(F("vl2idx"))) { + newConfig.vl2idx = domoticzObj[F("vl2idx")]; + } + if(domoticzObj.containsKey(F("vl3idx"))) { + newConfig.vl3idx = domoticzObj[F("vl3idx")]; + } + if(domoticzObj.containsKey(F("cl1idx"))) { + newConfig.cl1idx = domoticzObj[F("cl1idx")]; + } + config->setDomoticzConfig(newConfig); + } + + if(mqttObj.containsKey(F("homeAssistant"))) { + HomeAssistantConfig newConfig; + config->getHomeAssistantConfig(newConfig); + JsonObject haObj = mqttObj[F("homeAssistant")]; + if(haObj.containsKey(F("discoveryPrefix"))) { + strlcpy(newConfig.discoveryPrefix, haObj[F("discoveryPrefix")], sizeof(newConfig.discoveryPrefix)); + } + if(haObj.containsKey(F("discoveryHostname"))) { + strlcpy(newConfig.discoveryHostname, haObj[F("discoveryHostname")], sizeof(newConfig.discoveryHostname)); + } + if(haObj.containsKey(F("discoveryNameTag"))) { + strlcpy(newConfig.discoveryNameTag, haObj[F("discoveryNameTag")], sizeof(newConfig.discoveryNameTag)); + } + config->setHomeAssistantConfig(newConfig); + } + } + + if(configObj.containsKey(F("debug"))) { + DebugConfig newConfig; + config->getDebugConfig(newConfig); + + JsonObject debugObj = configObj[F("debug")]; + if(debugObj.containsKey(F("telnet"))) { + newConfig.telnet = debugObj[F("telnet")]; + } + if(debugObj.containsKey(F("serial"))) { + newConfig.serial = debugObj[F("serial")]; + } + if(debugObj.containsKey(F("level"))) { + newConfig.level = debugObj[F("level")]; + } + config->setDebugConfig(newConfig); + } + + if(configObj.containsKey(F("gpio"))) { + GpioConfig newConfig; + config->getGpioConfig(newConfig); + + JsonObject gpioObj = configObj[F("gpio")]; + if(gpioObj.containsKey(F("apPin"))) { + newConfig.apPin = gpioObj[F("apPin")]; + } + if(gpioObj.containsKey(F("ledPin"))) { + newConfig.ledPin = gpioObj[F("ledPin")]; + } + if(gpioObj.containsKey(F("ledInverted"))) { + newConfig.ledInverted = gpioObj[F("ledInverted")]; + } + if(gpioObj.containsKey(F("ledPinRed"))) { + newConfig.ledPinRed = gpioObj[F("ledPinRed")]; + } + if(gpioObj.containsKey(F("ledPinGreen"))) { + newConfig.ledPinGreen = gpioObj[F("ledPinGreen")]; + } + if(gpioObj.containsKey(F("ledPinBlue"))) { + newConfig.ledPinBlue = gpioObj[F("ledPinBlue")]; + } + if(gpioObj.containsKey(F("ledRgbInverted"))) { + newConfig.ledRgbInverted = gpioObj[F("ledRgbInverted")]; + } + if(gpioObj.containsKey(F("tempSensorPin"))) { + newConfig.tempSensorPin = gpioObj[F("tempSensorPin")]; + } + if(gpioObj.containsKey(F("tempAnalogSensorPin"))) { + newConfig.tempAnalogSensorPin = gpioObj[F("tempAnalogSensorPin")]; + } + if(gpioObj.containsKey(F("vccPin"))) { + newConfig.vccPin = gpioObj[F("vccPin")]; + } + if(gpioObj.containsKey(F("vccOffset"))) { + newConfig.vccOffset = gpioObj[F("vccOffset")]; + } + if(gpioObj.containsKey(F("vccMultiplier"))) { + newConfig.vccMultiplier = gpioObj[F("vccMultiplier")]; + } + if(gpioObj.containsKey(F("vccBootLimit"))) { + newConfig.vccBootLimit = gpioObj[F("vccBootLimit")]; + } + if(gpioObj.containsKey(F("vccResistorGnd"))) { + newConfig.vccResistorGnd = gpioObj[F("vccResistorGnd")]; + } + if(gpioObj.containsKey(F("vccResistorVcc"))) { + newConfig.vccResistorVcc = gpioObj[F("vccResistorVcc")]; + } + if(gpioObj.containsKey(F("ledDisablePin"))) { + newConfig.ledDisablePin = gpioObj[F("ledDisablePin")]; + } + if(gpioObj.containsKey(F("ledBehaviour"))) { + newConfig.ledBehaviour = gpioObj[F("ledBehaviour")]; + } + config->setGpioConfig(newConfig); + } + + if(configObj.containsKey(F("ntp"))) { + NtpConfig newConfig; + config->getNtpConfig(newConfig); + + JsonObject ntpObj = configObj[F("ntp")]; + if(ntpObj.containsKey(F("enable"))) { + newConfig.enable = ntpObj[F("enable")]; + } + if(ntpObj.containsKey(F("dhcp"))) { + newConfig.dhcp = ntpObj[F("dhcp")]; + } + if(ntpObj.containsKey(F("server"))) { + strlcpy(newConfig.server, ntpObj[F("server")], sizeof(newConfig.server)); + } + config->setNtpConfig(newConfig); + } + + if(configObj.containsKey(F("priceService"))) { + PriceServiceConfig newConfig; + config->getPriceServiceConfig(newConfig); + JsonObject priceServiceObj = configObj[F("priceService")]; + if(priceServiceObj.containsKey(F("area"))) { + strlcpy(newConfig.area, priceServiceObj[F("area")], sizeof(newConfig.area)); + } + if(priceServiceObj.containsKey(F("currency"))) { + strlcpy(newConfig.currency, priceServiceObj[F("currency")], sizeof(newConfig.currency)); + } + if(priceServiceObj.containsKey(F("resolutionInMinutes"))) { + newConfig.resolutionInMinutes = priceServiceObj[F("resolutionInMinutes")]; + } + if(priceServiceObj.containsKey(F("enabled"))) { + newConfig.enabled = priceServiceObj[F("enabled")]; + } + config->setPriceServiceConfig(newConfig); + } + + if(configObj.containsKey(F("cloud"))) { + JsonObject cloudObj = configObj[F("cloud")]; + + if(cloudObj.containsKey(F("amsleser"))) { + CloudConfig newConfig; + config->getCloudConfig(newConfig); + + JsonObject amsCloudObj = cloudObj[F("amsleser")]; + if(amsCloudObj.containsKey(F("enabled"))) { + newConfig.enabled = amsCloudObj[F("enabled")]; + } + if(amsCloudObj.containsKey(F("interval"))) { + newConfig.interval = amsCloudObj[F("interval")]; + } + if(amsCloudObj.containsKey(F("hostname"))) { + strlcpy(newConfig.hostname, amsCloudObj[F("hostname")], sizeof(newConfig.hostname)); + } + if(amsCloudObj.containsKey(F("port"))) { + newConfig.port = amsCloudObj[F("port")]; + } + if(amsCloudObj.containsKey(F("clientId"))) { + strlcpy((char*)newConfig.clientId, amsCloudObj[F("clientId")], sizeof(newConfig.clientId)); + } + if(amsCloudObj.containsKey(F("proto"))) { + newConfig.proto = amsCloudObj[F("proto")]; + } + config->setCloudConfig(newConfig); + } + + if(cloudObj.containsKey(F("zmartcharge"))) { + ZmartChargeConfig newConfig; + config->getZmartChargeConfig(newConfig); + JsonObject zmartChargeObj = cloudObj[F("zmartcharge")]; + if(zmartChargeObj.containsKey(F("enabled"))) { + newConfig.enabled = zmartChargeObj[F("enabled")]; + } + if(zmartChargeObj.containsKey(F("token"))) { + strlcpy(newConfig.token, zmartChargeObj[F("token")], sizeof(newConfig.token)); + } + if(zmartChargeObj.containsKey(F("baseUrl"))) { + strlcpy(newConfig.baseUrl, zmartChargeObj[F("baseUrl")], sizeof(newConfig.baseUrl)); + } + config->setZmartChargeConfig(newConfig); + } + + if(cloudObj.containsKey(F("energyspeedometer"))) { + SystemConfig newConfig; + config->getSystemConfig(newConfig); + JsonObject speedometerObj = cloudObj[F("energyspeedometer")]; + if(speedometerObj.containsKey(F("enabled"))) { + newConfig.energyspeedometer = speedometerObj[F("enabled")]; + } + config->setSystemConfig(newConfig); + } + } +} + void JsonMqttHandler::toJsonIsoTimestamp(time_t t, char* buf, size_t buflen) { memset(buf, 0, buflen); if(t > 0) { diff --git a/lib/SvelteUi/json/conf_cloud.json b/lib/SvelteUi/json/conf_cloud.json deleted file mode 100644 index 7597ace3..00000000 --- a/lib/SvelteUi/json/conf_cloud.json +++ /dev/null @@ -1,7 +0,0 @@ -"c": { - "e" : %s, - "p" : %d, - "es": %s, - "ze": %s, - "zt" : "%s" -} diff --git a/lib/SvelteUi/json/conf_debug.json b/lib/SvelteUi/json/conf_debug.json deleted file mode 100644 index e9ec284b..00000000 --- a/lib/SvelteUi/json/conf_debug.json +++ /dev/null @@ -1,5 +0,0 @@ -"d": { - "s": %s, - "t": %s, - "l": %d -}, diff --git a/lib/SvelteUi/json/conf_domoticz.json b/lib/SvelteUi/json/conf_domoticz.json deleted file mode 100644 index b6528ec9..00000000 --- a/lib/SvelteUi/json/conf_domoticz.json +++ /dev/null @@ -1,7 +0,0 @@ -"o": { - "e" : %d, - "c" : %d, - "u1" : %d, - "u2" : %d, - "u3" : %d -}, diff --git a/lib/SvelteUi/json/conf_general.json b/lib/SvelteUi/json/conf_general.json deleted file mode 100644 index a6577184..00000000 --- a/lib/SvelteUi/json/conf_general.json +++ /dev/null @@ -1,8 +0,0 @@ -"g": { - "t": "%s", - "h": "%s", - "s": %d, - "u": "%s", - "p": "%s", - "c": "%s" -}, \ No newline at end of file diff --git a/lib/SvelteUi/json/conf_gpio.json b/lib/SvelteUi/json/conf_gpio.json deleted file mode 100644 index b435c713..00000000 --- a/lib/SvelteUi/json/conf_gpio.json +++ /dev/null @@ -1,37 +0,0 @@ -"i": { - "h": { - "p": %s, - "u": %s, - "t": %s - }, - "a": %s, - "l": { - "p": %s, - "i": %s - }, - "r": { - "r": %s, - "g": %s, - "b": %s, - "i": %s - }, - "d": { - "d": %s, - "b": %d - }, - "t": { - "d": %s, - "a": %s - }, - "v": { - "p": %s, - "o": %.2f, - "m": %.3f, - "d": { - "v": %d, - "g": %d - }, - "b": %.1f - }, - "p": %d -}, diff --git a/lib/SvelteUi/json/conf_ha.json b/lib/SvelteUi/json/conf_ha.json deleted file mode 100644 index e1e5013e..00000000 --- a/lib/SvelteUi/json/conf_ha.json +++ /dev/null @@ -1,5 +0,0 @@ -"h": { - "t" : "%s", - "h" : "%s", - "n" : "%s" -}, diff --git a/lib/SvelteUi/json/conf_meter.json b/lib/SvelteUi/json/conf_meter.json deleted file mode 100644 index 52bfe390..00000000 --- a/lib/SvelteUi/json/conf_meter.json +++ /dev/null @@ -1,23 +0,0 @@ -"m": { - "o": %d, - "a": %d, - "b": %d, - "p": %d, - "i": %s, - "s": %d, - "d": %d, - "f": %d, - "r": %d, - "e": { - "e": %s, - "k": "%s", - "a": "%s" - }, - "m": { - "e": %s, - "w": %.3f, - "v": %.3f, - "a": %.3f, - "c": %.3f - } -}, \ No newline at end of file diff --git a/lib/SvelteUi/json/conf_mqtt.json b/lib/SvelteUi/json/conf_mqtt.json deleted file mode 100644 index efcf0325..00000000 --- a/lib/SvelteUi/json/conf_mqtt.json +++ /dev/null @@ -1,21 +0,0 @@ -"q": { - "h": "%s", - "p": %d, - "u": "%s", - "a": "%s", - "c": "%s", - "b": "%s", - "r": "%s", - "m": %d, - "s": { - "e": %s, - "c": %s, - "r": %s, - "k": %s - }, - "t": %d, - "d": %d, - "i": %d, - "k": %d, - "e": %s -}, diff --git a/lib/SvelteUi/json/conf_net.json b/lib/SvelteUi/json/conf_net.json deleted file mode 100644 index 5a3fc9eb..00000000 --- a/lib/SvelteUi/json/conf_net.json +++ /dev/null @@ -1,13 +0,0 @@ -"n": { - "c": %d, - "m": "%s", - "i": "%s", - "s": "%s", - "g": "%s", - "d1": "%s", - "d2": "%s", - "d": %s, - "n1": "%s", - "h": %s, - "x": %s -}, diff --git a/lib/SvelteUi/json/conf_price.json b/lib/SvelteUi/json/conf_price.json deleted file mode 100644 index e8d0125c..00000000 --- a/lib/SvelteUi/json/conf_price.json +++ /dev/null @@ -1,7 +0,0 @@ -"p": { - "e": %s, - "t": "%s", - "r": "%s", - "c": "%s", - "m": %d -}, \ No newline at end of file diff --git a/lib/SvelteUi/json/conf_price_row.json b/lib/SvelteUi/json/conf_price_row.json deleted file mode 100644 index 6fffd02a..00000000 --- a/lib/SvelteUi/json/conf_price_row.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "t" : %d, - "n" : "%s", - "d" : %d, - "a" : [%s], - "h" : [%s], - "v" : %.4f, - "s" : { "m":%d,"d":%d}, - "e" : { "m":%d,"d":%d} -}%s \ No newline at end of file diff --git a/lib/SvelteUi/json/conf_thresholds.json b/lib/SvelteUi/json/conf_thresholds.json deleted file mode 100644 index fd911368..00000000 --- a/lib/SvelteUi/json/conf_thresholds.json +++ /dev/null @@ -1,15 +0,0 @@ -"t": { - "t": [ - %d, - %d, - %d, - %d, - %d, - %d, - %d, - %d, - %d, - %d - ], - "h": %d -}, \ No newline at end of file diff --git a/lib/SvelteUi/json/conf_ui.json b/lib/SvelteUi/json/conf_ui.json deleted file mode 100644 index 1231d954..00000000 --- a/lib/SvelteUi/json/conf_ui.json +++ /dev/null @@ -1,18 +0,0 @@ -"u": { - "i": %d, - "e": %d, - "v": %d, - "a": %d, - "r": %d, - "c": %d, - "t": %d, - "p": %d, - "d": %d, - "m": %d, - "s": %d, - "l": %d, - "h": %d, - "f": %d, - "k": %d, - "lang" : "%s" -}, \ No newline at end of file diff --git a/lib/SvelteUi/json/conf_wifi.json b/lib/SvelteUi/json/conf_wifi.json deleted file mode 100644 index 81a565e6..00000000 --- a/lib/SvelteUi/json/conf_wifi.json +++ /dev/null @@ -1,7 +0,0 @@ -"w": { - "s": "%s", - "p": "%s", - "w": %.1f, - "z": %d, - "b": %s -}, diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp index d036b163..b4033891 100644 --- a/lib/SvelteUi/src/AmsWebServer.cpp +++ b/lib/SvelteUi/src/AmsWebServer.cpp @@ -19,20 +19,6 @@ #include "html/response_json.h" #include "html/sysinfo_json.h" #include "html/tariff_json.h" -#include "html/conf_general_json.h" -#include "html/conf_meter_json.h" -#include "html/conf_wifi_json.h" -#include "html/conf_net_json.h" -#include "html/conf_mqtt_json.h" -#include "html/conf_price_json.h" -#include "html/conf_price_row_json.h" -#include "html/conf_thresholds_json.h" -#include "html/conf_debug_json.h" -#include "html/conf_gpio_json.h" -#include "html/conf_domoticz_json.h" -#include "html/conf_ha_json.h" -#include "html/conf_ui_json.h" -#include "html/conf_cloud_json.h" #include "html/firmware_html.h" #if defined(ESP32) @@ -892,244 +878,14 @@ void AmsWebServer::configurationJson() { if(!checkSecurity(1)) return; - - MeterConfig meterConfig; - config->getMeterConfig(meterConfig); - - bool multEnable = false; - if(meterConfig.wattageMultiplier != 1.0 && meterConfig.wattageMultiplier != 0.0) - multEnable = true; - if(meterConfig.voltageMultiplier != 1.0 && meterConfig.voltageMultiplier != 0.0) - multEnable = true; - if(meterConfig.amperageMultiplier != 1.0 && meterConfig.amperageMultiplier != 0.0) - multEnable = true; - if(meterConfig.accumulatedMultiplier != 1.0 && meterConfig.accumulatedMultiplier != 0.0) - multEnable = true; - - SystemConfig sysConfig; - config->getSystemConfig(sysConfig); - NtpConfig ntpConfig; - config->getNtpConfig(ntpConfig); - NetworkConfig networkConfig; - config->getNetworkConfig(networkConfig); - - bool encen = false; - for(uint8_t i = 0; i < 16; i++) { - if(meterConfig.encryptionKey[i] > 0) { - encen = true; - } - } - - EnergyAccountingConfig* eac = ea->getConfig(); - MqttConfig mqttConfig; - config->getMqttConfig(mqttConfig); - - PriceServiceConfig price; - config->getPriceServiceConfig(price); - DebugConfig debugConfig; - config->getDebugConfig(debugConfig); - DomoticzConfig domo; - config->getDomoticzConfig(domo); - UiConfig ui; - config->getUiConfig(ui); - HomeAssistantConfig haconf; - config->getHomeAssistantConfig(haconf); - CloudConfig cloud; - config->getCloudConfig(cloud); - ZmartChargeConfig zcc; - config->getZmartChargeConfig(zcc); - stripNonAscii((uint8_t*) zcc.token, 21); - - bool qsc = false; - bool qsr = false; - bool qsk = false; - - if(LittleFS.begin()) { - qsc = LittleFS.exists(FILE_MQTT_CA); - qsr = LittleFS.exists(FILE_MQTT_CERT); - qsk = LittleFS.exists(FILE_MQTT_KEY); - } - addConditionalCloudHeaders(); server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE); server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE); server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF); server.setContentLength(CONTENT_LENGTH_UNKNOWN); - server.send_P(200, MIME_JSON, PSTR("{\"version\":\"")); - server.sendContent_P(FirmwareVersion::VersionString); - server.sendContent_P(PSTR("\",")); - snprintf_P(buf, BufferSize, CONF_GENERAL_JSON, - ntpConfig.timezone, - networkConfig.hostname, - webConfig.security, - webConfig.username, - strlen(webConfig.password) > 0 ? "***" : "", - webConfig.context - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_METER_JSON, - meterConfig.source, - meterConfig.parser, - meterConfig.baud, - meterConfig.parity, - meterConfig.invert ? "true" : "false", - meterConfig.bufferSize * 64, - meterConfig.distributionSystem, - meterConfig.mainFuse, - meterConfig.productionCapacity, - encen ? "true" : "false", - toHex(meterConfig.encryptionKey, 16).c_str(), - toHex(meterConfig.authenticationKey, 16).c_str(), - multEnable ? "true" : "false", - meterConfig.wattageMultiplier == 0.0 ? 1.0 : meterConfig.wattageMultiplier / 1000.0, - meterConfig.voltageMultiplier == 0.0 ? 1.0 : meterConfig.voltageMultiplier / 1000.0, - meterConfig.amperageMultiplier == 0.0 ? 1.0 : meterConfig.amperageMultiplier / 1000.0, - meterConfig.accumulatedMultiplier == 0.0 ? 1.0 : meterConfig.accumulatedMultiplier / 1000.0 - ); - server.sendContent(buf); - - snprintf_P(buf, BufferSize, CONF_THRESHOLDS_JSON, - eac->thresholds[0], - eac->thresholds[1], - eac->thresholds[2], - eac->thresholds[3], - eac->thresholds[4], - eac->thresholds[5], - eac->thresholds[6], - eac->thresholds[7], - eac->thresholds[8], - eac->thresholds[9], - eac->hours - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_WIFI_JSON, - networkConfig.ssid, - strlen(networkConfig.psk) > 0 ? "***" : "", - networkConfig.power / 10.0, - networkConfig.sleep, - networkConfig.use11b ? "true" : "false" - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_NET_JSON, - networkConfig.mode, - strlen(networkConfig.ip) > 0 ? "static" : "dhcp", - networkConfig.ip, - networkConfig.subnet, - networkConfig.gateway, - networkConfig.dns1, - networkConfig.dns2, - networkConfig.mdns ? "true" : "false", - ntpConfig.server, - ntpConfig.dhcp ? "true" : "false", - networkConfig.ipv6 ? "true" : "false" - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_MQTT_JSON, - mqttConfig.host, - mqttConfig.port, - mqttConfig.username, - strlen(mqttConfig.password) > 0 ? "***" : "", - mqttConfig.clientId, - mqttConfig.publishTopic, - mqttConfig.subscribeTopic, - mqttConfig.payloadFormat, - mqttConfig.ssl ? "true" : "false", - qsc ? "true" : "false", - qsr ? "true" : "false", - qsk ? "true" : "false", - mqttConfig.stateUpdate, - mqttConfig.stateUpdateInterval, - mqttConfig.timeout, - mqttConfig.keepalive, - mqttConfig.rebootMinutes == 0 ? "null" : String(mqttConfig.rebootMinutes, 10).c_str() - ); - server.sendContent(buf); - - snprintf_P(buf, BufferSize, CONF_PRICE_JSON, - price.enabled ? "true" : "false", - price.entsoeToken, - price.area, - price.currency, - price.resolutionInMinutes - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_DEBUG_JSON, - debugConfig.serial ? "true" : "false", - debugConfig.telnet ? "true" : "false", - debugConfig.level - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_GPIO_JSON, - meterConfig.rxPin == 0xff ? "null" : String(meterConfig.rxPin, 10).c_str(), - meterConfig.rxPinPullup ? "true" : "false", - meterConfig.txPin == 0xff ? "null" : String(meterConfig.txPin, 10).c_str(), - gpioConfig->apPin == 0xff ? "null" : String(gpioConfig->apPin, 10).c_str(), - gpioConfig->ledPin == 0xff ? "null" : String(gpioConfig->ledPin, 10).c_str(), - gpioConfig->ledInverted ? "true" : "false", - gpioConfig->ledPinRed == 0xff ? "null" : String(gpioConfig->ledPinRed, 10).c_str(), - gpioConfig->ledPinGreen == 0xff ? "null" : String(gpioConfig->ledPinGreen, 10).c_str(), - gpioConfig->ledPinBlue == 0xff ? "null" : String(gpioConfig->ledPinBlue, 10).c_str(), - gpioConfig->ledRgbInverted ? "true" : "false", - gpioConfig->ledDisablePin == 0xff ? "null" : String(gpioConfig->ledDisablePin, 10).c_str(), - gpioConfig->ledBehaviour, - gpioConfig->tempSensorPin == 0xff ? "null" : String(gpioConfig->tempSensorPin, 10).c_str(), - gpioConfig->tempAnalogSensorPin == 0xff ? "null" : String(gpioConfig->tempAnalogSensorPin, 10).c_str(), - gpioConfig->vccPin == 0xff ? "null" : String(gpioConfig->vccPin, 10).c_str(), - gpioConfig->vccOffset / 100.0, - gpioConfig->vccMultiplier / 1000.0, - gpioConfig->vccResistorVcc, - gpioConfig->vccResistorGnd, - gpioConfig->vccBootLimit / 10.0, - gpioConfig->powersaving - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_UI_JSON, - ui.showImport, - ui.showExport, - ui.showVoltage, - ui.showAmperage, - ui.showReactive, - ui.showRealtime, - ui.showPeaks, - ui.showPricePlot, - ui.showDayPlot, - ui.showMonthPlot, - ui.showTemperaturePlot, - ui.showRealtimePlot, - ui.showPerPhasePower, - ui.showPowerFactor, - ui.darkMode, - ui.language - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_DOMOTICZ_JSON, - domo.elidx, - domo.cl1idx, - domo.vl1idx, - domo.vl2idx, - domo.vl3idx - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_HA_JSON, - haconf.discoveryPrefix, - haconf.discoveryHostname, - haconf.discoveryNameTag - ); - server.sendContent(buf); - snprintf_P(buf, BufferSize, CONF_CLOUD_JSON, - cloud.enabled ? "true" : "false", - cloud.proto, - #if defined(ESP32) && defined(ENERGY_SPEEDOMETER_PASS) - sysConfig.energyspeedometer == 7 ? "true" : "false", - #else - "null", - #endif - zcc.enabled ? "true" : "false", - zcc.token - ); - server.sendContent(buf); - server.sendContent_P(PSTR("}")); + AmsJsonGenerator::generateConfigurationJson(config, buf, BufferSize); + server.send(200, MIME_JSON, buf); } void AmsWebServer::priceConfigJson() { @@ -1165,7 +921,7 @@ void AmsWebServer::priceConfigJson() { } hours = hours.substring(0, hours.length()-1); - snprintf_P(buf, BufferSize, CONF_PRICE_ROW_JSON, + snprintf_P(buf, BufferSize, PSTR("{\"t\":%d,\"n\":\"%s\",\"d\":%d,\"a\":[%s],\"h\":[%s],\"v\":%.4f,\"s\":{\"m\":%d,\"d\":%d},\"e\":{\"m\":%d,\"d\":%d}}%s"), p.type, p.name, p.direction,