Merge branch 'pr2360' into dev

This commit is contained in:
Thomas Basler 2024-11-06 19:55:03 +01:00
commit 74e3947cb2
11 changed files with 235 additions and 142 deletions

View File

@ -3,6 +3,9 @@
#include "PinMapping.h"
#include <cstdint>
#include <TaskSchedulerDeclarations.h>
#include <mutex>
#include <condition_variable>
#define CONFIG_FILENAME "/config.json"
#define CONFIG_VERSION 0x00011d00 // 0.1.29 // make sure to clean all after change
@ -162,15 +165,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<std::mutex> _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;

View File

@ -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));
}
@ -319,6 +328,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;
write();
}
MessageOutput.println("done");
return true;
}
@ -407,11 +430,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++) {
@ -456,4 +484,30 @@ void ConfigurationClass::deleteInverterById(const uint8_t id)
}
}
void ConfigurationClass::loop()
{
std::unique_lock<std::mutex> 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;

View File

@ -48,7 +48,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;
}
@ -66,7 +66,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 {

View File

@ -129,23 +129,28 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
return;
}
CONFIG_T& config = Configuration.get();
bool performRestart = root["curPin"]["name"].as<String>() != config.Dev_PinMapping;
{
auto guard = Configuration.getWriteGuard();
auto& config = guard.getConfig();
strlcpy(config.Dev_PinMapping, root["curPin"]["name"].as<String>().c_str(), sizeof(config.Dev_PinMapping));
config.Display.Rotation = root["display"]["rotation"].as<uint8_t>();
config.Display.PowerSafe = root["display"]["power_safe"].as<bool>();
config.Display.ScreenSaver = root["display"]["screensaver"].as<bool>();
config.Display.Contrast = root["display"]["contrast"].as<uint8_t>();
strlcpy(config.Display.Locale, root["display"]["locale"].as<String>().c_str(), sizeof(config.Display.Locale));
config.Display.Diagram.Duration = root["display"]["diagramduration"].as<uint32_t>();
config.Display.Diagram.Mode = root["display"]["diagrammode"].as<DiagramMode_t>();
strlcpy(config.Dev_PinMapping, root["curPin"]["name"].as<String>().c_str(), sizeof(config.Dev_PinMapping));
config.Display.Rotation = root["display"]["rotation"].as<uint8_t>();
config.Display.PowerSafe = root["display"]["power_safe"].as<bool>();
config.Display.ScreenSaver = root["display"]["screensaver"].as<bool>();
config.Display.Contrast = root["display"]["contrast"].as<uint8_t>();
strlcpy(config.Display.Locale, root["display"]["locale"].as<String>().c_str(), sizeof(config.Display.Locale));
config.Display.Diagram.Duration = root["display"]["diagramduration"].as<uint32_t>();
config.Display.Diagram.Mode = root["display"]["diagrammode"].as<DiagramMode_t>();
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
config.Led_Single[i].Brightness = root["led"][i]["brightness"].as<uint8_t>();
config.Led_Single[i].Brightness = min<uint8_t>(100, config.Led_Single[i].Brightness);
for (uint8_t i = 0; i < PINMAPPING_LED_COUNT; i++) {
config.Led_Single[i].Brightness = root["led"][i]["brightness"].as<uint8_t>();
config.Led_Single[i].Brightness = min<uint8_t>(100, config.Led_Single[i].Brightness);
}
}
auto const& config = Configuration.get();
bool performRestart = root["curPin"]["name"].as<String>() != config.Dev_PinMapping;
Display.setDiagramMode(static_cast<DiagramMode_t>(config.Display.Diagram.Mode));
Display.setOrientation(config.Display.Rotation);
Display.enablePowerSafe = config.Display.PowerSafe;

View File

@ -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<uint32_t>();
config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as<uint8_t>();
config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as<int8_t>();
config.Dtu.Cmt.Frequency = root["cmt_frequency"].as<uint32_t>();
config.Dtu.Cmt.CountryMode = root["cmt_country"].as<CountryModeId_t>();
{
auto guard = Configuration.getWriteGuard();
auto& config = guard.getConfig();
config.Dtu.Serial = serial;
config.Dtu.PollInterval = root["pollinterval"].as<uint32_t>();
config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as<uint8_t>();
config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as<int8_t>();
config.Dtu.Cmt.Frequency = root["cmt_frequency"].as<uint32_t>();
config.Dtu.Cmt.CountryMode = root["cmt_country"].as<CountryModeId_t>();
}
WebApi.writeConfig(retMsg);

View File

@ -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<String>().c_str(), NULL, 16);
const uint64_t new_serial = strtoll(root["serial"].as<String>().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,42 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
return;
}
INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[root["id"].as<uint8_t>()];
uint64_t old_serial = 0;
uint64_t new_serial = serial;
uint64_t old_serial = inverter.Serial;
{
auto guard = Configuration.getWriteGuard();
auto& config = guard.getConfig();
// Interpret the string as a hex value and convert it to uint64_t
inverter.Serial = new_serial;
strncpy(inverter.Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN);
INVERTER_CONFIG_T& inverter = config.Inverter[root["id"].as<uint8_t>()];
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;
old_serial = inverter.Serial;
inverter.Serial = new_serial;
strncpy(inverter.Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN);
uint8_t arrayCount = 0;
for (JsonVariant channel : channelArray) {
inverter.channel[arrayCount].MaxChannelPower = channel["max_power"].as<uint16_t>();
inverter.channel[arrayCount].YieldTotalOffset = channel["yield_total_offset"].as<float>();
strncpy(inverter.channel[arrayCount].Name, channel["name"] | "", sizeof(inverter.channel[arrayCount].Name));
arrayCount++;
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<uint16_t>();
inverter.channel[arrayCount].YieldTotalOffset = channel["yield_total_offset"].as<float>();
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<uint8_t>()];
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(old_serial);
if (inv != nullptr && new_serial != old_serial) {
@ -300,7 +305,7 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
}
uint8_t inverter_id = root["id"].as<uint8_t>();
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 +342,18 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request)
// The order array contains list or id in the right order
JsonArray orderArray = root["order"].as<JsonArray>();
uint8_t order = 0;
for (JsonVariant id : orderArray) {
uint8_t inverter_id = id.as<uint8_t>();
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<uint8_t>();
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!");

View File

@ -271,36 +271,40 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
}
}
CONFIG_T& config = Configuration.get();
config.Mqtt.Enabled = root["mqtt_enabled"].as<bool>();
config.Mqtt.Retain = root["mqtt_retain"].as<bool>();
config.Mqtt.Tls.Enabled = root["mqtt_tls"].as<bool>();
strlcpy(config.Mqtt.Tls.RootCaCert, root["mqtt_root_ca_cert"].as<String>().c_str(), sizeof(config.Mqtt.Tls.RootCaCert));
config.Mqtt.Tls.CertLogin = root["mqtt_tls_cert_login"].as<bool>();
strlcpy(config.Mqtt.Tls.ClientCert, root["mqtt_client_cert"].as<String>().c_str(), sizeof(config.Mqtt.Tls.ClientCert));
strlcpy(config.Mqtt.Tls.ClientKey, root["mqtt_client_key"].as<String>().c_str(), sizeof(config.Mqtt.Tls.ClientKey));
config.Mqtt.Port = root["mqtt_port"].as<uint>();
strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as<String>().c_str(), sizeof(config.Mqtt.Hostname));
strlcpy(config.Mqtt.ClientId, root["mqtt_clientid"].as<String>().c_str(), sizeof(config.Mqtt.ClientId));
strlcpy(config.Mqtt.Username, root["mqtt_username"].as<String>().c_str(), sizeof(config.Mqtt.Username));
strlcpy(config.Mqtt.Password, root["mqtt_password"].as<String>().c_str(), sizeof(config.Mqtt.Password));
strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Topic));
strlcpy(config.Mqtt.Lwt.Value_Online, root["mqtt_lwt_online"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Online));
strlcpy(config.Mqtt.Lwt.Value_Offline, root["mqtt_lwt_offline"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Offline));
config.Mqtt.Lwt.Qos = root["mqtt_lwt_qos"].as<uint8_t>();
config.Mqtt.PublishInterval = root["mqtt_publish_interval"].as<uint32_t>();
config.Mqtt.CleanSession = root["mqtt_clean_session"].as<bool>();
config.Mqtt.Hass.Enabled = root["mqtt_hass_enabled"].as<bool>();
config.Mqtt.Hass.Expire = root["mqtt_hass_expire"].as<bool>();
config.Mqtt.Hass.Retain = root["mqtt_hass_retain"].as<bool>();
config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as<bool>();
strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as<String>().c_str(), sizeof(config.Mqtt.Hass.Topic));
{
auto guard = Configuration.getWriteGuard();
auto& config = guard.getConfig();
// Check if base topic was changed
if (strcmp(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str())) {
MqttHandleInverter.unsubscribeTopics();
strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Topic));
MqttHandleInverter.subscribeTopics();
config.Mqtt.Enabled = root["mqtt_enabled"].as<bool>();
config.Mqtt.Retain = root["mqtt_retain"].as<bool>();
config.Mqtt.Tls.Enabled = root["mqtt_tls"].as<bool>();
strlcpy(config.Mqtt.Tls.RootCaCert, root["mqtt_root_ca_cert"].as<String>().c_str(), sizeof(config.Mqtt.Tls.RootCaCert));
config.Mqtt.Tls.CertLogin = root["mqtt_tls_cert_login"].as<bool>();
strlcpy(config.Mqtt.Tls.ClientCert, root["mqtt_client_cert"].as<String>().c_str(), sizeof(config.Mqtt.Tls.ClientCert));
strlcpy(config.Mqtt.Tls.ClientKey, root["mqtt_client_key"].as<String>().c_str(), sizeof(config.Mqtt.Tls.ClientKey));
config.Mqtt.Port = root["mqtt_port"].as<uint>();
strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as<String>().c_str(), sizeof(config.Mqtt.Hostname));
strlcpy(config.Mqtt.ClientId, root["mqtt_clientid"].as<String>().c_str(), sizeof(config.Mqtt.ClientId));
strlcpy(config.Mqtt.Username, root["mqtt_username"].as<String>().c_str(), sizeof(config.Mqtt.Username));
strlcpy(config.Mqtt.Password, root["mqtt_password"].as<String>().c_str(), sizeof(config.Mqtt.Password));
strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Topic));
strlcpy(config.Mqtt.Lwt.Value_Online, root["mqtt_lwt_online"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Online));
strlcpy(config.Mqtt.Lwt.Value_Offline, root["mqtt_lwt_offline"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Offline));
config.Mqtt.Lwt.Qos = root["mqtt_lwt_qos"].as<uint8_t>();
config.Mqtt.PublishInterval = root["mqtt_publish_interval"].as<uint32_t>();
config.Mqtt.CleanSession = root["mqtt_clean_session"].as<bool>();
config.Mqtt.Hass.Enabled = root["mqtt_hass_enabled"].as<bool>();
config.Mqtt.Hass.Expire = root["mqtt_hass_expire"].as<bool>();
config.Mqtt.Hass.Retain = root["mqtt_hass_retain"].as<bool>();
config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as<bool>();
strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as<String>().c_str(), sizeof(config.Mqtt.Hass.Topic));
// Check if base topic was changed
if (strcmp(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str())) {
MqttHandleInverter.unsubscribeTopics();
strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Topic));
MqttHandleInverter.subscribeTopics();
}
}
WebApi.writeConfig(retMsg);

View File

@ -164,37 +164,41 @@ 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<String>().c_str(), sizeof(config.WiFi.Ssid));
strlcpy(config.WiFi.Password, root["password"].as<String>().c_str(), sizeof(config.WiFi.Password));
strlcpy(config.WiFi.Hostname, root["hostname"].as<String>().c_str(), sizeof(config.WiFi.Hostname));
if (root["dhcp"].as<bool>()) {
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<String>().c_str(), sizeof(config.WiFi.Ssid));
strlcpy(config.WiFi.Password, root["password"].as<String>().c_str(), sizeof(config.WiFi.Password));
strlcpy(config.WiFi.Hostname, root["hostname"].as<String>().c_str(), sizeof(config.WiFi.Hostname));
if (root["dhcp"].as<bool>()) {
config.WiFi.Dhcp = true;
} else {
config.WiFi.Dhcp = false;
}
config.WiFi.ApTimeout = root["aptimeout"].as<uint>();
config.Mdns.Enabled = root["mdnsenabled"].as<bool>();
}
config.WiFi.ApTimeout = root["aptimeout"].as<uint>();
config.Mdns.Enabled = root["mdnsenabled"].as<bool>();
WebApi.writeConfig(retMsg);

View File

@ -135,13 +135,17 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
return;
}
CONFIG_T& config = Configuration.get();
strlcpy(config.Ntp.Server, root["ntp_server"].as<String>().c_str(), sizeof(config.Ntp.Server));
strlcpy(config.Ntp.Timezone, root["ntp_timezone"].as<String>().c_str(), sizeof(config.Ntp.Timezone));
strlcpy(config.Ntp.TimezoneDescr, root["ntp_timezone_descr"].as<String>().c_str(), sizeof(config.Ntp.TimezoneDescr));
config.Ntp.Latitude = root["latitude"].as<double>();
config.Ntp.Longitude = root["longitude"].as<double>();
config.Ntp.SunsetType = root["sunsettype"].as<uint8_t>();
{
auto guard = Configuration.getWriteGuard();
auto& config = guard.getConfig();
strlcpy(config.Ntp.Server, root["ntp_server"].as<String>().c_str(), sizeof(config.Ntp.Server));
strlcpy(config.Ntp.Timezone, root["ntp_timezone"].as<String>().c_str(), sizeof(config.Ntp.Timezone));
strlcpy(config.Ntp.TimezoneDescr, root["ntp_timezone_descr"].as<String>().c_str(), sizeof(config.Ntp.TimezoneDescr));
config.Ntp.Latitude = root["latitude"].as<double>();
config.Ntp.Longitude = root["longitude"].as<double>();
config.Ntp.SunsetType = root["sunsettype"].as<uint8_t>();
}
WebApi.writeConfig(retMsg);

View File

@ -64,9 +64,13 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
return;
}
CONFIG_T& config = Configuration.get();
strlcpy(config.Security.Password, root["password"].as<String>().c_str(), sizeof(config.Security.Password));
config.Security.AllowReadonly = root["allow_readonly"].as<bool>();
{
auto guard = Configuration.getWriteGuard();
auto& config = guard.getConfig();
strlcpy(config.Security.Password, root["password"].as<String>().c_str(), sizeof(config.Security.Password));
config.Security.AllowReadonly = root["allow_readonly"].as<bool>();
}
WebApi.writeConfig(retMsg);

View File

@ -65,10 +65,9 @@ void setup()
}
// Read configuration values
Configuration.init(scheduler);
MessageOutput.print("Reading configuration... ");
if (!Configuration.read()) {
MessageOutput.print("initializing... ");
Configuration.init();
if (Configuration.write()) {
MessageOutput.print("written... ");
} else {
@ -150,19 +149,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 "... ",
static_cast<uint32_t>((dtuId >> 32) & 0xFFFFFFFF),
static_cast<uint32_t>(dtuId & 0xFFFFFFFF));
config.Dtu.Serial = dtuId;
Configuration.write();
}
MessageOutput.println("done");
InverterSettings.init(scheduler);
Datastore.init(scheduler);