Remove not required F() macro. Frees ~20kb flash.
This commit is contained in:
parent
dab5b4d723
commit
ca0b8e9afc
@ -35,7 +35,7 @@ void HoymilesClass::loop()
|
|||||||
if (_radio->isIdle()) {
|
if (_radio->isIdle()) {
|
||||||
std::shared_ptr<InverterAbstract> iv = getInverterByPos(inverterPos);
|
std::shared_ptr<InverterAbstract> iv = getInverterByPos(inverterPos);
|
||||||
if (iv != nullptr) {
|
if (iv != nullptr) {
|
||||||
_messageOutput->print(F("Fetch inverter: "));
|
_messageOutput->print("Fetch inverter: ");
|
||||||
_messageOutput->println(iv->serial(), HEX);
|
_messageOutput->println(iv->serial(), HEX);
|
||||||
|
|
||||||
iv->sendStatsRequest(_radio.get());
|
iv->sendStatsRequest(_radio.get());
|
||||||
@ -54,19 +54,19 @@ void HoymilesClass::loop()
|
|||||||
|
|
||||||
// Set limit if required
|
// Set limit if required
|
||||||
if (iv->SystemConfigPara()->getLastLimitCommandSuccess() == CMD_NOK) {
|
if (iv->SystemConfigPara()->getLastLimitCommandSuccess() == CMD_NOK) {
|
||||||
_messageOutput->println(F("Resend ActivePowerControl"));
|
_messageOutput->println("Resend ActivePowerControl");
|
||||||
iv->resendActivePowerControlRequest(_radio.get());
|
iv->resendActivePowerControlRequest(_radio.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set power status if required
|
// Set power status if required
|
||||||
if (iv->PowerCommand()->getLastPowerCommandSuccess() == CMD_NOK) {
|
if (iv->PowerCommand()->getLastPowerCommandSuccess() == CMD_NOK) {
|
||||||
_messageOutput->println(F("Resend PowerCommand"));
|
_messageOutput->println("Resend PowerCommand");
|
||||||
iv->resendPowerControlRequest(_radio.get());
|
iv->resendPowerControlRequest(_radio.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch dev info (but first fetch stats)
|
// Fetch dev info (but first fetch stats)
|
||||||
if (iv->Statistics()->getLastUpdate() > 0 && (iv->DevInfo()->getLastUpdateAll() == 0 || iv->DevInfo()->getLastUpdateSimple() == 0)) {
|
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());
|
iv->sendDevInfoRequest(_radio.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,9 +25,9 @@ void HoymilesRadio::init(SPIClass* initialisedSpiBus, uint8_t pinCE, uint8_t pin
|
|||||||
_radio->setRetries(0, 0);
|
_radio->setRetries(0, 0);
|
||||||
_radio->maskIRQ(true, true, false); // enable only receiving interrupts
|
_radio->maskIRQ(true, true, false); // enable only receiving interrupts
|
||||||
if (_radio->isChipConnected()) {
|
if (_radio->isChipConnected()) {
|
||||||
Hoymiles.getMessageOutput()->println(F("Connection successful"));
|
Hoymiles.getMessageOutput()->println("Connection successful");
|
||||||
} else {
|
} else {
|
||||||
Hoymiles.getMessageOutput()->println(F("Connection error!!"));
|
Hoymiles.getMessageOutput()->println("Connection error!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
attachInterrupt(digitalPinToInterrupt(pinIRQ), std::bind(&HoymilesRadio::handleIntr, this), FALLING);
|
attachInterrupt(digitalPinToInterrupt(pinIRQ), std::bind(&HoymilesRadio::handleIntr, this), FALLING);
|
||||||
@ -44,7 +44,7 @@ void HoymilesRadio::loop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_packetReceived) {
|
if (_packetReceived) {
|
||||||
Hoymiles.getMessageOutput()->println(F("Interrupt received"));
|
Hoymiles.getMessageOutput()->println("Interrupt received");
|
||||||
while (_radio->available()) {
|
while (_radio->available()) {
|
||||||
if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) {
|
if (!(_rxBuffer.size() > FRAGMENT_BUFFER_SIZE)) {
|
||||||
fragment_t f;
|
fragment_t f;
|
||||||
@ -56,7 +56,7 @@ void HoymilesRadio::loop()
|
|||||||
_radio->read(f.fragment, f.len);
|
_radio->read(f.fragment, f.len);
|
||||||
_rxBuffer.push(f);
|
_rxBuffer.push(f);
|
||||||
} else {
|
} else {
|
||||||
Hoymiles.getMessageOutput()->println(F("Buffer full"));
|
Hoymiles.getMessageOutput()->println("Buffer full");
|
||||||
_radio->flush_rx();
|
_radio->flush_rx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,11 +76,11 @@ void HoymilesRadio::loop()
|
|||||||
dumpBuf(buf, f.fragment, f.len);
|
dumpBuf(buf, f.fragment, f.len);
|
||||||
inv->addRxFragment(f.fragment, f.len);
|
inv->addRxFragment(f.fragment, f.len);
|
||||||
} else {
|
} else {
|
||||||
Hoymiles.getMessageOutput()->println(F("Inverter Not found!"));
|
Hoymiles.getMessageOutput()->println("Inverter Not found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Hoymiles.getMessageOutput()->println(F("Frame kaputt"));
|
Hoymiles.getMessageOutput()->println("Frame kaputt");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove paket from buffer even it was corrupted
|
// Remove paket from buffer even it was corrupted
|
||||||
@ -89,46 +89,46 @@ void HoymilesRadio::loop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_busyFlag && _rxTimeout.occured()) {
|
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());
|
std::shared_ptr<InverterAbstract> inv = Hoymiles.getInverterBySerial(_commandQueue.front().get()->getTargetAddress());
|
||||||
|
|
||||||
if (nullptr != inv) {
|
if (nullptr != inv) {
|
||||||
CommandAbstract* cmd = _commandQueue.front().get();
|
CommandAbstract* cmd = _commandQueue.front().get();
|
||||||
uint8_t verifyResult = inv->verifyAllFragments(cmd);
|
uint8_t verifyResult = inv->verifyAllFragments(cmd);
|
||||||
if (verifyResult == FRAGMENT_ALL_MISSING_RESEND) {
|
if (verifyResult == FRAGMENT_ALL_MISSING_RESEND) {
|
||||||
Hoymiles.getMessageOutput()->println(F("Nothing received, resend whole request"));
|
Hoymiles.getMessageOutput()->println("Nothing received, resend whole request");
|
||||||
sendLastPacketAgain();
|
sendLastPacketAgain();
|
||||||
|
|
||||||
} else if (verifyResult == FRAGMENT_ALL_MISSING_TIMEOUT) {
|
} 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();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
|
|
||||||
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
|
} else if (verifyResult == FRAGMENT_RETRANSMIT_TIMEOUT) {
|
||||||
Hoymiles.getMessageOutput()->println(F("Retransmit timeout"));
|
Hoymiles.getMessageOutput()->println("Retransmit timeout");
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
|
|
||||||
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
|
} else if (verifyResult == FRAGMENT_HANDLE_ERROR) {
|
||||||
Hoymiles.getMessageOutput()->println(F("Packet handling error"));
|
Hoymiles.getMessageOutput()->println("Packet handling error");
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
|
|
||||||
} else if (verifyResult > 0) {
|
} else if (verifyResult > 0) {
|
||||||
// Perform Retransmit
|
// Perform Retransmit
|
||||||
Hoymiles.getMessageOutput()->print(F("Request retransmit: "));
|
Hoymiles.getMessageOutput()->print("Request retransmit: ");
|
||||||
Hoymiles.getMessageOutput()->println(verifyResult);
|
Hoymiles.getMessageOutput()->println(verifyResult);
|
||||||
sendRetransmitPacket(verifyResult);
|
sendRetransmitPacket(verifyResult);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Successful received all packages
|
// Successful received all packages
|
||||||
Hoymiles.getMessageOutput()->println(F("Success"));
|
Hoymiles.getMessageOutput()->println("Success");
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If inverter was not found, assume the command is invalid
|
// 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();
|
_commandQueue.pop();
|
||||||
_busyFlag = false;
|
_busyFlag = false;
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ void HoymilesRadio::loop()
|
|||||||
inv->clearRxFragmentBuffer();
|
inv->clearRxFragmentBuffer();
|
||||||
sendEsbPacket(cmd);
|
sendEsbPacket(cmd);
|
||||||
} else {
|
} else {
|
||||||
Hoymiles.getMessageOutput()->println(F("TX: Invalid inverter found"));
|
Hoymiles.getMessageOutput()->println("TX: Invalid inverter found");
|
||||||
_commandQueue.pop();
|
_commandQueue.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,11 +252,11 @@ void HoymilesRadio::sendEsbPacket(CommandAbstract* cmd)
|
|||||||
openWritingPipe(s);
|
openWritingPipe(s);
|
||||||
_radio->setRetries(3, 15);
|
_radio->setRetries(3, 15);
|
||||||
|
|
||||||
Hoymiles.getMessageOutput()->print(F("TX "));
|
Hoymiles.getMessageOutput()->print("TX ");
|
||||||
Hoymiles.getMessageOutput()->print(cmd->getCommandName());
|
Hoymiles.getMessageOutput()->print(cmd->getCommandName());
|
||||||
Hoymiles.getMessageOutput()->print(F(" Channel: "));
|
Hoymiles.getMessageOutput()->print(" Channel: ");
|
||||||
Hoymiles.getMessageOutput()->print(_radio->getChannel());
|
Hoymiles.getMessageOutput()->print(_radio->getChannel());
|
||||||
Hoymiles.getMessageOutput()->print(F(" --> "));
|
Hoymiles.getMessageOutput()->print(" --> ");
|
||||||
cmd->dumpDataPayload(Hoymiles.getMessageOutput());
|
cmd->dumpDataPayload(Hoymiles.getMessageOutput());
|
||||||
_radio->write(cmd->getDataPayload(), cmd->getDataSize());
|
_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++) {
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
Hoymiles.getMessageOutput()->printf("%02X ", buf[i]);
|
Hoymiles.getMessageOutput()->printf("%02X ", buf[i]);
|
||||||
}
|
}
|
||||||
Hoymiles.getMessageOutput()->println(F(""));
|
Hoymiles.getMessageOutput()->println("");
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ bool HM_1CH::isValidSerial(uint64_t serial)
|
|||||||
|
|
||||||
String HM_1CH::typeName()
|
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()
|
const std::list<byteAssign_t>* HM_1CH::getByteAssignment()
|
||||||
|
|||||||
@ -30,7 +30,7 @@ bool HM_2CH::isValidSerial(uint64_t serial)
|
|||||||
|
|
||||||
String HM_2CH::typeName()
|
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()
|
const std::list<byteAssign_t>* HM_2CH::getByteAssignment()
|
||||||
|
|||||||
@ -29,7 +29,7 @@ bool HM_4CH::isValidSerial(uint64_t serial)
|
|||||||
|
|
||||||
String HM_4CH::typeName()
|
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()
|
const std::list<byteAssign_t>* HM_4CH::getByteAssignment()
|
||||||
|
|||||||
@ -169,7 +169,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract* cmd)
|
|||||||
{
|
{
|
||||||
// All missing
|
// All missing
|
||||||
if (_rxFragmentLastPacketId == 0) {
|
if (_rxFragmentLastPacketId == 0) {
|
||||||
Hoymiles.getMessageOutput()->println(F("All missing"));
|
Hoymiles.getMessageOutput()->println("All missing");
|
||||||
if (cmd->getSendCount() <= MAX_RESEND_COUNT) {
|
if (cmd->getSendCount() <= MAX_RESEND_COUNT) {
|
||||||
return FRAGMENT_ALL_MISSING_RESEND;
|
return FRAGMENT_ALL_MISSING_RESEND;
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +180,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract* cmd)
|
|||||||
|
|
||||||
// Last fragment is missing (the one with 0x80)
|
// Last fragment is missing (the one with 0x80)
|
||||||
if (_rxFragmentMaxPacketId == 0) {
|
if (_rxFragmentMaxPacketId == 0) {
|
||||||
Hoymiles.getMessageOutput()->println(F("Last missing"));
|
Hoymiles.getMessageOutput()->println("Last missing");
|
||||||
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
|
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
|
||||||
return _rxFragmentLastPacketId + 1;
|
return _rxFragmentLastPacketId + 1;
|
||||||
} else {
|
} else {
|
||||||
@ -192,7 +192,7 @@ uint8_t InverterAbstract::verifyAllFragments(CommandAbstract* cmd)
|
|||||||
// Middle fragment is missing
|
// Middle fragment is missing
|
||||||
for (uint8_t i = 0; i < _rxFragmentMaxPacketId - 1; i++) {
|
for (uint8_t i = 0; i < _rxFragmentMaxPacketId - 1; i++) {
|
||||||
if (!_rxFragmentBuffer[i].wasReceived) {
|
if (!_rxFragmentBuffer[i].wasReceived) {
|
||||||
Hoymiles.getMessageOutput()->println(F("Middle missing"));
|
Hoymiles.getMessageOutput()->println("Middle missing");
|
||||||
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
|
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
|
||||||
return i + 1;
|
return i + 1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -64,214 +64,214 @@ void AlarmLogParser::getLogEntry(uint8_t entryId, AlarmLogEntry_t* entry)
|
|||||||
|
|
||||||
switch (entry->MessageId) {
|
switch (entry->MessageId) {
|
||||||
case 1:
|
case 1:
|
||||||
entry->Message = F("Inverter start");
|
entry->Message = "Inverter start";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
entry->Message = F("DTU command failed");
|
entry->Message = "DTU command failed";
|
||||||
break;
|
break;
|
||||||
case 121:
|
case 121:
|
||||||
entry->Message = F("Over temperature protection");
|
entry->Message = "Over temperature protection";
|
||||||
break;
|
break;
|
||||||
case 124:
|
case 124:
|
||||||
entry->Message = F("Shut down by remote control");
|
entry->Message = "Shut down by remote control";
|
||||||
break;
|
break;
|
||||||
case 125:
|
case 125:
|
||||||
entry->Message = F("Grid configuration parameter error");
|
entry->Message = "Grid configuration parameter error";
|
||||||
break;
|
break;
|
||||||
case 126:
|
case 126:
|
||||||
entry->Message = F("Software error code 126");
|
entry->Message = "Software error code 126";
|
||||||
break;
|
break;
|
||||||
case 127:
|
case 127:
|
||||||
entry->Message = F("Firmware error");
|
entry->Message = "Firmware error";
|
||||||
break;
|
break;
|
||||||
case 128:
|
case 128:
|
||||||
entry->Message = F("Software error code 128");
|
entry->Message = "Software error code 128";
|
||||||
break;
|
break;
|
||||||
case 129:
|
case 129:
|
||||||
entry->Message = F("Abnormal bias");
|
entry->Message = "Abnormal bias";
|
||||||
break;
|
break;
|
||||||
case 130:
|
case 130:
|
||||||
entry->Message = F("Offline");
|
entry->Message = "Offline";
|
||||||
break;
|
break;
|
||||||
case 141:
|
case 141:
|
||||||
entry->Message = F("Grid: Grid overvoltage");
|
entry->Message = "Grid: Grid overvoltage";
|
||||||
break;
|
break;
|
||||||
case 142:
|
case 142:
|
||||||
entry->Message = F("Grid: 10 min value grid overvoltage");
|
entry->Message = "Grid: 10 min value grid overvoltage";
|
||||||
break;
|
break;
|
||||||
case 143:
|
case 143:
|
||||||
entry->Message = F("Grid: Grid undervoltage");
|
entry->Message = "Grid: Grid undervoltage";
|
||||||
break;
|
break;
|
||||||
case 144:
|
case 144:
|
||||||
entry->Message = F("Grid: Grid overfrequency");
|
entry->Message = "Grid: Grid overfrequency";
|
||||||
break;
|
break;
|
||||||
case 145:
|
case 145:
|
||||||
entry->Message = F("Grid: Grid underfrequency");
|
entry->Message = "Grid: Grid underfrequency";
|
||||||
break;
|
break;
|
||||||
case 146:
|
case 146:
|
||||||
entry->Message = F("Grid: Rapid grid frequency change rate");
|
entry->Message = "Grid: Rapid grid frequency change rate";
|
||||||
break;
|
break;
|
||||||
case 147:
|
case 147:
|
||||||
entry->Message = F("Grid: Power grid outage");
|
entry->Message = "Grid: Power grid outage";
|
||||||
break;
|
break;
|
||||||
case 148:
|
case 148:
|
||||||
entry->Message = F("Grid: Grid disconnection");
|
entry->Message = "Grid: Grid disconnection";
|
||||||
break;
|
break;
|
||||||
case 149:
|
case 149:
|
||||||
entry->Message = F("Grid: Island detected");
|
entry->Message = "Grid: Island detected";
|
||||||
break;
|
break;
|
||||||
case 205:
|
case 205:
|
||||||
entry->Message = F("MPPT-A: Input overvoltage");
|
entry->Message = "MPPT-A: Input overvoltage";
|
||||||
break;
|
break;
|
||||||
case 206:
|
case 206:
|
||||||
entry->Message = F("MPPT-B: Input overvoltage");
|
entry->Message = "MPPT-B: Input overvoltage";
|
||||||
break;
|
break;
|
||||||
case 207:
|
case 207:
|
||||||
entry->Message = F("MPPT-A: Input undervoltage");
|
entry->Message = "MPPT-A: Input undervoltage";
|
||||||
break;
|
break;
|
||||||
case 208:
|
case 208:
|
||||||
entry->Message = F("MPPT-B: Input undervoltage");
|
entry->Message = "MPPT-B: Input undervoltage";
|
||||||
break;
|
break;
|
||||||
case 209:
|
case 209:
|
||||||
entry->Message = F("PV-1: No input");
|
entry->Message = "PV-1: No input";
|
||||||
break;
|
break;
|
||||||
case 210:
|
case 210:
|
||||||
entry->Message = F("PV-2: No input");
|
entry->Message = "PV-2: No input";
|
||||||
break;
|
break;
|
||||||
case 211:
|
case 211:
|
||||||
entry->Message = F("PV-3: No input");
|
entry->Message = "PV-3: No input";
|
||||||
break;
|
break;
|
||||||
case 212:
|
case 212:
|
||||||
entry->Message = F("PV-4: No input");
|
entry->Message = "PV-4: No input";
|
||||||
break;
|
break;
|
||||||
case 213:
|
case 213:
|
||||||
entry->Message = F("MPPT-A: PV-1 & PV-2 abnormal wiring");
|
entry->Message = "MPPT-A: PV-1 & PV-2 abnormal wiring";
|
||||||
break;
|
break;
|
||||||
case 214:
|
case 214:
|
||||||
entry->Message = F("MPPT-B: PV-3 & PV-4 abnormal wiring");
|
entry->Message = "MPPT-B: PV-3 & PV-4 abnormal wiring";
|
||||||
break;
|
break;
|
||||||
case 215:
|
case 215:
|
||||||
entry->Message = F("PV-1: Input overvoltage");
|
entry->Message = "PV-1: Input overvoltage";
|
||||||
break;
|
break;
|
||||||
case 216:
|
case 216:
|
||||||
entry->Message = F("PV-1: Input undervoltage");
|
entry->Message = "PV-1: Input undervoltage";
|
||||||
break;
|
break;
|
||||||
case 217:
|
case 217:
|
||||||
entry->Message = F("PV-2: Input overvoltage");
|
entry->Message = "PV-2: Input overvoltage";
|
||||||
break;
|
break;
|
||||||
case 218:
|
case 218:
|
||||||
entry->Message = F("PV-2: Input undervoltage");
|
entry->Message = "PV-2: Input undervoltage";
|
||||||
break;
|
break;
|
||||||
case 219:
|
case 219:
|
||||||
entry->Message = F("PV-3: Input overvoltage");
|
entry->Message = "PV-3: Input overvoltage";
|
||||||
break;
|
break;
|
||||||
case 220:
|
case 220:
|
||||||
entry->Message = F("PV-3: Input undervoltage");
|
entry->Message = "PV-3: Input undervoltage";
|
||||||
break;
|
break;
|
||||||
case 221:
|
case 221:
|
||||||
entry->Message = F("PV-4: Input overvoltage");
|
entry->Message = "PV-4: Input overvoltage";
|
||||||
break;
|
break;
|
||||||
case 222:
|
case 222:
|
||||||
entry->Message = F("PV-4: Input undervoltage");
|
entry->Message = "PV-4: Input undervoltage";
|
||||||
break;
|
break;
|
||||||
case 301:
|
case 301:
|
||||||
entry->Message = F("Hardware error code 301");
|
entry->Message = "Hardware error code 301";
|
||||||
break;
|
break;
|
||||||
case 302:
|
case 302:
|
||||||
entry->Message = F("Hardware error code 302");
|
entry->Message = "Hardware error code 302";
|
||||||
break;
|
break;
|
||||||
case 303:
|
case 303:
|
||||||
entry->Message = F("Hardware error code 303");
|
entry->Message = "Hardware error code 303";
|
||||||
break;
|
break;
|
||||||
case 304:
|
case 304:
|
||||||
entry->Message = F("Hardware error code 304");
|
entry->Message = "Hardware error code 304";
|
||||||
break;
|
break;
|
||||||
case 305:
|
case 305:
|
||||||
entry->Message = F("Hardware error code 305");
|
entry->Message = "Hardware error code 305";
|
||||||
break;
|
break;
|
||||||
case 306:
|
case 306:
|
||||||
entry->Message = F("Hardware error code 306");
|
entry->Message = "Hardware error code 306";
|
||||||
break;
|
break;
|
||||||
case 307:
|
case 307:
|
||||||
entry->Message = F("Hardware error code 307");
|
entry->Message = "Hardware error code 307";
|
||||||
break;
|
break;
|
||||||
case 308:
|
case 308:
|
||||||
entry->Message = F("Hardware error code 308");
|
entry->Message = "Hardware error code 308";
|
||||||
break;
|
break;
|
||||||
case 309:
|
case 309:
|
||||||
entry->Message = F("Hardware error code 309");
|
entry->Message = "Hardware error code 309";
|
||||||
break;
|
break;
|
||||||
case 310:
|
case 310:
|
||||||
entry->Message = F("Hardware error code 310");
|
entry->Message = "Hardware error code 310";
|
||||||
break;
|
break;
|
||||||
case 311:
|
case 311:
|
||||||
entry->Message = F("Hardware error code 311");
|
entry->Message = "Hardware error code 311";
|
||||||
break;
|
break;
|
||||||
case 312:
|
case 312:
|
||||||
entry->Message = F("Hardware error code 312");
|
entry->Message = "Hardware error code 312";
|
||||||
break;
|
break;
|
||||||
case 313:
|
case 313:
|
||||||
entry->Message = F("Hardware error code 313");
|
entry->Message = "Hardware error code 313";
|
||||||
break;
|
break;
|
||||||
case 314:
|
case 314:
|
||||||
entry->Message = F("Hardware error code 314");
|
entry->Message = "Hardware error code 314";
|
||||||
break;
|
break;
|
||||||
case 5041:
|
case 5041:
|
||||||
entry->Message = F("Error code-04 Port 1");
|
entry->Message = "Error code-04 Port 1";
|
||||||
break;
|
break;
|
||||||
case 5042:
|
case 5042:
|
||||||
entry->Message = F("Error code-04 Port 2");
|
entry->Message = "Error code-04 Port 2";
|
||||||
break;
|
break;
|
||||||
case 5043:
|
case 5043:
|
||||||
entry->Message = F("Error code-04 Port 3");
|
entry->Message = "Error code-04 Port 3";
|
||||||
break;
|
break;
|
||||||
case 5044:
|
case 5044:
|
||||||
entry->Message = F("Error code-04 Port 4");
|
entry->Message = "Error code-04 Port 4";
|
||||||
break;
|
break;
|
||||||
case 5051:
|
case 5051:
|
||||||
entry->Message = F("PV Input 1 Overvoltage/Undervoltage");
|
entry->Message = "PV Input 1 Overvoltage/Undervoltage";
|
||||||
break;
|
break;
|
||||||
case 5052:
|
case 5052:
|
||||||
entry->Message = F("PV Input 2 Overvoltage/Undervoltage");
|
entry->Message = "PV Input 2 Overvoltage/Undervoltage";
|
||||||
break;
|
break;
|
||||||
case 5053:
|
case 5053:
|
||||||
entry->Message = F("PV Input 3 Overvoltage/Undervoltage");
|
entry->Message = "PV Input 3 Overvoltage/Undervoltage";
|
||||||
break;
|
break;
|
||||||
case 5054:
|
case 5054:
|
||||||
entry->Message = F("PV Input 4 Overvoltage/Undervoltage");
|
entry->Message = "PV Input 4 Overvoltage/Undervoltage";
|
||||||
break;
|
break;
|
||||||
case 5060:
|
case 5060:
|
||||||
entry->Message = F("Abnormal bias");
|
entry->Message = "Abnormal bias";
|
||||||
break;
|
break;
|
||||||
case 5070:
|
case 5070:
|
||||||
entry->Message = F("Over temperature protection");
|
entry->Message = "Over temperature protection";
|
||||||
break;
|
break;
|
||||||
case 5080:
|
case 5080:
|
||||||
entry->Message = F("Grid Overvoltage/Undervoltage");
|
entry->Message = "Grid Overvoltage/Undervoltage";
|
||||||
break;
|
break;
|
||||||
case 5090:
|
case 5090:
|
||||||
entry->Message = F("Grid Overfrequency/Underfrequency");
|
entry->Message = "Grid Overfrequency/Underfrequency";
|
||||||
break;
|
break;
|
||||||
case 5100:
|
case 5100:
|
||||||
entry->Message = F("Island detected");
|
entry->Message = "Island detected";
|
||||||
break;
|
break;
|
||||||
case 5120:
|
case 5120:
|
||||||
entry->Message = F("EEPROM reading and writing error");
|
entry->Message = "EEPROM reading and writing error";
|
||||||
break;
|
break;
|
||||||
case 5150:
|
case 5150:
|
||||||
entry->Message = F("10 min value grid overvoltage");
|
entry->Message = "10 min value grid overvoltage";
|
||||||
break;
|
break;
|
||||||
case 5200:
|
case 5200:
|
||||||
entry->Message = F("Firmware error");
|
entry->Message = "Firmware error";
|
||||||
break;
|
break;
|
||||||
case 8310:
|
case 8310:
|
||||||
entry->Message = F("Shut down");
|
entry->Message = "Shut down";
|
||||||
break;
|
break;
|
||||||
case 9000:
|
case 9000:
|
||||||
entry->Message = F("Microinverter is suspected of being stolen");
|
entry->Message = "Microinverter is suspected of being stolen";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
entry->Message = F("Unknown");
|
entry->Message = "Unknown";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,58 +29,58 @@ String ResetReasonClass::get_reset_reason_verbose(uint8_t cpu_id)
|
|||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case 1:
|
case 1:
|
||||||
reason_str = F("Vbat power on reset");
|
reason_str = "Vbat power on reset";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
reason_str = F("Software reset digital core");
|
reason_str = "Software reset digital core";
|
||||||
break;
|
break;
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
case 4:
|
case 4:
|
||||||
reason_str = F("Legacy watch dog reset digital core");
|
reason_str = "Legacy watch dog reset digital core";
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 5:
|
case 5:
|
||||||
reason_str = F("Deep Sleep reset digital core");
|
reason_str = "Deep Sleep reset digital core";
|
||||||
break;
|
break;
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
case 6:
|
case 6:
|
||||||
reason_str = F("Reset by SLC module, reset digital core");
|
reason_str = "Reset by SLC module, reset digital core";
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 7:
|
case 7:
|
||||||
reason_str = F("Timer Group0 Watch dog reset digital core");
|
reason_str = "Timer Group0 Watch dog reset digital core";
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
reason_str = F("Timer Group1 Watch dog reset digital core");
|
reason_str = "Timer Group1 Watch dog reset digital core";
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
reason_str = F("RTC Watch dog Reset digital core");
|
reason_str = "RTC Watch dog Reset digital core";
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
reason_str = F("Instrusion tested to reset CPU");
|
reason_str = "Instrusion tested to reset CPU";
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
reason_str = F("Time Group reset CPU");
|
reason_str = "Time Group reset CPU";
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
reason_str = F("Software reset CPU");
|
reason_str = "Software reset CPU";
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
reason_str = F("RTC Watch dog Reset CPU");
|
reason_str = "RTC Watch dog Reset CPU";
|
||||||
break;
|
break;
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
case 14:
|
case 14:
|
||||||
reason_str = F("for APP CPU, reset by PRO CPU");
|
reason_str = "for APP CPU, reset by PRO CPU";
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 15:
|
case 15:
|
||||||
reason_str = F("Reset when the vdd voltage is not stable");
|
reason_str = "Reset when the vdd voltage is not stable";
|
||||||
break;
|
break;
|
||||||
case 16:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
reason_str = F("NO_MEAN");
|
reason_str = "NO_MEAN";
|
||||||
}
|
}
|
||||||
|
|
||||||
return reason_str;
|
return reason_str;
|
||||||
@ -95,58 +95,58 @@ String ResetReasonClass::get_reset_reason_short(uint8_t cpu_id)
|
|||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case 1:
|
case 1:
|
||||||
reason_str = F("POWERON_RESET");
|
reason_str = "POWERON_RESET";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
reason_str = F("SW_RESET");
|
reason_str = "SW_RESET";
|
||||||
break;
|
break;
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
case 4:
|
case 4:
|
||||||
reason_str = F("OWDT_RESET");
|
reason_str = "OWDT_RESET";
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 5:
|
case 5:
|
||||||
reason_str = F("DEEPSLEEP_RESET");
|
reason_str = "DEEPSLEEP_RESET";
|
||||||
break;
|
break;
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
case 6:
|
case 6:
|
||||||
reason_str = F("SDIO_RESET");
|
reason_str = "SDIO_RESET";
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 7:
|
case 7:
|
||||||
reason_str = F("TG0WDT_SYS_RESET");
|
reason_str = "TG0WDT_SYS_RESET";
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
reason_str = F("TG1WDT_SYS_RESET");
|
reason_str = "TG1WDT_SYS_RESET";
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
reason_str = F("RTCWDT_SYS_RESET");
|
reason_str = "RTCWDT_SYS_RESET";
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
reason_str = F("INTRUSION_RESET");
|
reason_str = "INTRUSION_RESET";
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
reason_str = F("TGWDT_CPU_RESET");
|
reason_str = "TGWDT_CPU_RESET";
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
reason_str = F("SW_CPU_RESET");
|
reason_str = "SW_CPU_RESET";
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
reason_str = F("RTCWDT_CPU_RESET");
|
reason_str = "RTCWDT_CPU_RESET";
|
||||||
break;
|
break;
|
||||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||||
case 14:
|
case 14:
|
||||||
reason_str = F("EXT_CPU_RESET");
|
reason_str = "EXT_CPU_RESET";
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 15:
|
case 15:
|
||||||
reason_str = F("RTCWDT_BROWN_OUT_RESET");
|
reason_str = "RTCWDT_BROWN_OUT_RESET";
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
reason_str = F("RTCWDT_RTC_RESET");
|
reason_str = "RTCWDT_RTC_RESET";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
reason_str = F("NO_MEAN");
|
reason_str = "NO_MEAN";
|
||||||
}
|
}
|
||||||
|
|
||||||
return reason_str;
|
return reason_str;
|
||||||
|
|||||||
@ -180,7 +180,7 @@ bool ConfigurationClass::read()
|
|||||||
// Deserialize the JSON document
|
// Deserialize the JSON document
|
||||||
DeserializationError error = deserializeJson(doc, f);
|
DeserializationError error = deserializeJson(doc, f);
|
||||||
if (error) {
|
if (error) {
|
||||||
MessageOutput.printf("Failed to read file, using default configuration. Error: %s (capacity: %d)\r\n", error.c_str(), doc.capacity());
|
MessageOutput.println("Failed to read file, using default configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject cfg = doc["cfg"];
|
JsonObject cfg = doc["cfg"];
|
||||||
@ -359,7 +359,7 @@ void ConfigurationClass::migrate()
|
|||||||
{
|
{
|
||||||
File f = LittleFS.open(CONFIG_FILENAME, "r", false);
|
File f = LittleFS.open(CONFIG_FILENAME, "r", false);
|
||||||
if (!f) {
|
if (!f) {
|
||||||
MessageOutput.println(F("Failed to open file, cancel migration"));
|
MessageOutput.println("Failed to open file, cancel migration");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,27 +21,27 @@ void InverterSettingsClass::init()
|
|||||||
const PinMapping_t& pin = PinMapping.get();
|
const PinMapping_t& pin = PinMapping.get();
|
||||||
|
|
||||||
// Initialize inverter communication
|
// Initialize inverter communication
|
||||||
MessageOutput.print(F("Initialize Hoymiles interface... "));
|
MessageOutput.print("Initialize Hoymiles interface... ");
|
||||||
if (PinMapping.isValidNrf24Config()) {
|
if (PinMapping.isValidNrf24Config()) {
|
||||||
SPIClass* spiClass = new SPIClass(VSPI);
|
SPIClass* spiClass = new SPIClass(VSPI);
|
||||||
spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs);
|
spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs);
|
||||||
Hoymiles.setMessageOutput(&MessageOutput);
|
Hoymiles.setMessageOutput(&MessageOutput);
|
||||||
Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq);
|
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);
|
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);
|
Hoymiles.getRadio()->setDtuSerial(config.Dtu_Serial);
|
||||||
|
|
||||||
MessageOutput.println(F(" Setting poll interval... "));
|
MessageOutput.println(" Setting poll interval... ");
|
||||||
Hoymiles.setPollInterval(config.Dtu_PollInterval);
|
Hoymiles.setPollInterval(config.Dtu_PollInterval);
|
||||||
|
|
||||||
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
||||||
if (config.Inverter[i].Serial > 0) {
|
if (config.Inverter[i].Serial > 0) {
|
||||||
MessageOutput.print(F(" Adding inverter: "));
|
MessageOutput.print(" Adding inverter: ");
|
||||||
MessageOutput.print(config.Inverter[i].Serial, HEX);
|
MessageOutput.print(config.Inverter[i].Serial, HEX);
|
||||||
MessageOutput.print(F(" - "));
|
MessageOutput.print(" - ");
|
||||||
MessageOutput.print(config.Inverter[i].Name);
|
MessageOutput.print(config.Inverter[i].Name);
|
||||||
auto inv = Hoymiles.addInverter(
|
auto inv = Hoymiles.addInverter(
|
||||||
config.Inverter[i].Name,
|
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);
|
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 {
|
} else {
|
||||||
MessageOutput.println(F("Invalid pin config"));
|
MessageOutput.println("Invalid pin config");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -121,26 +121,26 @@ void MqttHandleHassClass::publishField(std::shared_ptr<InverterAbstract> inv, Ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(1024);
|
||||||
root[F("name")] = name;
|
root["name"] = name;
|
||||||
root[F("stat_t")] = stateTopic;
|
root["stat_t"] = stateTopic;
|
||||||
root[F("uniq_id")] = serial + "_ch" + chanNum + "_" + fieldName;
|
root["uniq_id"] = serial + "_ch" + chanNum + "_" + fieldName;
|
||||||
|
|
||||||
String unit_of_measure = inv->Statistics()->getChannelFieldUnit(type, channel, fieldType.fieldId);
|
String unit_of_measure = inv->Statistics()->getChannelFieldUnit(type, channel, fieldType.fieldId);
|
||||||
if (unit_of_measure != "") {
|
if (unit_of_measure != "") {
|
||||||
root[F("unit_of_meas")] = unit_of_measure;
|
root["unit_of_meas"] = unit_of_measure;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject deviceObj = root.createNestedObject("dev");
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
createDeviceInfo(deviceObj, inv);
|
createDeviceInfo(deviceObj, inv);
|
||||||
|
|
||||||
if (Configuration.get().Mqtt_Hass_Expire) {
|
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) {
|
if (devCls != 0) {
|
||||||
root[F("dev_cla")] = devCls;
|
root["dev_cla"] = devCls;
|
||||||
}
|
}
|
||||||
if (stateCls != 0) {
|
if (stateCls != 0) {
|
||||||
root[F("stat_cla")] = stateCls;
|
root["stat_cla"] = stateCls;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
@ -166,17 +166,17 @@ void MqttHandleHassClass::publishInverterButton(std::shared_ptr<InverterAbstract
|
|||||||
String cmdTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
|
String cmdTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
|
||||||
|
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(1024);
|
||||||
root[F("name")] = String(inv->name()) + " " + caption;
|
root["name"] = String(inv->name()) + " " + caption;
|
||||||
root[F("uniq_id")] = serial + "_" + buttonId;
|
root["uniq_id"] = serial + "_" + buttonId;
|
||||||
if (strcmp(icon, "")) {
|
if (strcmp(icon, "")) {
|
||||||
root[F("ic")] = icon;
|
root["ic"] = icon;
|
||||||
}
|
}
|
||||||
if (strcmp(deviceClass, "")) {
|
if (strcmp(deviceClass, "")) {
|
||||||
root[F("dev_cla")] = deviceClass;
|
root["dev_cla"] = deviceClass;
|
||||||
}
|
}
|
||||||
root[F("ent_cat")] = category;
|
root["ent_cat"] = category;
|
||||||
root[F("cmd_t")] = cmdTopic;
|
root["cmd_t"] = cmdTopic;
|
||||||
root[F("payload_press")] = payload;
|
root["payload_press"] = payload;
|
||||||
|
|
||||||
JsonObject deviceObj = root.createNestedObject("dev");
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
createDeviceInfo(deviceObj, inv);
|
createDeviceInfo(deviceObj, inv);
|
||||||
@ -205,17 +205,17 @@ void MqttHandleHassClass::publishInverterNumber(
|
|||||||
String statTopic = MqttSettings.getPrefix() + serial + "/" + stateTopic;
|
String statTopic = MqttSettings.getPrefix() + serial + "/" + stateTopic;
|
||||||
|
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(1024);
|
||||||
root[F("name")] = String(inv->name()) + " " + caption;
|
root["name"] = String(inv->name()) + " " + caption;
|
||||||
root[F("uniq_id")] = serial + "_" + buttonId;
|
root["uniq_id"] = serial + "_" + buttonId;
|
||||||
if (strcmp(icon, "")) {
|
if (strcmp(icon, "")) {
|
||||||
root[F("ic")] = icon;
|
root["ic"] = icon;
|
||||||
}
|
}
|
||||||
root[F("ent_cat")] = category;
|
root["ent_cat"] = category;
|
||||||
root[F("cmd_t")] = cmdTopic;
|
root["cmd_t"] = cmdTopic;
|
||||||
root[F("stat_t")] = statTopic;
|
root["stat_t"] = statTopic;
|
||||||
root[F("unit_of_meas")] = unitOfMeasure;
|
root["unit_of_meas"] = unitOfMeasure;
|
||||||
root[F("min")] = min;
|
root["min"] = min;
|
||||||
root[F("max")] = max;
|
root["max"] = max;
|
||||||
|
|
||||||
JsonObject deviceObj = root.createNestedObject("dev");
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
createDeviceInfo(deviceObj, inv);
|
createDeviceInfo(deviceObj, inv);
|
||||||
@ -240,11 +240,11 @@ void MqttHandleHassClass::publishInverterBinarySensor(std::shared_ptr<InverterAb
|
|||||||
String statTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
|
String statTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
|
||||||
|
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(1024);
|
||||||
root[F("name")] = String(inv->name()) + " " + caption;
|
root["name"] = String(inv->name()) + " " + caption;
|
||||||
root[F("uniq_id")] = serial + "_" + sensorId;
|
root["uniq_id"] = serial + "_" + sensorId;
|
||||||
root[F("stat_t")] = statTopic;
|
root["stat_t"] = statTopic;
|
||||||
root[F("pl_on")] = payload_on;
|
root["pl_on"] = payload_on;
|
||||||
root[F("pl_off")] = payload_off;
|
root["pl_off"] = payload_off;
|
||||||
|
|
||||||
JsonObject deviceObj = root.createNestedObject("dev");
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
createDeviceInfo(deviceObj, inv);
|
createDeviceInfo(deviceObj, inv);
|
||||||
@ -256,12 +256,12 @@ void MqttHandleHassClass::publishInverterBinarySensor(std::shared_ptr<InverterAb
|
|||||||
|
|
||||||
void MqttHandleHassClass::createDeviceInfo(JsonObject& object, std::shared_ptr<InverterAbstract> inv)
|
void MqttHandleHassClass::createDeviceInfo(JsonObject& object, std::shared_ptr<InverterAbstract> inv)
|
||||||
{
|
{
|
||||||
object[F("name")] = inv->name();
|
object["name"] = inv->name();
|
||||||
object[F("ids")] = inv->serialString();
|
object["ids"] = inv->serialString();
|
||||||
object[F("cu")] = String(F("http://")) + NetworkSettings.localIP().toString();
|
object["cu"] = String("http://") + NetworkSettings.localIP().toString();
|
||||||
object[F("mf")] = F("OpenDTU");
|
object["mf"] = "OpenDTU";
|
||||||
object[F("mdl")] = inv->typeName();
|
object["mdl"] = inv->typeName();
|
||||||
object[F("sw")] = AUTO_GIT_HASH;
|
object["sw"] = AUTO_GIT_HASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttHandleHassClass::publish(const String& subtopic, const String& payload)
|
void MqttHandleHassClass::publish(const String& subtopic, const String& payload)
|
||||||
|
|||||||
@ -185,7 +185,7 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
|
|||||||
auto inv = Hoymiles.getInverterBySerial(serial);
|
auto inv = Hoymiles.getInverterBySerial(serial);
|
||||||
|
|
||||||
if (inv == nullptr) {
|
if (inv == nullptr) {
|
||||||
MessageOutput.println(F("Inverter not found"));
|
MessageOutput.println("Inverter not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,11 +14,11 @@ void MqttSettingsClass::NetworkEvent(network_event event)
|
|||||||
{
|
{
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case network_event::NETWORK_GOT_IP:
|
case network_event::NETWORK_GOT_IP:
|
||||||
MessageOutput.println(F("Network connected"));
|
MessageOutput.println("Network connected");
|
||||||
performConnect();
|
performConnect();
|
||||||
break;
|
break;
|
||||||
case network_event::NETWORK_DISCONNECTED:
|
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
|
mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -28,7 +28,7 @@ void MqttSettingsClass::NetworkEvent(network_event event)
|
|||||||
|
|
||||||
void MqttSettingsClass::onMqttConnect(bool sessionPresent)
|
void MqttSettingsClass::onMqttConnect(bool sessionPresent)
|
||||||
{
|
{
|
||||||
MessageOutput.println(F("Connected to MQTT."));
|
MessageOutput.println("Connected to MQTT.");
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Online);
|
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Online);
|
||||||
|
|
||||||
@ -51,30 +51,30 @@ void MqttSettingsClass::unsubscribe(const String& topic)
|
|||||||
|
|
||||||
void MqttSettingsClass::onMqttDisconnect(espMqttClientTypes::DisconnectReason reason)
|
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) {
|
switch (reason) {
|
||||||
case espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED:
|
case espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED:
|
||||||
MessageOutput.println(F("TCP_DISCONNECTED"));
|
MessageOutput.println("TCP_DISCONNECTED");
|
||||||
break;
|
break;
|
||||||
case espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
|
case espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
|
||||||
MessageOutput.println(F("MQTT_UNACCEPTABLE_PROTOCOL_VERSION"));
|
MessageOutput.println("MQTT_UNACCEPTABLE_PROTOCOL_VERSION");
|
||||||
break;
|
break;
|
||||||
case espMqttClientTypes::DisconnectReason::MQTT_IDENTIFIER_REJECTED:
|
case espMqttClientTypes::DisconnectReason::MQTT_IDENTIFIER_REJECTED:
|
||||||
MessageOutput.println(F("MQTT_IDENTIFIER_REJECTED"));
|
MessageOutput.println("MQTT_IDENTIFIER_REJECTED");
|
||||||
break;
|
break;
|
||||||
case espMqttClientTypes::DisconnectReason::MQTT_SERVER_UNAVAILABLE:
|
case espMqttClientTypes::DisconnectReason::MQTT_SERVER_UNAVAILABLE:
|
||||||
MessageOutput.println(F("MQTT_SERVER_UNAVAILABLE"));
|
MessageOutput.println("MQTT_SERVER_UNAVAILABLE");
|
||||||
break;
|
break;
|
||||||
case espMqttClientTypes::DisconnectReason::MQTT_MALFORMED_CREDENTIALS:
|
case espMqttClientTypes::DisconnectReason::MQTT_MALFORMED_CREDENTIALS:
|
||||||
MessageOutput.println(F("MQTT_MALFORMED_CREDENTIALS"));
|
MessageOutput.println("MQTT_MALFORMED_CREDENTIALS");
|
||||||
break;
|
break;
|
||||||
case espMqttClientTypes::DisconnectReason::MQTT_NOT_AUTHORIZED:
|
case espMqttClientTypes::DisconnectReason::MQTT_NOT_AUTHORIZED:
|
||||||
MessageOutput.println(F("MQTT_NOT_AUTHORIZED"));
|
MessageOutput.println("MQTT_NOT_AUTHORIZED");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
MessageOutput.println(F("Unknown"));
|
MessageOutput.println("Unknown");
|
||||||
}
|
}
|
||||||
mqttReconnectTimer.once(
|
mqttReconnectTimer.once(
|
||||||
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
|
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)
|
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);
|
MessageOutput.println(topic);
|
||||||
|
|
||||||
_mqttSubscribeParser.handle_message(properties, topic, payload, len, index, total);
|
_mqttSubscribeParser.handle_message(properties, topic, payload, len, index, total);
|
||||||
@ -97,7 +97,7 @@ void MqttSettingsClass::performConnect()
|
|||||||
using std::placeholders::_4;
|
using std::placeholders::_4;
|
||||||
using std::placeholders::_5;
|
using std::placeholders::_5;
|
||||||
using std::placeholders::_6;
|
using std::placeholders::_6;
|
||||||
MessageOutput.println(F("Connecting to MQTT..."));
|
MessageOutput.println("Connecting to MQTT...");
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
willTopic = getPrefix() + config.Mqtt_LwtTopic;
|
willTopic = getPrefix() + config.Mqtt_LwtTopic;
|
||||||
clientId = NetworkSettings.getApName();
|
clientId = NetworkSettings.getApName();
|
||||||
|
|||||||
@ -29,19 +29,19 @@ void NetworkSettingsClass::NetworkEvent(WiFiEvent_t event)
|
|||||||
{
|
{
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ARDUINO_EVENT_ETH_START:
|
case ARDUINO_EVENT_ETH_START:
|
||||||
MessageOutput.println(F("ETH start"));
|
MessageOutput.println("ETH start");
|
||||||
if (_networkMode == network_mode::Ethernet) {
|
if (_networkMode == network_mode::Ethernet) {
|
||||||
raiseEvent(network_event::NETWORK_START);
|
raiseEvent(network_event::NETWORK_START);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARDUINO_EVENT_ETH_STOP:
|
case ARDUINO_EVENT_ETH_STOP:
|
||||||
MessageOutput.println(F("ETH stop"));
|
MessageOutput.println("ETH stop");
|
||||||
if (_networkMode == network_mode::Ethernet) {
|
if (_networkMode == network_mode::Ethernet) {
|
||||||
raiseEvent(network_event::NETWORK_STOP);
|
raiseEvent(network_event::NETWORK_STOP);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||||
MessageOutput.println(F("ETH connected"));
|
MessageOutput.println("ETH connected");
|
||||||
_ethConnected = true;
|
_ethConnected = true;
|
||||||
raiseEvent(network_event::NETWORK_CONNECTED);
|
raiseEvent(network_event::NETWORK_CONNECTED);
|
||||||
break;
|
break;
|
||||||
@ -52,22 +52,22 @@ void NetworkSettingsClass::NetworkEvent(WiFiEvent_t event)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||||
MessageOutput.println(F("ETH disconnected"));
|
MessageOutput.println("ETH disconnected");
|
||||||
_ethConnected = false;
|
_ethConnected = false;
|
||||||
if (_networkMode == network_mode::Ethernet) {
|
if (_networkMode == network_mode::Ethernet) {
|
||||||
raiseEvent(network_event::NETWORK_DISCONNECTED);
|
raiseEvent(network_event::NETWORK_DISCONNECTED);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||||
MessageOutput.println(F("WiFi connected"));
|
MessageOutput.println("WiFi connected");
|
||||||
if (_networkMode == network_mode::WiFi) {
|
if (_networkMode == network_mode::WiFi) {
|
||||||
raiseEvent(network_event::NETWORK_CONNECTED);
|
raiseEvent(network_event::NETWORK_CONNECTED);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||||
MessageOutput.println(F("WiFi disconnected"));
|
MessageOutput.println("WiFi disconnected");
|
||||||
if (_networkMode == network_mode::WiFi) {
|
if (_networkMode == network_mode::WiFi) {
|
||||||
MessageOutput.println(F("Try reconnecting"));
|
MessageOutput.println("Try reconnecting");
|
||||||
WiFi.reconnect();
|
WiFi.reconnect();
|
||||||
raiseEvent(network_event::NETWORK_DISCONNECTED);
|
raiseEvent(network_event::NETWORK_DISCONNECTED);
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ void NetworkSettingsClass::loop()
|
|||||||
if (_ethConnected) {
|
if (_ethConnected) {
|
||||||
if (_networkMode != network_mode::Ethernet) {
|
if (_networkMode != network_mode::Ethernet) {
|
||||||
// Do stuff when switching to Ethernet mode
|
// Do stuff when switching to Ethernet mode
|
||||||
MessageOutput.println(F("Switch to Ethernet mode"));
|
MessageOutput.println("Switch to Ethernet mode");
|
||||||
_networkMode = network_mode::Ethernet;
|
_networkMode = network_mode::Ethernet;
|
||||||
WiFi.mode(WIFI_MODE_NULL);
|
WiFi.mode(WIFI_MODE_NULL);
|
||||||
setStaticIp();
|
setStaticIp();
|
||||||
@ -163,7 +163,7 @@ void NetworkSettingsClass::loop()
|
|||||||
} else
|
} else
|
||||||
if (_networkMode != network_mode::WiFi) {
|
if (_networkMode != network_mode::WiFi) {
|
||||||
// Do stuff when switching to Ethernet mode
|
// Do stuff when switching to Ethernet mode
|
||||||
MessageOutput.println(F("Switch to WiFi mode"));
|
MessageOutput.println("Switch to WiFi mode");
|
||||||
_networkMode = network_mode::WiFi;
|
_networkMode = network_mode::WiFi;
|
||||||
enableAdminMode();
|
enableAdminMode();
|
||||||
applyConfig();
|
applyConfig();
|
||||||
@ -184,7 +184,7 @@ void NetworkSettingsClass::loop()
|
|||||||
// seconds, disable the internal Access Point
|
// seconds, disable the internal Access Point
|
||||||
if (adminTimeoutCounter > ADMIN_TIMEOUT) {
|
if (adminTimeoutCounter > ADMIN_TIMEOUT) {
|
||||||
adminEnabled = false;
|
adminEnabled = false;
|
||||||
MessageOutput.println(F("Admin mode disabled"));
|
MessageOutput.println("Admin mode disabled");
|
||||||
setupMode();
|
setupMode();
|
||||||
}
|
}
|
||||||
// It's nearly not possible to use the internal AP if the
|
// It's nearly not possible to use the internal AP if the
|
||||||
@ -195,16 +195,16 @@ void NetworkSettingsClass::loop()
|
|||||||
connectRedoTimer = 0;
|
connectRedoTimer = 0;
|
||||||
} else {
|
} else {
|
||||||
if (connectTimeoutTimer > WIFI_RECONNECT_TIMEOUT && !forceDisconnection) {
|
if (connectTimeoutTimer > WIFI_RECONNECT_TIMEOUT && !forceDisconnection) {
|
||||||
MessageOutput.print(F("Disable search for AP... "));
|
MessageOutput.print("Disable search for AP... ");
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
connectRedoTimer = 0;
|
connectRedoTimer = 0;
|
||||||
forceDisconnection = true;
|
forceDisconnection = true;
|
||||||
}
|
}
|
||||||
if (connectRedoTimer > WIFI_RECONNECT_REDO_TIMEOUT && forceDisconnection) {
|
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);
|
WiFi.mode(WIFI_AP_STA);
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
applyConfig();
|
applyConfig();
|
||||||
connectTimeoutTimer = 0;
|
connectTimeoutTimer = 0;
|
||||||
forceDisconnection = false;
|
forceDisconnection = false;
|
||||||
@ -222,28 +222,28 @@ void NetworkSettingsClass::applyConfig()
|
|||||||
if (!strcmp(Configuration.get().WiFi_Ssid, "")) {
|
if (!strcmp(Configuration.get().WiFi_Ssid, "")) {
|
||||||
return;
|
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)) {
|
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(
|
WiFi.begin(
|
||||||
Configuration.get().WiFi_Ssid,
|
Configuration.get().WiFi_Ssid,
|
||||||
Configuration.get().WiFi_Password);
|
Configuration.get().WiFi_Password);
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.print(F("existing credentials... "));
|
MessageOutput.print("existing credentials... ");
|
||||||
WiFi.begin();
|
WiFi.begin();
|
||||||
}
|
}
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
setStaticIp();
|
setStaticIp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSettingsClass::setHostname()
|
void NetworkSettingsClass::setHostname()
|
||||||
{
|
{
|
||||||
MessageOutput.print(F("Setting Hostname... "));
|
MessageOutput.print("Setting Hostname... ");
|
||||||
if (_networkMode == network_mode::WiFi) {
|
if (_networkMode == network_mode::WiFi) {
|
||||||
if (WiFi.hostname(getHostname())) {
|
if (WiFi.hostname(getHostname())) {
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.println(F("failed"));
|
MessageOutput.println("failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evil bad hack to get the hostname set up correctly
|
// Evil bad hack to get the hostname set up correctly
|
||||||
@ -253,9 +253,9 @@ void NetworkSettingsClass::setHostname()
|
|||||||
}
|
}
|
||||||
else if (_networkMode == network_mode::Ethernet) {
|
else if (_networkMode == network_mode::Ethernet) {
|
||||||
if (ETH.setHostname(getHostname().c_str())) {
|
if (ETH.setHostname(getHostname().c_str())) {
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.println(F("failed"));
|
MessageOutput.println("failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,34 +264,34 @@ void NetworkSettingsClass::setStaticIp()
|
|||||||
{
|
{
|
||||||
if (_networkMode == network_mode::WiFi) {
|
if (_networkMode == network_mode::WiFi) {
|
||||||
if (Configuration.get().WiFi_Dhcp) {
|
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);
|
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.print(F("Configuring WiFi STA static IP... "));
|
MessageOutput.print("Configuring WiFi STA static IP... ");
|
||||||
WiFi.config(
|
WiFi.config(
|
||||||
IPAddress(Configuration.get().WiFi_Ip),
|
IPAddress(Configuration.get().WiFi_Ip),
|
||||||
IPAddress(Configuration.get().WiFi_Gateway),
|
IPAddress(Configuration.get().WiFi_Gateway),
|
||||||
IPAddress(Configuration.get().WiFi_Netmask),
|
IPAddress(Configuration.get().WiFi_Netmask),
|
||||||
IPAddress(Configuration.get().WiFi_Dns1),
|
IPAddress(Configuration.get().WiFi_Dns1),
|
||||||
IPAddress(Configuration.get().WiFi_Dns2));
|
IPAddress(Configuration.get().WiFi_Dns2));
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_networkMode == network_mode::Ethernet) {
|
else if (_networkMode == network_mode::Ethernet) {
|
||||||
if (Configuration.get().WiFi_Dhcp) {
|
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);
|
ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.print(F("Configuring Ethernet static IP... "));
|
MessageOutput.print("Configuring Ethernet static IP... ");
|
||||||
ETH.config(
|
ETH.config(
|
||||||
IPAddress(Configuration.get().WiFi_Ip),
|
IPAddress(Configuration.get().WiFi_Ip),
|
||||||
IPAddress(Configuration.get().WiFi_Gateway),
|
IPAddress(Configuration.get().WiFi_Gateway),
|
||||||
IPAddress(Configuration.get().WiFi_Netmask),
|
IPAddress(Configuration.get().WiFi_Netmask),
|
||||||
IPAddress(Configuration.get().WiFi_Dns1),
|
IPAddress(Configuration.get().WiFi_Dns1),
|
||||||
IPAddress(Configuration.get().WiFi_Dns2));
|
IPAddress(Configuration.get().WiFi_Dns2));
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,7 +92,7 @@ bool PinMappingClass::init(const String& deviceMapping)
|
|||||||
// Deserialize the JSON document
|
// Deserialize the JSON document
|
||||||
DeserializationError error = deserializeJson(doc, f);
|
DeserializationError error = deserializeJson(doc, f);
|
||||||
if (error) {
|
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++) {
|
for (uint8_t i = 0; i < doc.size(); i++) {
|
||||||
|
|||||||
@ -91,7 +91,7 @@ bool WebApiClass::checkCredentials(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
// WebAPI should set the X-Requested-With to prevent browser internal auth dialogs
|
// WebAPI should set the X-Requested-With to prevent browser internal auth dialogs
|
||||||
if (!request->hasHeader("X-Requested-With")) {
|
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);
|
request->send(r);
|
||||||
|
|
||||||
|
|||||||
@ -59,11 +59,11 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -72,8 +72,8 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -83,32 +83,32 @@ void WebApiConfigClass::onConfigDelete(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("delete"))) {
|
if (!(root.containsKey("delete"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("delete")].as<bool>() == false) {
|
if (root["delete"].as<bool>() == false) {
|
||||||
retMsg[F("message")] = F("Not deleted anything!");
|
retMsg["message"] = "Not deleted anything!";
|
||||||
retMsg[F("code")] = WebApiError::ConfigNotDeleted;
|
retMsg["code"] = WebApiError::ConfigNotDeleted;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Configuration resettet. Rebooting now...");
|
retMsg["message"] = "Configuration resettet. Rebooting now...";
|
||||||
retMsg[F("code")] = WebApiError::ConfigSuccess;
|
retMsg["code"] = WebApiError::ConfigSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -125,7 +125,7 @@ void WebApiConfigClass::onConfigListGet(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
JsonArray data = root.createNestedArray(F("configs"));
|
JsonArray data = root.createNestedArray("configs");
|
||||||
|
|
||||||
File rootfs = LittleFS.open("/");
|
File rootfs = LittleFS.open("/");
|
||||||
File file = rootfs.openNextFile();
|
File file = rootfs.openNextFile();
|
||||||
|
|||||||
@ -37,37 +37,37 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
|
|||||||
const PinMapping_t& pin = PinMapping.get();
|
const PinMapping_t& pin = PinMapping.get();
|
||||||
|
|
||||||
JsonObject curPin = root.createNestedObject("curPin");
|
JsonObject curPin = root.createNestedObject("curPin");
|
||||||
curPin[F("name")] = config.Dev_PinMapping;
|
curPin["name"] = config.Dev_PinMapping;
|
||||||
|
|
||||||
JsonObject nrfPinObj = curPin.createNestedObject("nrf24");
|
JsonObject nrfPinObj = curPin.createNestedObject("nrf24");
|
||||||
nrfPinObj[F("clk")] = pin.nrf24_clk;
|
nrfPinObj["clk"] = pin.nrf24_clk;
|
||||||
nrfPinObj[F("cs")] = pin.nrf24_cs;
|
nrfPinObj["cs"] = pin.nrf24_cs;
|
||||||
nrfPinObj[F("en")] = pin.nrf24_en;
|
nrfPinObj["en"] = pin.nrf24_en;
|
||||||
nrfPinObj[F("irq")] = pin.nrf24_irq;
|
nrfPinObj["irq"] = pin.nrf24_irq;
|
||||||
nrfPinObj[F("miso")] = pin.nrf24_miso;
|
nrfPinObj["miso"] = pin.nrf24_miso;
|
||||||
nrfPinObj[F("mosi")] = pin.nrf24_mosi;
|
nrfPinObj["mosi"] = pin.nrf24_mosi;
|
||||||
|
|
||||||
JsonObject ethPinObj = curPin.createNestedObject("eth");
|
JsonObject ethPinObj = curPin.createNestedObject("eth");
|
||||||
ethPinObj[F("enabled")] = pin.eth_enabled;
|
ethPinObj["enabled"] = pin.eth_enabled;
|
||||||
ethPinObj[F("phy_addr")] = pin.eth_phy_addr;
|
ethPinObj["phy_addr"] = pin.eth_phy_addr;
|
||||||
ethPinObj[F("power")] = pin.eth_power;
|
ethPinObj["power"] = pin.eth_power;
|
||||||
ethPinObj[F("mdc")] = pin.eth_mdc;
|
ethPinObj["mdc"] = pin.eth_mdc;
|
||||||
ethPinObj[F("mdio")] = pin.eth_mdio;
|
ethPinObj["mdio"] = pin.eth_mdio;
|
||||||
ethPinObj[F("type")] = pin.eth_type;
|
ethPinObj["type"] = pin.eth_type;
|
||||||
ethPinObj[F("clk_mode")] = pin.eth_clk_mode;
|
ethPinObj["clk_mode"] = pin.eth_clk_mode;
|
||||||
|
|
||||||
JsonObject displayPinObj = curPin.createNestedObject("display");
|
JsonObject displayPinObj = curPin.createNestedObject("display");
|
||||||
displayPinObj[F("type")] = pin.display_type;
|
displayPinObj["type"] = pin.display_type;
|
||||||
displayPinObj[F("data")] = pin.display_data;
|
displayPinObj["data"] = pin.display_data;
|
||||||
displayPinObj[F("clk")] = pin.display_clk;
|
displayPinObj["clk"] = pin.display_clk;
|
||||||
displayPinObj[F("cs")] = pin.display_cs;
|
displayPinObj["cs"] = pin.display_cs;
|
||||||
displayPinObj[F("reset")] = pin.display_reset;
|
displayPinObj["reset"] = pin.display_reset;
|
||||||
|
|
||||||
JsonObject display = root.createNestedObject("display");
|
JsonObject display = root.createNestedObject("display");
|
||||||
display[F("rotation")] = config.Display_Rotation;
|
display["rotation"] = config.Display_Rotation;
|
||||||
display[F("power_safe")] = config.Display_PowerSafe;
|
display["power_safe"] = config.Display_PowerSafe;
|
||||||
display[F("screensaver")] = config.Display_ScreenSaver;
|
display["screensaver"] = config.Display_ScreenSaver;
|
||||||
display[F("contrast")] = config.Display_Contrast;
|
display["contrast"] = config.Display_Contrast;
|
||||||
|
|
||||||
JsonObject victronPinObj = curPin.createNestedObject("victron");
|
JsonObject victronPinObj = curPin.createNestedObject("victron");
|
||||||
victronPinObj[F("rx")] = pin.victron_rx;
|
victronPinObj[F("rx")] = pin.victron_rx;
|
||||||
@ -97,11 +97,11 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -110,8 +110,8 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > MQTT_JSON_DOC_SIZE) {
|
if (json.length() > MQTT_JSON_DOC_SIZE) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -121,38 +121,38 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("curPin") || root.containsKey("display"))) {
|
if (!(root.containsKey("curPin") || root.containsKey("display"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("curPin")][F("name")].as<String>().length() == 0 || root[F("curPin")][F("name")].as<String>().length() > 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[F("message")] = F("Pin mapping must between 1 and " STR(DEV_MAX_MAPPING_NAME_STRLEN) " characters long!");
|
retMsg["message"] = "Pin mapping must between 1 and " STR(DEV_MAX_MAPPING_NAME_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::HardwarePinMappingLength;
|
retMsg["code"] = WebApiError::HardwarePinMappingLength;
|
||||||
retMsg[F("param")][F("max")] = DEV_MAX_MAPPING_NAME_STRLEN;
|
retMsg["param"]["max"] = DEV_MAX_MAPPING_NAME_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_T& config = Configuration.get();
|
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));
|
strlcpy(config.Dev_PinMapping, root["curPin"]["name"].as<String>().c_str(), sizeof(config.Dev_PinMapping));
|
||||||
config.Display_Rotation = root[F("display")][F("rotation")].as<uint8_t>();
|
config.Display_Rotation = root["display"]["rotation"].as<uint8_t>();
|
||||||
config.Display_PowerSafe = root[F("display")][F("power_safe")].as<bool>();
|
config.Display_PowerSafe = root["display"]["power_safe"].as<bool>();
|
||||||
config.Display_ScreenSaver = root[F("display")][F("screensaver")].as<bool>();
|
config.Display_ScreenSaver = root["display"]["screensaver"].as<bool>();
|
||||||
config.Display_Contrast = root[F("display")][F("contrast")].as<uint8_t>();
|
config.Display_Contrast = root["display"]["contrast"].as<uint8_t>();
|
||||||
|
|
||||||
Display.setOrientation(config.Display_Rotation);
|
Display.setOrientation(config.Display_Rotation);
|
||||||
Display.enablePowerSafe = config.Display_PowerSafe;
|
Display.enablePowerSafe = config.Display_PowerSafe;
|
||||||
@ -161,9 +161,9 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -34,18 +34,18 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
|
|||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
JsonObject devInfoObj = root[inv->serialString()].createNestedObject();
|
JsonObject devInfoObj = root[inv->serialString()].createNestedObject();
|
||||||
devInfoObj[F("valid_data")] = inv->DevInfo()->getLastUpdate() > 0;
|
devInfoObj["valid_data"] = inv->DevInfo()->getLastUpdate() > 0;
|
||||||
devInfoObj[F("fw_bootloader_version")] = inv->DevInfo()->getFwBootloaderVersion();
|
devInfoObj["fw_bootloader_version"] = inv->DevInfo()->getFwBootloaderVersion();
|
||||||
devInfoObj[F("fw_build_version")] = inv->DevInfo()->getFwBuildVersion();
|
devInfoObj["fw_build_version"] = inv->DevInfo()->getFwBuildVersion();
|
||||||
devInfoObj[F("hw_part_number")] = inv->DevInfo()->getHwPartNumber();
|
devInfoObj["hw_part_number"] = inv->DevInfo()->getHwPartNumber();
|
||||||
devInfoObj[F("hw_version")] = inv->DevInfo()->getHwVersion();
|
devInfoObj["hw_version"] = inv->DevInfo()->getHwVersion();
|
||||||
devInfoObj[F("hw_model_name")] = inv->DevInfo()->getHwModelName();
|
devInfoObj["hw_model_name"] = inv->DevInfo()->getHwModelName();
|
||||||
devInfoObj[F("max_power")] = inv->DevInfo()->getMaxPower();
|
devInfoObj["max_power"] = inv->DevInfo()->getMaxPower();
|
||||||
|
|
||||||
char timebuffer[32];
|
char timebuffer[32];
|
||||||
const time_t t = inv->DevInfo()->getFwBuildDateTime();
|
const time_t t = inv->DevInfo()->getFwBuildDateTime();
|
||||||
std::strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", gmtime(&t));
|
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();
|
response->setLength();
|
||||||
|
|||||||
@ -38,9 +38,9 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request)
|
|||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
||||||
((uint32_t)((config.Dtu_Serial >> 32) & 0xFFFFFFFF)),
|
((uint32_t)((config.Dtu_Serial >> 32) & 0xFFFFFFFF)),
|
||||||
((uint32_t)(config.Dtu_Serial & 0xFFFFFFFF)));
|
((uint32_t)(config.Dtu_Serial & 0xFFFFFFFF)));
|
||||||
root[F("dtu_serial")] = buffer;
|
root["dtu_serial"] = buffer;
|
||||||
root[F("dtu_pollinterval")] = config.Dtu_PollInterval;
|
root["dtu_pollinterval"] = config.Dtu_PollInterval;
|
||||||
root[F("dtu_palevel")] = config.Dtu_PaLevel;
|
root["dtu_palevel"] = config.Dtu_PaLevel;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -54,11 +54,11 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -67,8 +67,8 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -78,40 +78,40 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("dtu_serial") && root.containsKey("dtu_pollinterval") && root.containsKey("dtu_palevel"))) {
|
if (!(root.containsKey("dtu_serial") && root.containsKey("dtu_pollinterval") && root.containsKey("dtu_palevel"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("dtu_serial")].as<uint64_t>() == 0) {
|
if (root["dtu_serial"].as<uint64_t>() == 0) {
|
||||||
retMsg[F("message")] = F("Serial cannot be zero!");
|
retMsg["message"] = "Serial cannot be zero!";
|
||||||
retMsg[F("code")] = WebApiError::DtuSerialZero;
|
retMsg["code"] = WebApiError::DtuSerialZero;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("dtu_pollinterval")].as<uint32_t>() == 0) {
|
if (root["dtu_pollinterval"].as<uint32_t>() == 0) {
|
||||||
retMsg[F("message")] = F("Poll interval must be greater zero!");
|
retMsg["message"] = "Poll interval must be greater zero!";
|
||||||
retMsg[F("code")] = WebApiError::DtuPollZero;
|
retMsg["code"] = WebApiError::DtuPollZero;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("dtu_palevel")].as<uint8_t>() > 3) {
|
if (root["dtu_palevel"].as<uint8_t>() > 3) {
|
||||||
retMsg[F("message")] = F("Invalid power level setting!");
|
retMsg["message"] = "Invalid power level setting!";
|
||||||
retMsg[F("code")] = WebApiError::DtuInvalidPowerLevel;
|
retMsg["code"] = WebApiError::DtuInvalidPowerLevel;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -120,14 +120,14 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
|
|||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
// Interpret the string as a hex value and convert it to uint64_t
|
// 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_Serial = strtoll(root["dtu_serial"].as<String>().c_str(), NULL, 16);
|
||||||
config.Dtu_PollInterval = root[F("dtu_pollinterval")].as<uint32_t>();
|
config.Dtu_PollInterval = root["dtu_pollinterval"].as<uint32_t>();
|
||||||
config.Dtu_PaLevel = root[F("dtu_palevel")].as<uint8_t>();
|
config.Dtu_PaLevel = root["dtu_palevel"].as<uint8_t>();
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -43,7 +43,7 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
|
|||||||
uint8_t logEntryCount = inv->EventLog()->getEntryCount();
|
uint8_t logEntryCount = inv->EventLog()->getEntryCount();
|
||||||
|
|
||||||
root[serial]["count"] = logEntryCount;
|
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++) {
|
for (uint8_t logEntry = 0; logEntry < logEntryCount; logEntry++) {
|
||||||
JsonObject eventsObject = eventsArray.createNestedObject();
|
JsonObject eventsObject = eventsArray.createNestedObject();
|
||||||
@ -51,10 +51,10 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
|
|||||||
AlarmLogEntry_t entry;
|
AlarmLogEntry_t entry;
|
||||||
inv->EventLog()->getLogEntry(logEntry, &entry);
|
inv->EventLog()->getLogEntry(logEntry, &entry);
|
||||||
|
|
||||||
eventsObject[F("message_id")] = entry.MessageId;
|
eventsObject["message_id"] = entry.MessageId;
|
||||||
eventsObject[F("message")] = entry.Message;
|
eventsObject["message"] = entry.Message;
|
||||||
eventsObject[F("start_time")] = entry.StartTime;
|
eventsObject["start_time"] = entry.StartTime;
|
||||||
eventsObject[F("end_time")] = entry.EndTime;
|
eventsObject["end_time"] = entry.EndTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,34 +35,34 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, 4096U);
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, 4096U);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
JsonArray data = root.createNestedArray(F("inverter"));
|
JsonArray data = root.createNestedArray("inverter");
|
||||||
|
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
||||||
if (config.Inverter[i].Serial > 0) {
|
if (config.Inverter[i].Serial > 0) {
|
||||||
JsonObject obj = data.createNestedObject();
|
JsonObject obj = data.createNestedObject();
|
||||||
obj[F("id")] = i;
|
obj["id"] = i;
|
||||||
obj[F("name")] = String(config.Inverter[i].Name);
|
obj["name"] = String(config.Inverter[i].Name);
|
||||||
|
|
||||||
// Inverter Serial is read as HEX
|
// Inverter Serial is read as HEX
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
char buffer[sizeof(uint64_t) * 8 + 1];
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
||||||
((uint32_t)((config.Inverter[i].Serial >> 32) & 0xFFFFFFFF)),
|
((uint32_t)((config.Inverter[i].Serial >> 32) & 0xFFFFFFFF)),
|
||||||
((uint32_t)(config.Inverter[i].Serial & 0xFFFFFFFF)));
|
((uint32_t)(config.Inverter[i].Serial & 0xFFFFFFFF)));
|
||||||
obj[F("serial")] = buffer;
|
obj["serial"] = buffer;
|
||||||
obj[F("poll_enable")] = config.Inverter[i].Poll_Enable;
|
obj["poll_enable"] = config.Inverter[i].Poll_Enable;
|
||||||
obj[F("poll_enable_night")] = config.Inverter[i].Poll_Enable_Night;
|
obj["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night;
|
||||||
obj[F("command_enable")] = config.Inverter[i].Command_Enable;
|
obj["command_enable"] = config.Inverter[i].Command_Enable;
|
||||||
obj[F("command_enable_night")] = config.Inverter[i].Command_Enable_Night;
|
obj["command_enable_night"] = config.Inverter[i].Command_Enable_Night;
|
||||||
|
|
||||||
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
|
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
|
||||||
uint8_t max_channels;
|
uint8_t max_channels;
|
||||||
if (inv == nullptr) {
|
if (inv == nullptr) {
|
||||||
obj[F("type")] = F("Unknown");
|
obj["type"] = "Unknown";
|
||||||
max_channels = INV_MAX_CHAN_COUNT;
|
max_channels = INV_MAX_CHAN_COUNT;
|
||||||
} else {
|
} else {
|
||||||
obj[F("type")] = inv->typeName();
|
obj["type"] = inv->typeName();
|
||||||
max_channels = inv->Statistics()->getChannelsByType(TYPE_DC).size();
|
max_channels = inv->Statistics()->getChannelsByType(TYPE_DC).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,11 +88,11 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -101,8 +101,8 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -112,33 +112,33 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("serial") && root.containsKey("name"))) {
|
if (!(root.containsKey("serial") && root.containsKey("name"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("serial")].as<uint64_t>() == 0) {
|
if (root["serial"].as<uint64_t>() == 0) {
|
||||||
retMsg[F("message")] = F("Serial must be a number > 0!");
|
retMsg["message"] = "Serial must be a number > 0!";
|
||||||
retMsg[F("code")] = WebApiError::InverterSerialZero;
|
retMsg["code"] = WebApiError::InverterSerialZero;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("name")].as<String>().length() == 0 || root[F("name")].as<String>().length() > INV_MAX_NAME_STRLEN) {
|
if (root["name"].as<String>().length() == 0 || root["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["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::InverterNameLength;
|
retMsg["code"] = WebApiError::InverterNameLength;
|
||||||
retMsg[F("param")][F("max")] = INV_MAX_NAME_STRLEN;
|
retMsg["param"]["max"] = INV_MAX_NAME_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -147,23 +147,23 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
|
|||||||
INVERTER_CONFIG_T* inverter = Configuration.getFreeInverterSlot();
|
INVERTER_CONFIG_T* inverter = Configuration.getFreeInverterSlot();
|
||||||
|
|
||||||
if (!inverter) {
|
if (!inverter) {
|
||||||
retMsg[F("message")] = F("Only " STR(INV_MAX_COUNT) " inverters are supported!");
|
retMsg["message"] = "Only " STR(INV_MAX_COUNT) " inverters are supported!";
|
||||||
retMsg[F("code")] = WebApiError::InverterCount;
|
retMsg["code"] = WebApiError::InverterCount;
|
||||||
retMsg[F("param")][F("max")] = INV_MAX_COUNT;
|
retMsg["param"]["max"] = INV_MAX_COUNT;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpret the string as a hex value and convert it to uint64_t
|
// 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();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Inverter created!");
|
retMsg["message"] = "Inverter created!";
|
||||||
retMsg[F("code")] = WebApiError::InverterAdded;
|
retMsg["code"] = WebApiError::InverterAdded;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -187,11 +187,11 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -200,8 +200,8 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -211,82 +211,82 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("id") && root.containsKey("serial") && root.containsKey("name") && root.containsKey("channel"))) {
|
if (!(root.containsKey("id") && root.containsKey("serial") && root.containsKey("name") && root.containsKey("channel"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("id")].as<uint8_t>() > INV_MAX_COUNT - 1) {
|
if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) {
|
||||||
retMsg[F("message")] = F("Invalid ID specified!");
|
retMsg["message"] = "Invalid ID specified!";
|
||||||
retMsg[F("code")] = WebApiError::InverterInvalidId;
|
retMsg["code"] = WebApiError::InverterInvalidId;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("serial")].as<uint64_t>() == 0) {
|
if (root["serial"].as<uint64_t>() == 0) {
|
||||||
retMsg[F("message")] = F("Serial must be a number > 0!");
|
retMsg["message"] = "Serial must be a number > 0!";
|
||||||
retMsg[F("code")] = WebApiError::InverterSerialZero;
|
retMsg["code"] = WebApiError::InverterSerialZero;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("name")].as<String>().length() == 0 || root[F("name")].as<String>().length() > INV_MAX_NAME_STRLEN) {
|
if (root["name"].as<String>().length() == 0 || root["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["message"] = "Name must between 1 and " STR(INV_MAX_NAME_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::InverterNameLength;
|
retMsg["code"] = WebApiError::InverterNameLength;
|
||||||
retMsg[F("param")][F("max")] = INV_MAX_NAME_STRLEN;
|
retMsg["param"]["max"] = INV_MAX_NAME_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray channelArray = root[F("channel")].as<JsonArray>();
|
JsonArray channelArray = root["channel"].as<JsonArray>();
|
||||||
if (channelArray.size() == 0 || channelArray.size() > INV_MAX_CHAN_COUNT) {
|
if (channelArray.size() == 0 || channelArray.size() > INV_MAX_CHAN_COUNT) {
|
||||||
retMsg[F("message")] = F("Invalid amount of max channel setting given!");
|
retMsg["message"] = "Invalid amount of max channel setting given!";
|
||||||
retMsg[F("code")] = WebApiError::InverterInvalidMaxChannel;
|
retMsg["code"] = WebApiError::InverterInvalidMaxChannel;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
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;
|
uint64_t old_serial = inverter.Serial;
|
||||||
|
|
||||||
// Interpret the string as a hex value and convert it to uint64_t
|
// Interpret the string as a hex value and convert it to uint64_t
|
||||||
inverter.Serial = new_serial;
|
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;
|
uint8_t arrayCount = 0;
|
||||||
for (JsonVariant channel : channelArray) {
|
for (JsonVariant channel : channelArray) {
|
||||||
inverter.channel[arrayCount].MaxChannelPower = channel[F("max_power")].as<uint16_t>();
|
inverter.channel[arrayCount].MaxChannelPower = channel["max_power"].as<uint16_t>();
|
||||||
inverter.channel[arrayCount].YieldTotalOffset = channel[F("yield_total_offset")].as<float>();
|
inverter.channel[arrayCount].YieldTotalOffset = channel["yield_total_offset"].as<float>();
|
||||||
strncpy(inverter.channel[arrayCount].Name, channel[F("name")] | "", sizeof(inverter.channel[arrayCount].Name));
|
strncpy(inverter.channel[arrayCount].Name, channel["name"] | "", sizeof(inverter.channel[arrayCount].Name));
|
||||||
inverter.Poll_Enable = root[F("poll_enable")] | true;
|
inverter.Poll_Enable = root["poll_enable"] | true;
|
||||||
inverter.Poll_Enable_Night = root[F("poll_enable_night")] | true;
|
inverter.Poll_Enable_Night = root["poll_enable_night"] | true;
|
||||||
inverter.Command_Enable = root[F("command_enable")] | true;
|
inverter.Command_Enable = root["command_enable"] | true;
|
||||||
inverter.Command_Enable_Night = root[F("command_enable_night")] | true;
|
inverter.Command_Enable_Night = root["command_enable_night"] | true;
|
||||||
|
|
||||||
arrayCount++;
|
arrayCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("code")] = WebApiError::InverterChanged;
|
retMsg["code"] = WebApiError::InverterChanged;
|
||||||
retMsg[F("message")] = F("Inverter changed!");
|
retMsg["message"] = "Inverter changed!";
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -325,11 +325,11 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -338,8 +338,8 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -349,30 +349,30 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("id"))) {
|
if (!(root.containsKey("id"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("id")].as<uint8_t>() > INV_MAX_COUNT - 1) {
|
if (root["id"].as<uint8_t>() > INV_MAX_COUNT - 1) {
|
||||||
retMsg[F("message")] = F("Invalid ID specified!");
|
retMsg["message"] = "Invalid ID specified!";
|
||||||
retMsg[F("code")] = WebApiError::InverterInvalidId;
|
retMsg["code"] = WebApiError::InverterInvalidId;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
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];
|
INVERTER_CONFIG_T& inverter = Configuration.get().Inverter[inverter_id];
|
||||||
|
|
||||||
Hoymiles.removeInverterBySerial(inverter.Serial);
|
Hoymiles.removeInverterBySerial(inverter.Serial);
|
||||||
@ -381,9 +381,9 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
|
|||||||
strncpy(inverter.Name, "", sizeof(inverter.Name));
|
strncpy(inverter.Name, "", sizeof(inverter.Name));
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Inverter deleted!");
|
retMsg["message"] = "Inverter deleted!";
|
||||||
retMsg[F("code")] = WebApiError::InverterDeleted;
|
retMsg["code"] = WebApiError::InverterDeleted;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -63,11 +63,11 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -76,8 +76,8 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -87,8 +87,8 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -97,50 +97,50 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
|
|||||||
if (!(root.containsKey("serial")
|
if (!(root.containsKey("serial")
|
||||||
&& root.containsKey("limit_value")
|
&& root.containsKey("limit_value")
|
||||||
&& root.containsKey("limit_type"))) {
|
&& root.containsKey("limit_type"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("serial")].as<uint64_t>() == 0) {
|
if (root["serial"].as<uint64_t>() == 0) {
|
||||||
retMsg[F("message")] = F("Serial must be a number > 0!");
|
retMsg["message"] = "Serial must be a number > 0!";
|
||||||
retMsg[F("code")] = WebApiError::LimitSerialZero;
|
retMsg["code"] = WebApiError::LimitSerialZero;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("limit_value")].as<uint16_t>() == 0 || root[F("limit_value")].as<uint16_t>() > 1500) {
|
if (root["limit_value"].as<uint16_t>() == 0 || root["limit_value"].as<uint16_t>() > 1500) {
|
||||||
retMsg[F("message")] = F("Limit must between 1 and 1500!");
|
retMsg["message"] = "Limit must between 1 and 1500!";
|
||||||
retMsg[F("code")] = WebApiError::LimitInvalidLimit;
|
retMsg["code"] = WebApiError::LimitInvalidLimit;
|
||||||
retMsg[F("param")][F("max")] = 1500;
|
retMsg["param"]["max"] = 1500;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::AbsolutNonPersistent)
|
if (!((root["limit_type"].as<uint16_t>() == PowerLimitControlType::AbsolutNonPersistent)
|
||||||
|| (root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::AbsolutPersistent)
|
|| (root["limit_type"].as<uint16_t>() == PowerLimitControlType::AbsolutPersistent)
|
||||||
|| (root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::RelativNonPersistent)
|
|| (root["limit_type"].as<uint16_t>() == PowerLimitControlType::RelativNonPersistent)
|
||||||
|| (root[F("limit_type")].as<uint16_t>() == PowerLimitControlType::RelativPersistent))) {
|
|| (root["limit_type"].as<uint16_t>() == PowerLimitControlType::RelativPersistent))) {
|
||||||
|
|
||||||
retMsg[F("message")] = F("Invalid type specified!");
|
retMsg["message"] = "Invalid type specified!";
|
||||||
retMsg[F("code")] = WebApiError::LimitInvalidType;
|
retMsg["code"] = WebApiError::LimitInvalidType;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
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);
|
||||||
uint16_t limit = root[F("limit_value")].as<uint16_t>();
|
uint16_t limit = root["limit_value"].as<uint16_t>();
|
||||||
PowerLimitControlType type = root[F("limit_type")].as<PowerLimitControlType>();
|
PowerLimitControlType type = root["limit_type"].as<PowerLimitControlType>();
|
||||||
|
|
||||||
auto inv = Hoymiles.getInverterBySerial(serial);
|
auto inv = Hoymiles.getInverterBySerial(serial);
|
||||||
if (inv == nullptr) {
|
if (inv == nullptr) {
|
||||||
retMsg[F("message")] = F("Invalid inverter specified!");
|
retMsg["message"] = "Invalid inverter specified!";
|
||||||
retMsg[F("code")] = WebApiError::LimitInvalidInverter;
|
retMsg["code"] = WebApiError::LimitInvalidInverter;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -148,9 +148,9 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
inv->sendActivePowerControlRequest(Hoymiles.getRadio(), limit, type);
|
inv->sendActivePowerControlRequest(Hoymiles.getRadio(), limit, type);
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -29,11 +29,11 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -42,8 +42,8 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > MQTT_JSON_DOC_SIZE) {
|
if (json.length() > MQTT_JSON_DOC_SIZE) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -53,25 +53,25 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("reboot"))) {
|
if (!(root.containsKey("reboot"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("reboot")].as<bool>()) {
|
if (root["reboot"].as<bool>()) {
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Reboot triggered!");
|
retMsg["message"] = "Reboot triggered!";
|
||||||
retMsg[F("code")] = WebApiError::MaintenanceRebootTriggered;
|
retMsg["code"] = WebApiError::MaintenanceRebootTriggered;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -80,8 +80,8 @@ void WebApiMaintenanceClass::onRebootPost(AsyncWebServerRequest* request)
|
|||||||
yield();
|
yield();
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
} else {
|
} else {
|
||||||
retMsg[F("message")] = F("Reboot cancled!");
|
retMsg["message"] = "Reboot cancled!";
|
||||||
retMsg[F("code")] = WebApiError::MaintenanceRebootCancled;
|
retMsg["code"] = WebApiError::MaintenanceRebootCancled;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -39,22 +39,22 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
|
|||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
root[F("mqtt_enabled")] = config.Mqtt_Enabled;
|
root["mqtt_enabled"] = config.Mqtt_Enabled;
|
||||||
root[F("mqtt_hostname")] = config.Mqtt_Hostname;
|
root["mqtt_hostname"] = config.Mqtt_Hostname;
|
||||||
root[F("mqtt_port")] = config.Mqtt_Port;
|
root["mqtt_port"] = config.Mqtt_Port;
|
||||||
root[F("mqtt_username")] = config.Mqtt_Username;
|
root["mqtt_username"] = config.Mqtt_Username;
|
||||||
root[F("mqtt_topic")] = config.Mqtt_Topic;
|
root["mqtt_topic"] = config.Mqtt_Topic;
|
||||||
root[F("mqtt_connected")] = MqttSettings.getConnected();
|
root["mqtt_connected"] = MqttSettings.getConnected();
|
||||||
root[F("mqtt_retain")] = config.Mqtt_Retain;
|
root["mqtt_retain"] = config.Mqtt_Retain;
|
||||||
root[F("mqtt_tls")] = config.Mqtt_Tls;
|
root["mqtt_tls"] = config.Mqtt_Tls;
|
||||||
root[F("mqtt_root_ca_cert_info")] = getRootCaCertInfo(config.Mqtt_RootCaCert);
|
root["mqtt_root_ca_cert_info"] = getRootCaCertInfo(config.Mqtt_RootCaCert);
|
||||||
root[F("mqtt_lwt_topic")] = String(config.Mqtt_Topic) + config.Mqtt_LwtTopic;
|
root["mqtt_lwt_topic"] = String(config.Mqtt_Topic) + config.Mqtt_LwtTopic;
|
||||||
root[F("mqtt_publish_interval")] = config.Mqtt_PublishInterval;
|
root["mqtt_publish_interval"] = config.Mqtt_PublishInterval;
|
||||||
root[F("mqtt_hass_enabled")] = config.Mqtt_Hass_Enabled;
|
root["mqtt_hass_enabled"] = config.Mqtt_Hass_Enabled;
|
||||||
root[F("mqtt_hass_expire")] = config.Mqtt_Hass_Expire;
|
root["mqtt_hass_expire"] = config.Mqtt_Hass_Expire;
|
||||||
root[F("mqtt_hass_retain")] = config.Mqtt_Hass_Retain;
|
root["mqtt_hass_retain"] = config.Mqtt_Hass_Retain;
|
||||||
root[F("mqtt_hass_topic")] = config.Mqtt_Hass_Topic;
|
root["mqtt_hass_topic"] = config.Mqtt_Hass_Topic;
|
||||||
root[F("mqtt_hass_individualpanels")] = config.Mqtt_Hass_IndividualPanels;
|
root["mqtt_hass_individualpanels"] = config.Mqtt_Hass_IndividualPanels;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -70,24 +70,24 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
|
|||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
root[F("mqtt_enabled")] = config.Mqtt_Enabled;
|
root["mqtt_enabled"] = config.Mqtt_Enabled;
|
||||||
root[F("mqtt_hostname")] = config.Mqtt_Hostname;
|
root["mqtt_hostname"] = config.Mqtt_Hostname;
|
||||||
root[F("mqtt_port")] = config.Mqtt_Port;
|
root["mqtt_port"] = config.Mqtt_Port;
|
||||||
root[F("mqtt_username")] = config.Mqtt_Username;
|
root["mqtt_username"] = config.Mqtt_Username;
|
||||||
root[F("mqtt_password")] = config.Mqtt_Password;
|
root["mqtt_password"] = config.Mqtt_Password;
|
||||||
root[F("mqtt_topic")] = config.Mqtt_Topic;
|
root["mqtt_topic"] = config.Mqtt_Topic;
|
||||||
root[F("mqtt_retain")] = config.Mqtt_Retain;
|
root["mqtt_retain"] = config.Mqtt_Retain;
|
||||||
root[F("mqtt_tls")] = config.Mqtt_Tls;
|
root["mqtt_tls"] = config.Mqtt_Tls;
|
||||||
root[F("mqtt_root_ca_cert")] = config.Mqtt_RootCaCert;
|
root["mqtt_root_ca_cert"] = config.Mqtt_RootCaCert;
|
||||||
root[F("mqtt_lwt_topic")] = config.Mqtt_LwtTopic;
|
root["mqtt_lwt_topic"] = config.Mqtt_LwtTopic;
|
||||||
root[F("mqtt_lwt_online")] = config.Mqtt_LwtValue_Online;
|
root["mqtt_lwt_online"] = config.Mqtt_LwtValue_Online;
|
||||||
root[F("mqtt_lwt_offline")] = config.Mqtt_LwtValue_Offline;
|
root["mqtt_lwt_offline"] = config.Mqtt_LwtValue_Offline;
|
||||||
root[F("mqtt_publish_interval")] = config.Mqtt_PublishInterval;
|
root["mqtt_publish_interval"] = config.Mqtt_PublishInterval;
|
||||||
root[F("mqtt_hass_enabled")] = config.Mqtt_Hass_Enabled;
|
root["mqtt_hass_enabled"] = config.Mqtt_Hass_Enabled;
|
||||||
root[F("mqtt_hass_expire")] = config.Mqtt_Hass_Expire;
|
root["mqtt_hass_expire"] = config.Mqtt_Hass_Expire;
|
||||||
root[F("mqtt_hass_retain")] = config.Mqtt_Hass_Retain;
|
root["mqtt_hass_retain"] = config.Mqtt_Hass_Retain;
|
||||||
root[F("mqtt_hass_topic")] = config.Mqtt_Hass_Topic;
|
root["mqtt_hass_topic"] = config.Mqtt_Hass_Topic;
|
||||||
root[F("mqtt_hass_individualpanels")] = config.Mqtt_Hass_IndividualPanels;
|
root["mqtt_hass_individualpanels"] = config.Mqtt_Hass_IndividualPanels;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -101,11 +101,11 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -114,8 +114,8 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > MQTT_JSON_DOC_SIZE) {
|
if (json.length() > MQTT_JSON_DOC_SIZE) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -125,8 +125,8 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -149,139 +149,139 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
&& root.containsKey("mqtt_hass_retain")
|
&& root.containsKey("mqtt_hass_retain")
|
||||||
&& root.containsKey("mqtt_hass_topic")
|
&& root.containsKey("mqtt_hass_topic")
|
||||||
&& root.containsKey("mqtt_hass_individualpanels"))) {
|
&& root.containsKey("mqtt_hass_individualpanels"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_enabled")].as<bool>()) {
|
if (root["mqtt_enabled"].as<bool>()) {
|
||||||
if (root[F("mqtt_hostname")].as<String>().length() == 0 || root[F("mqtt_hostname")].as<String>().length() > MQTT_MAX_HOSTNAME_STRLEN) {
|
if (root["mqtt_hostname"].as<String>().length() == 0 || root["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["message"] = "MqTT Server must between 1 and " STR(MQTT_MAX_HOSTNAME_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::MqttHostnameLength;
|
retMsg["code"] = WebApiError::MqttHostnameLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_HOSTNAME_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_HOSTNAME_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_username")].as<String>().length() > MQTT_MAX_USERNAME_STRLEN) {
|
if (root["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["message"] = "Username must not longer then " STR(MQTT_MAX_USERNAME_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttUsernameLength;
|
retMsg["code"] = WebApiError::MqttUsernameLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_USERNAME_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_USERNAME_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (root[F("mqtt_password")].as<String>().length() > MQTT_MAX_PASSWORD_STRLEN) {
|
if (root["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["message"] = "Password must not longer then " STR(MQTT_MAX_PASSWORD_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttPasswordLength;
|
retMsg["code"] = WebApiError::MqttPasswordLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_PASSWORD_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_PASSWORD_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (root[F("mqtt_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
if (root["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["message"] = "Topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttTopicLength;
|
retMsg["code"] = WebApiError::MqttTopicLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_TOPIC_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_topic")].as<String>().indexOf(' ') != -1) {
|
if (root["mqtt_topic"].as<String>().indexOf(' ') != -1) {
|
||||||
retMsg[F("message")] = F("Topic must not contain space characters!");
|
retMsg["message"] = "Topic must not contain space characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttTopicCharacter;
|
retMsg["code"] = WebApiError::MqttTopicCharacter;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!root[F("mqtt_topic")].as<String>().endsWith("/")) {
|
if (!root["mqtt_topic"].as<String>().endsWith("/")) {
|
||||||
retMsg[F("message")] = F("Topic must end with slash (/)!");
|
retMsg["message"] = "Topic must end with slash (/)!";
|
||||||
retMsg[F("code")] = WebApiError::MqttTopicTrailingSlash;
|
retMsg["code"] = WebApiError::MqttTopicTrailingSlash;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_port")].as<uint>() == 0 || root[F("mqtt_port")].as<uint>() > 65535) {
|
if (root["mqtt_port"].as<uint>() == 0 || root["mqtt_port"].as<uint>() > 65535) {
|
||||||
retMsg[F("message")] = F("Port must be a number between 1 and 65535!");
|
retMsg["message"] = "Port must be a number between 1 and 65535!";
|
||||||
retMsg[F("code")] = WebApiError::MqttPort;
|
retMsg["code"] = WebApiError::MqttPort;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_root_ca_cert")].as<String>().length() > MQTT_MAX_ROOT_CA_CERT_STRLEN) {
|
if (root["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["message"] = "Certificate must not longer then " STR(MQTT_MAX_ROOT_CA_CERT_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttCertificateLength;
|
retMsg["code"] = WebApiError::MqttCertificateLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_ROOT_CA_CERT_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_ROOT_CA_CERT_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_lwt_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
if (root["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["message"] = "LWT topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttLwtTopicLength;
|
retMsg["code"] = WebApiError::MqttLwtTopicLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_TOPIC_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_lwt_topic")].as<String>().indexOf(' ') != -1) {
|
if (root["mqtt_lwt_topic"].as<String>().indexOf(' ') != -1) {
|
||||||
retMsg[F("message")] = F("LWT topic must not contain space characters!");
|
retMsg["message"] = "LWT topic must not contain space characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttLwtTopicCharacter;
|
retMsg["code"] = WebApiError::MqttLwtTopicCharacter;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_lwt_online")].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
|
if (root["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["message"] = "LWT online value must not longer then " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttLwtOnlineLength;
|
retMsg["code"] = WebApiError::MqttLwtOnlineLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_LWTVALUE_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_lwt_offline")].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
|
if (root["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["message"] = "LWT offline value must not longer then " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttLwtOfflineLength;
|
retMsg["code"] = WebApiError::MqttLwtOfflineLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_LWTVALUE_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_publish_interval")].as<uint32_t>() < 5 || root[F("mqtt_publish_interval")].as<uint32_t>() > 65535) {
|
if (root["mqtt_publish_interval"].as<uint32_t>() < 5 || root["mqtt_publish_interval"].as<uint32_t>() > 65535) {
|
||||||
retMsg[F("message")] = F("Publish interval must be a number between 5 and 65535!");
|
retMsg["message"] = "Publish interval must be a number between 5 and 65535!";
|
||||||
retMsg[F("code")] = WebApiError::MqttPublishInterval;
|
retMsg["code"] = WebApiError::MqttPublishInterval;
|
||||||
retMsg[F("param")][F("min")] = 5;
|
retMsg["param"]["min"] = 5;
|
||||||
retMsg[F("param")][F("max")] = 65535;
|
retMsg["param"]["max"] = 65535;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_hass_enabled")].as<bool>()) {
|
if (root["mqtt_hass_enabled"].as<bool>()) {
|
||||||
if (root[F("mqtt_hass_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
if (root["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["message"] = "Hass topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttHassTopicLength;
|
retMsg["code"] = WebApiError::MqttHassTopicLength;
|
||||||
retMsg[F("param")][F("max")] = MQTT_MAX_TOPIC_STRLEN;
|
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_hass_topic")].as<String>().indexOf(' ') != -1) {
|
if (root["mqtt_hass_topic"].as<String>().indexOf(' ') != -1) {
|
||||||
retMsg[F("message")] = F("Hass topic must not contain space characters!");
|
retMsg["message"] = "Hass topic must not contain space characters!";
|
||||||
retMsg[F("code")] = WebApiError::MqttHassTopicCharacter;
|
retMsg["code"] = WebApiError::MqttHassTopicCharacter;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -290,29 +290,29 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
config.Mqtt_Enabled = root[F("mqtt_enabled")].as<bool>();
|
config.Mqtt_Enabled = root["mqtt_enabled"].as<bool>();
|
||||||
config.Mqtt_Retain = root[F("mqtt_retain")].as<bool>();
|
config.Mqtt_Retain = root["mqtt_retain"].as<bool>();
|
||||||
config.Mqtt_Tls = root[F("mqtt_tls")].as<bool>();
|
config.Mqtt_Tls = root["mqtt_tls"].as<bool>();
|
||||||
strlcpy(config.Mqtt_RootCaCert, root[F("mqtt_root_ca_cert")].as<String>().c_str(), sizeof(config.Mqtt_RootCaCert));
|
strlcpy(config.Mqtt_RootCaCert, root["mqtt_root_ca_cert"].as<String>().c_str(), sizeof(config.Mqtt_RootCaCert));
|
||||||
config.Mqtt_Port = root[F("mqtt_port")].as<uint>();
|
config.Mqtt_Port = root["mqtt_port"].as<uint>();
|
||||||
strlcpy(config.Mqtt_Hostname, root[F("mqtt_hostname")].as<String>().c_str(), sizeof(config.Mqtt_Hostname));
|
strlcpy(config.Mqtt_Hostname, root["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_Username, root["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_Password, root["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_Topic, root["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_LwtTopic, root["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_Online, root["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));
|
strlcpy(config.Mqtt_LwtValue_Offline, root["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_PublishInterval = root["mqtt_publish_interval"].as<uint32_t>();
|
||||||
config.Mqtt_Hass_Enabled = root[F("mqtt_hass_enabled")].as<bool>();
|
config.Mqtt_Hass_Enabled = root["mqtt_hass_enabled"].as<bool>();
|
||||||
config.Mqtt_Hass_Expire = root[F("mqtt_hass_expire")].as<bool>();
|
config.Mqtt_Hass_Expire = root["mqtt_hass_expire"].as<bool>();
|
||||||
config.Mqtt_Hass_Retain = root[F("mqtt_hass_retain")].as<bool>();
|
config.Mqtt_Hass_Retain = root["mqtt_hass_retain"].as<bool>();
|
||||||
config.Mqtt_Hass_IndividualPanels = root[F("mqtt_hass_individualpanels")].as<bool>();
|
config.Mqtt_Hass_IndividualPanels = root["mqtt_hass_individualpanels"].as<bool>();
|
||||||
strlcpy(config.Mqtt_Hass_Topic, root[F("mqtt_hass_topic")].as<String>().c_str(), sizeof(config.Mqtt_Hass_Topic));
|
strlcpy(config.Mqtt_Hass_Topic, root["mqtt_hass_topic"].as<String>().c_str(), sizeof(config.Mqtt_Hass_Topic));
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -34,22 +34,22 @@ void WebApiNetworkClass::onNetworkStatus(AsyncWebServerRequest* request)
|
|||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
root[F("sta_status")] = ((WiFi.getMode() & WIFI_STA) != 0);
|
root["sta_status"] = ((WiFi.getMode() & WIFI_STA) != 0);
|
||||||
root[F("sta_ssid")] = WiFi.SSID();
|
root["sta_ssid"] = WiFi.SSID();
|
||||||
root[F("sta_rssi")] = WiFi.RSSI();
|
root["sta_rssi"] = WiFi.RSSI();
|
||||||
root[F("network_hostname")] = NetworkSettings.getHostname();
|
root["network_hostname"] = NetworkSettings.getHostname();
|
||||||
root[F("network_ip")] = NetworkSettings.localIP().toString();
|
root["network_ip"] = NetworkSettings.localIP().toString();
|
||||||
root[F("network_netmask")] = NetworkSettings.subnetMask().toString();
|
root["network_netmask"] = NetworkSettings.subnetMask().toString();
|
||||||
root[F("network_gateway")] = NetworkSettings.gatewayIP().toString();
|
root["network_gateway"] = NetworkSettings.gatewayIP().toString();
|
||||||
root[F("network_dns1")] = NetworkSettings.dnsIP(0).toString();
|
root["network_dns1"] = NetworkSettings.dnsIP(0).toString();
|
||||||
root[F("network_dns2")] = NetworkSettings.dnsIP(1).toString();
|
root["network_dns2"] = NetworkSettings.dnsIP(1).toString();
|
||||||
root[F("network_mac")] = NetworkSettings.macAddress();
|
root["network_mac"] = NetworkSettings.macAddress();
|
||||||
root[F("network_mode")] = NetworkSettings.NetworkMode() == network_mode::WiFi ? F("Station") : F("Ethernet");
|
root["network_mode"] = NetworkSettings.NetworkMode() == network_mode::WiFi ? "Station" : "Ethernet";
|
||||||
root[F("ap_status")] = ((WiFi.getMode() & WIFI_AP) != 0);
|
root["ap_status"] = ((WiFi.getMode() & WIFI_AP) != 0);
|
||||||
root[F("ap_ssid")] = NetworkSettings.getApName();
|
root["ap_ssid"] = NetworkSettings.getApName();
|
||||||
root[F("ap_ip")] = WiFi.softAPIP().toString();
|
root["ap_ip"] = WiFi.softAPIP().toString();
|
||||||
root[F("ap_mac")] = WiFi.softAPmacAddress();
|
root["ap_mac"] = WiFi.softAPmacAddress();
|
||||||
root[F("ap_stationnum")] = WiFi.softAPgetStationNum();
|
root["ap_stationnum"] = WiFi.softAPgetStationNum();
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -65,15 +65,15 @@ void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request)
|
|||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
root[F("hostname")] = config.WiFi_Hostname;
|
root["hostname"] = config.WiFi_Hostname;
|
||||||
root[F("dhcp")] = config.WiFi_Dhcp;
|
root["dhcp"] = config.WiFi_Dhcp;
|
||||||
root[F("ipaddress")] = IPAddress(config.WiFi_Ip).toString();
|
root["ipaddress"] = IPAddress(config.WiFi_Ip).toString();
|
||||||
root[F("netmask")] = IPAddress(config.WiFi_Netmask).toString();
|
root["netmask"] = IPAddress(config.WiFi_Netmask).toString();
|
||||||
root[F("gateway")] = IPAddress(config.WiFi_Gateway).toString();
|
root["gateway"] = IPAddress(config.WiFi_Gateway).toString();
|
||||||
root[F("dns1")] = IPAddress(config.WiFi_Dns1).toString();
|
root["dns1"] = IPAddress(config.WiFi_Dns1).toString();
|
||||||
root[F("dns2")] = IPAddress(config.WiFi_Dns2).toString();
|
root["dns2"] = IPAddress(config.WiFi_Dns2).toString();
|
||||||
root[F("ssid")] = config.WiFi_Ssid;
|
root["ssid"] = config.WiFi_Ssid;
|
||||||
root[F("password")] = config.WiFi_Password;
|
root["password"] = config.WiFi_Password;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -87,11 +87,11 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -100,8 +100,8 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -111,78 +111,78 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
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"))) {
|
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["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress ipaddress;
|
IPAddress ipaddress;
|
||||||
if (!ipaddress.fromString(root[F("ipaddress")].as<String>())) {
|
if (!ipaddress.fromString(root["ipaddress"].as<String>())) {
|
||||||
retMsg[F("message")] = F("IP address is invalid!");
|
retMsg["message"] = "IP address is invalid!";
|
||||||
retMsg[F("code")] = WebApiError::NetworkIpInvalid;
|
retMsg["code"] = WebApiError::NetworkIpInvalid;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IPAddress netmask;
|
IPAddress netmask;
|
||||||
if (!netmask.fromString(root[F("netmask")].as<String>())) {
|
if (!netmask.fromString(root["netmask"].as<String>())) {
|
||||||
retMsg[F("message")] = F("Netmask is invalid!");
|
retMsg["message"] = "Netmask is invalid!";
|
||||||
retMsg[F("code")] = WebApiError::NetworkNetmaskInvalid;
|
retMsg["code"] = WebApiError::NetworkNetmaskInvalid;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IPAddress gateway;
|
IPAddress gateway;
|
||||||
if (!gateway.fromString(root[F("gateway")].as<String>())) {
|
if (!gateway.fromString(root["gateway"].as<String>())) {
|
||||||
retMsg[F("message")] = F("Gateway is invalid!");
|
retMsg["message"] = "Gateway is invalid!";
|
||||||
retMsg[F("code")] = WebApiError::NetworkGatewayInvalid;
|
retMsg["code"] = WebApiError::NetworkGatewayInvalid;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IPAddress dns1;
|
IPAddress dns1;
|
||||||
if (!dns1.fromString(root[F("dns1")].as<String>())) {
|
if (!dns1.fromString(root["dns1"].as<String>())) {
|
||||||
retMsg[F("message")] = F("DNS Server IP 1 is invalid!");
|
retMsg["message"] = "DNS Server IP 1 is invalid!";
|
||||||
retMsg[F("code")] = WebApiError::NetworkDns1Invalid;
|
retMsg["code"] = WebApiError::NetworkDns1Invalid;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IPAddress dns2;
|
IPAddress dns2;
|
||||||
if (!dns2.fromString(root[F("dns2")].as<String>())) {
|
if (!dns2.fromString(root["dns2"].as<String>())) {
|
||||||
retMsg[F("message")] = F("DNS Server IP 2 is invalid!");
|
retMsg["message"] = "DNS Server IP 2 is invalid!";
|
||||||
retMsg[F("code")] = WebApiError::NetworkDns2Invalid;
|
retMsg["code"] = WebApiError::NetworkDns2Invalid;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("hostname")].as<String>().length() == 0 || root[F("hostname")].as<String>().length() > WIFI_MAX_HOSTNAME_STRLEN) {
|
if (root["hostname"].as<String>().length() == 0 || root["hostname"].as<String>().length() > WIFI_MAX_HOSTNAME_STRLEN) {
|
||||||
retMsg[F("message")] = F("Hostname must between 1 and " STR(WIFI_MAX_HOSTNAME_STRLEN) " characters long!");
|
retMsg["message"] = "Hostname must between 1 and " STR(WIFI_MAX_HOSTNAME_STRLEN) " characters long!";
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (NetworkSettings.NetworkMode() == network_mode::WiFi) {
|
if (NetworkSettings.NetworkMode() == network_mode::WiFi) {
|
||||||
if (root[F("ssid")].as<String>().length() == 0 || root[F("ssid")].as<String>().length() > WIFI_MAX_SSID_STRLEN) {
|
if (root["ssid"].as<String>().length() == 0 || root["ssid"].as<String>().length() > WIFI_MAX_SSID_STRLEN) {
|
||||||
retMsg[F("message")] = F("SSID must between 1 and " STR(WIFI_MAX_SSID_STRLEN) " characters long!");
|
retMsg["message"] = "SSID must between 1 and " STR(WIFI_MAX_SSID_STRLEN) " characters long!";
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (root[F("password")].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN - 1) {
|
if (root["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!");
|
retMsg["message"] = "Password must not be longer than " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!";
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -209,19 +209,19 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
|
|||||||
config.WiFi_Dns2[1] = dns2[1];
|
config.WiFi_Dns2[1] = dns2[1];
|
||||||
config.WiFi_Dns2[2] = dns2[2];
|
config.WiFi_Dns2[2] = dns2[2];
|
||||||
config.WiFi_Dns2[3] = dns2[3];
|
config.WiFi_Dns2[3] = dns2[3];
|
||||||
strlcpy(config.WiFi_Ssid, root[F("ssid")].as<String>().c_str(), sizeof(config.WiFi_Ssid));
|
strlcpy(config.WiFi_Ssid, root["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_Password, root["password"].as<String>().c_str(), sizeof(config.WiFi_Password));
|
||||||
strlcpy(config.WiFi_Hostname, root[F("hostname")].as<String>().c_str(), sizeof(config.WiFi_Hostname));
|
strlcpy(config.WiFi_Hostname, root["hostname"].as<String>().c_str(), sizeof(config.WiFi_Hostname));
|
||||||
if (root[F("dhcp")].as<bool>()) {
|
if (root["dhcp"].as<bool>()) {
|
||||||
config.WiFi_Dhcp = true;
|
config.WiFi_Dhcp = true;
|
||||||
} else {
|
} else {
|
||||||
config.WiFi_Dhcp = false;
|
config.WiFi_Dhcp = false;
|
||||||
}
|
}
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -38,29 +38,29 @@ void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request)
|
|||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
root[F("ntp_server")] = config.Ntp_Server;
|
root["ntp_server"] = config.Ntp_Server;
|
||||||
root[F("ntp_timezone")] = config.Ntp_Timezone;
|
root["ntp_timezone"] = config.Ntp_Timezone;
|
||||||
root[F("ntp_timezone_descr")] = config.Ntp_TimezoneDescr;
|
root["ntp_timezone_descr"] = config.Ntp_TimezoneDescr;
|
||||||
|
|
||||||
struct tm timeinfo;
|
struct tm timeinfo;
|
||||||
if (!getLocalTime(&timeinfo, 5)) {
|
if (!getLocalTime(&timeinfo, 5)) {
|
||||||
root[F("ntp_status")] = false;
|
root["ntp_status"] = false;
|
||||||
} else {
|
} else {
|
||||||
root[F("ntp_status")] = true;
|
root["ntp_status"] = true;
|
||||||
}
|
}
|
||||||
char timeStringBuff[50];
|
char timeStringBuff[50];
|
||||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo);
|
||||||
root[F("ntp_localtime")] = timeStringBuff;
|
root["ntp_localtime"] = timeStringBuff;
|
||||||
|
|
||||||
SunPosition.sunriseTime(&timeinfo);
|
SunPosition.sunriseTime(&timeinfo);
|
||||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &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);
|
SunPosition.sunsetTime(&timeinfo);
|
||||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &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();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -76,11 +76,11 @@ void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request)
|
|||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
root[F("ntp_server")] = config.Ntp_Server;
|
root["ntp_server"] = config.Ntp_Server;
|
||||||
root[F("ntp_timezone")] = config.Ntp_Timezone;
|
root["ntp_timezone"] = config.Ntp_Timezone;
|
||||||
root[F("ntp_timezone_descr")] = config.Ntp_TimezoneDescr;
|
root["ntp_timezone_descr"] = config.Ntp_TimezoneDescr;
|
||||||
root[F("longitude")] = config.Ntp_Longitude;
|
root["longitude"] = config.Ntp_Longitude;
|
||||||
root[F("latitude")] = config.Ntp_Latitude;
|
root["latitude"] = config.Ntp_Latitude;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -94,11 +94,11 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -107,8 +107,8 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -118,59 +118,59 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone") && root.containsKey("longitude") && root.containsKey("latitude"))) {
|
if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone") && root.containsKey("longitude") && root.containsKey("latitude"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("ntp_server")].as<String>().length() == 0 || root[F("ntp_server")].as<String>().length() > NTP_MAX_SERVER_STRLEN) {
|
if (root["ntp_server"].as<String>().length() == 0 || root["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["message"] = "NTP Server must between 1 and " STR(NTP_MAX_SERVER_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::NtpServerLength;
|
retMsg["code"] = WebApiError::NtpServerLength;
|
||||||
retMsg[F("param")][F("max")] = NTP_MAX_SERVER_STRLEN;
|
retMsg["param"]["max"] = NTP_MAX_SERVER_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("ntp_timezone")].as<String>().length() == 0 || root[F("ntp_timezone")].as<String>().length() > NTP_MAX_TIMEZONE_STRLEN) {
|
if (root["ntp_timezone"].as<String>().length() == 0 || root["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["message"] = "Timezone must between 1 and " STR(NTP_MAX_TIMEZONE_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::NtpTimezoneLength;
|
retMsg["code"] = WebApiError::NtpTimezoneLength;
|
||||||
retMsg[F("param")][F("max")] = NTP_MAX_TIMEZONE_STRLEN;
|
retMsg["param"]["max"] = NTP_MAX_TIMEZONE_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("ntp_timezone_descr")].as<String>().length() == 0 || root[F("ntp_timezone_descr")].as<String>().length() > 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[F("message")] = F("Timezone description must between 1 and " STR(NTP_MAX_TIMEZONEDESCR_STRLEN) " characters long!");
|
retMsg["message"] = "Timezone description must between 1 and " STR(NTP_MAX_TIMEZONEDESCR_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::NtpTimezoneDescriptionLength;
|
retMsg["code"] = WebApiError::NtpTimezoneDescriptionLength;
|
||||||
retMsg[F("param")][F("max")] = NTP_MAX_TIMEZONEDESCR_STRLEN;
|
retMsg["param"]["max"] = NTP_MAX_TIMEZONEDESCR_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
strlcpy(config.Ntp_Server, root[F("ntp_server")].as<String>().c_str(), sizeof(config.Ntp_Server));
|
strlcpy(config.Ntp_Server, root["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_Timezone, root["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));
|
strlcpy(config.Ntp_TimezoneDescr, root["ntp_timezone_descr"].as<String>().c_str(), sizeof(config.Ntp_TimezoneDescr));
|
||||||
config.Ntp_Latitude = root[F("latitude")].as<double>();
|
config.Ntp_Latitude = root["latitude"].as<double>();
|
||||||
config.Ntp_Longitude = root[F("longitude")].as<double>();
|
config.Ntp_Longitude = root["longitude"].as<double>();
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -190,17 +190,17 @@ void WebApiNtpClass::onNtpTimeGet(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
struct tm timeinfo;
|
struct tm timeinfo;
|
||||||
if (!getLocalTime(&timeinfo, 5)) {
|
if (!getLocalTime(&timeinfo, 5)) {
|
||||||
root[F("ntp_status")] = false;
|
root["ntp_status"] = false;
|
||||||
} else {
|
} else {
|
||||||
root[F("ntp_status")] = true;
|
root["ntp_status"] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
root[F("year")] = timeinfo.tm_year + 1900;
|
root["year"] = timeinfo.tm_year + 1900;
|
||||||
root[F("month")] = timeinfo.tm_mon + 1;
|
root["month"] = timeinfo.tm_mon + 1;
|
||||||
root[F("day")] = timeinfo.tm_mday;
|
root["day"] = timeinfo.tm_mday;
|
||||||
root[F("hour")] = timeinfo.tm_hour;
|
root["hour"] = timeinfo.tm_hour;
|
||||||
root[F("minute")] = timeinfo.tm_min;
|
root["minute"] = timeinfo.tm_min;
|
||||||
root[F("second")] = timeinfo.tm_sec;
|
root["second"] = timeinfo.tm_sec;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -214,11 +214,11 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -227,8 +227,8 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -238,8 +238,8 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -251,89 +251,89 @@ void WebApiNtpClass::onNtpTimePost(AsyncWebServerRequest* request)
|
|||||||
&& root.containsKey("hour")
|
&& root.containsKey("hour")
|
||||||
&& root.containsKey("minute")
|
&& root.containsKey("minute")
|
||||||
&& root.containsKey("second"))) {
|
&& root.containsKey("second"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("year")].as<uint>() < 2022 || root[F("year")].as<uint>() > 2100) {
|
if (root["year"].as<uint>() < 2022 || root["year"].as<uint>() > 2100) {
|
||||||
retMsg[F("message")] = F("Year must be a number between 2022 and 2100!");
|
retMsg["message"] = "Year must be a number between 2022 and 2100!";
|
||||||
retMsg[F("code")] = WebApiError::NtpYearInvalid;
|
retMsg["code"] = WebApiError::NtpYearInvalid;
|
||||||
retMsg[F("param")][F("min")] = 2022;
|
retMsg["param"]["min"] = 2022;
|
||||||
retMsg[F("param")][F("max")] = 2100;
|
retMsg["param"]["max"] = 2100;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("month")].as<uint>() < 1 || root[F("month")].as<uint>() > 12) {
|
if (root["month"].as<uint>() < 1 || root["month"].as<uint>() > 12) {
|
||||||
retMsg[F("message")] = F("Month must be a number between 1 and 12!");
|
retMsg["message"] = "Month must be a number between 1 and 12!";
|
||||||
retMsg[F("code")] = WebApiError::NtpMonthInvalid;
|
retMsg["code"] = WebApiError::NtpMonthInvalid;
|
||||||
retMsg[F("param")][F("min")] = 1;
|
retMsg["param"]["min"] = 1;
|
||||||
retMsg[F("param")][F("max")] = 12;
|
retMsg["param"]["max"] = 12;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("day")].as<uint>() < 1 || root[F("day")].as<uint>() > 31) {
|
if (root["day"].as<uint>() < 1 || root["day"].as<uint>() > 31) {
|
||||||
retMsg[F("message")] = F("Day must be a number between 1 and 31!");
|
retMsg["message"] = "Day must be a number between 1 and 31!";
|
||||||
retMsg[F("code")] = WebApiError::NtpDayInvalid;
|
retMsg["code"] = WebApiError::NtpDayInvalid;
|
||||||
retMsg[F("param")][F("min")] = 1;
|
retMsg["param"]["min"] = 1;
|
||||||
retMsg[F("param")][F("max")] = 31;
|
retMsg["param"]["max"] = 31;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("hour")].as<uint>() > 23) {
|
if (root["hour"].as<uint>() > 23) {
|
||||||
retMsg[F("message")] = F("Hour must be a number between 0 and 23!");
|
retMsg["message"] = "Hour must be a number between 0 and 23!";
|
||||||
retMsg[F("code")] = WebApiError::NtpHourInvalid;
|
retMsg["code"] = WebApiError::NtpHourInvalid;
|
||||||
retMsg[F("param")][F("min")] = 0;
|
retMsg["param"]["min"] = 0;
|
||||||
retMsg[F("param")][F("max")] = 23;
|
retMsg["param"]["max"] = 23;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("minute")].as<uint>() > 59) {
|
if (root["minute"].as<uint>() > 59) {
|
||||||
retMsg[F("message")] = F("Minute must be a number between 0 and 59!");
|
retMsg["message"] = "Minute must be a number between 0 and 59!";
|
||||||
retMsg[F("code")] = WebApiError::NtpMinuteInvalid;
|
retMsg["code"] = WebApiError::NtpMinuteInvalid;
|
||||||
retMsg[F("param")][F("min")] = 0;
|
retMsg["param"]["min"] = 0;
|
||||||
retMsg[F("param")][F("max")] = 59;
|
retMsg["param"]["max"] = 59;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("second")].as<uint>() > 59) {
|
if (root["second"].as<uint>() > 59) {
|
||||||
retMsg[F("message")] = F("Second must be a number between 0 and 59!");
|
retMsg["message"] = "Second must be a number between 0 and 59!";
|
||||||
retMsg[F("code")] = WebApiError::NtpSecondInvalid;
|
retMsg["code"] = WebApiError::NtpSecondInvalid;
|
||||||
retMsg[F("param")][F("min")] = 0;
|
retMsg["param"]["min"] = 0;
|
||||||
retMsg[F("param")][F("max")] = 59;
|
retMsg["param"]["max"] = 59;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tm local;
|
tm local;
|
||||||
local.tm_sec = root[F("second")].as<uint>(); // seconds after the minute - [ 0 to 59 ]
|
local.tm_sec = root["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_min = root["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_hour = root["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_mday = root["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_mon = root["month"].as<uint>() - 1; // months since January - [ 0 to 11 ]
|
||||||
local.tm_year = root[F("year")].as<uint>() - 1900; // years since 1900
|
local.tm_year = root["year"].as<uint>() - 1900; // years since 1900
|
||||||
local.tm_isdst = -1;
|
local.tm_isdst = -1;
|
||||||
|
|
||||||
time_t t = mktime(&local);
|
time_t t = mktime(&local);
|
||||||
struct timeval now = { .tv_sec = t, .tv_usec = 0 };
|
struct timeval now = { .tv_sec = t, .tv_usec = 0 };
|
||||||
settimeofday(&now, NULL);
|
settimeofday(&now, NULL);
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Time updated!");
|
retMsg["message"] = "Time updated!";
|
||||||
retMsg[F("code")] = WebApiError::NtpTimeUpdated;
|
retMsg["code"] = WebApiError::NtpTimeUpdated;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -58,11 +58,11 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -71,8 +71,8 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -82,8 +82,8 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -91,43 +91,43 @@ void WebApiPowerClass::onPowerPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
if (!(root.containsKey("serial")
|
if (!(root.containsKey("serial")
|
||||||
&& (root.containsKey("power") || root.containsKey("restart")))) {
|
&& (root.containsKey("power") || root.containsKey("restart")))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("serial")].as<uint64_t>() == 0) {
|
if (root["serial"].as<uint64_t>() == 0) {
|
||||||
retMsg[F("message")] = F("Serial must be a number > 0!");
|
retMsg["message"] = "Serial must be a number > 0!";
|
||||||
retMsg[F("code")] = WebApiError::PowerSerialZero;
|
retMsg["code"] = WebApiError::PowerSerialZero;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
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);
|
auto inv = Hoymiles.getInverterBySerial(serial);
|
||||||
if (inv == nullptr) {
|
if (inv == nullptr) {
|
||||||
retMsg[F("message")] = F("Invalid inverter specified!");
|
retMsg["message"] = "Invalid inverter specified!";
|
||||||
retMsg[F("code")] = WebApiError::PowerInvalidInverter;
|
retMsg["code"] = WebApiError::PowerInvalidInverter;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root.containsKey("power")) {
|
if (root.containsKey("power")) {
|
||||||
uint16_t power = root[F("power")].as<bool>();
|
uint16_t power = root["power"].as<bool>();
|
||||||
inv->sendPowerControlRequest(Hoymiles.getRadio(), power);
|
inv->sendPowerControlRequest(Hoymiles.getRadio(), power);
|
||||||
} else {
|
} else {
|
||||||
if (root[F("restart")].as<bool>()) {
|
if (root["restart"].as<bool>()) {
|
||||||
inv->sendRestartControlRequest(Hoymiles.getRadio());
|
inv->sendRestartControlRequest(Hoymiles.getRadio());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -29,29 +29,29 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
|
|||||||
try {
|
try {
|
||||||
auto stream = request->beginResponseStream("text/plain; charset=utf-8", 40960);
|
auto stream = request->beginResponseStream("text/plain; charset=utf-8", 40960);
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_build Build info\n"));
|
stream->print("# HELP opendtu_build Build info\n");
|
||||||
stream->print(F("# TYPE opendtu_build gauge\n"));
|
stream->print("# TYPE opendtu_build gauge\n");
|
||||||
stream->printf("opendtu_build{name=\"%s\",id=\"%s\",version=\"%d.%d.%d\"} 1\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);
|
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("# HELP opendtu_platform Platform info\n");
|
||||||
stream->print(F("# TYPE opendtu_platform gauge\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->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("# HELP opendtu_uptime Uptime in seconds\n");
|
||||||
stream->print(F("# TYPE opendtu_uptime counter\n"));
|
stream->print("# TYPE opendtu_uptime counter\n");
|
||||||
stream->printf("opendtu_uptime %lld\n", esp_timer_get_time() / 1000000);
|
stream->printf("opendtu_uptime %lld\n", esp_timer_get_time() / 1000000);
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_heap_size System memory size\n"));
|
stream->print("# HELP opendtu_heap_size System memory size\n");
|
||||||
stream->print(F("# TYPE opendtu_heap_size gauge\n"));
|
stream->print("# TYPE opendtu_heap_size gauge\n");
|
||||||
stream->printf("opendtu_heap_size %zu\n", ESP.getHeapSize());
|
stream->printf("opendtu_heap_size %zu\n", ESP.getHeapSize());
|
||||||
|
|
||||||
stream->print(F("# HELP opendtu_free_heap_size System free memory\n"));
|
stream->print("# HELP opendtu_free_heap_size System free memory\n");
|
||||||
stream->print(F("# TYPE opendtu_free_heap_size gauge\n"));
|
stream->print("# TYPE opendtu_free_heap_size gauge\n");
|
||||||
stream->printf("opendtu_free_heap_size %zu\n", ESP.getFreeHeap());
|
stream->printf("opendtu_free_heap_size %zu\n", ESP.getFreeHeap());
|
||||||
|
|
||||||
stream->print(F("# HELP wifi_rssi WiFi RSSI\n"));
|
stream->print("# HELP wifi_rssi WiFi RSSI\n");
|
||||||
stream->print(F("# TYPE wifi_rssi gauge\n"));
|
stream->print("# TYPE wifi_rssi gauge\n");
|
||||||
stream->printf("wifi_rssi %d\n", WiFi.RSSI());
|
stream->printf("wifi_rssi %d\n", WiFi.RSSI());
|
||||||
|
|
||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
@ -60,8 +60,8 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
|
|||||||
String serial = inv->serialString();
|
String serial = inv->serialString();
|
||||||
const char* name = inv->name();
|
const char* name = inv->name();
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
stream->print(F("# HELP opendtu_last_update last update from inverter in s\n"));
|
stream->print("# HELP opendtu_last_update last update from inverter in s\n");
|
||||||
stream->print(F("# TYPE opendtu_last_update gauge\n"));
|
stream->print("# TYPE opendtu_last_update gauge\n");
|
||||||
}
|
}
|
||||||
stream->printf("opendtu_last_update{serial=\"%s\",unit=\"%d\",name=\"%s\"} %d\n",
|
stream->printf("opendtu_last_update{serial=\"%s\",unit=\"%d\",name=\"%s\"} %d\n",
|
||||||
serial.c_str(), i, name, inv->Statistics()->getLastUpdate() / 1000);
|
serial.c_str(), i, name, inv->Statistics()->getLastUpdate() / 1000);
|
||||||
@ -93,7 +93,7 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream->addHeader(F("Cache-Control"), F("no-cache"));
|
stream->addHeader("Cache-Control", "no-cache");
|
||||||
request->send(stream);
|
request->send(stream);
|
||||||
|
|
||||||
} catch (std::bad_alloc& bad_alloc) {
|
} catch (std::bad_alloc& bad_alloc) {
|
||||||
@ -132,8 +132,8 @@ void WebApiPrometheusClass::addPanelInfo(AsyncResponseStream* stream, String& se
|
|||||||
|
|
||||||
const bool printHelp = (idx == 0 && channel == 0);
|
const bool printHelp = (idx == 0 && channel == 0);
|
||||||
if (printHelp) {
|
if (printHelp) {
|
||||||
stream->print(F("# HELP opendtu_PanelInfo panel information\n"));
|
stream->print("# HELP opendtu_PanelInfo panel information\n");
|
||||||
stream->print(F("# TYPE opendtu_PanelInfo gauge\n"));
|
stream->print("# TYPE opendtu_PanelInfo gauge\n");
|
||||||
}
|
}
|
||||||
stream->printf("opendtu_PanelInfo{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\",panelname=\"%s\"} 1\n",
|
stream->printf("opendtu_PanelInfo{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\",panelname=\"%s\"} 1\n",
|
||||||
serial.c_str(),
|
serial.c_str(),
|
||||||
@ -144,8 +144,8 @@ void WebApiPrometheusClass::addPanelInfo(AsyncResponseStream* stream, String& se
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (printHelp) {
|
if (printHelp) {
|
||||||
stream->print(F("# HELP opendtu_MaxPower panel maximum output power\n"));
|
stream->print("# HELP opendtu_MaxPower panel maximum output power\n");
|
||||||
stream->print(F("# TYPE opendtu_MaxPower gauge\n"));
|
stream->print("# TYPE opendtu_MaxPower gauge\n");
|
||||||
}
|
}
|
||||||
stream->printf("opendtu_MaxPower{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %d\n",
|
stream->printf("opendtu_MaxPower{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %d\n",
|
||||||
serial.c_str(),
|
serial.c_str(),
|
||||||
@ -156,8 +156,8 @@ void WebApiPrometheusClass::addPanelInfo(AsyncResponseStream* stream, String& se
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (printHelp) {
|
if (printHelp) {
|
||||||
stream->print(F("# HELP opendtu_YieldTotalOffset panel yield offset (for used inverters)\n"));
|
stream->print("# HELP opendtu_YieldTotalOffset panel yield offset (for used inverters)\n");
|
||||||
stream->print(F("# TYPE opendtu_YieldTotalOffset gauge\n"));
|
stream->print("# TYPE opendtu_YieldTotalOffset gauge\n");
|
||||||
}
|
}
|
||||||
stream->printf("opendtu_YieldTotalOffset{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %f\n",
|
stream->printf("opendtu_YieldTotalOffset{serial=\"%s\",unit=\"%d\",name=\"%s\",channel=\"%d\"} %f\n",
|
||||||
serial.c_str(),
|
serial.c_str(),
|
||||||
|
|||||||
@ -34,8 +34,8 @@ void WebApiSecurityClass::onSecurityGet(AsyncWebServerRequest* request)
|
|||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
const CONFIG_T& config = Configuration.get();
|
const CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
root[F("password")] = config.Security_Password;
|
root["password"] = config.Security_Password;
|
||||||
root[F("allow_readonly")] = config.Security_AllowReadonly;
|
root["allow_readonly"] = config.Security_AllowReadonly;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -49,11 +49,11 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg["type"] = "warning";
|
||||||
|
|
||||||
if (!request->hasParam("data", true)) {
|
if (!request->hasParam("data", true)) {
|
||||||
retMsg[F("message")] = F("No values found!");
|
retMsg["message"] = "No values found!";
|
||||||
retMsg[F("code")] = WebApiError::GenericNoValueFound;
|
retMsg["code"] = WebApiError::GenericNoValueFound;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -62,8 +62,8 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
|
|||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > 1024) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg["message"] = "Data too large!";
|
||||||
retMsg[F("code")] = WebApiError::GenericDataTooLarge;
|
retMsg["code"] = WebApiError::GenericDataTooLarge;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -73,8 +73,8 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
|
|||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
retMsg[F("message")] = F("Failed to parse data!");
|
retMsg["message"] = "Failed to parse data!";
|
||||||
retMsg[F("code")] = WebApiError::GenericParseError;
|
retMsg["code"] = WebApiError::GenericParseError;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@ -82,30 +82,30 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
if (!root.containsKey("password")
|
if (!root.containsKey("password")
|
||||||
&& root.containsKey("allow_readonly")) {
|
&& root.containsKey("allow_readonly")) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg["message"] = "Values are missing!";
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root[F("password")].as<String>().length() < 8 || root[F("password")].as<String>().length() > WIFI_MAX_PASSWORD_STRLEN) {
|
if (root["password"].as<String>().length() < 8 || root["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["message"] = "Password must between 8 and " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!";
|
||||||
retMsg[F("code")] = WebApiError::SecurityPasswordLength;
|
retMsg["code"] = WebApiError::SecurityPasswordLength;
|
||||||
retMsg[F("param")][F("max")] = WIFI_MAX_PASSWORD_STRLEN;
|
retMsg["param"]["max"] = WIFI_MAX_PASSWORD_STRLEN;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
strlcpy(config.Security_Password, root[F("password")].as<String>().c_str(), sizeof(config.Security_Password));
|
strlcpy(config.Security_Password, root["password"].as<String>().c_str(), sizeof(config.Security_Password));
|
||||||
config.Security_AllowReadonly = root[F("allow_readonly")].as<bool>();
|
config.Security_AllowReadonly = root["allow_readonly"].as<bool>();
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Settings saved!");
|
retMsg["message"] = "Settings saved!";
|
||||||
retMsg[F("code")] = WebApiError::GenericSuccess;
|
retMsg["code"] = WebApiError::GenericSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -119,9 +119,9 @@ void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("success");
|
retMsg["type"] = "success";
|
||||||
retMsg[F("message")] = F("Authentication successful!");
|
retMsg["message"] = "Authentication successful!";
|
||||||
retMsg[F("code")] = WebApiError::SecurityAuthSuccess;
|
retMsg["code"] = WebApiError::SecurityAuthSuccess;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -37,40 +37,40 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
|
|||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
root[F("hostname")] = NetworkSettings.getHostname();
|
root["hostname"] = NetworkSettings.getHostname();
|
||||||
|
|
||||||
root[F("sdkversion")] = ESP.getSdkVersion();
|
root["sdkversion"] = ESP.getSdkVersion();
|
||||||
root[F("cpufreq")] = ESP.getCpuFreqMHz();
|
root["cpufreq"] = ESP.getCpuFreqMHz();
|
||||||
|
|
||||||
root[F("heap_total")] = ESP.getHeapSize();
|
root["heap_total"] = ESP.getHeapSize();
|
||||||
root[F("heap_used")] = ESP.getHeapSize() - ESP.getFreeHeap();
|
root["heap_used"] = ESP.getHeapSize() - ESP.getFreeHeap();
|
||||||
root[F("sketch_total")] = ESP.getFreeSketchSpace();
|
root["sketch_total"] = ESP.getFreeSketchSpace();
|
||||||
root[F("sketch_used")] = ESP.getSketchSize();
|
root["sketch_used"] = ESP.getSketchSize();
|
||||||
root[F("littlefs_total")] = LittleFS.totalBytes();
|
root["littlefs_total"] = LittleFS.totalBytes();
|
||||||
root[F("littlefs_used")] = LittleFS.usedBytes();
|
root["littlefs_used"] = LittleFS.usedBytes();
|
||||||
|
|
||||||
root[F("chiprevision")] = ESP.getChipRevision();
|
root["chiprevision"] = ESP.getChipRevision();
|
||||||
root[F("chipmodel")] = ESP.getChipModel();
|
root["chipmodel"] = ESP.getChipModel();
|
||||||
root[F("chipcores")] = ESP.getChipCores();
|
root["chipcores"] = ESP.getChipCores();
|
||||||
|
|
||||||
String reason;
|
String reason;
|
||||||
reason = ResetReason.get_reset_reason_verbose(0);
|
reason = ResetReason.get_reset_reason_verbose(0);
|
||||||
root[F("resetreason_0")] = reason;
|
root["resetreason_0"] = reason;
|
||||||
|
|
||||||
reason = ResetReason.get_reset_reason_verbose(1);
|
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];
|
char version[16];
|
||||||
snprintf(version, sizeof(version), "%d.%d.%d", CONFIG_VERSION >> 24 & 0xff, CONFIG_VERSION >> 16 & 0xff, CONFIG_VERSION >> 8 & 0xff);
|
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["config_version"] = version;
|
||||||
root[F("git_hash")] = AUTO_GIT_HASH;
|
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["radio_connected"] = Hoymiles.getRadio()->isConnected();
|
||||||
root[F("radio_pvariant")] = Hoymiles.getRadio()->isPVariant();
|
root["radio_pvariant"] = Hoymiles.getRadio()->isPVariant();
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@ -105,17 +105,17 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
|
|
||||||
JsonObject invObject = invArray.createNestedObject();
|
JsonObject invObject = invArray.createNestedObject();
|
||||||
|
|
||||||
invObject[F("serial")] = inv->serialString();
|
invObject["serial"] = inv->serialString();
|
||||||
invObject[F("name")] = inv->name();
|
invObject["name"] = inv->name();
|
||||||
invObject[F("data_age")] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
invObject["data_age"] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
||||||
invObject[F("poll_enabled")] = inv->getEnablePolling();
|
invObject["poll_enabled"] = inv->getEnablePolling();
|
||||||
invObject[F("reachable")] = inv->isReachable();
|
invObject["reachable"] = inv->isReachable();
|
||||||
invObject[F("producing")] = inv->isProducing();
|
invObject["producing"] = inv->isProducing();
|
||||||
invObject[F("limit_relative")] = inv->SystemConfigPara()->getLimitPercent();
|
invObject["limit_relative"] = inv->SystemConfigPara()->getLimitPercent();
|
||||||
if (inv->DevInfo()->getMaxPower() > 0) {
|
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 {
|
} else {
|
||||||
invObject[F("limit_absolute")] = -1;
|
invObject["limit_absolute"] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop all channels
|
// Loop all channels
|
||||||
@ -125,14 +125,14 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
if (t == TYPE_DC) {
|
if (t == TYPE_DC) {
|
||||||
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
INVERTER_CONFIG_T* inv_cfg = Configuration.getInverterConfig(inv->serial());
|
||||||
if (inv_cfg != nullptr) {
|
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_PAC);
|
||||||
addField(chanTypeObj, i, inv, t, c, FLD_UAC);
|
addField(chanTypeObj, i, inv, t, c, FLD_UAC);
|
||||||
addField(chanTypeObj, i, inv, t, c, FLD_IAC);
|
addField(chanTypeObj, i, inv, t, c, FLD_IAC);
|
||||||
if (t == TYPE_AC) {
|
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 {
|
} else {
|
||||||
addField(chanTypeObj, i, inv, t, c, FLD_PDC);
|
addField(chanTypeObj, i, inv, t, c, FLD_PDC);
|
||||||
}
|
}
|
||||||
@ -152,9 +152,9 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inv->Statistics()->hasChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG)) {
|
if (inv->Statistics()->hasChannelFieldValue(TYPE_INV, CH0, FLD_EVT_LOG)) {
|
||||||
invObject[F("events")] = inv->EventLog()->getEntryCount();
|
invObject["events"] = inv->EventLog()->getEntryCount();
|
||||||
} else {
|
} else {
|
||||||
invObject[F("events")] = -1;
|
invObject["events"] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inv->Statistics()->getLastUpdate() > _newestInverterTimestamp) {
|
if (inv->Statistics()->getLastUpdate() > _newestInverterTimestamp) {
|
||||||
@ -176,12 +176,12 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
|
|
||||||
JsonObject hintObj = root.createNestedObject("hints");
|
JsonObject hintObj = root.createNestedObject("hints");
|
||||||
struct tm timeinfo;
|
struct tm timeinfo;
|
||||||
hintObj[F("time_sync")] = !getLocalTime(&timeinfo, 5);
|
hintObj["time_sync"] = !getLocalTime(&timeinfo, 5);
|
||||||
hintObj[F("radio_problem")] = (!Hoymiles.getRadio()->isConnected() || !Hoymiles.getRadio()->isPVariant());
|
hintObj["radio_problem"] = (!Hoymiles.getRadio()->isConnected() || !Hoymiles.getRadio()->isPVariant());
|
||||||
if (!strcmp(Configuration.get().Security_Password, ACCESS_POINT_PASSWORD)) {
|
if (!strcmp(Configuration.get().Security_Password, ACCESS_POINT_PASSWORD)) {
|
||||||
hintObj[F("default_password")] = true;
|
hintObj["default_password"] = true;
|
||||||
} else {
|
} else {
|
||||||
hintObj[F("default_password")] = false;
|
hintObj["default_password"] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject vedirectObj = root.createNestedObject("vedirect");
|
JsonObject vedirectObj = root.createNestedObject("vedirect");
|
||||||
|
|||||||
58
src/main.cpp
58
src/main.cpp
@ -35,67 +35,67 @@ void setup()
|
|||||||
while (!Serial)
|
while (!Serial)
|
||||||
yield();
|
yield();
|
||||||
MessageOutput.println();
|
MessageOutput.println();
|
||||||
MessageOutput.println(F("Starting OpenDTU"));
|
MessageOutput.println("Starting OpenDTU");
|
||||||
|
|
||||||
// Initialize file system
|
// Initialize file system
|
||||||
MessageOutput.print(F("Initialize FS... "));
|
MessageOutput.print("Initialize FS... ");
|
||||||
if (!LittleFS.begin(false)) { // Do not format if mount failed
|
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)) {
|
if (!LittleFS.begin(true)) {
|
||||||
MessageOutput.print("success");
|
MessageOutput.print("success");
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.print("failed");
|
MessageOutput.print("failed");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read configuration values
|
// Read configuration values
|
||||||
MessageOutput.print(F("Reading configuration... "));
|
MessageOutput.print("Reading configuration... ");
|
||||||
if (!Configuration.read()) {
|
if (!Configuration.read()) {
|
||||||
MessageOutput.print(F("initializing... "));
|
MessageOutput.print("initializing... ");
|
||||||
Configuration.init();
|
Configuration.init();
|
||||||
if (Configuration.write()) {
|
if (Configuration.write()) {
|
||||||
MessageOutput.print(F("written... "));
|
MessageOutput.print("written... ");
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.print(F("failed... "));
|
MessageOutput.print("failed... ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Configuration.get().Cfg_Version != CONFIG_VERSION) {
|
if (Configuration.get().Cfg_Version != CONFIG_VERSION) {
|
||||||
MessageOutput.print(F("migrated... "));
|
MessageOutput.print("migrated... ");
|
||||||
Configuration.migrate();
|
Configuration.migrate();
|
||||||
}
|
}
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
// Load PinMapping
|
// Load PinMapping
|
||||||
MessageOutput.print(F("Reading PinMapping... "));
|
MessageOutput.print("Reading PinMapping... ");
|
||||||
if (PinMapping.init(String(Configuration.get().Dev_PinMapping))) {
|
if (PinMapping.init(String(Configuration.get().Dev_PinMapping))) {
|
||||||
MessageOutput.print(F("found valid mapping "));
|
MessageOutput.print("found valid mapping ");
|
||||||
} else {
|
} else {
|
||||||
MessageOutput.print(F("using default config "));
|
MessageOutput.print("using default config ");
|
||||||
}
|
}
|
||||||
const PinMapping_t& pin = PinMapping.get();
|
const PinMapping_t& pin = PinMapping.get();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
// Initialize WiFi
|
// Initialize WiFi
|
||||||
MessageOutput.print(F("Initialize Network... "));
|
MessageOutput.print("Initialize Network... ");
|
||||||
NetworkSettings.init();
|
NetworkSettings.init();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
NetworkSettings.applyConfig();
|
NetworkSettings.applyConfig();
|
||||||
|
|
||||||
// Initialize NTP
|
// Initialize NTP
|
||||||
MessageOutput.print(F("Initialize NTP... "));
|
MessageOutput.print("Initialize NTP... ");
|
||||||
NtpSettings.init();
|
NtpSettings.init();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
// Initialize SunPosition
|
// Initialize SunPosition
|
||||||
MessageOutput.print(F("Initialize SunPosition... "));
|
MessageOutput.print("Initialize SunPosition... ");
|
||||||
SunPosition.init();
|
SunPosition.init();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
// Initialize MqTT
|
// Initialize MqTT
|
||||||
MessageOutput.print(F("Initialize MqTT... "));
|
MessageOutput.print("Initialize MqTT... ");
|
||||||
MqttSettings.init();
|
MqttSettings.init();
|
||||||
MqttHandleDtu.init();
|
MqttHandleDtu.init();
|
||||||
MqttHandleInverter.init();
|
MqttHandleInverter.init();
|
||||||
@ -103,15 +103,15 @@ void setup()
|
|||||||
MqttHandleHass.init();
|
MqttHandleHass.init();
|
||||||
MqttHandleVedirectHass.init();
|
MqttHandleVedirectHass.init();
|
||||||
MqttHandleHuawei.init();
|
MqttHandleHuawei.init();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
// Initialize WebApi
|
// Initialize WebApi
|
||||||
MessageOutput.print(F("Initialize WebApi... "));
|
MessageOutput.print("Initialize WebApi... ");
|
||||||
WebApi.init();
|
WebApi.init();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
// Initialize Display
|
// Initialize Display
|
||||||
MessageOutput.print(F("Initialize Display... "));
|
MessageOutput.print("Initialize Display... ");
|
||||||
Display.init(
|
Display.init(
|
||||||
static_cast<DisplayType_t>(pin.display_type),
|
static_cast<DisplayType_t>(pin.display_type),
|
||||||
pin.display_data,
|
pin.display_data,
|
||||||
@ -123,12 +123,12 @@ void setup()
|
|||||||
Display.enableScreensaver = config.Display_ScreenSaver;
|
Display.enableScreensaver = config.Display_ScreenSaver;
|
||||||
Display.setContrast(config.Display_Contrast);
|
Display.setContrast(config.Display_Contrast);
|
||||||
Display.setStartupDisplay();
|
Display.setStartupDisplay();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
// Check for default DTU serial
|
// 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) {
|
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();
|
uint64_t dtuId = Utils::generateDtuSerial();
|
||||||
MessageOutput.printf("%0x%08x... ",
|
MessageOutput.printf("%0x%08x... ",
|
||||||
((uint32_t)((dtuId >> 32) & 0xFFFFFFFF)),
|
((uint32_t)((dtuId >> 32) & 0xFFFFFFFF)),
|
||||||
@ -136,7 +136,7 @@ void setup()
|
|||||||
config.Dtu_Serial = dtuId;
|
config.Dtu_Serial = dtuId;
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
}
|
}
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println("done");
|
||||||
|
|
||||||
InverterSettings.init();
|
InverterSettings.init();
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user