[SolaxX1] Improve web presentation (#20535)

* [SolaxX1] Improve web presentation

* [SolaxX1] delay
This commit is contained in:
SteWers 2024-01-20 11:10:40 +01:00 committed by GitHub
parent 6c3f70589a
commit 47384e7057
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 61 additions and 69 deletions

View File

@ -108,7 +108,7 @@ struct SOLAXX1_LIVEDATA {
float dc2_power = 0;
int16_t runMode = 0;
uint32_t errorCode = 0;
uint8_t SerialNumber[16] = {0x6e, 0x2f, 0x61}; // "n/a"
uint8_t SerialNumber[16] = {0x00};
} solaxX1;
struct SOLAXX1_GLOBALDATA {
@ -127,15 +127,14 @@ struct SOLAXX1_SENDDATA {
uint8_t ControlCode[1] = {0x00};
uint8_t FunctionCode[1] = {0x00};
uint8_t DataLength[1] = {0x00};
uint8_t Payload[16] = {0};
uint8_t Payload[16] = {0x00};
} solaxX1_SendData;
TasmotaSerial *solaxX1Serial;
/*********************************************************************************************/
void solaxX1_RS485Send(void)
{
void solaxX1_RS485Send(void) {
uint8_t message[30];
memcpy(message, solaxX1_SendData.Header, 2);
memcpy(message + 2, solaxX1_SendData.Source, 2);
@ -162,8 +161,7 @@ void solaxX1_RS485Send(void)
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, message, 9 + solaxX1_SendData.DataLength[0]);
}
bool solaxX1_RS485Receive(uint8_t *ReadBuffer)
{
bool solaxX1_RS485Receive(uint8_t *ReadBuffer) {
uint8_t len = 0;
while (solaxX1Serial->available() > 0) {
ReadBuffer[len++] = (uint8_t)solaxX1Serial->read();
@ -173,8 +171,7 @@ bool solaxX1_RS485Receive(uint8_t *ReadBuffer)
return !(ReadBuffer[len - 1] == lowByte(crc) && ReadBuffer[len - 2] == highByte(crc));
}
uint16_t solaxX1_calculateCRC(uint8_t *bExternTxPackage, uint8_t bLen)
{
uint16_t solaxX1_calculateCRC(uint8_t *bExternTxPackage, uint8_t bLen) {
uint8_t i;
uint16_t wChkSum = 0;
for (i = 0; i < bLen; i++) {
@ -183,8 +180,7 @@ uint16_t solaxX1_calculateCRC(uint8_t *bExternTxPackage, uint8_t bLen)
return wChkSum;
}
void solaxX1_ExtractText(uint8_t *DataIn, uint8_t *DataOut, uint8_t Begin, uint8_t End)
{
void solaxX1_ExtractText(uint8_t *DataIn, uint8_t *DataOut, uint8_t Begin, uint8_t End) {
uint8_t i;
for (i = Begin; i <= End; i++) {
DataOut[i - Begin] = DataIn[i];
@ -192,8 +188,7 @@ void solaxX1_ExtractText(uint8_t *DataIn, uint8_t *DataOut, uint8_t Begin, uint8
DataOut[End - Begin + 1] = 0;
}
void solaxX1_QueryOfflineInverters(void)
{
void solaxX1_QueryOfflineInverters(void) {
solaxX1_SendData.Source[0] = 0x01;
solaxX1_SendData.Destination[0] = 0x00;
solaxX1_SendData.Destination[1] = 0x00;
@ -203,8 +198,7 @@ void solaxX1_QueryOfflineInverters(void)
solaxX1_RS485Send();
}
void solaxX1_SendInverterAddress(void)
{
void solaxX1_SendInverterAddress(void) {
solaxX1_SendData.Source[0] = 0x00;
solaxX1_SendData.Destination[0] = 0x00;
solaxX1_SendData.Destination[1] = 0x00;
@ -215,8 +209,7 @@ void solaxX1_SendInverterAddress(void)
solaxX1_RS485Send();
}
void solaxX1_QueryLiveData(void)
{
void solaxX1_QueryLiveData(void) {
solaxX1_SendData.Source[0] = 0x01;
solaxX1_SendData.Destination[0] = 0x00;
solaxX1_SendData.Destination[1] = INVERTER_ADDRESS;
@ -226,8 +219,7 @@ void solaxX1_QueryLiveData(void)
solaxX1_RS485Send();
}
void solaxX1_QueryIDData(void)
{
void solaxX1_QueryIDData(void) {
solaxX1_SendData.Source[0] = 0x01;
solaxX1_SendData.Destination[0] = 0x00;
solaxX1_SendData.Destination[1] = INVERTER_ADDRESS;
@ -237,8 +229,7 @@ void solaxX1_QueryIDData(void)
solaxX1_RS485Send();
}
void solaxX1_QueryConfigData(void)
{
void solaxX1_QueryConfigData(void) {
solaxX1_SendData.Source[0] = 0x01;
solaxX1_SendData.Destination[0] = 0x00;
solaxX1_SendData.Destination[1] = INVERTER_ADDRESS;
@ -248,7 +239,7 @@ void solaxX1_QueryConfigData(void)
solaxX1_RS485Send();
}
uint8_t solaxX1_ParseErrorCode(uint32_t code){
uint8_t solaxX1_ParseErrorCode(uint32_t code) {
solaxX1_ErrCode.ErrMessage = code;
if (code == 0) return 0;
if (solaxX1_ErrCode.MainsLostFault) return 1;
@ -264,8 +255,7 @@ uint8_t solaxX1_ParseErrorCode(uint32_t code){
/*********************************************************************************************/
void solaxX1_250MSecond(void) // Every 250 milliseconds
{
void solaxX1_250MSecond(void) { // Every 250 milliseconds
uint8_t DataRead[80] = {0};
uint8_t TempData[16] = {0};
char TempDataChar[32];
@ -299,7 +289,8 @@ void solaxX1_250MSecond(void) // Every 250 milliseconds
Energy->apparent_power[0] = Energy->active_power[0]; // U*I from inverter is not valid for apparent power; U*I could be lower than active power
//temporal = (float)((DataRead[29] << 8) | DataRead[30]) * 0.1f; // Not Used
Energy->import_active[0] = ((DataRead[31] << 24) | (DataRead[32] << 16) | (DataRead[33] << 8) | DataRead[34]) * 0.1f; // Energy Total
solaxX1.runtime_total = (DataRead[35] << 24) | (DataRead[36] << 16) | (DataRead[37] << 8) | DataRead[38]; // Work Time Total
uint32_t runtime_total = (DataRead[35] << 24) | (DataRead[36] << 16) | (DataRead[37] << 8) | DataRead[38]; // Work Time Total
if (runtime_total) solaxX1.runtime_total = runtime_total; // Work Time valid
solaxX1.runMode = (DataRead[39] << 8) | DataRead[40]; // Work mode
//temporal = (float)((DataRead[41] << 8) | DataRead[42]); // Grid voltage fault value 0.1V
//temporal = (float)((DataRead[43] << 8) | DataRead[44]); // Gird frequency fault value 0.01Hz
@ -460,12 +451,10 @@ void solaxX1_250MSecond(void) // Every 250 milliseconds
}
}
solaxX1_global.SendRetry_count--;
return;
} // end solaxX1_250MSecond
void solaxX1_SnsInit(void)
{
void solaxX1_SnsInit(void) {
AddLog(LOG_LEVEL_INFO, PSTR("SX1: Init - RX-pin: %d, TX-pin: %d, RTS-pin: %d"), Pin(GPIO_SOLAXX1_RX), Pin(GPIO_SOLAXX1_TX), Pin(GPIO_SOLAXX1_RTS));
solaxX1Serial = new TasmotaSerial(Pin(GPIO_SOLAXX1_RX), Pin(GPIO_SOLAXX1_TX), 1);
if (solaxX1Serial->begin(SOLAXX1_SPEED)) {
@ -481,15 +470,13 @@ void solaxX1_SnsInit(void)
}
}
void solaxX1_DrvInit(void)
{
void solaxX1_DrvInit(void) {
if (PinUsed(GPIO_SOLAXX1_RX) && PinUsed(GPIO_SOLAXX1_TX)) {
TasmotaGlobal.energy_driver = XNRG_12;
}
}
bool SolaxX1_cmd(void)
{
bool SolaxX1_cmd(void) {
if (!solaxX1_global.AddressAssigned) {
AddLog(LOG_LEVEL_INFO, PSTR("SX1: No inverter registered"));
return false;
@ -514,12 +501,11 @@ bool SolaxX1_cmd(void)
}
#ifdef USE_WEBSERVER
const char HTTP_SNS_solaxX1_Num[] PROGMEM = "{s}" D_SOLAX_X1 " %s{m}</td><td style='text-align:%s'>%s</td><td>&nbsp;</td><td> %s{e}";
const char HTTP_SNS_solaxX1_Str[] PROGMEM = "{s}" D_SOLAX_X1 " %s{m}</td><td colspan='3' style='text-align:%s'>%s{e}";
const char HTTP_SNS_solaxX1_Num[] PROGMEM = "{s}" D_SOLAX_X1 " %s{m}</td><td style='text-align:%s'>%s{m}{m} %s{e}";
const char HTTP_SNS_solaxX1_Str[] PROGMEM = "{s}" D_SOLAX_X1 " %s{m}%s{e}";
#endif // USE_WEBSERVER
void solaxX1_Show(bool json)
{
void solaxX1_Show(uint32_t function) {
char solar_power[33];
dtostrfd(solaxX1.dc1_power + solaxX1.dc2_power, Settings->flag2.wattage_resolution, solar_power);
char pv1_voltage[33];
@ -539,41 +525,49 @@ void solaxX1_Show(bool json)
char status[33];
GetTextIndexed(status, sizeof(status), solaxX1.runMode + 1, kSolaxMode);
if (json) {
ResponseAppend_P(PSTR(",\"" D_JSON_SOLAR_POWER "\":%s,\"" D_JSON_PV1_VOLTAGE "\":%s,\"" D_JSON_PV1_CURRENT "\":%s,\"" D_JSON_PV1_POWER "\":%s"),
solar_power, pv1_voltage, pv1_current, pv1_power);
switch (function) {
case FUNC_JSON_APPEND:
ResponseAppend_P(PSTR(",\"" D_JSON_SOLAR_POWER "\":%s,\"" D_JSON_PV1_VOLTAGE "\":%s,\"" D_JSON_PV1_CURRENT "\":%s,\"" D_JSON_PV1_POWER "\":%s"),
solar_power, pv1_voltage, pv1_current, pv1_power);
#ifdef SOLAXX1_PV2
ResponseAppend_P(PSTR(",\"" D_JSON_PV2_VOLTAGE "\":%s,\"" D_JSON_PV2_CURRENT "\":%s,\"" D_JSON_PV2_POWER "\":%s"),
pv2_voltage, pv2_current, pv2_power);
ResponseAppend_P(PSTR(",\"" D_JSON_PV2_VOLTAGE "\":%s,\"" D_JSON_PV2_CURRENT "\":%s,\"" D_JSON_PV2_POWER "\":%s"),
pv2_voltage, pv2_current, pv2_power);
#endif
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%d,\"" D_JSON_RUNTIME "\":%d,\"" D_JSON_STATUS "\":\"%s\",\"" D_JSON_ERROR "\":%d"),
solaxX1.temperature, solaxX1.runtime_total, status, solaxX1.errorCode);
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%d,\"" D_JSON_RUNTIME "\":%d,\"" D_JSON_STATUS "\":\"%s\",\"" D_JSON_ERROR "\":%d"),
solaxX1.temperature, solaxX1.runtime_total, status, solaxX1.errorCode);
#ifdef USE_DOMOTICZ
// Avoid bad temperature report at beginning of the day (spikes of 1200 celsius degrees)
if (0 == TasmotaGlobal.tele_period && solaxX1.temperature < 100) { DomoticzSensor(DZ_TEMP, solaxX1.temperature); }
// Avoid bad temperature report at beginning of the day (spikes of 1200 celsius degrees)
if (0 == TasmotaGlobal.tele_period && solaxX1.temperature < 100) { DomoticzSensor(DZ_TEMP, solaxX1.temperature); }
#endif // USE_DOMOTICZ
break;
#ifdef USE_WEBSERVER
} else {
String table_align = Settings->flag5.gui_table_align?"right":"left";
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_SOLAR_POWER, table_align.c_str(), solar_power, D_UNIT_WATT);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV1_VOLTAGE, table_align.c_str(), pv1_voltage, D_UNIT_VOLT);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV1_CURRENT, table_align.c_str(), pv1_current, D_UNIT_AMPERE);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV1_POWER, table_align.c_str(), pv1_power, D_UNIT_WATT);
case FUNC_WEB_COL_SENSOR: {
String table_align = Settings->flag5.gui_table_align?"right":"left";
static uint32_t LastOnlineTime;
if (solaxX1.runMode != -1) LastOnlineTime = TasmotaGlobal.uptime;
if (TasmotaGlobal.uptime < LastOnlineTime + 300) { // Hide numeric live data, when inverter is offline for more than 5 min
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_SOLAR_POWER, table_align.c_str(), solar_power, D_UNIT_WATT);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV1_VOLTAGE, table_align.c_str(), pv1_voltage, D_UNIT_VOLT);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV1_CURRENT, table_align.c_str(), pv1_current, D_UNIT_AMPERE);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV1_POWER, table_align.c_str(), pv1_power, D_UNIT_WATT);
#ifdef SOLAXX1_PV2
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV2_VOLTAGE, table_align.c_str(), pv2_voltage, D_UNIT_VOLT);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV2_CURRENT, table_align.c_str(), pv2_current, D_UNIT_AMPERE);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV2_POWER, table_align.c_str(), pv2_power, D_UNIT_WATT);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV2_VOLTAGE, table_align.c_str(), pv2_voltage, D_UNIT_VOLT);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV2_CURRENT, table_align.c_str(), pv2_current, D_UNIT_AMPERE);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_PV2_POWER, table_align.c_str(), pv2_power, D_UNIT_WATT);
#endif
char SXTemperature[16];
dtostrfd(solaxX1.temperature, Settings->flag2.temperature_resolution, SXTemperature);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_TEMPERATURE, table_align.c_str(), SXTemperature, D_UNIT_DEGREE D_UNIT_CELSIUS);
WSContentSend_P(HTTP_SNS_solaxX1_Num, D_UPTIME, table_align.c_str(), String(solaxX1.runtime_total).c_str(), D_UNIT_HOUR);
WSContentSend_P(HTTP_SNS_solaxX1_Str, D_STATUS, table_align.c_str(), status);
char errorCodeString[33];
WSContentSend_P(HTTP_SNS_solaxX1_Str, D_ERROR, table_align.c_str(), GetTextIndexed(errorCodeString, sizeof(errorCodeString), solaxX1_ParseErrorCode(solaxX1.errorCode), kSolaxError));
WSContentSend_P(HTTP_SNS_solaxX1_Str, "Inverter SN", table_align.c_str(), solaxX1.SerialNumber);
char SXTemperature[16];
dtostrfd(solaxX1.temperature, Settings->flag2.temperature_resolution, SXTemperature);
WSContentSend_PD(HTTP_SNS_solaxX1_Num, D_TEMPERATURE, table_align.c_str(), SXTemperature, D_UNIT_DEGREE D_UNIT_CELSIUS);
}
WSContentSend_P(HTTP_SNS_solaxX1_Num, D_UPTIME, table_align.c_str(), String(solaxX1.runtime_total).c_str(), D_UNIT_HOUR);
break; }
case FUNC_WEB_SENSOR:
char errorCodeString[33];
WSContentSend_P(HTTP_SNS_solaxX1_Str, D_STATUS, status);
WSContentSend_P(HTTP_SNS_solaxX1_Str, D_ERROR, GetTextIndexed(errorCodeString, sizeof(errorCodeString), solaxX1_ParseErrorCode(solaxX1.errorCode), kSolaxError));
if (solaxX1.SerialNumber[0]) WSContentSend_P(HTTP_SNS_solaxX1_Str, "Inverter SN", solaxX1.SerialNumber);
break;
#endif // USE_WEBSERVER
}
}
@ -582,22 +576,20 @@ void solaxX1_Show(bool json)
* Interface
\*********************************************************************************************/
bool Xnrg12(uint32_t function)
{
bool Xnrg12(uint32_t function) {
bool result = false;
switch (function) {
case FUNC_EVERY_250_MSECOND:
solaxX1_250MSecond();
break;
case FUNC_JSON_APPEND:
solaxX1_Show(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_COL_SENSOR:
solaxX1_Show(0);
break;
case FUNC_WEB_SENSOR:
#endif // USE_WEBSERVER
case FUNC_JSON_APPEND:
solaxX1_Show(function);
break;
case FUNC_INIT:
solaxX1_SnsInit();
break;