diff --git a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino
index f74b59b5a..356c8d65d 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino
@@ -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}
%s | | %s{e}";
-const char HTTP_SNS_solaxX1_Str[] PROGMEM = "{s}" D_SOLAX_X1 " %s{m} | %s{e}";
+const char HTTP_SNS_solaxX1_Num[] PROGMEM = "{s}" D_SOLAX_X1 " %s{m} | %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;
|