From 9f4f4fab069d931a1f3710e8fb55f5f717d8849d Mon Sep 17 00:00:00 2001 From: Bernhard Kirchen Date: Thu, 17 Oct 2024 21:46:32 +0200 Subject: [PATCH] PoC: config write guard --- include/Configuration.h | 24 +++++++++++-- src/Configuration.cpp | 58 +++++++++++++++++++++++++++++-- src/WebApi.cpp | 4 +-- src/WebApi_device.cpp | 35 +++++++++++-------- src/WebApi_dtu.cpp | 20 ++++++----- src/WebApi_inverter.cpp | 76 +++++++++++++++++++++++------------------ src/WebApi_mqtt.cpp | 63 ++++++++++++++++++---------------- src/WebApi_network.cpp | 63 ++++++++++++++++++---------------- src/WebApi_ntp.cpp | 17 +++++---- src/WebApi_security.cpp | 9 +++-- src/main.cpp | 17 ++------- 11 files changed, 237 insertions(+), 149 deletions(-) diff --git a/include/Configuration.h b/include/Configuration.h index 4a802e4e1..ce7bfbeea 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -3,6 +3,9 @@ #include "PinMapping.h" #include +#include +#include +#include #define CONFIG_FILENAME "/config.json" #define CONFIG_VERSION 0x00011c00 // 0.1.28 // make sure to clean all after change @@ -161,15 +164,32 @@ 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); void deleteInverterById(const uint8_t id); + +private: + void loop(); + + Task _loopTask; }; extern ConfigurationClass Configuration; diff --git a/src/Configuration.cpp b/src/Configuration.cpp index db47d9c8a..bba2732a8 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -13,8 +13,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)); } @@ -318,6 +327,20 @@ bool ConfigurationClass::read() } 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; } @@ -390,11 +413,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++) { @@ -439,4 +467,30 @@ void ConfigurationClass::deleteInverterById(const uint8_t id) } } +void ConfigurationClass::loop() +{ + std::unique_lock lock(sWriterMutex); + if (sWriterCount == 0) { return; } + + sWriterCv.notify_all(); + sWriterCv.wait(lock, [] { return sWriterCount == 0; }); +} + +CONFIG_T& ConfigurationClass::WriteGuard::getConfig() +{ + return config; +} + +ConfigurationClass::WriteGuard::WriteGuard() + : _lock(sWriterMutex) +{ + sWriterCount++; + sWriterCv.wait(_lock); +} + +ConfigurationClass::WriteGuard::~WriteGuard() { + sWriterCount--; + if (sWriterCount == 0) { sWriterCv.notify_all(); } +} + ConfigurationClass Configuration; diff --git a/src/WebApi.cpp b/src/WebApi.cpp index b3255c417..31eb122cc 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -47,7 +47,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; } @@ -65,7 +65,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_device.cpp b/src/WebApi_device.cpp index 29686fe08..109ff1a99 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -129,23 +129,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 7c6c3f738..e6fb8994c 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); @@ -153,14 +153,16 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) return; } - CONFIG_T& config = Configuration.get(); - - config.Dtu.Serial = serial; - config.Dtu.PollInterval = root["pollinterval"].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.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 0c8ee5c6e..25e13ac13 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -271,36 +271,39 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) } } - CONFIG_T& config = Configuration.get(); - config.Mqtt.Enabled = root["mqtt_enabled"].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(); - strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as().c_str(), sizeof(config.Mqtt.Topic)); - MqttHandleInverter.subscribeTopics(); + { + auto guard = Configuration.getWriteGuard(); + auto& config = guard.getConfig(); + config.Mqtt.Enabled = root["mqtt_enabled"].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(); + strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as().c_str(), sizeof(config.Mqtt.Topic)); + MqttHandleInverter.subscribeTopics(); + } } WebApi.writeConfig(retMsg); diff --git a/src/WebApi_network.cpp b/src/WebApi_network.cpp index 75275755f..142567a1a 100644 --- a/src/WebApi_network.cpp +++ b/src/WebApi_network.cpp @@ -164,37 +164,40 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) return; } - 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; + { + 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.WiFi.ApTimeout = root["aptimeout"].as(); - config.Mdns.Enabled = root["mdnsenabled"].as(); WebApi.writeConfig(retMsg); diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 5dc874b53..f5ad3786a 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -135,13 +135,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_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/main.cpp b/src/main.cpp index b1d974d74..7b04e7cd6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -65,11 +65,11 @@ 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 { @@ -146,19 +146,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);