From 09740192c121f30404ff2e2c19642e62d1897a2a Mon Sep 17 00:00:00 2001 From: Bernhard Kirchen Date: Thu, 17 Oct 2024 21:46:32 +0200 Subject: [PATCH] WIP: config write guard --- include/Configuration.h | 24 ++++++++++- src/Battery.cpp | 4 +- src/Configuration.cpp | 64 ++++++++++++++++++++++++++++- src/JkBmsController.cpp | 4 +- src/MqttHandleBatteryHass.cpp | 4 +- src/MqttHandleVedirect.cpp | 2 +- src/VictronMppt.cpp | 2 +- src/WebApi.cpp | 4 +- src/WebApi_Huawei.cpp | 30 ++++++++------ src/WebApi_battery.cpp | 7 +++- src/WebApi_device.cpp | 35 +++++++++------- src/WebApi_dtu.cpp | 49 +++++++++++++++++----- src/WebApi_inverter.cpp | 76 +++++++++++++++++++---------------- src/WebApi_mqtt.cpp | 75 +++++++++++++++++----------------- src/WebApi_network.cpp | 71 ++++++++++++++++---------------- src/WebApi_ntp.cpp | 18 +++++---- src/WebApi_powerlimiter.cpp | 74 ++++++++++++++++++---------------- src/WebApi_powermeter.cpp | 27 +++++++------ src/WebApi_security.cpp | 9 +++-- src/WebApi_vedirect.cpp | 11 +++-- src/main.cpp | 16 +------- 21 files changed, 373 insertions(+), 233 deletions(-) diff --git a/include/Configuration.h b/include/Configuration.h index 49b1c60cc..876e279eb 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -4,6 +4,9 @@ #include "PinMapping.h" #include #include +#include +#include +#include #define CONFIG_FILENAME "/config.json" #define CONFIG_VERSION 0x00011c00 // 0.1.28 // make sure to clean all after change @@ -333,11 +336,23 @@ struct CONFIG_T { class ConfigurationClass { public: - void init(); + void init(Scheduler& scheduler); bool read(); bool write(); void migrate(); - CONFIG_T& get(); + CONFIG_T const& get(); + + class WriteGuard { + public: + WriteGuard(); + CONFIG_T& getConfig(); + ~WriteGuard(); + + private: + std::unique_lock _lock; + }; + + WriteGuard getWriteGuard(); INVERTER_CONFIG_T* getFreeInverterSlot(); INVERTER_CONFIG_T* getInverterConfig(const uint64_t serial); @@ -356,6 +371,11 @@ class ConfigurationClass { static void deserializePowerMeterHttpJsonConfig(JsonObject const& source, PowerMeterHttpJsonConfig& target); static void deserializePowerMeterHttpSmlConfig(JsonObject const& source, PowerMeterHttpSmlConfig& target); static void deserializeBatteryConfig(JsonObject const& source, BatteryConfig& target); + +private: + void loop(); + + Task _loopTask; }; extern ConfigurationClass Configuration; diff --git a/src/Battery.cpp b/src/Battery.cpp index 106888e2b..c6f574921 100644 --- a/src/Battery.cpp +++ b/src/Battery.cpp @@ -41,7 +41,7 @@ void BatteryClass::updateSettings() _upProvider = nullptr; } - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (!config.Battery.Enabled) { return; } bool verboseLogging = config.Battery.VerboseLogging; @@ -86,7 +86,7 @@ void BatteryClass::loop() float BatteryClass::getDischargeCurrentLimit() { - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (!config.Battery.EnableDischargeCurrentLimit) { return FLT_MAX; } diff --git a/src/Configuration.cpp b/src/Configuration.cpp index b260ccee2..41e4ee794 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -12,8 +12,17 @@ CONFIG_T config; -void ConfigurationClass::init() +static std::condition_variable sWriterCv; +static std::mutex sWriterMutex; +static unsigned sWriterCount = 0; + +void ConfigurationClass::init(Scheduler& scheduler) { + scheduler.addTask(_loopTask); + _loopTask.setCallback(std::bind(&ConfigurationClass::loop, this)); + _loopTask.setIterations(TASK_FOREVER); + _loopTask.enable(); + memset(&config, 0x0, sizeof(config)); } @@ -662,6 +671,20 @@ bool ConfigurationClass::read() config.Huawei.Auto_Power_Target_Power_Consumption = huawei["target_power_consumption"] | HUAWEI_AUTO_POWER_TARGET_POWER_CONSUMPTION; f.close(); + + // Check for default DTU serial + MessageOutput.print("Check for default DTU serial... "); + if (config.Dtu.Serial == DTU_SERIAL) { + MessageOutput.print("generate serial based on ESP chip id: "); + const uint64_t dtuId = Utils::generateDtuSerial(); + MessageOutput.printf("%0" PRIx32 "%08" PRIx32 "... ", + ((uint32_t)((dtuId >> 32) & 0xFFFFFFFF)), + ((uint32_t)(dtuId & 0xFFFFFFFF))); + config.Dtu.Serial = dtuId; + Configuration.write(); + } + MessageOutput.println("done"); + return true; } @@ -734,11 +757,16 @@ void ConfigurationClass::migrate() read(); } -CONFIG_T& ConfigurationClass::get() +CONFIG_T const& ConfigurationClass::get() { return config; } +ConfigurationClass::WriteGuard ConfigurationClass::getWriteGuard() +{ + return WriteGuard(); +} + INVERTER_CONFIG_T* ConfigurationClass::getFreeInverterSlot() { for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { @@ -783,4 +811,36 @@ void ConfigurationClass::deleteInverterById(const uint8_t id) } } +void ConfigurationClass::loop() +{ + std::unique_lock lock(sWriterMutex); + if (sWriterCount == 0) { return; } + + MessageOutput.println("notify all"); + sWriterCv.notify_all(); + MessageOutput.println("waiting for writers to finish"); + sWriterCv.wait(lock, [] { return sWriterCount == 0; }); + MessageOutput.println("configurationclass::loop done"); +} + +CONFIG_T& ConfigurationClass::WriteGuard::getConfig() +{ + return config; +} + +ConfigurationClass::WriteGuard::WriteGuard() + : _lock(sWriterMutex) +{ + MessageOutput.println("writeguard c'tor locked mutex"); + sWriterCount++; + MessageOutput.println("writeguard c'tor incremented writer count"); + sWriterCv.wait(_lock); + MessageOutput.println("writeguard c'tor completed"); +} + +ConfigurationClass::WriteGuard::~WriteGuard() { + sWriterCount--; + if (sWriterCount == 0) { sWriterCv.notify_all(); } +} + ConfigurationClass Configuration; diff --git a/src/JkBmsController.cpp b/src/JkBmsController.cpp index db1a2d5b7..0a53ec2f2 100644 --- a/src/JkBmsController.cpp +++ b/src/JkBmsController.cpp @@ -68,7 +68,7 @@ void Controller::deinit() Controller::Interface Controller::getInterface() const { - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (0x00 == config.Battery.JkBmsInterface) { return Interface::Uart; } if (0x01 == config.Battery.JkBmsInterface) { return Interface::Transceiver; } return Interface::Invalid; @@ -141,7 +141,7 @@ void Controller::sendRequest(uint8_t pollInterval) void Controller::loop() { - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); uint8_t pollInterval = config.Battery.JkBmsPollingInterval; while (_upSerial->available()) { diff --git a/src/MqttHandleBatteryHass.cpp b/src/MqttHandleBatteryHass.cpp index b2af9e66b..e69d341aa 100644 --- a/src/MqttHandleBatteryHass.cpp +++ b/src/MqttHandleBatteryHass.cpp @@ -21,7 +21,7 @@ void MqttHandleBatteryHassClass::init(Scheduler& scheduler) void MqttHandleBatteryHassClass::loop() { - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (!config.Battery.Enabled) { return; } @@ -323,7 +323,7 @@ void MqttHandleBatteryHassClass::createDeviceInfo(JsonObject& object) { object["name"] = "Battery(" + serial + ")"; - auto& config = Configuration.get(); + auto const& config = Configuration.get(); if (config.Battery.Provider == 1) { object["name"] = "JK BMS (" + Battery.getStats()->getManufacturer() + ")"; } diff --git a/src/MqttHandleVedirect.cpp b/src/MqttHandleVedirect.cpp index c244afc68..4dec5c1a6 100644 --- a/src/MqttHandleVedirect.cpp +++ b/src/MqttHandleVedirect.cpp @@ -35,7 +35,7 @@ void MqttHandleVedirectClass::forceUpdate() void MqttHandleVedirectClass::loop() { - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (!MqttSettings.getConnected() || !config.Vedirect.Enabled) { return; diff --git a/src/VictronMppt.cpp b/src/VictronMppt.cpp index a994e20d6..aa68b551a 100644 --- a/src/VictronMppt.cpp +++ b/src/VictronMppt.cpp @@ -27,7 +27,7 @@ void VictronMpptClass::updateSettings() } _serialPortOwners.clear(); - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (!config.Vedirect.Enabled) { return; } const PinMapping_t& pin = PinMapping.get(); diff --git a/src/WebApi.cpp b/src/WebApi.cpp index 7d23e5fb5..892bd947f 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -58,7 +58,7 @@ void WebApiClass::reload() bool WebApiClass::checkCredentials(AsyncWebServerRequest* request) { - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (request->authenticate(AUTH_USERNAME, config.Security.Password)) { return true; } @@ -76,7 +76,7 @@ bool WebApiClass::checkCredentials(AsyncWebServerRequest* request) bool WebApiClass::checkCredentialsReadonly(AsyncWebServerRequest* request) { - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); if (config.Security.AllowReadonly) { return true; } else { diff --git a/src/WebApi_Huawei.cpp b/src/WebApi_Huawei.cpp index e836842e7..b929cfb16 100644 --- a/src/WebApi_Huawei.cpp +++ b/src/WebApi_Huawei.cpp @@ -200,19 +200,22 @@ void WebApiHuaweiClass::onAdminPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - config.Huawei.Enabled = root["enabled"].as(); - config.Huawei.VerboseLogging = root["verbose_logging"]; - config.Huawei.CAN_Controller_Frequency = root["can_controller_frequency"].as(); - config.Huawei.Auto_Power_Enabled = root["auto_power_enabled"].as(); - config.Huawei.Auto_Power_BatterySoC_Limits_Enabled = root["auto_power_batterysoc_limits_enabled"].as(); - config.Huawei.Emergency_Charge_Enabled = root["emergency_charge_enabled"].as(); - config.Huawei.Auto_Power_Voltage_Limit = root["voltage_limit"].as(); - config.Huawei.Auto_Power_Enable_Voltage_Limit = root["enable_voltage_limit"].as(); - config.Huawei.Auto_Power_Lower_Power_Limit = root["lower_power_limit"].as(); - config.Huawei.Auto_Power_Upper_Power_Limit = root["upper_power_limit"].as(); - config.Huawei.Auto_Power_Stop_BatterySoC_Threshold = root["stop_batterysoc_threshold"]; - config.Huawei.Auto_Power_Target_Power_Consumption = root["target_power_consumption"]; + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + config.Huawei.Enabled = root["enabled"].as(); + config.Huawei.VerboseLogging = root["verbose_logging"]; + config.Huawei.CAN_Controller_Frequency = root["can_controller_frequency"].as(); + config.Huawei.Auto_Power_Enabled = root["auto_power_enabled"].as(); + config.Huawei.Auto_Power_BatterySoC_Limits_Enabled = root["auto_power_batterysoc_limits_enabled"].as(); + config.Huawei.Emergency_Charge_Enabled = root["emergency_charge_enabled"].as(); + config.Huawei.Auto_Power_Voltage_Limit = root["voltage_limit"].as(); + config.Huawei.Auto_Power_Enable_Voltage_Limit = root["enable_voltage_limit"].as(); + config.Huawei.Auto_Power_Lower_Power_Limit = root["lower_power_limit"].as(); + config.Huawei.Auto_Power_Upper_Power_Limit = root["upper_power_limit"].as(); + config.Huawei.Auto_Power_Stop_BatterySoC_Threshold = root["stop_batterysoc_threshold"]; + config.Huawei.Auto_Power_Target_Power_Consumption = root["target_power_consumption"]; + } WebApi.writeConfig(retMsg); @@ -226,6 +229,7 @@ void WebApiHuaweiClass::onAdminPost(AsyncWebServerRequest* request) yield(); ESP.restart(); + auto const& config = Configuration.get(); const PinMapping_t& pin = PinMapping.get(); // Properly turn this on if (config.Huawei.Enabled) { diff --git a/src/WebApi_battery.cpp b/src/WebApi_battery.cpp index bc3081e9a..681c88bc4 100644 --- a/src/WebApi_battery.cpp +++ b/src/WebApi_battery.cpp @@ -70,8 +70,11 @@ void WebApiBatteryClass::onAdminPost(AsyncWebServerRequest* request) return; } - auto& config = Configuration.get(); - ConfigurationClass::deserializeBatteryConfig(root.as(), config.Battery); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + ConfigurationClass::deserializeBatteryConfig(root.as(), config.Battery); + } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_device.cpp b/src/WebApi_device.cpp index 405602241..d3b057742 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -158,23 +158,28 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - bool performRestart = root["curPin"]["name"].as() != config.Dev_PinMapping; - - strlcpy(config.Dev_PinMapping, root["curPin"]["name"].as().c_str(), sizeof(config.Dev_PinMapping)); - config.Display.Rotation = root["display"]["rotation"].as(); - config.Display.PowerSafe = root["display"]["power_safe"].as(); - config.Display.ScreenSaver = root["display"]["screensaver"].as(); - config.Display.Contrast = root["display"]["contrast"].as(); - config.Display.Language = root["display"]["language"].as(); - config.Display.Diagram.Duration = root["display"]["diagramduration"].as(); - config.Display.Diagram.Mode = root["display"]["diagrammode"].as(); - - for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) { - config.Led_Single[i].Brightness = root["led"][i]["brightness"].as(); - config.Led_Single[i].Brightness = min(100, config.Led_Single[i].Brightness); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + + strlcpy(config.Dev_PinMapping, root["curPin"]["name"].as().c_str(), sizeof(config.Dev_PinMapping)); + config.Display.Rotation = root["display"]["rotation"].as(); + config.Display.PowerSafe = root["display"]["power_safe"].as(); + config.Display.ScreenSaver = root["display"]["screensaver"].as(); + config.Display.Contrast = root["display"]["contrast"].as(); + config.Display.Language = root["display"]["language"].as(); + config.Display.Diagram.Duration = root["display"]["diagramduration"].as(); + config.Display.Diagram.Mode = root["display"]["diagrammode"].as(); + + for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) { + config.Led_Single[i].Brightness = root["led"][i]["brightness"].as(); + config.Led_Single[i].Brightness = min(100, config.Led_Single[i].Brightness); + } } + auto const& config = Configuration.get(); + bool performRestart = root["curPin"]["name"].as() != config.Dev_PinMapping; + Display.setDiagramMode(static_cast(config.Display.Diagram.Mode)); Display.setOrientation(config.Display.Rotation); Display.enablePowerSafe = config.Display.PowerSafe; diff --git a/src/WebApi_dtu.cpp b/src/WebApi_dtu.cpp index 8d9f1c431..abe2190c9 100644 --- a/src/WebApi_dtu.cpp +++ b/src/WebApi_dtu.cpp @@ -27,7 +27,7 @@ void WebApiDtuClass::init(AsyncWebServer& server, Scheduler& scheduler) void WebApiDtuClass::applyDataTaskCb() { // Execute stuff in main thread to avoid busy SPI bus - CONFIG_T& config = Configuration.get(); + auto const& config = Configuration.get(); Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu.Nrf.PaLevel); Hoymiles.getRadioCmt()->setPALevel(config.Dtu.Cmt.PaLevel); Hoymiles.getRadioNrf()->setDtuSerial(config.Dtu.Serial); @@ -91,6 +91,33 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) auto& retMsg = response->getRoot(); + auto foo = [&retMsg,&request,&response](char const* what) { + retMsg["message"] = String("Value missing: ") + what; + retMsg["code"] = WebApiError::GenericValueMissing; + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); + }; + + if (!root["serial"].is()) + { return foo("serial"); } + + if (!root["pollinterval"].is()) + { return foo("pollinterval"); } + + if (!root["verbose_logging"].is()) + { return foo("verbose_logging"); } + + if (!root["nrf_palevel"].is()) + { return foo("nrf_palevel"); } + + if (!root["cmt_palevel"].is()) + { return foo("cmt_palevel"); } + + if (!root["cmt_frequency"].is()) + { return foo("cmt_frequency"); } + + if (root["cmt_country"].is()) + { return foo("cmt_country"); } + if (!(root["serial"].is() && root["pollinterval"].is() && root["verbose_logging"].is() @@ -155,15 +182,17 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - - config.Dtu.Serial = serial; - config.Dtu.PollInterval = root["pollinterval"].as(); - config.Dtu.VerboseLogging = root["verbose_logging"].as(); - config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as(); - config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as(); - config.Dtu.Cmt.Frequency = root["cmt_frequency"].as(); - config.Dtu.Cmt.CountryMode = root["cmt_country"].as(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + config.Dtu.Serial = serial; + config.Dtu.PollInterval = root["pollinterval"].as(); + config.Dtu.VerboseLogging = root["verbose_logging"].as(); + config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as(); + config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as(); + config.Dtu.Cmt.Frequency = root["cmt_frequency"].as(); + config.Dtu.Cmt.CountryMode = root["cmt_country"].as(); + } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_inverter.cpp b/src/WebApi_inverter.cpp index ef353158f..d1a8727f5 100644 --- a/src/WebApi_inverter.cpp +++ b/src/WebApi_inverter.cpp @@ -184,9 +184,9 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) } // Interpret the string as a hex value and convert it to uint64_t - const uint64_t serial = strtoll(root["serial"].as().c_str(), NULL, 16); + const uint64_t new_serial = strtoll(root["serial"].as().c_str(), NULL, 16); - if (serial == 0) { + if (new_serial == 0) { retMsg["message"] = "Serial must be a number > 0!"; retMsg["code"] = WebApiError::InverterSerialZero; WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); @@ -209,37 +209,41 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) return; } - INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[root["id"].as()]; - - uint64_t new_serial = serial; - uint64_t old_serial = inverter.Serial; - - // Interpret the string as a hex value and convert it to uint64_t - inverter.Serial = new_serial; - strncpy(inverter.Name, root["name"].as().c_str(), INV_MAX_NAME_STRLEN); - - inverter.Poll_Enable = root["poll_enable"] | true; - inverter.Poll_Enable_Night = root["poll_enable_night"] | true; - inverter.Command_Enable = root["command_enable"] | true; - inverter.Command_Enable_Night = root["command_enable_night"] | true; - inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD; - inverter.ZeroRuntimeDataIfUnrechable = root["zero_runtime"] | false; - inverter.ZeroYieldDayOnMidnight = root["zero_day"] | false; - inverter.ClearEventlogOnMidnight = root["clear_eventlog"] | false; - inverter.YieldDayCorrection = root["yieldday_correction"] | false; - - uint8_t arrayCount = 0; - for (JsonVariant channel : channelArray) { - inverter.channel[arrayCount].MaxChannelPower = channel["max_power"].as(); - inverter.channel[arrayCount].YieldTotalOffset = channel["yield_total_offset"].as(); - strncpy(inverter.channel[arrayCount].Name, channel["name"] | "", sizeof(inverter.channel[arrayCount].Name)); - arrayCount++; + uint64_t old_serial = 0; + + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + INVERTER_CONFIG_T& inverter = config.Inverter[root["id"].as()]; + + old_serial = inverter.Serial; + inverter.Serial = new_serial; + strncpy(inverter.Name, root["name"].as().c_str(), INV_MAX_NAME_STRLEN); + + inverter.Poll_Enable = root["poll_enable"] | true; + inverter.Poll_Enable_Night = root["poll_enable_night"] | true; + inverter.Command_Enable = root["command_enable"] | true; + inverter.Command_Enable_Night = root["command_enable_night"] | true; + inverter.ReachableThreshold = root["reachable_threshold"] | REACHABLE_THRESHOLD; + inverter.ZeroRuntimeDataIfUnrechable = root["zero_runtime"] | false; + inverter.ZeroYieldDayOnMidnight = root["zero_day"] | false; + inverter.ClearEventlogOnMidnight = root["clear_eventlog"] | false; + inverter.YieldDayCorrection = root["yieldday_correction"] | false; + + uint8_t arrayCount = 0; + for (JsonVariant channel : channelArray) { + inverter.channel[arrayCount].MaxChannelPower = channel["max_power"].as(); + inverter.channel[arrayCount].YieldTotalOffset = channel["yield_total_offset"].as(); + strncpy(inverter.channel[arrayCount].Name, channel["name"] | "", sizeof(inverter.channel[arrayCount].Name)); + arrayCount++; + } } WebApi.writeConfig(retMsg, WebApiError::InverterChanged, "Inverter changed!"); WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); + INVERTER_CONFIG_T const& inverter = Configuration.get().Inverter[root["id"].as()]; std::shared_ptr inv = Hoymiles.getInverterBySerial(old_serial); if (inv != nullptr && new_serial != old_serial) { @@ -300,7 +304,7 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request) } uint8_t inverter_id = root["id"].as(); - INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[inverter_id]; + INVERTER_CONFIG_T const& inverter = Configuration.get().Inverter[inverter_id]; Hoymiles.removeInverterBySerial(inverter.Serial); @@ -337,13 +341,17 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request) // The order array contains list or id in the right order JsonArray orderArray = root["order"].as(); uint8_t order = 0; - for (JsonVariant id : orderArray) { - uint8_t inverter_id = id.as(); - if (inverter_id < INV_MAX_COUNT) { - INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[inverter_id]; - inverter.Order = order; + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + for (JsonVariant id : orderArray) { + uint8_t inverter_id = id.as(); + if (inverter_id < INV_MAX_COUNT) { + INVERTER_CONFIG_T& inverter = config.Inverter[inverter_id]; + inverter.Order = order; + } + order++; } - order++; } WebApi.writeConfig(retMsg, WebApiError::InverterOrdered, "Inverter order saved!"); diff --git a/src/WebApi_mqtt.cpp b/src/WebApi_mqtt.cpp index 9f04d6221..5f8138de6 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -282,42 +282,45 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) } } - CONFIG_T& config = Configuration.get(); - config.Mqtt.Enabled = root["mqtt_enabled"].as(); - config.Mqtt.VerboseLogging = root["mqtt_verbose_logging"].as(); - config.Mqtt.Retain = root["mqtt_retain"].as(); - config.Mqtt.Tls.Enabled = root["mqtt_tls"].as(); - strlcpy(config.Mqtt.Tls.RootCaCert, root["mqtt_root_ca_cert"].as().c_str(), sizeof(config.Mqtt.Tls.RootCaCert)); - config.Mqtt.Tls.CertLogin = root["mqtt_tls_cert_login"].as(); - strlcpy(config.Mqtt.Tls.ClientCert, root["mqtt_client_cert"].as().c_str(), sizeof(config.Mqtt.Tls.ClientCert)); - strlcpy(config.Mqtt.Tls.ClientKey, root["mqtt_client_key"].as().c_str(), sizeof(config.Mqtt.Tls.ClientKey)); - config.Mqtt.Port = root["mqtt_port"].as(); - strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as().c_str(), sizeof(config.Mqtt.Hostname)); - strlcpy(config.Mqtt.ClientId, root["mqtt_clientid"].as().c_str(), sizeof(config.Mqtt.ClientId)); - strlcpy(config.Mqtt.Username, root["mqtt_username"].as().c_str(), sizeof(config.Mqtt.Username)); - strlcpy(config.Mqtt.Password, root["mqtt_password"].as().c_str(), sizeof(config.Mqtt.Password)); - strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as().c_str(), sizeof(config.Mqtt.Lwt.Topic)); - strlcpy(config.Mqtt.Lwt.Value_Online, root["mqtt_lwt_online"].as().c_str(), sizeof(config.Mqtt.Lwt.Value_Online)); - strlcpy(config.Mqtt.Lwt.Value_Offline, root["mqtt_lwt_offline"].as().c_str(), sizeof(config.Mqtt.Lwt.Value_Offline)); - config.Mqtt.Lwt.Qos = root["mqtt_lwt_qos"].as(); - config.Mqtt.PublishInterval = root["mqtt_publish_interval"].as(); - config.Mqtt.CleanSession = root["mqtt_clean_session"].as(); - config.Mqtt.Hass.Enabled = root["mqtt_hass_enabled"].as(); - config.Mqtt.Hass.Expire = root["mqtt_hass_expire"].as(); - config.Mqtt.Hass.Retain = root["mqtt_hass_retain"].as(); - config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as(); - strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as().c_str(), sizeof(config.Mqtt.Hass.Topic)); - - // Check if base topic was changed - if (strcmp(config.Mqtt.Topic, root["mqtt_topic"].as().c_str())) { - MqttHandleInverter.unsubscribeTopics(); - MqttHandleHuawei.unsubscribeTopics(); - MqttHandlePowerLimiter.unsubscribeTopics(); - - strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as().c_str(), sizeof(config.Mqtt.Topic)); - MqttHandleInverter.subscribeTopics(); - MqttHandleHuawei.subscribeTopics(); - MqttHandlePowerLimiter.subscribeTopics(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + config.Mqtt.Enabled = root["mqtt_enabled"].as(); + config.Mqtt.VerboseLogging = root["mqtt_verbose_logging"].as(); + config.Mqtt.Retain = root["mqtt_retain"].as(); + config.Mqtt.Tls.Enabled = root["mqtt_tls"].as(); + strlcpy(config.Mqtt.Tls.RootCaCert, root["mqtt_root_ca_cert"].as().c_str(), sizeof(config.Mqtt.Tls.RootCaCert)); + config.Mqtt.Tls.CertLogin = root["mqtt_tls_cert_login"].as(); + strlcpy(config.Mqtt.Tls.ClientCert, root["mqtt_client_cert"].as().c_str(), sizeof(config.Mqtt.Tls.ClientCert)); + strlcpy(config.Mqtt.Tls.ClientKey, root["mqtt_client_key"].as().c_str(), sizeof(config.Mqtt.Tls.ClientKey)); + config.Mqtt.Port = root["mqtt_port"].as(); + strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as().c_str(), sizeof(config.Mqtt.Hostname)); + strlcpy(config.Mqtt.ClientId, root["mqtt_clientid"].as().c_str(), sizeof(config.Mqtt.ClientId)); + strlcpy(config.Mqtt.Username, root["mqtt_username"].as().c_str(), sizeof(config.Mqtt.Username)); + strlcpy(config.Mqtt.Password, root["mqtt_password"].as().c_str(), sizeof(config.Mqtt.Password)); + strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as().c_str(), sizeof(config.Mqtt.Lwt.Topic)); + strlcpy(config.Mqtt.Lwt.Value_Online, root["mqtt_lwt_online"].as().c_str(), sizeof(config.Mqtt.Lwt.Value_Online)); + strlcpy(config.Mqtt.Lwt.Value_Offline, root["mqtt_lwt_offline"].as().c_str(), sizeof(config.Mqtt.Lwt.Value_Offline)); + config.Mqtt.Lwt.Qos = root["mqtt_lwt_qos"].as(); + config.Mqtt.PublishInterval = root["mqtt_publish_interval"].as(); + config.Mqtt.CleanSession = root["mqtt_clean_session"].as(); + config.Mqtt.Hass.Enabled = root["mqtt_hass_enabled"].as(); + config.Mqtt.Hass.Expire = root["mqtt_hass_expire"].as(); + config.Mqtt.Hass.Retain = root["mqtt_hass_retain"].as(); + config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as(); + strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as().c_str(), sizeof(config.Mqtt.Hass.Topic)); + + // Check if base topic was changed + if (strcmp(config.Mqtt.Topic, root["mqtt_topic"].as().c_str())) { + MqttHandleInverter.unsubscribeTopics(); + MqttHandleHuawei.unsubscribeTopics(); + MqttHandlePowerLimiter.unsubscribeTopics(); + + strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as().c_str(), sizeof(config.Mqtt.Topic)); + MqttHandleInverter.subscribeTopics(); + MqttHandleHuawei.subscribeTopics(); + MqttHandlePowerLimiter.subscribeTopics(); + } } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_network.cpp b/src/WebApi_network.cpp index 98ebe23c9..094869a4e 100644 --- a/src/WebApi_network.cpp +++ b/src/WebApi_network.cpp @@ -184,40 +184,43 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) } - CONFIG_T& config = Configuration.get(); - config.WiFi.Ip[0] = ipaddress[0]; - config.WiFi.Ip[1] = ipaddress[1]; - config.WiFi.Ip[2] = ipaddress[2]; - config.WiFi.Ip[3] = ipaddress[3]; - config.WiFi.Netmask[0] = netmask[0]; - config.WiFi.Netmask[1] = netmask[1]; - config.WiFi.Netmask[2] = netmask[2]; - config.WiFi.Netmask[3] = netmask[3]; - config.WiFi.Gateway[0] = gateway[0]; - config.WiFi.Gateway[1] = gateway[1]; - config.WiFi.Gateway[2] = gateway[2]; - config.WiFi.Gateway[3] = gateway[3]; - config.WiFi.Dns1[0] = dns1[0]; - config.WiFi.Dns1[1] = dns1[1]; - config.WiFi.Dns1[2] = dns1[2]; - config.WiFi.Dns1[3] = dns1[3]; - config.WiFi.Dns2[0] = dns2[0]; - config.WiFi.Dns2[1] = dns2[1]; - config.WiFi.Dns2[2] = dns2[2]; - config.WiFi.Dns2[3] = dns2[3]; - strlcpy(config.WiFi.Ssid, root["ssid"].as().c_str(), sizeof(config.WiFi.Ssid)); - strlcpy(config.WiFi.Password, root["password"].as().c_str(), sizeof(config.WiFi.Password)); - strlcpy(config.WiFi.Hostname, root["hostname"].as().c_str(), sizeof(config.WiFi.Hostname)); - if (root["dhcp"].as()) { - config.WiFi.Dhcp = true; - } else { - config.WiFi.Dhcp = false; - } - config.WiFi.ApTimeout = root["aptimeout"].as(); - config.Mdns.Enabled = root["mdnsenabled"].as(); - config.Syslog.Enabled = root["syslogenabled"].as(); - strlcpy(config.Syslog.Hostname, root["sysloghostname"].as().c_str(), sizeof(config.Syslog.Hostname)); - config.Syslog.Port = root["syslogport"].as(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + config.WiFi.Ip[0] = ipaddress[0]; + config.WiFi.Ip[1] = ipaddress[1]; + config.WiFi.Ip[2] = ipaddress[2]; + config.WiFi.Ip[3] = ipaddress[3]; + config.WiFi.Netmask[0] = netmask[0]; + config.WiFi.Netmask[1] = netmask[1]; + config.WiFi.Netmask[2] = netmask[2]; + config.WiFi.Netmask[3] = netmask[3]; + config.WiFi.Gateway[0] = gateway[0]; + config.WiFi.Gateway[1] = gateway[1]; + config.WiFi.Gateway[2] = gateway[2]; + config.WiFi.Gateway[3] = gateway[3]; + config.WiFi.Dns1[0] = dns1[0]; + config.WiFi.Dns1[1] = dns1[1]; + config.WiFi.Dns1[2] = dns1[2]; + config.WiFi.Dns1[3] = dns1[3]; + config.WiFi.Dns2[0] = dns2[0]; + config.WiFi.Dns2[1] = dns2[1]; + config.WiFi.Dns2[2] = dns2[2]; + config.WiFi.Dns2[3] = dns2[3]; + strlcpy(config.WiFi.Ssid, root["ssid"].as().c_str(), sizeof(config.WiFi.Ssid)); + strlcpy(config.WiFi.Password, root["password"].as().c_str(), sizeof(config.WiFi.Password)); + strlcpy(config.WiFi.Hostname, root["hostname"].as().c_str(), sizeof(config.WiFi.Hostname)); + if (root["dhcp"].as()) { + config.WiFi.Dhcp = true; + } else { + config.WiFi.Dhcp = false; + } + config.WiFi.ApTimeout = root["aptimeout"].as(); + config.Mdns.Enabled = root["mdnsenabled"].as(); + config.Syslog.Enabled = root["syslogenabled"].as(); + strlcpy(config.Syslog.Hostname, root["sysloghostname"].as().c_str(), sizeof(config.Syslog.Hostname)); + config.Syslog.Port = root["syslogport"].as(); + } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 5dc874b53..3827346fc 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -2,6 +2,7 @@ /* * Copyright (C) 2022-2024 Thomas Basler and others */ +#include "MessageOutput.h" #include "WebApi_ntp.h" #include "Configuration.h" #include "NtpSettings.h" @@ -135,13 +136,16 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - strlcpy(config.Ntp.Server, root["ntp_server"].as().c_str(), sizeof(config.Ntp.Server)); - strlcpy(config.Ntp.Timezone, root["ntp_timezone"].as().c_str(), sizeof(config.Ntp.Timezone)); - strlcpy(config.Ntp.TimezoneDescr, root["ntp_timezone_descr"].as().c_str(), sizeof(config.Ntp.TimezoneDescr)); - config.Ntp.Latitude = root["latitude"].as(); - config.Ntp.Longitude = root["longitude"].as(); - config.Ntp.SunsetType = root["sunsettype"].as(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + strlcpy(config.Ntp.Server, root["ntp_server"].as().c_str(), sizeof(config.Ntp.Server)); + strlcpy(config.Ntp.Timezone, root["ntp_timezone"].as().c_str(), sizeof(config.Ntp.Timezone)); + strlcpy(config.Ntp.TimezoneDescr, root["ntp_timezone_descr"].as().c_str(), sizeof(config.Ntp.TimezoneDescr)); + config.Ntp.Latitude = root["latitude"].as(); + config.Ntp.Longitude = root["longitude"].as(); + config.Ntp.SunsetType = root["sunsettype"].as(); + } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_powerlimiter.cpp b/src/WebApi_powerlimiter.cpp index 89e671d8c..8bfce48f5 100644 --- a/src/WebApi_powerlimiter.cpp +++ b/src/WebApi_powerlimiter.cpp @@ -145,45 +145,49 @@ void WebApiPowerLimiterClass::onAdminPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - config.PowerLimiter.Enabled = root["enabled"].as(); - PowerLimiter.setMode(PowerLimiterClass::Mode::Normal); // User input sets PL to normal operation - config.PowerLimiter.VerboseLogging = root["verbose_logging"].as(); - - if (config.Vedirect.Enabled) { - config.PowerLimiter.SolarPassThroughEnabled = root["solar_passthrough_enabled"].as(); - config.PowerLimiter.SolarPassThroughLosses = root["solar_passthrough_losses"].as(); - config.PowerLimiter.FullSolarPassThroughStartVoltage = static_cast(root["full_solar_passthrough_start_voltage"].as() * 100) / 100.0; - config.PowerLimiter.FullSolarPassThroughStopVoltage = static_cast(root["full_solar_passthrough_stop_voltage"].as() * 100) / 100.0; - } + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + + config.PowerLimiter.Enabled = root["enabled"].as(); + PowerLimiter.setMode(PowerLimiterClass::Mode::Normal); // User input sets PL to normal operation + config.PowerLimiter.VerboseLogging = root["verbose_logging"].as(); - config.PowerLimiter.IsInverterBehindPowerMeter = root["is_inverter_behind_powermeter"].as(); - config.PowerLimiter.IsInverterSolarPowered = root["is_inverter_solar_powered"].as(); - config.PowerLimiter.BatteryAlwaysUseAtNight = root["battery_always_use_at_night"].as(); - config.PowerLimiter.UseOverscalingToCompensateShading = root["use_overscaling_to_compensate_shading"].as(); - config.PowerLimiter.InverterId = root["inverter_serial"].as(); - config.PowerLimiter.InverterChannelId = root["inverter_channel_id"].as(); - config.PowerLimiter.TargetPowerConsumption = root["target_power_consumption"].as(); - config.PowerLimiter.TargetPowerConsumptionHysteresis = root["target_power_consumption_hysteresis"].as(); - config.PowerLimiter.LowerPowerLimit = root["lower_power_limit"].as(); - config.PowerLimiter.BaseLoadLimit = root["base_load_limit"].as(); - config.PowerLimiter.UpperPowerLimit = root["upper_power_limit"].as(); - - if (config.Battery.Enabled) { - config.PowerLimiter.IgnoreSoc = root["ignore_soc"].as(); - config.PowerLimiter.BatterySocStartThreshold = root["battery_soc_start_threshold"].as(); - config.PowerLimiter.BatterySocStopThreshold = root["battery_soc_stop_threshold"].as(); if (config.Vedirect.Enabled) { - config.PowerLimiter.FullSolarPassThroughSoc = root["full_solar_passthrough_soc"].as(); + config.PowerLimiter.SolarPassThroughEnabled = root["solar_passthrough_enabled"].as(); + config.PowerLimiter.SolarPassThroughLosses = root["solar_passthrough_losses"].as(); + config.PowerLimiter.FullSolarPassThroughStartVoltage = static_cast(root["full_solar_passthrough_start_voltage"].as() * 100) / 100.0; + config.PowerLimiter.FullSolarPassThroughStopVoltage = static_cast(root["full_solar_passthrough_stop_voltage"].as() * 100) / 100.0; } - } - config.PowerLimiter.VoltageStartThreshold = root["voltage_start_threshold"].as(); - config.PowerLimiter.VoltageStartThreshold = static_cast(config.PowerLimiter.VoltageStartThreshold * 100) / 100.0; - config.PowerLimiter.VoltageStopThreshold = root["voltage_stop_threshold"].as(); - config.PowerLimiter.VoltageStopThreshold = static_cast(config.PowerLimiter.VoltageStopThreshold * 100) / 100.0; - config.PowerLimiter.VoltageLoadCorrectionFactor = root["voltage_load_correction_factor"].as(); - config.PowerLimiter.RestartHour = root["inverter_restart_hour"].as(); + config.PowerLimiter.IsInverterBehindPowerMeter = root["is_inverter_behind_powermeter"].as(); + config.PowerLimiter.IsInverterSolarPowered = root["is_inverter_solar_powered"].as(); + config.PowerLimiter.BatteryAlwaysUseAtNight = root["battery_always_use_at_night"].as(); + config.PowerLimiter.UseOverscalingToCompensateShading = root["use_overscaling_to_compensate_shading"].as(); + config.PowerLimiter.InverterId = root["inverter_serial"].as(); + config.PowerLimiter.InverterChannelId = root["inverter_channel_id"].as(); + config.PowerLimiter.TargetPowerConsumption = root["target_power_consumption"].as(); + config.PowerLimiter.TargetPowerConsumptionHysteresis = root["target_power_consumption_hysteresis"].as(); + config.PowerLimiter.LowerPowerLimit = root["lower_power_limit"].as(); + config.PowerLimiter.BaseLoadLimit = root["base_load_limit"].as(); + config.PowerLimiter.UpperPowerLimit = root["upper_power_limit"].as(); + + if (config.Battery.Enabled) { + config.PowerLimiter.IgnoreSoc = root["ignore_soc"].as(); + config.PowerLimiter.BatterySocStartThreshold = root["battery_soc_start_threshold"].as(); + config.PowerLimiter.BatterySocStopThreshold = root["battery_soc_stop_threshold"].as(); + if (config.Vedirect.Enabled) { + config.PowerLimiter.FullSolarPassThroughSoc = root["full_solar_passthrough_soc"].as(); + } + } + + config.PowerLimiter.VoltageStartThreshold = root["voltage_start_threshold"].as(); + config.PowerLimiter.VoltageStartThreshold = static_cast(config.PowerLimiter.VoltageStartThreshold * 100) / 100.0; + config.PowerLimiter.VoltageStopThreshold = root["voltage_stop_threshold"].as(); + config.PowerLimiter.VoltageStopThreshold = static_cast(config.PowerLimiter.VoltageStopThreshold * 100) / 100.0; + config.PowerLimiter.VoltageLoadCorrectionFactor = root["voltage_load_correction_factor"].as(); + config.PowerLimiter.RestartHour = root["inverter_restart_hour"].as(); + } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_powermeter.cpp b/src/WebApi_powermeter.cpp index d27fd65d1..8ecbb5d75 100644 --- a/src/WebApi_powermeter.cpp +++ b/src/WebApi_powermeter.cpp @@ -151,22 +151,25 @@ void WebApiPowerMeterClass::onAdminPost(AsyncWebServerRequest* request) } } - CONFIG_T& config = Configuration.get(); - config.PowerMeter.Enabled = root["enabled"].as(); - config.PowerMeter.VerboseLogging = root["verbose_logging"].as(); - config.PowerMeter.Source = root["source"].as(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + config.PowerMeter.Enabled = root["enabled"].as(); + config.PowerMeter.VerboseLogging = root["verbose_logging"].as(); + config.PowerMeter.Source = root["source"].as(); - Configuration.deserializePowerMeterMqttConfig(root["mqtt"].as(), - config.PowerMeter.Mqtt); + Configuration.deserializePowerMeterMqttConfig(root["mqtt"].as(), + config.PowerMeter.Mqtt); - Configuration.deserializePowerMeterSerialSdmConfig(root["serial_sdm"].as(), - config.PowerMeter.SerialSdm); + Configuration.deserializePowerMeterSerialSdmConfig(root["serial_sdm"].as(), + config.PowerMeter.SerialSdm); - Configuration.deserializePowerMeterHttpJsonConfig(root["http_json"].as(), - config.PowerMeter.HttpJson); + Configuration.deserializePowerMeterHttpJsonConfig(root["http_json"].as(), + config.PowerMeter.HttpJson); - Configuration.deserializePowerMeterHttpSmlConfig(root["http_sml"].as(), - config.PowerMeter.HttpSml); + Configuration.deserializePowerMeterHttpSmlConfig(root["http_sml"].as(), + config.PowerMeter.HttpSml); + } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_security.cpp b/src/WebApi_security.cpp index 6be21ca6a..e6e1bb11f 100644 --- a/src/WebApi_security.cpp +++ b/src/WebApi_security.cpp @@ -64,9 +64,12 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - strlcpy(config.Security.Password, root["password"].as().c_str(), sizeof(config.Security.Password)); - config.Security.AllowReadonly = root["allow_readonly"].as(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + strlcpy(config.Security.Password, root["password"].as().c_str(), sizeof(config.Security.Password)); + config.Security.AllowReadonly = root["allow_readonly"].as(); + } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_vedirect.cpp b/src/WebApi_vedirect.cpp index 653ab8ca4..83e499839 100644 --- a/src/WebApi_vedirect.cpp +++ b/src/WebApi_vedirect.cpp @@ -83,10 +83,13 @@ void WebApiVedirectClass::onVedirectAdminPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - config.Vedirect.Enabled = root["vedirect_enabled"].as(); - config.Vedirect.VerboseLogging = root["verbose_logging"].as(); - config.Vedirect.UpdatesOnly = root["vedirect_updatesonly"].as(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + config.Vedirect.Enabled = root["vedirect_enabled"].as(); + config.Vedirect.VerboseLogging = root["verbose_logging"].as(); + config.Vedirect.UpdatesOnly = root["vedirect_updatesonly"].as(); + } WebApi.writeConfig(retMsg); diff --git a/src/main.cpp b/src/main.cpp index 00d38bb3f..8717bc5a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,11 +77,12 @@ void setup() MessageOutput.println("done"); } + Configuration.init(scheduler); + // Read configuration values MessageOutput.print("Reading configuration... "); if (!Configuration.read()) { MessageOutput.print("initializing... "); - Configuration.init(); if (Configuration.write()) { MessageOutput.print("written... "); } else { @@ -166,19 +167,6 @@ void setup() LedSingle.init(scheduler); MessageOutput.println("done"); - // Check for default DTU serial - MessageOutput.print("Check for default DTU serial... "); - if (config.Dtu.Serial == DTU_SERIAL) { - MessageOutput.print("generate serial based on ESP chip id: "); - const uint64_t dtuId = Utils::generateDtuSerial(); - MessageOutput.printf("%0" PRIx32 "%08" PRIx32 "... ", - ((uint32_t)((dtuId >> 32) & 0xFFFFFFFF)), - ((uint32_t)(dtuId & 0xFFFFFFFF))); - config.Dtu.Serial = dtuId; - Configuration.write(); - } - MessageOutput.println("done"); - InverterSettings.init(scheduler); Datastore.init(scheduler);