Remove not required F() macro. Frees ~20kb flash.

This commit is contained in:
Thomas Basler 2023-04-04 18:51:18 +02:00
parent acf413b616
commit d6028cbd50
33 changed files with 868 additions and 868 deletions

View File

@ -35,7 +35,7 @@ void HoymilesClass::loop()
if (_radio->isIdle()) {
std::shared_ptr<InverterAbstract> iv = getInverterByPos(inverterPos);
if (iv != nullptr) {
_messageOutput->print(F("Fetch inverter: "));
_messageOutput->print("Fetch inverter: ");
_messageOutput->println(iv->serial(), HEX);
iv->sendStatsRequest(_radio.get());
@ -54,19 +54,19 @@ void HoymilesClass::loop()
// Set limit if required
if (iv->SystemConfigPara()->getLastLimitCommandSuccess() == CMD_NOK) {
_messageOutput->println(F("Resend ActivePowerControl"));
_messageOutput->println("Resend ActivePowerControl");
iv->resendActivePowerControlRequest(_radio.get());
}
// Set power status if required
if (iv->PowerCommand()->getLastPowerCommandSuccess() == CMD_NOK) {
_messageOutput->println(F("Resend PowerCommand"));
_messageOutput->println("Resend PowerCommand");
iv->resendPowerControlRequest(_radio.get());
}
// Fetch dev info (but first fetch stats)
if (iv->Statistics()->getLastUpdate() > 0 && (iv->DevInfo()->getLastUpdateAll() == 0 || iv->DevInfo()->getLastUpdateSimple() == 0)) {
_messageOutput->println(F("Request device info"));
_messageOutput->println("Request device info");
iv->sendDevInfoRequest(_radio.get());
}
}

View File

@ -25,9 +25,9 @@ void HoymilesRadio::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pin
_radio->setRetries(0, 0);
_radio->maskIRQ(true, true, false); // enable only receiving interrupts
if (_radio->isChipConnected()) {
Hoymiles.getMessageOutput()->println(F("Connection successful"));
Hoymiles.getMessageOutput()->println("Connection successful");
} else {
Hoymiles.getMessageOutput()->println(F("Connection error!!"));
Hoymiles.getMessageOutput()->println("Connection error!!");
}
attachInterrupt(digitalPinToInterrupt(pinIRQ), std::bind(&HoymilesRadio::handleIntr, this), FALLING);
@ -44,7 +44,7 @@ void HoymilesRadio::loop()
}
if (_packetReceived) {
Hoymiles.getMessageOutput()->println(F("Interrupt received"));
Hoymiles.getMessageOutput()->println("Interrupt received");
while (_radio->available()) {
if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) {
fragment_t f;
@ -56,7 +56,7 @@ void HoymilesRadio::loop()
_radio->read(f.fragment, f.len);
_rxBuffer.push(f);
} else {
Hoymiles.getMessageOutput()->println(F("Buffer full"));
Hoymiles.getMessageOutput()->println("Buffer full");
_radio->flush_rx();
}
}
@ -76,11 +76,11 @@ void HoymilesRadio::loop()
dumpBuf(buf, f.fragment, f.len);
inv->addRxFragment(f.fragment, f.len);
} else {
Hoymiles.getMessageOutput()->println(F("Inverter Not found!"));
Hoymiles.getMessageOutput()->println("Inverter Not found!");
}
} else {
Hoymiles.getMessageOutput()->println(F("Frame kaputt"));
Hoymiles.getMessageOutput()->println("Frame kaputt");
}
// Remove paket from buffer even it was corrupted
@ -89,46 +89,46 @@ void HoymilesRadio::loop()
}
if (_busyFlag && _rxTimeout.occured()) {
Hoymiles.getMessageOutput()->println(F("RX Period End"));
Hoymiles.getMessageOutput()->println("RX Period End");
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(_commandQueue.front().get()->getTargetAddress());
if (nullptr != inv) {
CommandAbstract* cmd = _commandQueue.front().get();
uint8_t verifyResult = inv->verifyAllFragments(cmd);
if (verifyResult == FRAGMENT_ALL_MISSING_RESEND) {
Hoymiles.getMessageOutput()->println(F("Nothing received, resend whole request"));
Hoymiles.getMessageOutput()->println("Nothing received, resend whole request");
sendLastPacketAgain();
} else if (verifyResult == FRAGMENT_ALL_MISSING_TIMEOUT) {
Hoymiles.getMessageOutput()->println(F("Nothing received, resend count exeeded"));
Hoymiles.getMessageOutput()->println("Nothing received, resend count exeeded");
_commandQueue.pop();
_busyFlag = false;
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
Hoymiles.getMessageOutput()->println(F("Retransmit timeout"));
Hoymiles.getMessageOutput()->println("Retransmit timeout");
_commandQueue.pop();
_busyFlag = false;
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
Hoymiles.getMessageOutput()->println(F("Packet handling error"));
Hoymiles.getMessageOutput()->println("Packet handling error");
_commandQueue.pop();
_busyFlag = false;
} else if (verifyResult > 0) {
// Perform Retransmit
Hoymiles.getMessageOutput()->print(F("Request retransmit: "));
Hoymiles.getMessageOutput()->print("Request retransmit: ");
Hoymiles.getMessageOutput()->println(verifyResult);
sendRetransmitPacket(verifyResult);
} else {
// Successful received all packages
Hoymiles.getMessageOutput()->println(F("Success"));
Hoymiles.getMessageOutput()->println("Success");
_commandQueue.pop();
_busyFlag = false;
}
} else {
// If inverter was not found, assume the command is invalid
Hoymiles.getMessageOutput()->println(F("RX: Invalid inverter found"));
Hoymiles.getMessageOutput()->println("RX: Invalid inverter found");
_commandQueue.pop();
_busyFlag = false;
}
@ -142,7 +142,7 @@ void HoymilesRadio::loop()
inv->clearRxFragmentBuffer();
sendEsbPacket(cmd);
} else {
Hoymiles.getMessageOutput()->println(F("TX: Invalid inverter found"));
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
_commandQueue.pop();
}
}
@ -252,11 +252,11 @@ void HoymilesRadio::sendEsbPacket(CommandAbstract* cmd)
openWritingPipe(s);
_radio->setRetries(3, 15);
Hoymiles.getMessageOutput()->print(F("TX "));
Hoymiles.getMessageOutput()->print("TX ");
Hoymiles.getMessageOutput()->print(cmd->getCommandName());
Hoymiles.getMessageOutput()->print(F(" Channel: "));
Hoymiles.getMessageOutput()->print(" Channel: ");
Hoymiles.getMessageOutput()->print(_radio->getChannel());
Hoymiles.getMessageOutput()->print(F(" --> "));
Hoymiles.getMessageOutput()->print(" --> ");
cmd->dumpDataPayload(Hoymiles.getMessageOutput());
_radio->write(cmd->getDataPayload(), cmd->getDataSize());
@ -294,5 +294,5 @@ void HoymilesRadio::dumpBuf(const char* info, uint8_t buf[], uint8_t len)
for (uint8_t i = 0; i < len; i++) {
Hoymiles.getMessageOutput()->printf("%02X ", buf[i]);
}
Hoymiles.getMessageOutput()->println(F(""));
Hoymiles.getMessageOutput()->println("");
}

View File

@ -29,7 +29,7 @@ bool HM_1CH::isValidSerial(uint64_t serial)
String HM_1CH::typeName()
{
return F("HM-300, HM-350, HM-400");
return "HM-300, HM-350, HM-400";
}
const std::list<byteAssign_t>* HM_1CH::getByteAssignment()

View File

@ -30,7 +30,7 @@ bool HM_2CH::isValidSerial(uint64_t serial)
String HM_2CH::typeName()
{
return F("HM-600, HM-700, HM-800");
return "HM-600, HM-700, HM-800";
}
const std::list<byteAssign_t>* HM_2CH::getByteAssignment()

View File

@ -29,7 +29,7 @@ bool HM_4CH::isValidSerial(uint64_t serial)
String HM_4CH::typeName()
{
return F("HM-1000, HM-1200, HM-1500");
return "HM-1000, HM-1200, HM-1500";
}
const std::list<byteAssign_t>* HM_4CH::getByteAssignment()

View File

@ -169,7 +169,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract* cmd)
{
// All missing
if (_rxFragmentLastPacketId == 0) {
Hoymiles.getMessageOutput()->println(F("All missing"));
Hoymiles.getMessageOutput()->println("All missing");
if (cmd->getSendCount() <= MAX_RESEND_COUNT) {
return FRAGMENT_ALL_MISSING_RESEND;
} else {
@ -180,7 +180,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract* cmd)
// Last fragment is missing (the one with 0x80)
if (_rxFragmentMaxPacketId == 0) {
Hoymiles.getMessageOutput()->println(F("Last missing"));
Hoymiles.getMessageOutput()->println("Last missing");
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
return _rxFragmentLastPacketId + 1;
} else {
@ -192,7 +192,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract* cmd)
// Middle fragment is missing
for (uint8_t i = 0; i < _rxFragmentMaxPacketId - 1; i++) {
if (!_rxFragmentBuffer[i].wasReceived) {
Hoymiles.getMessageOutput()->println(F("Middle missing"));
Hoymiles.getMessageOutput()->println("Middle missing");
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
return i + 1;
} else {

View File

@ -64,214 +64,214 @@ void AlarmLogParser::getLogEntry(uint8_t entryId, AlarmLogEntry_t* entry)
switch (entry->MessageId) {
case 1:
entry->Message = F("Inverter start");
entry->Message = "Inverter start";
break;
case 2:
entry->Message = F("DTU command failed");
entry->Message = "DTU command failed";
break;
case 121:
entry->Message = F("Over temperature protection");
entry->Message = "Over temperature protection";
break;
case 124:
entry->Message = F("Shut down by remote control");
entry->Message = "Shut down by remote control";
break;
case 125:
entry->Message = F("Grid configuration parameter error");
entry->Message = "Grid configuration parameter error";
break;
case 126:
entry->Message = F("Software error code 126");
entry->Message = "Software error code 126";
break;
case 127:
entry->Message = F("Firmware error");
entry->Message = "Firmware error";
break;
case 128:
entry->Message = F("Software error code 128");
entry->Message = "Software error code 128";
break;
case 129:
entry->Message = F("Abnormal bias");
entry->Message = "Abnormal bias";
break;
case 130:
entry->Message = F("Offline");
entry->Message = "Offline";
break;
case 141:
entry->Message = F("Grid: Grid overvoltage");
entry->Message = "Grid: Grid overvoltage";
break;
case 142:
entry->Message = F("Grid: 10 min value grid overvoltage");
entry->Message = "Grid: 10 min value grid overvoltage";
break;
case 143:
entry->Message = F("Grid: Grid undervoltage");
entry->Message = "Grid: Grid undervoltage";
break;
case 144:
entry->Message = F("Grid: Grid overfrequency");
entry->Message = "Grid: Grid overfrequency";
break;
case 145:
entry->Message = F("Grid: Grid underfrequency");
entry->Message = "Grid: Grid underfrequency";
break;
case 146:
entry->Message = F("Grid: Rapid grid frequency change rate");
entry->Message = "Grid: Rapid grid frequency change rate";
break;
case 147:
entry->Message = F("Grid: Power grid outage");
entry->Message = "Grid: Power grid outage";
break;
case 148:
entry->Message = F("Grid: Grid disconnection");
entry->Message = "Grid: Grid disconnection";
break;
case 149:
entry->Message = F("Grid: Island detected");
entry->Message = "Grid: Island detected";
break;
case 205:
entry->Message = F("MPPT-A: Input overvoltage");
entry->Message = "MPPT-A: Input overvoltage";
break;
case 206:
entry->Message = F("MPPT-B: Input overvoltage");
entry->Message = "MPPT-B: Input overvoltage";
break;
case 207:
entry->Message = F("MPPT-A: Input undervoltage");
entry->Message = "MPPT-A: Input undervoltage";
break;
case 208:
entry->Message = F("MPPT-B: Input undervoltage");
entry->Message = "MPPT-B: Input undervoltage";
break;
case 209:
entry->Message = F("PV-1: No input");
entry->Message = "PV-1: No input";
break;
case 210:
entry->Message = F("PV-2: No input");
entry->Message = "PV-2: No input";
break;
case 211:
entry->Message = F("PV-3: No input");
entry->Message = "PV-3: No input";
break;
case 212:
entry->Message = F("PV-4: No input");
entry->Message = "PV-4: No input";
break;
case 213:
entry->Message = F("MPPT-A: PV-1 & PV-2 abnormal wiring");
entry->Message = "MPPT-A: PV-1 & PV-2 abnormal wiring";
break;
case 214:
entry->Message = F("MPPT-B: PV-3 & PV-4 abnormal wiring");
entry->Message = "MPPT-B: PV-3 & PV-4 abnormal wiring";
break;
case 215:
entry->Message = F("PV-1: Input overvoltage");
entry->Message = "PV-1: Input overvoltage";
break;
case 216:
entry->Message = F("PV-1: Input undervoltage");
entry->Message = "PV-1: Input undervoltage";
break;
case 217:
entry->Message = F("PV-2: Input overvoltage");
entry->Message = "PV-2: Input overvoltage";
break;
case 218:
entry->Message = F("PV-2: Input undervoltage");
entry->Message = "PV-2: Input undervoltage";
break;
case 219:
entry->Message = F("PV-3: Input overvoltage");
entry->Message = "PV-3: Input overvoltage";
break;
case 220:
entry->Message = F("PV-3: Input undervoltage");
entry->Message = "PV-3: Input undervoltage";
break;
case 221:
entry->Message = F("PV-4: Input overvoltage");
entry->Message = "PV-4: Input overvoltage";
break;
case 222:
entry->Message = F("PV-4: Input undervoltage");
entry->Message = "PV-4: Input undervoltage";
break;
case 301:
entry->Message = F("Hardware error code 301");
entry->Message = "Hardware error code 301";
break;
case 302:
entry->Message = F("Hardware error code 302");
entry->Message = "Hardware error code 302";
break;
case 303:
entry->Message = F("Hardware error code 303");
entry->Message = "Hardware error code 303";
break;
case 304:
entry->Message = F("Hardware error code 304");
entry->Message = "Hardware error code 304";
break;
case 305:
entry->Message = F("Hardware error code 305");
entry->Message = "Hardware error code 305";
break;
case 306:
entry->Message = F("Hardware error code 306");
entry->Message = "Hardware error code 306";
break;
case 307:
entry->Message = F("Hardware error code 307");
entry->Message = "Hardware error code 307";
break;
case 308:
entry->Message = F("Hardware error code 308");
entry->Message = "Hardware error code 308";
break;
case 309:
entry->Message = F("Hardware error code 309");
entry->Message = "Hardware error code 309";
break;
case 310:
entry->Message = F("Hardware error code 310");
entry->Message = "Hardware error code 310";
break;
case 311:
entry->Message = F("Hardware error code 311");
entry->Message = "Hardware error code 311";
break;
case 312:
entry->Message = F("Hardware error code 312");
entry->Message = "Hardware error code 312";
break;
case 313:
entry->Message = F("Hardware error code 313");
entry->Message = "Hardware error code 313";
break;
case 314:
entry->Message = F("Hardware error code 314");
entry->Message = "Hardware error code 314";
break;
case 5041:
entry->Message = F("Error code-04 Port 1");
entry->Message = "Error code-04 Port 1";
break;
case 5042:
entry->Message = F("Error code-04 Port 2");
entry->Message = "Error code-04 Port 2";
break;
case 5043:
entry->Message = F("Error code-04 Port 3");
entry->Message = "Error code-04 Port 3";
break;
case 5044:
entry->Message = F("Error code-04 Port 4");
entry->Message = "Error code-04 Port 4";
break;
case 5051:
entry->Message = F("PV Input 1 Overvoltage/Undervoltage");
entry->Message = "PV Input 1 Overvoltage/Undervoltage";
break;
case 5052:
entry->Message = F("PV Input 2 Overvoltage/Undervoltage");
entry->Message = "PV Input 2 Overvoltage/Undervoltage";
break;
case 5053:
entry->Message = F("PV Input 3 Overvoltage/Undervoltage");
entry->Message = "PV Input 3 Overvoltage/Undervoltage";
break;
case 5054:
entry->Message = F("PV Input 4 Overvoltage/Undervoltage");
entry->Message = "PV Input 4 Overvoltage/Undervoltage";
break;
case 5060:
entry->Message = F("Abnormal bias");
entry->Message = "Abnormal bias";
break;
case 5070:
entry->Message = F("Over temperature protection");
entry->Message = "Over temperature protection";
break;
case 5080:
entry->Message = F("Grid Overvoltage/Undervoltage");
entry->Message = "Grid Overvoltage/Undervoltage";
break;
case 5090:
entry->Message = F("Grid Overfrequency/Underfrequency");
entry->Message = "Grid Overfrequency/Underfrequency";
break;
case 5100:
entry->Message = F("Island detected");
entry->Message = "Island detected";
break;
case 5120:
entry->Message = F("EEPROM reading and writing error");
entry->Message = "EEPROM reading and writing error";
break;
case 5150:
entry->Message = F("10 min value grid overvoltage");
entry->Message = "10 min value grid overvoltage";
break;
case 5200:
entry->Message = F("Firmware error");
entry->Message = "Firmware error";
break;
case 8310:
entry->Message = F("Shut down");
entry->Message = "Shut down";
break;
case 9000:
entry->Message = F("Microinverter is suspected of being stolen");
entry->Message = "Microinverter is suspected of being stolen";
break;
default:
entry->Message = F("Unknown");
entry->Message = "Unknown";
break;
}
}

View File

@ -29,58 +29,58 @@ String ResetReasonClass::get_reset_reason_verbose(uint8_t cpu_id)
switch (reason) {
case 1:
reason_str = F("Vbat power on reset");
reason_str = "Vbat power on reset";
break;
case 3:
reason_str = F("Software reset digital core");
reason_str = "Software reset digital core";
break;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
case 4:
reason_str = F("Legacy watch dog reset digital core");
reason_str = "Legacy watch dog reset digital core";
break;
#endif
case 5:
reason_str = F("Deep Sleep reset digital core");
reason_str = "Deep Sleep reset digital core";
break;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
case 6:
reason_str = F("Reset by SLC module, reset digital core");
reason_str = "Reset by SLC module, reset digital core";
break;
#endif
case 7:
reason_str = F("Timer Group0 Watch dog reset digital core");
reason_str = "Timer Group0 Watch dog reset digital core";
break;
case 8:
reason_str = F("Timer Group1 Watch dog reset digital core");
reason_str = "Timer Group1 Watch dog reset digital core";
break;
case 9:
reason_str = F("RTC Watch dog Reset digital core");
reason_str = "RTC Watch dog Reset digital core";
break;
case 10:
reason_str = F("Instrusion tested to reset CPU");
reason_str = "Instrusion tested to reset CPU";
break;
case 11:
reason_str = F("Time Group reset CPU");
reason_str = "Time Group reset CPU";
break;
case 12:
reason_str = F("Software reset CPU");
reason_str = "Software reset CPU";
break;
case 13:
reason_str = F("RTC Watch dog Reset CPU");
reason_str = "RTC Watch dog Reset CPU";
break;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
case 14:
reason_str = F("for APP CPU, reset by PRO CPU");
reason_str = "for APP CPU, reset by PRO CPU";
break;
#endif
case 15:
reason_str = F("Reset when the vdd voltage is not stable");
reason_str = "Reset when the vdd voltage is not stable";
break;
case 16:
reason_str = F("RTC Watch dog reset digital core and rtc module");
reason_str = "RTC Watch dog reset digital core and rtc module";
break;
default:
reason_str = F("NO_MEAN");
reason_str = "NO_MEAN";
}
return reason_str;
@ -95,58 +95,58 @@ String ResetReasonClass::get_reset_reason_short(uint8_t cpu_id)
switch (reason) {
case 1:
reason_str = F("POWERON_RESET");
reason_str = "POWERON_RESET";
break;
case 3:
reason_str = F("SW_RESET");
reason_str = "SW_RESET";
break;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
case 4:
reason_str = F("OWDT_RESET");
reason_str = "OWDT_RESET";
break;
#endif
case 5:
reason_str = F("DEEPSLEEP_RESET");
reason_str = "DEEPSLEEP_RESET";
break;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
case 6:
reason_str = F("SDIO_RESET");
reason_str = "SDIO_RESET";
break;
#endif
case 7:
reason_str = F("TG0WDT_SYS_RESET");
reason_str = "TG0WDT_SYS_RESET";
break;
case 8:
reason_str = F("TG1WDT_SYS_RESET");
reason_str = "TG1WDT_SYS_RESET";
break;
case 9:
reason_str = F("RTCWDT_SYS_RESET");
reason_str = "RTCWDT_SYS_RESET";
break;
case 10:
reason_str = F("INTRUSION_RESET");
reason_str = "INTRUSION_RESET";
break;
case 11:
reason_str = F("TGWDT_CPU_RESET");
reason_str = "TGWDT_CPU_RESET";
break;
case 12:
reason_str = F("SW_CPU_RESET");
reason_str = "SW_CPU_RESET";
break;
case 13:
reason_str = F("RTCWDT_CPU_RESET");
reason_str = "RTCWDT_CPU_RESET";
break;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
case 14:
reason_str = F("EXT_CPU_RESET");
reason_str = "EXT_CPU_RESET";
break;
#endif
case 15:
reason_str = F("RTCWDT_BROWN_OUT_RESET");
reason_str = "RTCWDT_BROWN_OUT_RESET";
break;
case 16:
reason_str = F("RTCWDT_RTC_RESET");
reason_str = "RTCWDT_RTC_RESET";
break;
default:
reason_str = F("NO_MEAN");
reason_str = "NO_MEAN";
}
return reason_str;

View File

@ -128,7 +128,7 @@ bool ConfigurationClass::read()
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, f);
if (error) {
MessageOutput.println(F("Failed to read file, using default configuration"));
MessageOutput.println("Failed to read file, using default configuration");
}
JsonObject cfg = doc["cfg"];
@ -255,7 +255,7 @@ void ConfigurationClass::migrate()
{
File f = LittleFS.open(CONFIG_FILENAME, "r", false);
if (!f) {
MessageOutput.println(F("Failed to open file, cancel migration"));
MessageOutput.println("Failed to open file, cancel migration");
return;
}

View File

@ -21,27 +21,27 @@ void InverterSettingsClass::init()
const PinMapping_t& pin = PinMapping.get();
// Initialize inverter communication
MessageOutput.print(F("Initialize Hoymiles interface... "));
MessageOutput.print("Initialize Hoymiles interface... ");
if (PinMapping.isValidNrf24Config()) {
SPIClass* spiClass = new SPIClass(VSPI);
spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs);
Hoymiles.setMessageOutput(&MessageOutput);
Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq);
MessageOutput.println(F(" Setting radio PA level... "));
MessageOutput.println(" Setting radio PA level... ");
Hoymiles.getRadio()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel);
MessageOutput.println(F(" Setting DTU serial... "));
MessageOutput.println(" Setting DTU serial... ");
Hoymiles.getRadio()->setDtuSerial(config.Dtu_Serial);
MessageOutput.println(F(" Setting poll interval... "));
MessageOutput.println(" Setting poll interval... ");
Hoymiles.setPollInterval(config.Dtu_PollInterval);
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
if (config.Inverter[i].Serial > 0) {
MessageOutput.print(F(" Adding inverter: "));
MessageOutput.print(" Adding inverter: ");
MessageOutput.print(config.Inverter[i].Serial, HEX);
MessageOutput.print(F(" - "));
MessageOutput.print(" - ");
MessageOutput.print(config.Inverter[i].Name);
auto inv = Hoymiles.addInverter(
config.Inverter[i].Name,
@ -53,12 +53,12 @@ void InverterSettingsClass::init()
inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast<ChannelNum_t>(c), FLD_YT, config.Inverter[i].channel[c].YieldTotalOffset);
}
}
MessageOutput.println(F(" done"));
MessageOutput.println(" done");
}
}
MessageOutput.println(F("done"));
MessageOutput.println("done");
} else {
MessageOutput.println(F("Invalid pin config"));
MessageOutput.println("Invalid pin config");
}
}

View File

@ -121,26 +121,26 @@ void MqttHandleHassClass::publishField(std::shared_ptr<InverterAbstract> inv, Ch
}
DynamicJsonDocument root(1024);
root[F("name")] = name;
root[F("stat_t")] = stateTopic;
root[F("uniq_id")] = serial + "_ch" + chanNum + "_" + fieldName;
root["name"] = name;
root["stat_t"] = stateTopic;
root["uniq_id"] = serial + "_ch" + chanNum + "_" + fieldName;
String unit_of_measure = inv->Statistics()->getChannelFieldUnit(type, channel, fieldType.fieldId);
if (unit_of_measure != "") {
root[F("unit_of_meas")] = unit_of_measure;
root["unit_of_meas"] = unit_of_measure;
}
JsonObject deviceObj = root.createNestedObject("dev");
createDeviceInfo(deviceObj, inv);
if (Configuration.get().Mqtt_Hass_Expire) {
root[F("exp_aft")] = Hoymiles.getNumInverters() * Configuration.get().Mqtt_PublishInterval * 3;
root["exp_aft"] = Hoymiles.getNumInverters() * Configuration.get().Mqtt_PublishInterval * 3;
}
if (devCls != 0) {
root[F("dev_cla")] = devCls;
root["dev_cla"] = devCls;
}
if (stateCls != 0) {
root[F("stat_cla")] = stateCls;
root["stat_cla"] = stateCls;
}
char buffer[512];
@ -166,17 +166,17 @@ void MqttHandleHassClass::publishInverterButton(std::shared_ptr<InverterAbstract
String cmdTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
DynamicJsonDocument root(1024);
root[F("name")] = String(inv->name()) + " " + caption;
root[F("uniq_id")] = serial + "_" + buttonId;
root["name"] = String(inv->name()) + " " + caption;
root["uniq_id"] = serial + "_" + buttonId;
if (strcmp(icon, "")) {
root[F("ic")] = icon;
root["ic"] = icon;
}
if (strcmp(deviceClass, "")) {
root[F("dev_cla")] = deviceClass;
root["dev_cla"] = deviceClass;
}
root[F("ent_cat")] = category;
root[F("cmd_t")] = cmdTopic;
root[F("payload_press")] = payload;
root["ent_cat"] = category;
root["cmd_t"] = cmdTopic;
root["payload_press"] = payload;
JsonObject deviceObj = root.createNestedObject("dev");
createDeviceInfo(deviceObj, inv);
@ -205,17 +205,17 @@ void MqttHandleHassClass::publishInverterNumber(
String statTopic = MqttSettings.getPrefix() + serial + "/" + stateTopic;
DynamicJsonDocument root(1024);
root[F("name")] = String(inv->name()) + " " + caption;
root[F("uniq_id")] = serial + "_" + buttonId;
root["name"] = String(inv->name()) + " " + caption;
root["uniq_id"] = serial + "_" + buttonId;
if (strcmp(icon, "")) {
root[F("ic")] = icon;
root["ic"] = icon;
}
root[F("ent_cat")] = category;
root[F("cmd_t")] = cmdTopic;
root[F("stat_t")] = statTopic;
root[F("unit_of_meas")] = unitOfMeasure;
root[F("min")] = min;
root[F("max")] = max;
root["ent_cat"] = category;
root["cmd_t"] = cmdTopic;
root["stat_t"] = statTopic;
root["unit_of_meas"] = unitOfMeasure;
root["min"] = min;
root["max"] = max;
JsonObject deviceObj = root.createNestedObject("dev");
createDeviceInfo(deviceObj, inv);
@ -240,11 +240,11 @@ void MqttHandleHassClass::publishInverterBinarySensor(std::shared_ptr<InverterAb
String statTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
DynamicJsonDocument root(1024);
root[F("name")] = String(inv->name()) + " " + caption;
root[F("uniq_id")] = serial + "_" + sensorId;
root[F("stat_t")] = statTopic;
root[F("pl_on")] = payload_on;
root[F("pl_off")] = payload_off;
root["name"] = String(inv->name()) + " " + caption;
root["uniq_id"] = serial + "_" + sensorId;
root["stat_t"] = statTopic;
root["pl_on"] = payload_on;
root["pl_off"] = payload_off;
JsonObject deviceObj = root.createNestedObject("dev");
createDeviceInfo(deviceObj, inv);
@ -256,12 +256,12 @@ void MqttHandleHassClass::publishInverterBinarySensor(std::shared_ptr<InverterAb
void MqttHandleHassClass::createDeviceInfo(JsonObject& object, std::shared_ptr<InverterAbstract> inv)
{
object[F("name")] = inv->name();
object[F("ids")] = inv->serialString();
object[F("cu")] = String(F("http://")) + NetworkSettings.localIP().toString();
object[F("mf")] = F("OpenDTU");
object[F("mdl")] = inv->typeName();
object[F("sw")] = AUTO_GIT_HASH;
object["name"] = inv->name();
object["ids"] = inv->serialString();
object["cu"] = String("http://") + NetworkSettings.localIP().toString();
object["mf"] = "OpenDTU";
object["mdl"] = inv->typeName();
object["sw"] = AUTO_GIT_HASH;
}
void MqttHandleHassClass::publish(const String& subtopic, const String& payload)

View File

@ -185,7 +185,7 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
auto inv = Hoymiles.getInverterBySerial(serial);
if (inv == nullptr) {
MessageOutput.println(F("Inverter not found"));
MessageOutput.println("Inverter not found");
return;
}

View File

@ -14,11 +14,11 @@ void MqttSettingsClass::NetworkEvent(network_event event)
{
switch (event) {
case network_event::NETWORK_GOT_IP:
MessageOutput.println(F("Network connected"));
MessageOutput.println("Network connected");
performConnect();
break;
case network_event::NETWORK_DISCONNECTED:
MessageOutput.println(F("Network lost connection"));
MessageOutput.println("Network lost connection");
mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
break;
default:
@ -28,7 +28,7 @@ void MqttSettingsClass::NetworkEvent(network_event event)
void MqttSettingsClass::onMqttConnect(bool sessionPresent)
{
MessageOutput.println(F("Connected to MQTT."));
MessageOutput.println("Connected to MQTT.");
const CONFIG_T& config = Configuration.get();
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Online);
@ -51,30 +51,30 @@ void MqttSettingsClass::unsubscribe(const String& topic)
void MqttSettingsClass::onMqttDisconnect(espMqttClientTypes::DisconnectReason reason)
{
MessageOutput.println(F("Disconnected from MQTT."));
MessageOutput.println("Disconnected from MQTT.");
MessageOutput.print(F("Disconnect reason:"));
MessageOutput.print("Disconnect reason:");
switch (reason) {
case espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED:
MessageOutput.println(F("TCP_DISCONNECTED"));
MessageOutput.println("TCP_DISCONNECTED");
break;
case espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
MessageOutput.println(F("MQTT_UNACCEPTABLE_PROTOCOL_VERSION"));
MessageOutput.println("MQTT_UNACCEPTABLE_PROTOCOL_VERSION");
break;
case espMqttClientTypes::DisconnectReason::MQTT_IDENTIFIER_REJECTED:
MessageOutput.println(F("MQTT_IDENTIFIER_REJECTED"));
MessageOutput.println("MQTT_IDENTIFIER_REJECTED");
break;
case espMqttClientTypes::DisconnectReason::MQTT_SERVER_UNAVAILABLE:
MessageOutput.println(F("MQTT_SERVER_UNAVAILABLE"));
MessageOutput.println("MQTT_SERVER_UNAVAILABLE");
break;
case espMqttClientTypes::DisconnectReason::MQTT_MALFORMED_CREDENTIALS:
MessageOutput.println(F("MQTT_MALFORMED_CREDENTIALS"));
MessageOutput.println("MQTT_MALFORMED_CREDENTIALS");
break;
case espMqttClientTypes::DisconnectReason::MQTT_NOT_AUTHORIZED:
MessageOutput.println(F("MQTT_NOT_AUTHORIZED"));
MessageOutput.println("MQTT_NOT_AUTHORIZED");
break;
default:
MessageOutput.println(F("Unknown"));
MessageOutput.println("Unknown");
}
mqttReconnectTimer.once(
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
@ -82,7 +82,7 @@ void MqttSettingsClass::onMqttDisconnect(espMqttClientTypes::DisconnectReason re
void MqttSettingsClass::onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total)
{
MessageOutput.print(F("Received MQTT message on topic: "));
MessageOutput.print("Received MQTT message on topic: ");
MessageOutput.println(topic);
_mqttSubscribeParser.handle_message(properties, topic, payload, len, index, total);
@ -97,7 +97,7 @@ void MqttSettingsClass::performConnect()
using std::placeholders::_4;
using std::placeholders::_5;
using std::placeholders::_6;
MessageOutput.println(F("Connecting to MQTT..."));
MessageOutput.println("Connecting to MQTT...");
const CONFIG_T& config = Configuration.get();
willTopic = getPrefix() + config.Mqtt_LwtTopic;
clientId = NetworkSettings.getApName();

View File

@ -29,19 +29,19 @@ void NetworkSettingsClass::NetworkEvent(WiFiEvent_t event)
{
switch (event) {
case ARDUINO_EVENT_ETH_START:
MessageOutput.println(F("ETH start"));
MessageOutput.println("ETH start");
if (_networkMode == network_mode::Ethernet) {
raiseEvent(network_event::NETWORK_START);
}
break;
case ARDUINO_EVENT_ETH_STOP:
MessageOutput.println(F("ETH stop"));
MessageOutput.println("ETH stop");
if (_networkMode == network_mode::Ethernet) {
raiseEvent(network_event::NETWORK_STOP);
}
break;
case ARDUINO_EVENT_ETH_CONNECTED:
MessageOutput.println(F("ETH connected"));
MessageOutput.println("ETH connected");
_ethConnected = true;
raiseEvent(network_event::NETWORK_CONNECTED);
break;
@ -52,22 +52,22 @@ void NetworkSettingsClass::NetworkEvent(WiFiEvent_t event)
}
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
MessageOutput.println(F("ETH disconnected"));
MessageOutput.println("ETH disconnected");
_ethConnected = false;
if (_networkMode == network_mode::Ethernet) {
raiseEvent(network_event::NETWORK_DISCONNECTED);
}
break;
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
MessageOutput.println(F("WiFi connected"));
MessageOutput.println("WiFi connected");
if (_networkMode == network_mode::WiFi) {
raiseEvent(network_event::NETWORK_CONNECTED);
}
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
MessageOutput.println(F("WiFi disconnected"));
MessageOutput.println("WiFi disconnected");
if (_networkMode == network_mode::WiFi) {
MessageOutput.println(F("Try reconnecting"));
MessageOutput.println("Try reconnecting");
WiFi.reconnect();
raiseEvent(network_event::NETWORK_DISCONNECTED);
}
@ -152,7 +152,7 @@ void NetworkSettingsClass::loop()
if (_ethConnected) {
if (_networkMode != network_mode::Ethernet) {
// Do stuff when switching to Ethernet mode
MessageOutput.println(F("Switch to Ethernet mode"));
MessageOutput.println("Switch to Ethernet mode");
_networkMode = network_mode::Ethernet;
WiFi.mode(WIFI_MODE_NULL);
setStaticIp();
@ -161,7 +161,7 @@ void NetworkSettingsClass::loop()
} else
if (_networkMode != network_mode::WiFi) {
// Do stuff when switching to Ethernet mode
MessageOutput.println(F("Switch to WiFi mode"));
MessageOutput.println("Switch to WiFi mode");
_networkMode = network_mode::WiFi;
enableAdminMode();
applyConfig();
@ -182,7 +182,7 @@ void NetworkSettingsClass::loop()
// seconds, disable the internal Access Point
if (adminTimeoutCounter > ADMIN_TIMEOUT) {
adminEnabled = false;
MessageOutput.println(F("Admin mode disabled"));
MessageOutput.println("Admin mode disabled");
setupMode();
}
// It's nearly not possible to use the internal AP if the
@ -193,16 +193,16 @@ void NetworkSettingsClass::loop()
connectRedoTimer = 0;
} else {
if (connectTimeoutTimer > WIFI_RECONNECT_TIMEOUT && !forceDisconnection) {
MessageOutput.print(F("Disable search for AP... "));
MessageOutput.print("Disable search for AP... ");
WiFi.mode(WIFI_AP);
MessageOutput.println(F("done"));
MessageOutput.println("done");
connectRedoTimer = 0;
forceDisconnection = true;
}
if (connectRedoTimer > WIFI_RECONNECT_REDO_TIMEOUT && forceDisconnection) {
MessageOutput.print(F("Enable search for AP... "));
MessageOutput.print("Enable search for AP... ");
WiFi.mode(WIFI_AP_STA);
MessageOutput.println(F("done"));
MessageOutput.println("done");
applyConfig();
connectTimeoutTimer = 0;
forceDisconnection = false;
@ -220,28 +220,28 @@ void NetworkSettingsClass::applyConfig()
if (!strcmp(Configuration.get().WiFi_Ssid, "")) {
return;
}
MessageOutput.print(F("Configuring WiFi STA using "));
MessageOutput.print("Configuring WiFi STA using ");
if (strcmp(WiFi.SSID().c_str(), Configuration.get().WiFi_Ssid) || strcmp(WiFi.psk().c_str(), Configuration.get().WiFi_Password)) {
MessageOutput.print(F("new credentials... "));
MessageOutput.print("new credentials... ");
WiFi.begin(
Configuration.get().WiFi_Ssid,
Configuration.get().WiFi_Password);
} else {
MessageOutput.print(F("existing credentials... "));
MessageOutput.print("existing credentials... ");
WiFi.begin();
}
MessageOutput.println(F("done"));
MessageOutput.println("done");
setStaticIp();
}
void NetworkSettingsClass::setHostname()
{
MessageOutput.print(F("Setting Hostname... "));
MessageOutput.print("Setting Hostname... ");
if (_networkMode == network_mode::WiFi) {
if (WiFi.hostname(getHostname())) {
MessageOutput.println(F("done"));
MessageOutput.println("done");
} else {
MessageOutput.println(F("failed"));
MessageOutput.println("failed");
}
// Evil bad hack to get the hostname set up correctly
@ -251,9 +251,9 @@ void NetworkSettingsClass::setHostname()
}
else if (_networkMode == network_mode::Ethernet) {
if (ETH.setHostname(getHostname().c_str())) {
MessageOutput.println(F("done"));
MessageOutput.println("done");
} else {
MessageOutput.println(F("failed"));
MessageOutput.println("failed");
}
}
}
@ -262,34 +262,34 @@ void NetworkSettingsClass::setStaticIp()
{
if (_networkMode == network_mode::WiFi) {
if (Configuration.get().WiFi_Dhcp) {
MessageOutput.print(F("Configuring WiFi STA DHCP IP... "));
MessageOutput.print("Configuring WiFi STA DHCP IP... ");
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
MessageOutput.println(F("done"));
MessageOutput.println("done");
} else {
MessageOutput.print(F("Configuring WiFi STA static IP... "));
MessageOutput.print("Configuring WiFi STA static IP... ");
WiFi.config(
IPAddress(Configuration.get().WiFi_Ip),
IPAddress(Configuration.get().WiFi_Gateway),
IPAddress(Configuration.get().WiFi_Netmask),
IPAddress(Configuration.get().WiFi_Dns1),
IPAddress(Configuration.get().WiFi_Dns2));
MessageOutput.println(F("done"));
MessageOutput.println("done");
}
}
else if (_networkMode == network_mode::Ethernet) {
if (Configuration.get().WiFi_Dhcp) {
MessageOutput.print(F("Configuring Ethernet DHCP IP... "));
MessageOutput.print("Configuring Ethernet DHCP IP... ");
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
MessageOutput.println(F("done"));
MessageOutput.println("done");
} else {
MessageOutput.print(F("Configuring Ethernet static IP... "));
MessageOutput.print("Configuring Ethernet static IP... ");
ETH.config(
IPAddress(Configuration.get().WiFi_Ip),
IPAddress(Configuration.get().WiFi_Gateway),
IPAddress(Configuration.get().WiFi_Netmask),
IPAddress(Configuration.get().WiFi_Dns1),
IPAddress(Configuration.get().WiFi_Dns2));
MessageOutput.println(F("done"));
MessageOutput.println("done");
}
}
}

View File

@ -80,7 +80,7 @@ bool PinMappingClass::init(const String& deviceMapping)
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, f);
if (error) {
MessageOutput.println(F("Failed to read file, using default configuration"));
MessageOutput.println("Failed to read file, using default configuration");
}
for (uint8_t i = 0; i < doc.size(); i++) {

View File

@ -73,7 +73,7 @@ bool WebApiClass::checkCredentials(AsyncWebServerRequest* request)
// WebAPI should set the X-Requested-With to prevent browser internal auth dialogs
if (!request->hasHeader("X-Requested-With")) {
r->addHeader(F("WWW-Authenticate"), F("Basic realm=\"Login Required\""));
r->addHeader("WWW-Authenticate", "Basic realm=\"Login Required\"");
}
request->send(r);

View File

@ -59,11 +59,11 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -72,8 +72,8 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -83,32 +83,32 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("delete"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("delete")].as<bool>() == false) {
retMsg[F("message")] = F("Not deleted anything!");
retMsg[F("code")] = WebApiError::ConfigNotDeleted;
if (root["delete"].as<bool>() == false) {
retMsg["message"] = "Not deleted anything!";
retMsg["code"] = WebApiError::ConfigNotDeleted;
response->setLength();
request->send(response);
return;
}
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Configuration resettet. Rebooting now...");
retMsg[F("code")] = WebApiError::ConfigSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Configuration resettet. Rebooting now...";
retMsg["code"] = WebApiError::ConfigSuccess;
response->setLength();
request->send(response);
@ -125,7 +125,7 @@ void WebApiConfigClass::onConfigListGet(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();
JsonArray data = root.createNestedArray(F("configs"));
JsonArray data = root.createNestedArray("configs");
File rootfs = LittleFS.open("/");
File file = rootfs.openNextFile();

View File

@ -37,37 +37,37 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
const PinMapping_t& pin = PinMapping.get();
JsonObject curPin = root.createNestedObject("curPin");
curPin[F("name")] = config.Dev_PinMapping;
curPin["name"] = config.Dev_PinMapping;
JsonObject nrfPinObj = curPin.createNestedObject("nrf24");
nrfPinObj[F("clk")] = pin.nrf24_clk;
nrfPinObj[F("cs")] = pin.nrf24_cs;
nrfPinObj[F("en")] = pin.nrf24_en;
nrfPinObj[F("irq")] = pin.nrf24_irq;
nrfPinObj[F("miso")] = pin.nrf24_miso;
nrfPinObj[F("mosi")] = pin.nrf24_mosi;
nrfPinObj["clk"] = pin.nrf24_clk;
nrfPinObj["cs"] = pin.nrf24_cs;
nrfPinObj["en"] = pin.nrf24_en;
nrfPinObj["irq"] = pin.nrf24_irq;
nrfPinObj["miso"] = pin.nrf24_miso;
nrfPinObj["mosi"] = pin.nrf24_mosi;
JsonObject ethPinObj = curPin.createNestedObject("eth");
ethPinObj[F("enabled")] = pin.eth_enabled;
ethPinObj[F("phy_addr")] = pin.eth_phy_addr;
ethPinObj[F("power")] = pin.eth_power;
ethPinObj[F("mdc")] = pin.eth_mdc;
ethPinObj[F("mdio")] = pin.eth_mdio;
ethPinObj[F("type")] = pin.eth_type;
ethPinObj[F("clk_mode")] = pin.eth_clk_mode;
ethPinObj["enabled"] = pin.eth_enabled;
ethPinObj["phy_addr"] = pin.eth_phy_addr;
ethPinObj["power"] = pin.eth_power;
ethPinObj["mdc"] = pin.eth_mdc;
ethPinObj["mdio"] = pin.eth_mdio;
ethPinObj["type"] = pin.eth_type;
ethPinObj["clk_mode"] = pin.eth_clk_mode;
JsonObject displayPinObj = curPin.createNestedObject("display");
displayPinObj[F("type")] = pin.display_type;
displayPinObj[F("data")] = pin.display_data;
displayPinObj[F("clk")] = pin.display_clk;
displayPinObj[F("cs")] = pin.display_cs;
displayPinObj[F("reset")] = pin.display_reset;
displayPinObj["type"] = pin.display_type;
displayPinObj["data"] = pin.display_data;
displayPinObj["clk"] = pin.display_clk;
displayPinObj["cs"] = pin.display_cs;
displayPinObj["reset"] = pin.display_reset;
JsonObject display = root.createNestedObject("display");
display[F("rotation")] = config.Display_Rotation;
display[F("power_safe")] = config.Display_PowerSafe;
display[F("screensaver")] = config.Display_ScreenSaver;
display[F("contrast")] = config.Display_Contrast;
display["rotation"] = config.Display_Rotation;
display["power_safe"] = config.Display_PowerSafe;
display["screensaver"] = config.Display_ScreenSaver;
display["contrast"] = config.Display_Contrast;
response->setLength();
request->send(response);
@ -81,11 +81,11 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -94,8 +94,8 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > MQTT_JSON_DOC_SIZE) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -105,38 +105,38 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("curPin") || root.containsKey("display"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("curPin")][F("name")].as<String>().length() == 0 || root[F("curPin")][F("name")].as<String>().length() > DEV_MAX_MAPPING_NAME_STRLEN) {
retMsg[F("message")] = F("Pin mapping must between 1 and " STR(DEV_MAX_MAPPING_NAME_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::HardwarePinMappingLength;
retMsg[F("param")][F("max")] = DEV_MAX_MAPPING_NAME_STRLEN;
if (root["curPin"]["name"].as<String>().length() == 0 || root["curPin"]["name"].as<String>().length() > DEV_MAX_MAPPING_NAME_STRLEN) {
retMsg["message"] = "Pin mapping must between 1 and " STR(DEV_MAX_MAPPING_NAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::HardwarePinMappingLength;
retMsg["param"]["max"] = DEV_MAX_MAPPING_NAME_STRLEN;
response->setLength();
request->send(response);
return;
}
CONFIG_T& config = Configuration.get();
bool performRestart = root[F("curPin")][F("name")].as<String>() != config.Dev_PinMapping;
bool performRestart = root["curPin"]["name"].as<String>() != config.Dev_PinMapping;
strlcpy(config.Dev_PinMapping, root[F("curPin")][F("name")].as<String>().c_str(), sizeof(config.Dev_PinMapping));
config.Display_Rotation = root[F("display")][F("rotation")].as<uint8_t>();
config.Display_PowerSafe = root[F("display")][F("power_safe")].as<bool>();
config.Display_ScreenSaver = root[F("display")][F("screensaver")].as<bool>();
config.Display_Contrast = root[F("display")][F("contrast")].as<uint8_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>();
Display.setOrientation(config.Display_Rotation);
Display.enablePowerSafe = config.Display_PowerSafe;
@ -145,9 +145,9 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);

View File

@ -34,18 +34,18 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
auto inv = Hoymiles.getInverterByPos(i);
JsonObject devInfoObj = root[inv->serialString()].createNestedObject();
devInfoObj[F("valid_data")] = inv->DevInfo()->getLastUpdate() > 0;
devInfoObj[F("fw_bootloader_version")] = inv->DevInfo()->getFwBootloaderVersion();
devInfoObj[F("fw_build_version")] = inv->DevInfo()->getFwBuildVersion();
devInfoObj[F("hw_part_number")] = inv->DevInfo()->getHwPartNumber();
devInfoObj[F("hw_version")] = inv->DevInfo()->getHwVersion();
devInfoObj[F("hw_model_name")] = inv->DevInfo()->getHwModelName();
devInfoObj[F("max_power")] = inv->DevInfo()->getMaxPower();
devInfoObj["valid_data"] = inv->DevInfo()->getLastUpdate() > 0;
devInfoObj["fw_bootloader_version"] = inv->DevInfo()->getFwBootloaderVersion();
devInfoObj["fw_build_version"] = inv->DevInfo()->getFwBuildVersion();
devInfoObj["hw_part_number"] = inv->DevInfo()->getHwPartNumber();
devInfoObj["hw_version"] = inv->DevInfo()->getHwVersion();
devInfoObj["hw_model_name"] = inv->DevInfo()->getHwModelName();
devInfoObj["max_power"] = inv->DevInfo()->getMaxPower();
char timebuffer[32];
const time_t t = inv->DevInfo()->getFwBuildDateTime();
std::strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", gmtime(&t));
devInfoObj[F("fw_build_datetime")] = String(timebuffer);
devInfoObj["fw_build_datetime"] = String(timebuffer);
}
response->setLength();

View File

@ -38,9 +38,9 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request)
snprintf(buffer, sizeof(buffer), "%0x%08x",
((uint32_t)((config.Dtu_Serial >> 32) & 0xFFFFFFFF)),
((uint32_t)(config.Dtu_Serial & 0xFFFFFFFF)));
root[F("dtu_serial")] = buffer;
root[F("dtu_pollinterval")] = config.Dtu_PollInterval;
root[F("dtu_palevel")] = config.Dtu_PaLevel;
root["dtu_serial"] = buffer;
root["dtu_pollinterval"] = config.Dtu_PollInterval;
root["dtu_palevel"] = config.Dtu_PaLevel;
response->setLength();
request->send(response);
@ -54,11 +54,11 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -67,8 +67,8 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -78,40 +78,40 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("dtu_serial") && root.containsKey("dtu_pollinterval") && root.containsKey("dtu_palevel"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("dtu_serial")].as<uint64_t>() == 0) {
retMsg[F("message")] = F("Serial cannot be zero!");
retMsg[F("code")] = WebApiError::DtuSerialZero;
if (root["dtu_serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial cannot be zero!";
retMsg["code"] = WebApiError::DtuSerialZero;
response->setLength();
request->send(response);
return;
}
if (root[F("dtu_pollinterval")].as<uint32_t>() == 0) {
retMsg[F("message")] = F("Poll interval must be greater zero!");
retMsg[F("code")] = WebApiError::DtuPollZero;
if (root["dtu_pollinterval"].as<uint32_t>() == 0) {
retMsg["message"] = "Poll interval must be greater zero!";
retMsg["code"] = WebApiError::DtuPollZero;
response->setLength();
request->send(response);
return;
}
if (root[F("dtu_palevel")].as<uint8_t>() > 3) {
retMsg[F("message")] = F("Invalid power level setting!");
retMsg[F("code")] = WebApiError::DtuInvalidPowerLevel;
if (root["dtu_palevel"].as<uint8_t>() > 3) {
retMsg["message"] = "Invalid power level setting!";
retMsg["code"] = WebApiError::DtuInvalidPowerLevel;
response->setLength();
request->send(response);
return;
@ -120,14 +120,14 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
CONFIG_T& config = Configuration.get();
// Interpret the string as a hex value and convert it to uint64_t
config.Dtu_Serial = strtoll(root[F("dtu_serial")].as<String>().c_str(), NULL, 16);
config.Dtu_PollInterval = root[F("dtu_pollinterval")].as<uint32_t>();
config.Dtu_PaLevel = root[F("dtu_palevel")].as<uint8_t>();
config.Dtu_Serial = strtoll(root["dtu_serial"].as<String>().c_str(), NULL, 16);
config.Dtu_PollInterval = root["dtu_pollinterval"].as<uint32_t>();
config.Dtu_PaLevel = root["dtu_palevel"].as<uint8_t>();
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);

View File

@ -43,7 +43,7 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
uint8_t logEntryCount = inv->EventLog()->getEntryCount();
root[serial]["count"] = logEntryCount;
JsonArray eventsArray = root[serial].createNestedArray(F("events"));
JsonArray eventsArray = root[serial].createNestedArray("events");
for (uint8_t logEntry = 0; logEntry < logEntryCount; logEntry++) {
JsonObject eventsObject = eventsArray.createNestedObject();
@ -51,10 +51,10 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
AlarmLogEntry_t entry;
inv->EventLog()->getLogEntry(logEntry, &entry);
eventsObject[F("message_id")] = entry.MessageId;
eventsObject[F("message")] = entry.Message;
eventsObject[F("start_time")] = entry.StartTime;
eventsObject[F("end_time")] = entry.EndTime;
eventsObject["message_id"] = entry.MessageId;
eventsObject["message"] = entry.Message;
eventsObject["start_time"] = entry.StartTime;
eventsObject["end_time"] = entry.EndTime;
}
}

View File

@ -35,34 +35,34 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse(false, 4096U);
JsonObject root = response->getRoot();
JsonArray data = root.createNestedArray(F("inverter"));
JsonArray data = root.createNestedArray("inverter");
const CONFIG_T& config = Configuration.get();
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
if (config.Inverter[i].Serial > 0) {
JsonObject obj = data.createNestedObject();
obj[F("id")] = i;
obj[F("name")] = String(config.Inverter[i].Name);
obj["id"] = i;
obj["name"] = String(config.Inverter[i].Name);
// Inverter Serial is read as HEX
char buffer[sizeof(uint64_t) * 8 + 1];
snprintf(buffer, sizeof(buffer), "%0x%08x",
((uint32_t)((config.Inverter[i].Serial >> 32) & 0xFFFFFFFF)),
((uint32_t)(config.Inverter[i].Serial & 0xFFFFFFFF)));
obj[F("serial")] = buffer;
obj[F("poll_enable")] = config.Inverter[i].Poll_Enable;
obj[F("poll_enable_night")] = config.Inverter[i].Poll_Enable_Night;
obj[F("command_enable")] = config.Inverter[i].Command_Enable;
obj[F("command_enable_night")] = config.Inverter[i].Command_Enable_Night;
obj["serial"] = buffer;
obj["poll_enable"] = config.Inverter[i].Poll_Enable;
obj["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night;
obj["command_enable"] = config.Inverter[i].Command_Enable;
obj["command_enable_night"] = config.Inverter[i].Command_Enable_Night;
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
uint8_t max_channels;
if (inv == nullptr) {
obj[F("type")] = F("Unknown");
obj["type"] = "Unknown";
max_channels = INV_MAX_CHAN_COUNT;
} else {
obj[F("type")] = inv->typeName();
obj["type"] = inv->typeName();
max_channels = inv->Statistics()->getChannelsByType(TYPE_DC).size();
}
@ -88,11 +88,11 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -101,8 +101,8 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -112,33 +112,33 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("serial") && root.containsKey("name"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("serial")].as<uint64_t>() == 0) {
retMsg[F("message")] = F("Serial must be a number > 0!");
retMsg[F("code")] = WebApiError::InverterSerialZero;
if (root["serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::InverterSerialZero;
response->setLength();
request->send(response);
return;
}
if (root[F("name")].as<String>().length() == 0 || root[F("name")].as<String>().length() > INV_MAX_NAME_STRLEN) {
retMsg[F("message")] = F("Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::InverterNameLength;
retMsg[F("param")][F("max")] = INV_MAX_NAME_STRLEN;
if (root["name"].as<String>().length() == 0 || root["name"].as<String>().length() > INV_MAX_NAME_STRLEN) {
retMsg["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::InverterNameLength;
retMsg["param"]["max"] = INV_MAX_NAME_STRLEN;
response->setLength();
request->send(response);
return;
@ -147,23 +147,23 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
INVERTER_CONFIG_T* inverter = Configuration.getFreeInverterSlot();
if (!inverter) {
retMsg[F("message")] = F("Only " STR(INV_MAX_COUNT) " inverters are supported!");
retMsg[F("code")] = WebApiError::InverterCount;
retMsg[F("param")][F("max")] = INV_MAX_COUNT;
retMsg["message"] = "Only " STR(INV_MAX_COUNT) " inverters are supported!";
retMsg["code"] = WebApiError::InverterCount;
retMsg["param"]["max"] = INV_MAX_COUNT;
response->setLength();
request->send(response);
return;
}
// Interpret the string as a hex value and convert it to uint64_t
inverter->Serial = strtoll(root[F("serial")].as<String>().c_str(), NULL, 16);
inverter->Serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
strncpy(inverter->Name, root[F("name")].as<String>().c_str(), INV_MAX_NAME_STRLEN);
strncpy(inverter->Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN);
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Inverter created!");
retMsg[F("code")] = WebApiError::InverterAdded;
retMsg["type"] = "success";
retMsg["message"] = "Inverter created!";
retMsg["code"] = WebApiError::InverterAdded;
response->setLength();
request->send(response);
@ -187,11 +187,11 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -200,8 +200,8 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -211,82 +211,82 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("id") && root.containsKey("serial") && root.containsKey("name") && root.containsKey("channel"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("id")].as<uint8_t>() > INV_MAX_COUNT - 1) {
retMsg[F("message")] = F("Invalid ID specified!");
retMsg[F("code")] = WebApiError::InverterInvalidId;
if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) {
retMsg["message"] = "Invalid ID specified!";
retMsg["code"] = WebApiError::InverterInvalidId;
response->setLength();
request->send(response);
return;
}
if (root[F("serial")].as<uint64_t>() == 0) {
retMsg[F("message")] = F("Serial must be a number > 0!");
retMsg[F("code")] = WebApiError::InverterSerialZero;
if (root["serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::InverterSerialZero;
response->setLength();
request->send(response);
return;
}
if (root[F("name")].as<String>().length() == 0 || root[F("name")].as<String>().length() > INV_MAX_NAME_STRLEN) {
retMsg[F("message")] = F("Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::InverterNameLength;
retMsg[F("param")][F("max")] = INV_MAX_NAME_STRLEN;
if (root["name"].as<String>().length() == 0 || root["name"].as<String>().length() > INV_MAX_NAME_STRLEN) {
retMsg["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::InverterNameLength;
retMsg["param"]["max"] = INV_MAX_NAME_STRLEN;
response->setLength();
request->send(response);
return;
}
JsonArray channelArray = root[F("channel")].as<JsonArray>();
JsonArray channelArray = root["channel"].as<JsonArray>();
if (channelArray.size() == 0 || channelArray.size() > INV_MAX_CHAN_COUNT) {
retMsg[F("message")] = F("Invalid amount of max channel setting given!");
retMsg[F("code")] = WebApiError::InverterInvalidMaxChannel;
retMsg["message"] = "Invalid amount of max channel setting given!";
retMsg["code"] = WebApiError::InverterInvalidMaxChannel;
response->setLength();
request->send(response);
return;
}
INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[root[F("id")].as<uint8_t>()];
INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[root["id"].as<uint8_t>()];
uint64_t new_serial = strtoll(root[F("serial")].as<String>().c_str(), NULL, 16);
uint64_t new_serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
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[F("name")].as<String>().c_str(), INV_MAX_NAME_STRLEN);
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[F("max_power")].as<uint16_t>();
inverter.channel[arrayCount].YieldTotalOffset = channel[F("yield_total_offset")].as<float>();
strncpy(inverter.channel[arrayCount].Name, channel[F("name")] | "", sizeof(inverter.channel[arrayCount].Name));
inverter.Poll_Enable = root[F("poll_enable")] | true;
inverter.Poll_Enable_Night = root[F("poll_enable_night")] | true;
inverter.Command_Enable = root[F("command_enable")] | true;
inverter.Command_Enable_Night = root[F("command_enable_night")] | true;
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));
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;
arrayCount++;
}
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("code")] = WebApiError::InverterChanged;
retMsg[F("message")] = F("Inverter changed!");
retMsg["type"] = "success";
retMsg["code"] = WebApiError::InverterChanged;
retMsg["message"] = "Inverter changed!";
response->setLength();
request->send(response);
@ -325,11 +325,11 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -338,8 +338,8 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -349,30 +349,30 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("id"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("id")].as<uint8_t>() > INV_MAX_COUNT - 1) {
retMsg[F("message")] = F("Invalid ID specified!");
retMsg[F("code")] = WebApiError::InverterInvalidId;
if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) {
retMsg["message"] = "Invalid ID specified!";
retMsg["code"] = WebApiError::InverterInvalidId;
response->setLength();
request->send(response);
return;
}
uint8_t inverter_id = root[F("id")].as<uint8_t>();
uint8_t inverter_id = root["id"].as<uint8_t>();
INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[inverter_id];
Hoymiles.removeInverterBySerial(inverter.Serial);
@ -381,9 +381,9 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
strncpy(inverter.Name, "", sizeof(inverter.Name));
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Inverter deleted!");
retMsg[F("code")] = WebApiError::InverterDeleted;
retMsg["type"] = "success";
retMsg["message"] = "Inverter deleted!";
retMsg["code"] = WebApiError::InverterDeleted;
response->setLength();
request->send(response);

View File

@ -63,11 +63,11 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -76,8 +76,8 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -87,8 +87,8 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
@ -97,50 +97,50 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
if (!(root.containsKey("serial")
&& root.containsKey("limit_value")
&& root.containsKey("limit_type"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("serial")].as<uint64_t>() == 0) {
retMsg[F("message")] = F("Serial must be a number > 0!");
retMsg[F("code")] = WebApiError::LimitSerialZero;
if (root["serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::LimitSerialZero;
response->setLength();
request->send(response);
return;
}
if (root[F("limit_value")].as<uint16_t>() == 0 || root[F("limit_value")].as<uint16_t>() > 1500) {
retMsg[F("message")] = F("Limit must between 1 and 1500!");
retMsg[F("code")] = WebApiError::LimitInvalidLimit;
retMsg[F("param")][F("max")] = 1500;
if (root["limit_value"].as<uint16_t>() == 0 || root["limit_value"].as<uint16_t>() > 1500) {
retMsg["message"] = "Limit must between 1 and 1500!";
retMsg["code"] = WebApiError::LimitInvalidLimit;
retMsg["param"]["max"] = 1500;
response->setLength();
request->send(response);
return;
}
if (!((root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::AbsolutNonPersistent)
|| (root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::AbsolutPersistent)
|| (root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::RelativNonPersistent)
|| (root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::RelativPersistent))) {
if (!((root["limit_type"].as<uint16_t>() == PowerLimitControlType::AbsolutNonPersistent)
|| (root["limit_type"].as<uint16_t>() == PowerLimitControlType::AbsolutPersistent)
|| (root["limit_type"].as<uint16_t>() == PowerLimitControlType::RelativNonPersistent)
|| (root["limit_type"].as<uint16_t>() == PowerLimitControlType::RelativPersistent))) {
retMsg[F("message")] = F("Invalid type specified!");
retMsg[F("code")] = WebApiError::LimitInvalidType;
retMsg["message"] = "Invalid type specified!";
retMsg["code"] = WebApiError::LimitInvalidType;
response->setLength();
request->send(response);
return;
}
uint64_t serial = strtoll(root[F("serial")].as<String>().c_str(), NULL, 16);
uint16_t limit = root[F("limit_value")].as<uint16_t>();
PowerLimitControlType type = root[F("limit_type")].as<PowerLimitControlType>();
uint64_t serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
uint16_t limit = root["limit_value"].as<uint16_t>();
PowerLimitControlType type = root["limit_type"].as<PowerLimitControlType>();
auto inv = Hoymiles.getInverterBySerial(serial);
if (inv == nullptr) {
retMsg[F("message")] = F("Invalid inverter specified!");
retMsg[F("code")] = WebApiError::LimitInvalidInverter;
retMsg["message"] = "Invalid inverter specified!";
retMsg["code"] = WebApiError::LimitInvalidInverter;
response->setLength();
request->send(response);
return;
@ -148,9 +148,9 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
inv->sendActivePowerControlRequest(Hoymiles.getRadio(), limit, type);
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);

View File

@ -29,11 +29,11 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -42,8 +42,8 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > MQTT_JSON_DOC_SIZE) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -53,25 +53,25 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("reboot"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("reboot")].as<bool>()) {
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Reboot triggered!");
retMsg[F("code")] = WebApiError::MaintenanceRebootTriggered;
if (root["reboot"].as<bool>()) {
retMsg["type"] = "success";
retMsg["message"] = "Reboot triggered!";
retMsg["code"] = WebApiError::MaintenanceRebootTriggered;
response->setLength();
request->send(response);
@ -80,8 +80,8 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
yield();
ESP.restart();
} else {
retMsg[F("message")] = F("Reboot cancled!");
retMsg[F("code")] = WebApiError::MaintenanceRebootCancled;
retMsg["message"] = "Reboot cancled!";
retMsg["code"] = WebApiError::MaintenanceRebootCancled;
response->setLength();
request->send(response);

View File

@ -36,22 +36,22 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
root[F("mqtt_enabled")] = config.Mqtt_Enabled;
root[F("mqtt_hostname")] = config.Mqtt_Hostname;
root[F("mqtt_port")] = config.Mqtt_Port;
root[F("mqtt_username")] = config.Mqtt_Username;
root[F("mqtt_topic")] = config.Mqtt_Topic;
root[F("mqtt_connected")] = MqttSettings.getConnected();
root[F("mqtt_retain")] = config.Mqtt_Retain;
root[F("mqtt_tls")] = config.Mqtt_Tls;
root[F("mqtt_root_ca_cert_info")] = getRootCaCertInfo(config.Mqtt_RootCaCert);
root[F("mqtt_lwt_topic")] = String(config.Mqtt_Topic) + config.Mqtt_LwtTopic;
root[F("mqtt_publish_interval")] = config.Mqtt_PublishInterval;
root[F("mqtt_hass_enabled")] = config.Mqtt_Hass_Enabled;
root[F("mqtt_hass_expire")] = config.Mqtt_Hass_Expire;
root[F("mqtt_hass_retain")] = config.Mqtt_Hass_Retain;
root[F("mqtt_hass_topic")] = config.Mqtt_Hass_Topic;
root[F("mqtt_hass_individualpanels")] = config.Mqtt_Hass_IndividualPanels;
root["mqtt_enabled"] = config.Mqtt_Enabled;
root["mqtt_hostname"] = config.Mqtt_Hostname;
root["mqtt_port"] = config.Mqtt_Port;
root["mqtt_username"] = config.Mqtt_Username;
root["mqtt_topic"] = config.Mqtt_Topic;
root["mqtt_connected"] = MqttSettings.getConnected();
root["mqtt_retain"] = config.Mqtt_Retain;
root["mqtt_tls"] = config.Mqtt_Tls;
root["mqtt_root_ca_cert_info"] = getRootCaCertInfo(config.Mqtt_RootCaCert);
root["mqtt_lwt_topic"] = String(config.Mqtt_Topic) + config.Mqtt_LwtTopic;
root["mqtt_publish_interval"] = config.Mqtt_PublishInterval;
root["mqtt_hass_enabled"] = config.Mqtt_Hass_Enabled;
root["mqtt_hass_expire"] = config.Mqtt_Hass_Expire;
root["mqtt_hass_retain"] = config.Mqtt_Hass_Retain;
root["mqtt_hass_topic"] = config.Mqtt_Hass_Topic;
root["mqtt_hass_individualpanels"] = config.Mqtt_Hass_IndividualPanels;
response->setLength();
request->send(response);
@ -67,24 +67,24 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
root[F("mqtt_enabled")] = config.Mqtt_Enabled;
root[F("mqtt_hostname")] = config.Mqtt_Hostname;
root[F("mqtt_port")] = config.Mqtt_Port;
root[F("mqtt_username")] = config.Mqtt_Username;
root[F("mqtt_password")] = config.Mqtt_Password;
root[F("mqtt_topic")] = config.Mqtt_Topic;
root[F("mqtt_retain")] = config.Mqtt_Retain;
root[F("mqtt_tls")] = config.Mqtt_Tls;
root[F("mqtt_root_ca_cert")] = config.Mqtt_RootCaCert;
root[F("mqtt_lwt_topic")] = config.Mqtt_LwtTopic;
root[F("mqtt_lwt_online")] = config.Mqtt_LwtValue_Online;
root[F("mqtt_lwt_offline")] = config.Mqtt_LwtValue_Offline;
root[F("mqtt_publish_interval")] = config.Mqtt_PublishInterval;
root[F("mqtt_hass_enabled")] = config.Mqtt_Hass_Enabled;
root[F("mqtt_hass_expire")] = config.Mqtt_Hass_Expire;
root[F("mqtt_hass_retain")] = config.Mqtt_Hass_Retain;
root[F("mqtt_hass_topic")] = config.Mqtt_Hass_Topic;
root[F("mqtt_hass_individualpanels")] = config.Mqtt_Hass_IndividualPanels;
root["mqtt_enabled"] = config.Mqtt_Enabled;
root["mqtt_hostname"] = config.Mqtt_Hostname;
root["mqtt_port"] = config.Mqtt_Port;
root["mqtt_username"] = config.Mqtt_Username;
root["mqtt_password"] = config.Mqtt_Password;
root["mqtt_topic"] = config.Mqtt_Topic;
root["mqtt_retain"] = config.Mqtt_Retain;
root["mqtt_tls"] = config.Mqtt_Tls;
root["mqtt_root_ca_cert"] = config.Mqtt_RootCaCert;
root["mqtt_lwt_topic"] = config.Mqtt_LwtTopic;
root["mqtt_lwt_online"] = config.Mqtt_LwtValue_Online;
root["mqtt_lwt_offline"] = config.Mqtt_LwtValue_Offline;
root["mqtt_publish_interval"] = config.Mqtt_PublishInterval;
root["mqtt_hass_enabled"] = config.Mqtt_Hass_Enabled;
root["mqtt_hass_expire"] = config.Mqtt_Hass_Expire;
root["mqtt_hass_retain"] = config.Mqtt_Hass_Retain;
root["mqtt_hass_topic"] = config.Mqtt_Hass_Topic;
root["mqtt_hass_individualpanels"] = config.Mqtt_Hass_IndividualPanels;
response->setLength();
request->send(response);
@ -98,11 +98,11 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -111,8 +111,8 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > MQTT_JSON_DOC_SIZE) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -122,8 +122,8 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
@ -146,139 +146,139 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
&& root.containsKey("mqtt_hass_retain")
&& root.containsKey("mqtt_hass_topic")
&& root.containsKey("mqtt_hass_individualpanels"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_enabled")].as<bool>()) {
if (root[F("mqtt_hostname")].as<String>().length() == 0 || root[F("mqtt_hostname")].as<String>().length() > MQTT_MAX_HOSTNAME_STRLEN) {
retMsg[F("message")] = F("MqTT Server must between 1 and " STR(MQTT_MAX_HOSTNAME_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::MqttHostnameLength;
retMsg[F("param")][F("max")] = MQTT_MAX_HOSTNAME_STRLEN;
if (root["mqtt_enabled"].as<bool>()) {
if (root["mqtt_hostname"].as<String>().length() == 0 || root["mqtt_hostname"].as<String>().length() > MQTT_MAX_HOSTNAME_STRLEN) {
retMsg["message"] = "MqTT Server must between 1 and " STR(MQTT_MAX_HOSTNAME_STRLEN) " characters long!";
retMsg["code"] = WebApiError::MqttHostnameLength;
retMsg["param"]["max"] = MQTT_MAX_HOSTNAME_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_username")].as<String>().length() > MQTT_MAX_USERNAME_STRLEN) {
retMsg[F("message")] = F("Username must not longer then " STR(MQTT_MAX_USERNAME_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttUsernameLength;
retMsg[F("param")][F("max")] = MQTT_MAX_USERNAME_STRLEN;
if (root["mqtt_username"].as<String>().length() > MQTT_MAX_USERNAME_STRLEN) {
retMsg["message"] = "Username must not longer then " STR(MQTT_MAX_USERNAME_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttUsernameLength;
retMsg["param"]["max"] = MQTT_MAX_USERNAME_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_password")].as<String>().length() > MQTT_MAX_PASSWORD_STRLEN) {
retMsg[F("message")] = F("Password must not longer then " STR(MQTT_MAX_PASSWORD_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttPasswordLength;
retMsg[F("param")][F("max")] = MQTT_MAX_PASSWORD_STRLEN;
if (root["mqtt_password"].as<String>().length() > MQTT_MAX_PASSWORD_STRLEN) {
retMsg["message"] = "Password must not longer then " STR(MQTT_MAX_PASSWORD_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttPasswordLength;
retMsg["param"]["max"] = MQTT_MAX_PASSWORD_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
retMsg[F("message")] = F("Topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttTopicLength;
retMsg[F("param")][F("max")] = MQTT_MAX_TOPIC_STRLEN;
if (root["mqtt_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
retMsg["message"] = "Topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttTopicLength;
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_topic")].as<String>().indexOf(' ') != -1) {
retMsg[F("message")] = F("Topic must not contain space characters!");
retMsg[F("code")] = WebApiError::MqttTopicCharacter;
if (root["mqtt_topic"].as<String>().indexOf(' ') != -1) {
retMsg["message"] = "Topic must not contain space characters!";
retMsg["code"] = WebApiError::MqttTopicCharacter;
response->setLength();
request->send(response);
return;
}
if (!root[F("mqtt_topic")].as<String>().endsWith("/")) {
retMsg[F("message")] = F("Topic must end with slash (/)!");
retMsg[F("code")] = WebApiError::MqttTopicTrailingSlash;
if (!root["mqtt_topic"].as<String>().endsWith("/")) {
retMsg["message"] = "Topic must end with slash (/)!";
retMsg["code"] = WebApiError::MqttTopicTrailingSlash;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_port")].as<uint>() == 0 || root[F("mqtt_port")].as<uint>() > 65535) {
retMsg[F("message")] = F("Port must be a number between 1 and 65535!");
retMsg[F("code")] = WebApiError::MqttPort;
if (root["mqtt_port"].as<uint>() == 0 || root["mqtt_port"].as<uint>() > 65535) {
retMsg["message"] = "Port must be a number between 1 and 65535!";
retMsg["code"] = WebApiError::MqttPort;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_root_ca_cert")].as<String>().length() > MQTT_MAX_ROOT_CA_CERT_STRLEN) {
retMsg[F("message")] = F("Certificate must not longer then " STR(MQTT_MAX_ROOT_CA_CERT_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttCertificateLength;
retMsg[F("param")][F("max")] = MQTT_MAX_ROOT_CA_CERT_STRLEN;
if (root["mqtt_root_ca_cert"].as<String>().length() > MQTT_MAX_ROOT_CA_CERT_STRLEN) {
retMsg["message"] = "Certificate must not longer then " STR(MQTT_MAX_ROOT_CA_CERT_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttCertificateLength;
retMsg["param"]["max"] = MQTT_MAX_ROOT_CA_CERT_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_lwt_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
retMsg[F("message")] = F("LWT topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttLwtTopicLength;
retMsg[F("param")][F("max")] = MQTT_MAX_TOPIC_STRLEN;
if (root["mqtt_lwt_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
retMsg["message"] = "LWT topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttLwtTopicLength;
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_lwt_topic")].as<String>().indexOf(' ') != -1) {
retMsg[F("message")] = F("LWT topic must not contain space characters!");
retMsg[F("code")] = WebApiError::MqttLwtTopicCharacter;
if (root["mqtt_lwt_topic"].as<String>().indexOf(' ') != -1) {
retMsg["message"] = "LWT topic must not contain space characters!";
retMsg["code"] = WebApiError::MqttLwtTopicCharacter;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_lwt_online")].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
retMsg[F("message")] = F("LWT online value must not longer then " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttLwtOnlineLength;
retMsg[F("param")][F("max")] = MQTT_MAX_LWTVALUE_STRLEN;
if (root["mqtt_lwt_online"].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
retMsg["message"] = "LWT online value must not longer then " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttLwtOnlineLength;
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_lwt_offline")].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
retMsg[F("message")] = F("LWT offline value must not longer then " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttLwtOfflineLength;
retMsg[F("param")][F("max")] = MQTT_MAX_LWTVALUE_STRLEN;
if (root["mqtt_lwt_offline"].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
retMsg["message"] = "LWT offline value must not longer then " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttLwtOfflineLength;
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_publish_interval")].as<uint32_t>() < 5 || root[F("mqtt_publish_interval")].as<uint32_t>() > 65535) {
retMsg[F("message")] = F("Publish interval must be a number between 5 and 65535!");
retMsg[F("code")] = WebApiError::MqttPublishInterval;
retMsg[F("param")][F("min")] = 5;
retMsg[F("param")][F("max")] = 65535;
if (root["mqtt_publish_interval"].as<uint32_t>() < 5 || root["mqtt_publish_interval"].as<uint32_t>() > 65535) {
retMsg["message"] = "Publish interval must be a number between 5 and 65535!";
retMsg["code"] = WebApiError::MqttPublishInterval;
retMsg["param"]["min"] = 5;
retMsg["param"]["max"] = 65535;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_hass_enabled")].as<bool>()) {
if (root[F("mqtt_hass_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
retMsg[F("message")] = F("Hass topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!");
retMsg[F("code")] = WebApiError::MqttHassTopicLength;
retMsg[F("param")][F("max")] = MQTT_MAX_TOPIC_STRLEN;
if (root["mqtt_hass_enabled"].as<bool>()) {
if (root["mqtt_hass_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
retMsg["message"] = "Hass topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
retMsg["code"] = WebApiError::MqttHassTopicLength;
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("mqtt_hass_topic")].as<String>().indexOf(' ') != -1) {
retMsg[F("message")] = F("Hass topic must not contain space characters!");
retMsg[F("code")] = WebApiError::MqttHassTopicCharacter;
if (root["mqtt_hass_topic"].as<String>().indexOf(' ') != -1) {
retMsg["message"] = "Hass topic must not contain space characters!";
retMsg["code"] = WebApiError::MqttHassTopicCharacter;
response->setLength();
request->send(response);
return;
@ -287,29 +287,29 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
}
CONFIG_T& config = Configuration.get();
config.Mqtt_Enabled = root[F("mqtt_enabled")].as<bool>();
config.Mqtt_Retain = root[F("mqtt_retain")].as<bool>();
config.Mqtt_Tls = root[F("mqtt_tls")].as<bool>();
strlcpy(config.Mqtt_RootCaCert, root[F("mqtt_root_ca_cert")].as<String>().c_str(), sizeof(config.Mqtt_RootCaCert));
config.Mqtt_Port = root[F("mqtt_port")].as<uint>();
strlcpy(config.Mqtt_Hostname, root[F("mqtt_hostname")].as<String>().c_str(), sizeof(config.Mqtt_Hostname));
strlcpy(config.Mqtt_Username, root[F("mqtt_username")].as<String>().c_str(), sizeof(config.Mqtt_Username));
strlcpy(config.Mqtt_Password, root[F("mqtt_password")].as<String>().c_str(), sizeof(config.Mqtt_Password));
strlcpy(config.Mqtt_Topic, root[F("mqtt_topic")].as<String>().c_str(), sizeof(config.Mqtt_Topic));
strlcpy(config.Mqtt_LwtTopic, root[F("mqtt_lwt_topic")].as<String>().c_str(), sizeof(config.Mqtt_LwtTopic));
strlcpy(config.Mqtt_LwtValue_Online, root[F("mqtt_lwt_online")].as<String>().c_str(), sizeof(config.Mqtt_LwtValue_Online));
strlcpy(config.Mqtt_LwtValue_Offline, root[F("mqtt_lwt_offline")].as<String>().c_str(), sizeof(config.Mqtt_LwtValue_Offline));
config.Mqtt_PublishInterval = root[F("mqtt_publish_interval")].as<uint32_t>();
config.Mqtt_Hass_Enabled = root[F("mqtt_hass_enabled")].as<bool>();
config.Mqtt_Hass_Expire = root[F("mqtt_hass_expire")].as<bool>();
config.Mqtt_Hass_Retain = root[F("mqtt_hass_retain")].as<bool>();
config.Mqtt_Hass_IndividualPanels = root[F("mqtt_hass_individualpanels")].as<bool>();
strlcpy(config.Mqtt_Hass_Topic, root[F("mqtt_hass_topic")].as<String>().c_str(), sizeof(config.Mqtt_Hass_Topic));
config.Mqtt_Enabled = root["mqtt_enabled"].as<bool>();
config.Mqtt_Retain = root["mqtt_retain"].as<bool>();
config.Mqtt_Tls = root["mqtt_tls"].as<bool>();
strlcpy(config.Mqtt_RootCaCert, root["mqtt_root_ca_cert"].as<String>().c_str(), sizeof(config.Mqtt_RootCaCert));
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_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_Topic, root["mqtt_topic"].as<String>().c_str(), sizeof(config.Mqtt_Topic));
strlcpy(config.Mqtt_LwtTopic, root["mqtt_lwt_topic"].as<String>().c_str(), sizeof(config.Mqtt_LwtTopic));
strlcpy(config.Mqtt_LwtValue_Online, root["mqtt_lwt_online"].as<String>().c_str(), sizeof(config.Mqtt_LwtValue_Online));
strlcpy(config.Mqtt_LwtValue_Offline, root["mqtt_lwt_offline"].as<String>().c_str(), sizeof(config.Mqtt_LwtValue_Offline));
config.Mqtt_PublishInterval = root["mqtt_publish_interval"].as<uint32_t>();
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));
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);

View File

@ -34,22 +34,22 @@ void WebApiNetworkClass::onNetworkStatus(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();
root[F("sta_status")] = ((WiFi.getMode() & WIFI_STA) != 0);
root[F("sta_ssid")] = WiFi.SSID();
root[F("sta_rssi")] = WiFi.RSSI();
root[F("network_hostname")] = NetworkSettings.getHostname();
root[F("network_ip")] = NetworkSettings.localIP().toString();
root[F("network_netmask")] = NetworkSettings.subnetMask().toString();
root[F("network_gateway")] = NetworkSettings.gatewayIP().toString();
root[F("network_dns1")] = NetworkSettings.dnsIP(0).toString();
root[F("network_dns2")] = NetworkSettings.dnsIP(1).toString();
root[F("network_mac")] = NetworkSettings.macAddress();
root[F("network_mode")] = NetworkSettings.NetworkMode() == network_mode::WiFi ? F("Station") : F("Ethernet");
root[F("ap_status")] = ((WiFi.getMode() & WIFI_AP) != 0);
root[F("ap_ssid")] = NetworkSettings.getApName();
root[F("ap_ip")] = WiFi.softAPIP().toString();
root[F("ap_mac")] = WiFi.softAPmacAddress();
root[F("ap_stationnum")] = WiFi.softAPgetStationNum();
root["sta_status"] = ((WiFi.getMode() & WIFI_STA) != 0);
root["sta_ssid"] = WiFi.SSID();
root["sta_rssi"] = WiFi.RSSI();
root["network_hostname"] = NetworkSettings.getHostname();
root["network_ip"] = NetworkSettings.localIP().toString();
root["network_netmask"] = NetworkSettings.subnetMask().toString();
root["network_gateway"] = NetworkSettings.gatewayIP().toString();
root["network_dns1"] = NetworkSettings.dnsIP(0).toString();
root["network_dns2"] = NetworkSettings.dnsIP(1).toString();
root["network_mac"] = NetworkSettings.macAddress();
root["network_mode"] = NetworkSettings.NetworkMode() == network_mode::WiFi ? "Station" : "Ethernet";
root["ap_status"] = ((WiFi.getMode() & WIFI_AP) != 0);
root["ap_ssid"] = NetworkSettings.getApName();
root["ap_ip"] = WiFi.softAPIP().toString();
root["ap_mac"] = WiFi.softAPmacAddress();
root["ap_stationnum"] = WiFi.softAPgetStationNum();
response->setLength();
request->send(response);
@ -65,15 +65,15 @@ void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request)
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
root[F("hostname")] = config.WiFi_Hostname;
root[F("dhcp")] = config.WiFi_Dhcp;
root[F("ipaddress")] = IPAddress(config.WiFi_Ip).toString();
root[F("netmask")] = IPAddress(config.WiFi_Netmask).toString();
root[F("gateway")] = IPAddress(config.WiFi_Gateway).toString();
root[F("dns1")] = IPAddress(config.WiFi_Dns1).toString();
root[F("dns2")] = IPAddress(config.WiFi_Dns2).toString();
root[F("ssid")] = config.WiFi_Ssid;
root[F("password")] = config.WiFi_Password;
root["hostname"] = config.WiFi_Hostname;
root["dhcp"] = config.WiFi_Dhcp;
root["ipaddress"] = IPAddress(config.WiFi_Ip).toString();
root["netmask"] = IPAddress(config.WiFi_Netmask).toString();
root["gateway"] = IPAddress(config.WiFi_Gateway).toString();
root["dns1"] = IPAddress(config.WiFi_Dns1).toString();
root["dns2"] = IPAddress(config.WiFi_Dns2).toString();
root["ssid"] = config.WiFi_Ssid;
root["password"] = config.WiFi_Password;
response->setLength();
request->send(response);
@ -87,11 +87,11 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -100,8 +100,8 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -111,78 +111,78 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("ssid") && root.containsKey("password") && root.containsKey("hostname") && root.containsKey("dhcp") && root.containsKey("ipaddress") && root.containsKey("netmask") && root.containsKey("gateway") && root.containsKey("dns1") && root.containsKey("dns2"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
IPAddress ipaddress;
if (!ipaddress.fromString(root[F("ipaddress")].as<String>())) {
retMsg[F("message")] = F("IP address is invalid!");
retMsg[F("code")] = WebApiError::NetworkIpInvalid;
if (!ipaddress.fromString(root["ipaddress"].as<String>())) {
retMsg["message"] = "IP address is invalid!";
retMsg["code"] = WebApiError::NetworkIpInvalid;
response->setLength();
request->send(response);
return;
}
IPAddress netmask;
if (!netmask.fromString(root[F("netmask")].as<String>())) {
retMsg[F("message")] = F("Netmask is invalid!");
retMsg[F("code")] = WebApiError::NetworkNetmaskInvalid;
if (!netmask.fromString(root["netmask"].as<String>())) {
retMsg["message"] = "Netmask is invalid!";
retMsg["code"] = WebApiError::NetworkNetmaskInvalid;
response->setLength();
request->send(response);
return;
}
IPAddress gateway;
if (!gateway.fromString(root[F("gateway")].as<String>())) {
retMsg[F("message")] = F("Gateway is invalid!");
retMsg[F("code")] = WebApiError::NetworkGatewayInvalid;
if (!gateway.fromString(root["gateway"].as<String>())) {
retMsg["message"] = "Gateway is invalid!";
retMsg["code"] = WebApiError::NetworkGatewayInvalid;
response->setLength();
request->send(response);
return;
}
IPAddress dns1;
if (!dns1.fromString(root[F("dns1")].as<String>())) {
retMsg[F("message")] = F("DNS Server IP 1 is invalid!");
retMsg[F("code")] = WebApiError::NetworkDns1Invalid;
if (!dns1.fromString(root["dns1"].as<String>())) {
retMsg["message"] = "DNS Server IP 1 is invalid!";
retMsg["code"] = WebApiError::NetworkDns1Invalid;
response->setLength();
request->send(response);
return;
}
IPAddress dns2;
if (!dns2.fromString(root[F("dns2")].as<String>())) {
retMsg[F("message")] = F("DNS Server IP 2 is invalid!");
retMsg[F("code")] = WebApiError::NetworkDns2Invalid;
if (!dns2.fromString(root["dns2"].as<String>())) {
retMsg["message"] = "DNS Server IP 2 is invalid!";
retMsg["code"] = WebApiError::NetworkDns2Invalid;
response->setLength();
request->send(response);
return;
}
if (root[F("hostname")].as<String>().length() == 0 || root[F("hostname")].as<String>().length() > WIFI_MAX_HOSTNAME_STRLEN) {
retMsg[F("message")] = F("Hostname must between 1 and " STR(WIFI_MAX_HOSTNAME_STRLEN) " characters long!");
if (root["hostname"].as<String>().length() == 0 || root["hostname"].as<String>().length() > WIFI_MAX_HOSTNAME_STRLEN) {
retMsg["message"] = "Hostname must between 1 and " STR(WIFI_MAX_HOSTNAME_STRLEN) " characters long!";
response->setLength();
request->send(response);
return;
}
if (NetworkSettings.NetworkMode() == network_mode::WiFi) {
if (root[F("ssid")].as<String>().length() == 0 || root[F("ssid")].as<String>().length() > WIFI_MAX_SSID_STRLEN) {
retMsg[F("message")] = F("SSID must between 1 and " STR(WIFI_MAX_SSID_STRLEN) " characters long!");
if (root["ssid"].as<String>().length() == 0 || root["ssid"].as<String>().length() > WIFI_MAX_SSID_STRLEN) {
retMsg["message"] = "SSID must between 1 and " STR(WIFI_MAX_SSID_STRLEN) " characters long!";
response->setLength();
request->send(response);
return;
}
}
if (root[F("password")].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN - 1) {
retMsg[F("message")] = F("Password must not be longer than " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!");
if (root["password"].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN - 1) {
retMsg["message"] = "Password must not be longer than " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!";
response->setLength();
request->send(response);
return;
@ -209,19 +209,19 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
config.WiFi_Dns2[1] = dns2[1];
config.WiFi_Dns2[2] = dns2[2];
config.WiFi_Dns2[3] = dns2[3];
strlcpy(config.WiFi_Ssid, root[F("ssid")].as<String>().c_str(), sizeof(config.WiFi_Ssid));
strlcpy(config.WiFi_Password, root[F("password")].as<String>().c_str(), sizeof(config.WiFi_Password));
strlcpy(config.WiFi_Hostname, root[F("hostname")].as<String>().c_str(), sizeof(config.WiFi_Hostname));
if (root[F("dhcp")].as<bool>()) {
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;
}
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);

View File

@ -38,29 +38,29 @@ void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request)
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
root[F("ntp_server")] = config.Ntp_Server;
root[F("ntp_timezone")] = config.Ntp_Timezone;
root[F("ntp_timezone_descr")] = config.Ntp_TimezoneDescr;
root["ntp_server"] = config.Ntp_Server;
root["ntp_timezone"] = config.Ntp_Timezone;
root["ntp_timezone_descr"] = config.Ntp_TimezoneDescr;
struct tm timeinfo;
if (!getLocalTime(&timeinfo, 5)) {
root[F("ntp_status")] = false;
root["ntp_status"] = false;
} else {
root[F("ntp_status")] = true;
root["ntp_status"] = true;
}
char timeStringBuff[50];
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
root[F("ntp_localtime")] = timeStringBuff;
root["ntp_localtime"] = timeStringBuff;
SunPosition.sunriseTime(&timeinfo);
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
root[F("sun_risetime")] = timeStringBuff;
root["sun_risetime"] = timeStringBuff;
SunPosition.sunsetTime(&timeinfo);
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
root[F("sun_settime")] = timeStringBuff;
root["sun_settime"] = timeStringBuff;
root[F("sun_isDayPeriod")] = SunPosition.isDayPeriod();
root["sun_isDayPeriod"] = SunPosition.isDayPeriod();
response->setLength();
request->send(response);
@ -76,11 +76,11 @@ void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request)
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
root[F("ntp_server")] = config.Ntp_Server;
root[F("ntp_timezone")] = config.Ntp_Timezone;
root[F("ntp_timezone_descr")] = config.Ntp_TimezoneDescr;
root[F("longitude")] = config.Ntp_Longitude;
root[F("latitude")] = config.Ntp_Latitude;
root["ntp_server"] = config.Ntp_Server;
root["ntp_timezone"] = config.Ntp_Timezone;
root["ntp_timezone_descr"] = config.Ntp_TimezoneDescr;
root["longitude"] = config.Ntp_Longitude;
root["latitude"] = config.Ntp_Latitude;
response->setLength();
request->send(response);
@ -94,11 +94,11 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -107,8 +107,8 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -118,59 +118,59 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
}
if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone") && root.containsKey("longitude") && root.containsKey("latitude"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("ntp_server")].as<String>().length() == 0 || root[F("ntp_server")].as<String>().length() > NTP_MAX_SERVER_STRLEN) {
retMsg[F("message")] = F("NTP Server must between 1 and " STR(NTP_MAX_SERVER_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::NtpServerLength;
retMsg[F("param")][F("max")] = NTP_MAX_SERVER_STRLEN;
if (root["ntp_server"].as<String>().length() == 0 || root["ntp_server"].as<String>().length() > NTP_MAX_SERVER_STRLEN) {
retMsg["message"] = "NTP Server must between 1 and " STR(NTP_MAX_SERVER_STRLEN) " characters long!";
retMsg["code"] = WebApiError::NtpServerLength;
retMsg["param"]["max"] = NTP_MAX_SERVER_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("ntp_timezone")].as<String>().length() == 0 || root[F("ntp_timezone")].as<String>().length() > NTP_MAX_TIMEZONE_STRLEN) {
retMsg[F("message")] = F("Timezone must between 1 and " STR(NTP_MAX_TIMEZONE_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::NtpTimezoneLength;
retMsg[F("param")][F("max")] = NTP_MAX_TIMEZONE_STRLEN;
if (root["ntp_timezone"].as<String>().length() == 0 || root["ntp_timezone"].as<String>().length() > NTP_MAX_TIMEZONE_STRLEN) {
retMsg["message"] = "Timezone must between 1 and " STR(NTP_MAX_TIMEZONE_STRLEN) " characters long!";
retMsg["code"] = WebApiError::NtpTimezoneLength;
retMsg["param"]["max"] = NTP_MAX_TIMEZONE_STRLEN;
response->setLength();
request->send(response);
return;
}
if (root[F("ntp_timezone_descr")].as<String>().length() == 0 || root[F("ntp_timezone_descr")].as<String>().length() > NTP_MAX_TIMEZONEDESCR_STRLEN) {
retMsg[F("message")] = F("Timezone description must between 1 and " STR(NTP_MAX_TIMEZONEDESCR_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::NtpTimezoneDescriptionLength;
retMsg[F("param")][F("max")] = NTP_MAX_TIMEZONEDESCR_STRLEN;
if (root["ntp_timezone_descr"].as<String>().length() == 0 || root["ntp_timezone_descr"].as<String>().length() > NTP_MAX_TIMEZONEDESCR_STRLEN) {
retMsg["message"] = "Timezone description must between 1 and " STR(NTP_MAX_TIMEZONEDESCR_STRLEN) " characters long!";
retMsg["code"] = WebApiError::NtpTimezoneDescriptionLength;
retMsg["param"]["max"] = NTP_MAX_TIMEZONEDESCR_STRLEN;
response->setLength();
request->send(response);
return;
}
CONFIG_T& config = Configuration.get();
strlcpy(config.Ntp_Server, root[F("ntp_server")].as<String>().c_str(), sizeof(config.Ntp_Server));
strlcpy(config.Ntp_Timezone, root[F("ntp_timezone")].as<String>().c_str(), sizeof(config.Ntp_Timezone));
strlcpy(config.Ntp_TimezoneDescr, root[F("ntp_timezone_descr")].as<String>().c_str(), sizeof(config.Ntp_TimezoneDescr));
config.Ntp_Latitude = root[F("latitude")].as<double>();
config.Ntp_Longitude = root[F("longitude")].as<double>();
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>();
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);
@ -190,17 +190,17 @@ void WebApiNtpClass::onNtpTimeGet(AsyncWebServerRequest* request)
struct tm timeinfo;
if (!getLocalTime(&timeinfo, 5)) {
root[F("ntp_status")] = false;
root["ntp_status"] = false;
} else {
root[F("ntp_status")] = true;
root["ntp_status"] = true;
}
root[F("year")] = timeinfo.tm_year + 1900;
root[F("month")] = timeinfo.tm_mon + 1;
root[F("day")] = timeinfo.tm_mday;
root[F("hour")] = timeinfo.tm_hour;
root[F("minute")] = timeinfo.tm_min;
root[F("second")] = timeinfo.tm_sec;
root["year"] = timeinfo.tm_year + 1900;
root["month"] = timeinfo.tm_mon + 1;
root["day"] = timeinfo.tm_mday;
root["hour"] = timeinfo.tm_hour;
root["minute"] = timeinfo.tm_min;
root["second"] = timeinfo.tm_sec;
response->setLength();
request->send(response);
@ -214,11 +214,11 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -227,8 +227,8 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -238,8 +238,8 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
@ -251,89 +251,89 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
&& root.containsKey("hour")
&& root.containsKey("minute")
&& root.containsKey("second"))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("year")].as<uint>() < 2022 || root[F("year")].as<uint>() > 2100) {
retMsg[F("message")] = F("Year must be a number between 2022 and 2100!");
retMsg[F("code")] = WebApiError::NtpYearInvalid;
retMsg[F("param")][F("min")] = 2022;
retMsg[F("param")][F("max")] = 2100;
if (root["year"].as<uint>() < 2022 || root["year"].as<uint>() > 2100) {
retMsg["message"] = "Year must be a number between 2022 and 2100!";
retMsg["code"] = WebApiError::NtpYearInvalid;
retMsg["param"]["min"] = 2022;
retMsg["param"]["max"] = 2100;
response->setLength();
request->send(response);
return;
}
if (root[F("month")].as<uint>() < 1 || root[F("month")].as<uint>() > 12) {
retMsg[F("message")] = F("Month must be a number between 1 and 12!");
retMsg[F("code")] = WebApiError::NtpMonthInvalid;
retMsg[F("param")][F("min")] = 1;
retMsg[F("param")][F("max")] = 12;
if (root["month"].as<uint>() < 1 || root["month"].as<uint>() > 12) {
retMsg["message"] = "Month must be a number between 1 and 12!";
retMsg["code"] = WebApiError::NtpMonthInvalid;
retMsg["param"]["min"] = 1;
retMsg["param"]["max"] = 12;
response->setLength();
request->send(response);
return;
}
if (root[F("day")].as<uint>() < 1 || root[F("day")].as<uint>() > 31) {
retMsg[F("message")] = F("Day must be a number between 1 and 31!");
retMsg[F("code")] = WebApiError::NtpDayInvalid;
retMsg[F("param")][F("min")] = 1;
retMsg[F("param")][F("max")] = 31;
if (root["day"].as<uint>() < 1 || root["day"].as<uint>() > 31) {
retMsg["message"] = "Day must be a number between 1 and 31!";
retMsg["code"] = WebApiError::NtpDayInvalid;
retMsg["param"]["min"] = 1;
retMsg["param"]["max"] = 31;
response->setLength();
request->send(response);
return;
}
if (root[F("hour")].as<uint>() > 23) {
retMsg[F("message")] = F("Hour must be a number between 0 and 23!");
retMsg[F("code")] = WebApiError::NtpHourInvalid;
retMsg[F("param")][F("min")] = 0;
retMsg[F("param")][F("max")] = 23;
if (root["hour"].as<uint>() > 23) {
retMsg["message"] = "Hour must be a number between 0 and 23!";
retMsg["code"] = WebApiError::NtpHourInvalid;
retMsg["param"]["min"] = 0;
retMsg["param"]["max"] = 23;
response->setLength();
request->send(response);
return;
}
if (root[F("minute")].as<uint>() > 59) {
retMsg[F("message")] = F("Minute must be a number between 0 and 59!");
retMsg[F("code")] = WebApiError::NtpMinuteInvalid;
retMsg[F("param")][F("min")] = 0;
retMsg[F("param")][F("max")] = 59;
if (root["minute"].as<uint>() > 59) {
retMsg["message"] = "Minute must be a number between 0 and 59!";
retMsg["code"] = WebApiError::NtpMinuteInvalid;
retMsg["param"]["min"] = 0;
retMsg["param"]["max"] = 59;
response->setLength();
request->send(response);
return;
}
if (root[F("second")].as<uint>() > 59) {
retMsg[F("message")] = F("Second must be a number between 0 and 59!");
retMsg[F("code")] = WebApiError::NtpSecondInvalid;
retMsg[F("param")][F("min")] = 0;
retMsg[F("param")][F("max")] = 59;
if (root["second"].as<uint>() > 59) {
retMsg["message"] = "Second must be a number between 0 and 59!";
retMsg["code"] = WebApiError::NtpSecondInvalid;
retMsg["param"]["min"] = 0;
retMsg["param"]["max"] = 59;
response->setLength();
request->send(response);
return;
}
tm local;
local.tm_sec = root[F("second")].as<uint>(); // seconds after the minute - [ 0 to 59 ]
local.tm_min = root[F("minute")].as<uint>(); // minutes after the hour - [ 0 to 59 ]
local.tm_hour = root[F("hour")].as<uint>(); // hours since midnight - [ 0 to 23 ]
local.tm_mday = root[F("day")].as<uint>(); // day of the month - [ 1 to 31 ]
local.tm_mon = root[F("month")].as<uint>() - 1; // months since January - [ 0 to 11 ]
local.tm_year = root[F("year")].as<uint>() - 1900; // years since 1900
local.tm_sec = root["second"].as<uint>(); // seconds after the minute - [ 0 to 59 ]
local.tm_min = root["minute"].as<uint>(); // minutes after the hour - [ 0 to 59 ]
local.tm_hour = root["hour"].as<uint>(); // hours since midnight - [ 0 to 23 ]
local.tm_mday = root["day"].as<uint>(); // day of the month - [ 1 to 31 ]
local.tm_mon = root["month"].as<uint>() - 1; // months since January - [ 0 to 11 ]
local.tm_year = root["year"].as<uint>() - 1900; // years since 1900
local.tm_isdst = -1;
time_t t = mktime(&local);
struct timeval now = { .tv_sec = t, .tv_usec = 0 };
settimeofday(&now, NULL);
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Time updated!");
retMsg[F("code")] = WebApiError::NtpTimeUpdated;
retMsg["type"] = "success";
retMsg["message"] = "Time updated!";
retMsg["code"] = WebApiError::NtpTimeUpdated;
response->setLength();
request->send(response);

View File

@ -58,11 +58,11 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -71,8 +71,8 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -82,8 +82,8 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
@ -91,43 +91,43 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
if (!(root.containsKey("serial")
&& (root.containsKey("power") || root.containsKey("restart")))) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("serial")].as<uint64_t>() == 0) {
retMsg[F("message")] = F("Serial must be a number > 0!");
retMsg[F("code")] = WebApiError::PowerSerialZero;
if (root["serial"].as<uint64_t>() == 0) {
retMsg["message"] = "Serial must be a number > 0!";
retMsg["code"] = WebApiError::PowerSerialZero;
response->setLength();
request->send(response);
return;
}
uint64_t serial = strtoll(root[F("serial")].as<String>().c_str(), NULL, 16);
uint64_t serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
auto inv = Hoymiles.getInverterBySerial(serial);
if (inv == nullptr) {
retMsg[F("message")] = F("Invalid inverter specified!");
retMsg[F("code")] = WebApiError::PowerInvalidInverter;
retMsg["message"] = "Invalid inverter specified!";
retMsg["code"] = WebApiError::PowerInvalidInverter;
response->setLength();
request->send(response);
return;
}
if (root.containsKey("power")) {
uint16_t power = root[F("power")].as<bool>();
uint16_t power = root["power"].as<bool>();
inv->sendPowerControlRequest(Hoymiles.getRadio(), power);
} else {
if (root[F("restart")].as<bool>()) {
if (root["restart"].as<bool>()) {
inv->sendRestartControlRequest(Hoymiles.getRadio());
}
}
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);

View File

@ -28,29 +28,29 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
try {
auto stream = request->beginResponseStream("text/plain; charset=utf-8", 40960);
stream->print(F("# HELP opendtu_build Build info\n"));
stream->print(F("# TYPE opendtu_build gauge\n"));
stream->print("# HELP opendtu_build Build info\n");
stream->print("# TYPE opendtu_build gauge\n");
stream->printf("opendtu_build{name=\"%s\",id=\"%s\",version=\"%d.%d.%d\"} 1\n",
NetworkSettings.getHostname().c_str(), AUTO_GIT_HASH, CONFIG_VERSION >> 24 & 0xff, CONFIG_VERSION >> 16 & 0xff, CONFIG_VERSION >> 8 & 0xff);
stream->print(F("# HELP opendtu_platform Platform info\n"));
stream->print(F("# TYPE opendtu_platform gauge\n"));
stream->print("# HELP opendtu_platform Platform info\n");
stream->print("# TYPE opendtu_platform gauge\n");
stream->printf("opendtu_platform{arch=\"%s\",mac=\"%s\"} 1\n", ESP.getChipModel(), NetworkSettings.macAddress().c_str());
stream->print(F("# HELP opendtu_uptime Uptime in seconds\n"));
stream->print(F("# TYPE opendtu_uptime counter\n"));
stream->print("# HELP opendtu_uptime Uptime in seconds\n");
stream->print("# TYPE opendtu_uptime counter\n");
stream->printf("opendtu_uptime %lld\n", esp_timer_get_time() / 1000000);
stream->print(F("# HELP opendtu_heap_size System memory size\n"));
stream->print(F("# TYPE opendtu_heap_size gauge\n"));
stream->print("# HELP opendtu_heap_size System memory size\n");
stream->print("# TYPE opendtu_heap_size gauge\n");
stream->printf("opendtu_heap_size %zu\n", ESP.getHeapSize());
stream->print(F("# HELP opendtu_free_heap_size System free memory\n"));
stream->print(F("# TYPE opendtu_free_heap_size gauge\n"));
stream->print("# HELP opendtu_free_heap_size System free memory\n");
stream->print("# TYPE opendtu_free_heap_size gauge\n");
stream->printf("opendtu_free_heap_size %zu\n", ESP.getFreeHeap());
stream->print(F("# HELP wifi_rssi WiFi RSSI\n"));
stream->print(F("# TYPE wifi_rssi gauge\n"));
stream->print("# HELP wifi_rssi WiFi RSSI\n");
stream->print("# TYPE wifi_rssi gauge\n");
stream->printf("wifi_rssi %d\n", WiFi.RSSI());
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
@ -59,8 +59,8 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
String serial = inv->serialString();
const char* name = inv->name();
if (i == 0) {
stream->print(F("# HELP opendtu_last_update last update from inverter in s\n"));
stream->print(F("# TYPE opendtu_last_update gauge\n"));
stream->print("# HELP opendtu_last_update last update from inverter in s\n");
stream->print("# TYPE opendtu_last_update gauge\n");
}
stream->printf("opendtu_last_update{serial=\"%s\",unit=\"%d\",name=\"%s\"} %d\n",
serial.c_str(), i, name, inv->Statistics()->getLastUpdate() / 1000);
@ -92,7 +92,7 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
}
}
}
stream->addHeader(F("Cache-Control"), F("no-cache"));
stream->addHeader("Cache-Control", "no-cache");
request->send(stream);
} catch (std::bad_alloc& bad_alloc) {
@ -131,8 +131,8 @@ void WebApiPrometheusClass::addPanelInfo(AsyncResponseStream* stream, String& se
const bool printHelp = (idx == 0 && channel == 0);
if (printHelp) {
stream->print(F("# HELP opendtu_PanelInfo panel information\n"));
stream->print(F("# TYPE opendtu_PanelInfo gauge\n"));
stream->print("# HELP opendtu_PanelInfo panel information\n");
stream->print("# TYPE opendtu_PanelInfo gauge\n");
}
stream->printf("opendtu_PanelInfo{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\",panelname=\"%s\"} 1\n",
serial.c_str(),
@ -143,8 +143,8 @@ void WebApiPrometheusClass::addPanelInfo(AsyncResponseStream* stream, String& se
);
if (printHelp) {
stream->print(F("# HELP opendtu_MaxPower panel maximum output power\n"));
stream->print(F("# TYPE opendtu_MaxPower gauge\n"));
stream->print("# HELP opendtu_MaxPower panel maximum output power\n");
stream->print("# TYPE opendtu_MaxPower gauge\n");
}
stream->printf("opendtu_MaxPower{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %d\n",
serial.c_str(),
@ -155,8 +155,8 @@ void WebApiPrometheusClass::addPanelInfo(AsyncResponseStream* stream, String& se
);
if (printHelp) {
stream->print(F("# HELP opendtu_YieldTotalOffset panel yield offset (for used inverters)\n"));
stream->print(F("# TYPE opendtu_YieldTotalOffset gauge\n"));
stream->print("# HELP opendtu_YieldTotalOffset panel yield offset (for used inverters)\n");
stream->print("# TYPE opendtu_YieldTotalOffset gauge\n");
}
stream->printf("opendtu_YieldTotalOffset{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %f\n",
serial.c_str(),

View File

@ -34,8 +34,8 @@ void WebApiSecurityClass::onSecurityGet(AsyncWebServerRequest* request)
JsonObject root = response->getRoot();
const CONFIG_T& config = Configuration.get();
root[F("password")] = config.Security_Password;
root[F("allow_readonly")] = config.Security_AllowReadonly;
root["password"] = config.Security_Password;
root["allow_readonly"] = config.Security_AllowReadonly;
response->setLength();
request->send(response);
@ -49,11 +49,11 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("warning");
retMsg["type"] = "warning";
if (!request->hasParam("data", true)) {
retMsg[F("message")] = F("No values found!");
retMsg[F("code")] = WebApiError::GenericNoValueFound;
retMsg["message"] = "No values found!";
retMsg["code"] = WebApiError::GenericNoValueFound;
response->setLength();
request->send(response);
return;
@ -62,8 +62,8 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
String json = request->getParam("data", true)->value();
if (json.length() > 1024) {
retMsg[F("message")] = F("Data too large!");
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
retMsg["message"] = "Data too large!";
retMsg["code"] = WebApiError::GenericDataTooLarge;
response->setLength();
request->send(response);
return;
@ -73,8 +73,8 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
DeserializationError error = deserializeJson(root, json);
if (error) {
retMsg[F("message")] = F("Failed to parse data!");
retMsg[F("code")] = WebApiError::GenericParseError;
retMsg["message"] = "Failed to parse data!";
retMsg["code"] = WebApiError::GenericParseError;
response->setLength();
request->send(response);
return;
@ -82,30 +82,30 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
if (!root.containsKey("password")
&& root.containsKey("allow_readonly")) {
retMsg[F("message")] = F("Values are missing!");
retMsg[F("code")] = WebApiError::GenericValueMissing;
retMsg["message"] = "Values are missing!";
retMsg["code"] = WebApiError::GenericValueMissing;
response->setLength();
request->send(response);
return;
}
if (root[F("password")].as<String>().length() < 8 || root[F("password")].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN) {
retMsg[F("message")] = F("Password must between 8 and " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!");
retMsg[F("code")] = WebApiError::SecurityPasswordLength;
retMsg[F("param")][F("max")] = WIFI_MAX_PASSWORD_STRLEN;
if (root["password"].as<String>().length() < 8 || root["password"].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN) {
retMsg["message"] = "Password must between 8 and " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!";
retMsg["code"] = WebApiError::SecurityPasswordLength;
retMsg["param"]["max"] = WIFI_MAX_PASSWORD_STRLEN;
response->setLength();
request->send(response);
return;
}
CONFIG_T& config = Configuration.get();
strlcpy(config.Security_Password, root[F("password")].as<String>().c_str(), sizeof(config.Security_Password));
config.Security_AllowReadonly = root[F("allow_readonly")].as<bool>();
strlcpy(config.Security_Password, root["password"].as<String>().c_str(), sizeof(config.Security_Password));
config.Security_AllowReadonly = root["allow_readonly"].as<bool>();
Configuration.write();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Settings saved!");
retMsg[F("code")] = WebApiError::GenericSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
response->setLength();
request->send(response);
@ -119,9 +119,9 @@ void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject retMsg = response->getRoot();
retMsg[F("type")] = F("success");
retMsg[F("message")] = F("Authentication successful!");
retMsg[F("code")] = WebApiError::SecurityAuthSuccess;
retMsg["type"] = "success";
retMsg["message"] = "Authentication successful!";
retMsg["code"] = WebApiError::SecurityAuthSuccess;
response->setLength();
request->send(response);

View File

@ -37,40 +37,40 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
AsyncJsonResponse* response = new AsyncJsonResponse();
JsonObject root = response->getRoot();
root[F("hostname")] = NetworkSettings.getHostname();
root["hostname"] = NetworkSettings.getHostname();
root[F("sdkversion")] = ESP.getSdkVersion();
root[F("cpufreq")] = ESP.getCpuFreqMHz();
root["sdkversion"] = ESP.getSdkVersion();
root["cpufreq"] = ESP.getCpuFreqMHz();
root[F("heap_total")] = ESP.getHeapSize();
root[F("heap_used")] = ESP.getHeapSize() - ESP.getFreeHeap();
root[F("sketch_total")] = ESP.getFreeSketchSpace();
root[F("sketch_used")] = ESP.getSketchSize();
root[F("littlefs_total")] = LittleFS.totalBytes();
root[F("littlefs_used")] = LittleFS.usedBytes();
root["heap_total"] = ESP.getHeapSize();
root["heap_used"] = ESP.getHeapSize() - ESP.getFreeHeap();
root["sketch_total"] = ESP.getFreeSketchSpace();
root["sketch_used"] = ESP.getSketchSize();
root["littlefs_total"] = LittleFS.totalBytes();
root["littlefs_used"] = LittleFS.usedBytes();
root[F("chiprevision")] = ESP.getChipRevision();
root[F("chipmodel")] = ESP.getChipModel();
root[F("chipcores")] = ESP.getChipCores();
root["chiprevision"] = ESP.getChipRevision();
root["chipmodel"] = ESP.getChipModel();
root["chipcores"] = ESP.getChipCores();
String reason;
reason = ResetReason.get_reset_reason_verbose(0);
root[F("resetreason_0")] = reason;
root["resetreason_0"] = reason;
reason = ResetReason.get_reset_reason_verbose(1);
root[F("resetreason_1")] = reason;
root["resetreason_1"] = reason;
root[F("cfgsavecount")] = Configuration.get().Cfg_SaveCount;
root["cfgsavecount"] = Configuration.get().Cfg_SaveCount;
char version[16];
snprintf(version, sizeof(version), "%d.%d.%d", CONFIG_VERSION >> 24 & 0xff, CONFIG_VERSION >> 16 & 0xff, CONFIG_VERSION >> 8 & 0xff);
root[F("config_version")] = version;
root[F("git_hash")] = AUTO_GIT_HASH;
root["config_version"] = version;
root["git_hash"] = AUTO_GIT_HASH;
root[F("uptime")] = esp_timer_get_time() / 1000000;
root["uptime"] = esp_timer_get_time() / 1000000;
root[F("radio_connected")] = Hoymiles.getRadio()->isConnected();
root[F("radio_pvariant")] = Hoymiles.getRadio()->isPVariant();
root["radio_connected"] = Hoymiles.getRadio()->isConnected();
root["radio_pvariant"] = Hoymiles.getRadio()->isPVariant();
response->setLength();
request->send(response);

View File

@ -103,17 +103,17 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
JsonObject invObject = invArray.createNestedObject();
invObject[F("serial")] = inv->serialString();
invObject[F("name")] = inv->name();
invObject[F("data_age")] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
invObject[F("poll_enabled")] = inv->getEnablePolling();
invObject[F("reachable")] = inv->isReachable();
invObject[F("producing")] = inv->isProducing();
invObject[F("limit_relative")] = inv->SystemConfigPara()->getLimitPercent();
invObject["serial"] = inv->serialString();
invObject["name"] = inv->name();
invObject["data_age"] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
invObject["poll_enabled"] = inv->getEnablePolling();
invObject["reachable"] = inv->isReachable();
invObject["producing"] = inv->isProducing();
invObject["limit_relative"] = inv->SystemConfigPara()->getLimitPercent();
if (inv->DevInfo()->getMaxPower() > 0) {
invObject[F("limit_absolute")] = inv->SystemConfigPara()->getLimitPercent() * inv->DevInfo()->getMaxPower() / 100.0;
invObject["limit_absolute"] = inv->SystemConfigPara()->getLimitPercent() * inv->DevInfo()->getMaxPower() / 100.0;
} else {
invObject[F("limit_absolute")] = -1;
invObject["limit_absolute"] = -1;
}
// Loop all channels
@ -123,14 +123,14 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
if (t == TYPE_DC) {
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
if (inv_cfg != nullptr) {
chanTypeObj[String(static_cast<uint8_t>(c))][F("name")]["u"] = inv_cfg->channel[c].Name;
chanTypeObj[String(static_cast<uint8_t>(c))]["name"]["u"] = inv_cfg->channel[c].Name;
}
}
addField(chanTypeObj, i, inv, t, c, FLD_PAC);
addField(chanTypeObj, i, inv, t, c, FLD_UAC);
addField(chanTypeObj, i, inv, t, c, FLD_IAC);
if (t == TYPE_AC) {
addField(chanTypeObj, i, inv, t, c, FLD_PDC, F("Power DC"));
addField(chanTypeObj, i, inv, t, c, FLD_PDC, "Power DC");
} else {
addField(chanTypeObj, i, inv, t, c, FLD_PDC);
}
@ -150,9 +150,9 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
}
if (inv->Statistics()->hasChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG)) {
invObject[F("events")] = inv->EventLog()->getEntryCount();
invObject["events"] = inv->EventLog()->getEntryCount();
} else {
invObject[F("events")] = -1;
invObject["events"] = -1;
}
if (inv->Statistics()->getLastUpdate() > _newestInverterTimestamp) {
@ -174,12 +174,12 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
JsonObject hintObj = root.createNestedObject("hints");
struct tm timeinfo;
hintObj[F("time_sync")] = !getLocalTime(&timeinfo, 5);
hintObj[F("radio_problem")] = (!Hoymiles.getRadio()->isConnected() || !Hoymiles.getRadio()->isPVariant());
hintObj["time_sync"] = !getLocalTime(&timeinfo, 5);
hintObj["radio_problem"] = (!Hoymiles.getRadio()->isConnected() || !Hoymiles.getRadio()->isPVariant());
if (!strcmp(Configuration.get().Security_Password, ACCESS_POINT_PASSWORD)) {
hintObj[F("default_password")] = true;
hintObj["default_password"] = true;
} else {
hintObj[F("default_password")] = false;
hintObj["default_password"] = false;
}
}

View File

@ -27,80 +27,80 @@ void setup()
while (!Serial)
yield();
MessageOutput.println();
MessageOutput.println(F("Starting OpenDTU"));
MessageOutput.println("Starting OpenDTU");
// Initialize file system
MessageOutput.print(F("Initialize FS... "));
MessageOutput.print("Initialize FS... ");
if (!LittleFS.begin(false)) { // Do not format if mount failed
MessageOutput.print(F("failed... trying to format..."));
MessageOutput.print("failed... trying to format...");
if (!LittleFS.begin(true)) {
MessageOutput.print("success");
} else {
MessageOutput.print("failed");
}
} else {
MessageOutput.println(F("done"));
MessageOutput.println("done");
}
// Read configuration values
MessageOutput.print(F("Reading configuration... "));
MessageOutput.print("Reading configuration... ");
if (!Configuration.read()) {
MessageOutput.print(F("initializing... "));
MessageOutput.print("initializing... ");
Configuration.init();
if (Configuration.write()) {
MessageOutput.print(F("written... "));
MessageOutput.print("written... ");
} else {
MessageOutput.print(F("failed... "));
MessageOutput.print("failed... ");
}
}
if (Configuration.get().Cfg_Version != CONFIG_VERSION) {
MessageOutput.print(F("migrated... "));
MessageOutput.print("migrated... ");
Configuration.migrate();
}
CONFIG_T& config = Configuration.get();
MessageOutput.println(F("done"));
MessageOutput.println("done");
// Load PinMapping
MessageOutput.print(F("Reading PinMapping... "));
MessageOutput.print("Reading PinMapping... ");
if (PinMapping.init(String(Configuration.get().Dev_PinMapping))) {
MessageOutput.print(F("found valid mapping "));
MessageOutput.print("found valid mapping ");
} else {
MessageOutput.print(F("using default config "));
MessageOutput.print("using default config ");
}
const PinMapping_t& pin = PinMapping.get();
MessageOutput.println(F("done"));
MessageOutput.println("done");
// Initialize WiFi
MessageOutput.print(F("Initialize Network... "));
MessageOutput.print("Initialize Network... ");
NetworkSettings.init();
MessageOutput.println(F("done"));
MessageOutput.println("done");
NetworkSettings.applyConfig();
// Initialize NTP
MessageOutput.print(F("Initialize NTP... "));
MessageOutput.print("Initialize NTP... ");
NtpSettings.init();
MessageOutput.println(F("done"));
MessageOutput.println("done");
// Initialize SunPosition
MessageOutput.print(F("Initialize SunPosition... "));
MessageOutput.print("Initialize SunPosition... ");
SunPosition.init();
MessageOutput.println(F("done"));
MessageOutput.println("done");
// Initialize MqTT
MessageOutput.print(F("Initialize MqTT... "));
MessageOutput.print("Initialize MqTT... ");
MqttSettings.init();
MqttHandleDtu.init();
MqttHandleInverter.init();
MqttHandleHass.init();
MessageOutput.println(F("done"));
MessageOutput.println("done");
// Initialize WebApi
MessageOutput.print(F("Initialize WebApi... "));
MessageOutput.print("Initialize WebApi... ");
WebApi.init();
MessageOutput.println(F("done"));
MessageOutput.println("done");
// Initialize Display
MessageOutput.print(F("Initialize Display... "));
MessageOutput.print("Initialize Display... ");
Display.init(
static_cast<DisplayType_t>(pin.display_type),
pin.display_data,
@ -112,12 +112,12 @@ void setup()
Display.enableScreensaver = config.Display_ScreenSaver;
Display.setContrast(config.Display_Contrast);
Display.setStartupDisplay();
MessageOutput.println(F("done"));
MessageOutput.println("done");
// Check for default DTU serial
MessageOutput.print(F("Check for default DTU serial... "));
MessageOutput.print("Check for default DTU serial... ");
if (config.Dtu_Serial == DTU_SERIAL) {
MessageOutput.print(F("generate serial based on ESP chip id: "));
MessageOutput.print("generate serial based on ESP chip id: ");
uint64_t dtuId = Utils::generateDtuSerial();
MessageOutput.printf("%0x%08x... ",
((uint32_t)((dtuId >> 32) & 0xFFFFFFFF)),
@ -125,7 +125,7 @@ void setup()
config.Dtu_Serial = dtuId;
Configuration.write();
}
MessageOutput.println(F("done"));
MessageOutput.println("done");
InverterSettings.init();
}