diff --git a/CHANGELOG.md b/CHANGELOG.md index 6be73cfb3..615136a82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,19 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.4.0.2] +## [12.4.0.3] +### Added + +### Breaking Changed + +### Changed + +### Fixed +- Refactor energy monitoring reducing stack usage and solve inherent exceptions and watchdogs (#18164) + +### Removed + +## [12.4.0.2] 20230317 ### Added - Support for multiple MCP23008 as switch/button/relay - Support for multiple PCF8574 as switch/button/relay @@ -32,8 +44,6 @@ All notable changes to this project will be documented in this file. - Rule topic comparison (#18144) - ESP32 energy period shows kWh value instead of Wh regression from v12.3.1.5 (#15856) -### Removed - ## [12.4.0.1] 20230301 ### Added - Matter read/write and commands (#18000) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 657adff89..05d0815d8 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,7 +110,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.4.0.2 +## Changelog v12.4.0.3 ### Added - Support for multiple MCP23008/MCP23017/MCP23S17 as switch/button/relay - Support for multiple PCF8574 as switch/button/relay @@ -143,4 +143,5 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - TuyaMcu v1 timer integer overflow [#18048](https://github.com/arendst/Tasmota/issues/18048) - PZEM energy monitor stabilize period on larger configs [#18103](https://github.com/arendst/Tasmota/issues/18103) - Rule topic comparison [#18144](https://github.com/arendst/Tasmota/issues/18144) +- Refactor energy monitoring reducing stack usage and solve inherent exceptions and watchdogs [#18164](https://github.com/arendst/Tasmota/issues/18164) - ESP32 energy period shows kWh value instead of Wh regression from v12.3.1.5 [#15856](https://github.com/arendst/Tasmota/issues/15856) diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index 78b17d960..7f0130695 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -200,11 +200,6 @@ const uint16_t MAX_INPUT_BUFFER_SIZE = 2048; // Max number of characters in Ardu const uint16_t FLOATSZ = 16; // Max number of characters in float result from dtostrfd (max 32) const uint16_t CMDSZ = 24; // Max number of characters in command const uint16_t TOPSZ = 151; // Max number of characters in topic string -#ifdef ESP8266 -const uint16_t GUISZ = 300; // Max number of characters in WebEnergyFormat string -#else -const uint16_t GUISZ = 600; // Max number of characters in WebEnergyFormat string -#endif #ifdef ESP8266 #ifdef PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 6b644b6fa..678b2a337 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C040002; // 12.4.0.2 +const uint32_t VERSION = 0x0C040003; // 12.4.0.3 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index cd0afaca8..252de3f48 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -101,6 +101,8 @@ typedef struct { int32_t kWhtoday[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily int32_t period[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + char* value; + uint8_t fifth_second; uint8_t command_code; uint8_t data_valid[ENERGY_MAX_PHASES]; @@ -143,14 +145,32 @@ Ticker ticker_energy; /********************************************************************************************/ -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +const uint16_t GUISZ = 300; // Max number of characters in WebEnergyFmt string + +bool EnergyFmtMalloc(void) { + if (Energy->value == nullptr) { + Energy->value = (char*)malloc(GUISZ); + if (!Energy->value) { return false; } + } + return true; +} + +void EnergyFmtFree(void) { + free(Energy->value); + Energy->value = nullptr; +} + +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx or [xx,xx] or [xx,xx,xx] // single = 1 - Energy->voltage_common or Energy->frequency_common - xx // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or if SO129 1 - [xx,xx,xx] // single = 5 - single &0x03 = 1 - xx // single = 6 - single &0x03 = 2 - [xx,xx] - used by tarriff // single = 7 - single &0x03 = 3 - [xx,xx,xx] + + if (!EnergyFmtMalloc()) { return EmptyStr; } + uint32_t index = (single > 3) ? single &0x03 : (0 == single) ? Energy->phase_count : 1; // 1,2,3 if (single > 2) { single = 0; } // 0,1,2 float input_sum = 0.0f; @@ -166,19 +186,22 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin index = Energy->phase_count; } } - result[0] = '\0'; + Energy->value[0] = '\0'; for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, TOPSZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%s%*_f%s"), Energy->value, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); } - return result; + return Energy->value; } #ifdef USE_WEBSERVER -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx / xx / xx or multi column // single = 1 - Energy->voltage_common or Energy->frequency_common - xx or single column using colspan (if needed) // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or single column using colspan (if needed) or if SO129 1 - xx / xx / xx or multi column + + if (!EnergyFmtMalloc()) { return EmptyStr; } + float input_sum = 0.0f; if (single > 1) { // Sum and/or Single column if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information @@ -193,32 +216,32 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t } } #ifdef USE_ENERGY_COLUMN_GUI - ext_snprintf_P(result, GUISZ, PSTR("")); // Skip first column + ext_snprintf_P(Energy->value, GUISZ, PSTR("")); // Skip first column if ((Energy->phase_count > 1) && single) { // Need to set colspan so need new columns // 1.23  // 1.23  // 1.23  - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f "), - result, (Energy->phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%*_f "), + Energy->value, (Energy->phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); } else { // 1.23  // 1.23 1.23  // 1.23 1.23 1.23  // 1.23 1.23 1.23 1.23  for (uint32_t i = 0; i < Energy->phase_count; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f "), - result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%*_f "), + Energy->value, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); } } - ext_snprintf_P(result, GUISZ, PSTR("%s"), result); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), Energy->value); #else // not USE_ENERGY_COLUMN_GUI uint32_t index = (single) ? 1 : Energy->phase_count; // 1,2,3 - result[0] = '\0'; + Energy->value[vidx][0] = '\0'; for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f"), result, (i)?" / ":"", resolution, &input[i]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%s%*_f"), Energy->value, (i)?" / ":"", resolution, &input[i]); } #endif // USE_ENERGY_COLUMN_GUI - return result; + return Energy->value; } #endif // USE_WEBSERVER @@ -495,8 +518,7 @@ void EnergyMarginCheck(void) { for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { power_diff_f[phase] = power_diff[phase]; } - char value_chr[TOPSZ]; - ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); + ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFmt(power_diff_f, 0)); } uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]); @@ -603,6 +625,7 @@ void EnergyMarginCheck(void) { } } #endif // USE_ENERGY_POWER_LIMIT + EnergyFmtFree(); } void EnergyMqttShow(void) { @@ -668,10 +691,6 @@ void EnergyEverySecond(void) { \*********************************************************************************************/ void ResponseCmndEnergyTotalYesterdayToday(void) { - char value_chr[TOPSZ]; // Used by EnergyFormatIndex - char value2_chr[TOPSZ]; - char value3_chr[TOPSZ]; - float energy_yesterday_ph[3]; for (uint32_t i = 0; i < Energy->phase_count; i++) { energy_yesterday_ph[i] = (float)Settings->energy_kWhyesterday_ph[i] / 100000; @@ -681,16 +700,19 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { } } - Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), + Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s"), XdrvMailbox.command, - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, energy_yesterday_ph, Settings->flag2.energy_resolution), - EnergyFormat(value3_chr, Energy->daily, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->total, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_ph, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily, Settings->flag2.energy_resolution)); if (Energy->local_energy_active_export) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution)); } ResponseJsonEndEnd(); + EnergyFmtFree(); } void CmndEnergyTotal(void) { @@ -1110,6 +1132,7 @@ void EnergyDrvInit(void) { Energy = (tEnergy*)calloc(sizeof(tEnergy), 1); // Need calloc to reset registers to 0/false if (!Energy) { return; } + EnergyFmtFree(); // Energy->voltage_common = false; // Energy->frequency_common = false; // Energy->use_overtemp = false; @@ -1165,17 +1188,19 @@ void EnergySnsInit(void) } #ifdef USE_WEBSERVER -const char HTTP_ENERGY_SNS1[] PROGMEM = - "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}" - "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}" +const char HTTP_ENERGY_POWERUSAGE_APPARENT[] PROGMEM = + "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}"; +const char HTTP_ENERGY_POWERUSAGE_REACTIVE[] PROGMEM = + "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}"; +const char HTTP_ENERGY_POWER_FACTOR[] PROGMEM = "{s}" D_POWER_FACTOR "{m}%s{e}"; - -const char HTTP_ENERGY_SNS2[] PROGMEM = - "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" +const char HTTP_ENERGY_TODAY[] PROGMEM = + "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_ENERGY_YESTERDAY[] PROGMEM = + "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_ENERGY_TOTAL[] PROGMEM = "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; // {s} = , {m} = , {e} = - -const char HTTP_ENERGY_SNS3[] PROGMEM = +const char HTTP_ENERGY_EXPORT_ACTIVE[] PROGMEM = "{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; #endif // USE_WEBSERVER @@ -1256,34 +1281,31 @@ void EnergyShow(bool json) { energy_tariff = true; } - char value_chr[GUISZ]; // Used by EnergyFormatIndex - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - if (json) { bool show_energy_period = (0 == TasmotaGlobal.tele_period); ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s"), GetDateAndTime(DT_ENERGY).c_str(), - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + EnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_usage, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_usage, Settings->flag2.energy_resolution, 6)); } - ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), - EnergyFormat(value_chr, energy_yesterday_ph, Settings->flag2.energy_resolution, 2), - EnergyFormat(value2_chr, Energy->daily, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_ph, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily, Settings->flag2.energy_resolution, 2)); /* #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP) if (!isnan(Energy->import_active[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->import_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->import_active, Settings->flag2.energy_resolution)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return, Settings->flag2.energy_resolution, 6)); } } #endif // SDM630_IMPORT || SDM72_IMPEXP @@ -1291,13 +1313,16 @@ void EnergyShow(bool json) { if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 0 : 1; - ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s,\"" D_JSON_TODAY_SUM_EXPORT "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, &Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value2_chr, &Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value3_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_EXPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); + if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return, Settings->flag2.energy_resolution, 6)); } } @@ -1308,30 +1333,32 @@ void EnergyShow(bool json) { Energy->period[i] = RtcSettings.energy_kWhtoday_ph[i]; } ResponseAppend_P(PSTR(",\"" D_JSON_PERIOD "\":%s"), - EnergyFormat(value_chr, energy_period, Settings->flag2.wattage_resolution)); + EnergyFmt(energy_period, Settings->flag2.wattage_resolution)); } ResponseAppend_P(PSTR(",\"" D_JSON_POWERUSAGE "\":%s"), - EnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + EnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), - EnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - EnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - EnergyFormat(value3_chr, power_factor, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s"), + EnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_REACTIVE_POWERUSAGE "\":%s"), + EnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_POWERFACTOR "\":%s"), + EnergyFmt(power_factor, 2)); } if (!isnan(Energy->frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + EnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + EnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (Energy->current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), - EnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + EnergyFmt(Energy->current, Settings->flag2.current_resolution)); } XnrgCall(FUNC_JSON_APPEND); ResponseJsonEnd(); @@ -1388,37 +1415,38 @@ void EnergyShow(bool json) { WSContentSend_P(PSTR("
{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, value_chr, 10)); + WSContentSend_P(PSTR(""), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, number, 10)); } WSContentSend_P(PSTR(") #endif // USE_ENERGY_COLUMN_GUI if (Energy->voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (!Energy->type_dc) { if (!isnan(Energy->frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + WebEnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFmt(Energy->current, Settings->flag2.current_resolution)); } - WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value3_chr, power_factor, 2)); + WSContentSend_PD(HTTP_ENERGY_POWERUSAGE_APPARENT, WebEnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_ENERGY_POWERUSAGE_REACTIVE, WebEnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_ENERGY_POWER_FACTOR, WebEnergyFmt(power_factor, 2)); } } - WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value2_chr, energy_yesterday_ph, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_TODAY, WebEnergyFmt(Energy->daily, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_YESTERDAY, WebEnergyFmt(energy_yesterday_ph, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_TOTAL, WebEnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; - WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + WSContentSend_PD(HTTP_ENERGY_EXPORT_ACTIVE, WebEnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); } #ifdef USE_ENERGY_COLUMN_GUI XnrgCall(FUNC_WEB_COL_SENSOR); @@ -1427,6 +1455,7 @@ void EnergyShow(bool json) { XnrgCall(FUNC_WEB_SENSOR); #endif // USE_WEBSERVER } + EnergyFmtFree(); } /*********************************************************************************************\ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 122c1a62b..2edf08b33 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -159,6 +159,8 @@ typedef struct { int32_t kWhtoday[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily // Local only + char* value; + float daily_kWh[ENERGY_MAX_PHASES]; // 123.123 kWh float energy_today_offset_kWh[ENERGY_MAX_PHASES]; // 123.12312 kWh = Energy->daily float period_kWh[ENERGY_MAX_PHASES]; // 123.12312 kWh = Energy->daily @@ -370,14 +372,32 @@ void EnergySettingsSave(void) { /********************************************************************************************/ -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +const uint16_t GUISZ = 600; // Max number of characters in WebEnergyFmt string + +bool EnergyFmtMalloc(void) { + if (Energy->value == nullptr) { + Energy->value = (char*)malloc(GUISZ); + if (!Energy->value) { return false; } + } + return true; +} + +void EnergyFmtFree(void) { + free(Energy->value); + Energy->value = nullptr; +} + +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx or [xx,xx] or [xx,xx,xx] // single = 1 - Energy->voltage_common or Energy->frequency_common - xx // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or if SO129 1 - [xx,xx,xx] // single = 5 - single &0x03 = 1 - xx // single = 6 - single &0x03 = 2 - [xx,xx] - used by tarriff // single = 7 - single &0x03 = 3 - [xx,xx,xx] + + if (!EnergyFmtMalloc()) { return EmptyStr; } + uint32_t index = (single > 3) ? single &0x03 : (0 == single) ? Energy->phase_count : 1; // 1,2,3 if (single > 2) { single = 0; } // 0,1,2 float input_sum = 0.0f; @@ -393,19 +413,22 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin index = Energy->phase_count; } } - result[0] = '\0'; + Energy->value[0] = '\0'; for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%s%*_f%s"), Energy->value, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); } - return result; + return Energy->value; } #ifdef USE_WEBSERVER -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx / xx / xx or multi column // single = 1 - Energy->voltage_common or Energy->frequency_common - xx or single column using colspan (if needed) // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or single column using colspan (if needed) or if SO129 1 - xx / xx / xx or multi column + + if (!EnergyFmtMalloc()) { return EmptyStr; } + float input_sum = 0.0f; if (single > 1) { // Sum and/or Single column if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information @@ -420,32 +443,32 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t } } #ifdef USE_ENERGY_COLUMN_GUI - ext_snprintf_P(result, GUISZ, PSTR("")); // Skip first column + ext_snprintf_P(Energy->value, GUISZ, PSTR("")); // Skip first column if ((Energy->gui_count > 1) && single) { // Need to set colspan so need new columns // "), - result, (Energy->gui_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[Energy->gui_indirect[0]]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), + Energy->value, (Energy->gui_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[Energy->gui_indirect[0]]); } else { // "), - result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[Energy->gui_indirect[Energy->gui_offset +i]]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), + Energy->value, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[Energy->gui_indirect[Energy->gui_offset +i]]); } } - ext_snprintf_P(result, GUISZ, PSTR("%s - -const char HTTP_ENERGY_SNS3[] PROGMEM = +const char HTTP_ENERGY_EXPORT_ACTIVE[] PROGMEM = "{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; #endif // USE_WEBSERVER @@ -1490,34 +1515,31 @@ void EnergyShow(bool json) { energy_tariff = true; } - char value_chr[GUISZ]; // Used by EnergyFormatIndex - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - if (json) { bool show_energy_period = (0 == TasmotaGlobal.tele_period); ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s"), GetDateAndTime(DT_ENERGY).c_str(), - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + EnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_usage_kWh, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_usage_kWh, Settings->flag2.energy_resolution, 6)); } - ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), - EnergyFormat(value_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), - EnergyFormat(value2_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_kWh, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily_kWh, Settings->flag2.energy_resolution, 2)); /* #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP) if (!isnan(Energy->import_active[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->import_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->import_active, Settings->flag2.energy_resolution)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return_kWh, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return_kWh, Settings->flag2.energy_resolution, 6)); } } #endif // SDM630_IMPORT || SDM72_IMPEXP @@ -1525,13 +1547,15 @@ void EnergyShow(bool json) { if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 0 : 1; - ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s,\"" D_JSON_TODAY_SUM_EXPORT "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, &Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value2_chr, &Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value3_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_EXPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return_kWh, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return_kWh, Settings->flag2.energy_resolution, 6)); } } @@ -1542,30 +1566,32 @@ void EnergyShow(bool json) { Energy->period_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; } ResponseAppend_P(PSTR(",\"" D_JSON_PERIOD "\":%s"), - EnergyFormat(value_chr, energy_period, Settings->flag2.wattage_resolution)); + EnergyFmt(energy_period, Settings->flag2.wattage_resolution)); } ResponseAppend_P(PSTR(",\"" D_JSON_POWERUSAGE "\":%s"), - EnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + EnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), - EnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - EnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - EnergyFormat(value3_chr, power_factor, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s"), + EnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_REACTIVE_POWERUSAGE "\":%s"), + EnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_POWERFACTOR "\":%s"), + EnergyFmt(power_factor, 2)); } if (!isnan(Energy->frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + EnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + EnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (Energy->current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), - EnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + EnergyFmt(Energy->current, Settings->flag2.current_resolution)); } XnrgCall(FUNC_JSON_APPEND); ResponseJsonEnd(); @@ -1667,39 +1693,40 @@ void EnergyShow(bool json) { // {s}")); // First column is empty ({t} =
) bool label_o = voltage_common; bool no_label = (1 == Energy->phase_count); + char number[4]; for (uint32_t i = 0; i < Energy->phase_count; i++) { - WSContentSend_P(PSTR("%s%s%s%s{e}")); // Last column is units ({e} =
1.23  // 1.23  // 1.23  - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f %*_f 1.23  // 1.23 1.23  // 1.23 1.23 1.23  // 1.23 1.23 1.23 1.23  for (uint32_t i = 0; i < Energy->gui_count; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f %*_f "), result); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), Energy->value); #else // not USE_ENERGY_COLUMN_GUI uint32_t index = (single) ? 1 : Energy->phase_count; // 1,2,3 - result[0] = '\0'; + Energy->value[0] = '\0'; for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f"), result, (i)?" / ":"", resolution, &input[i]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%s%*_f"), Energy->value, (i)?" / ":"", resolution, &input[i]); } #endif // USE_ENERGY_COLUMN_GUI - return result; + return Energy->value; } #endif // USE_WEBSERVER @@ -717,8 +740,7 @@ void EnergyMarginCheck(void) { for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { power_diff_f[phase] = power_diff[phase]; } - char value_chr[GUISZ]; - ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); + ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFmt(power_diff_f, 0)); } uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]); @@ -823,6 +845,7 @@ void EnergyMarginCheck(void) { SetAllPower(POWER_ALL_OFF, SRC_MAXENERGY); } } + EnergyFmtFree(); } void EnergyMqttShow(void) { @@ -885,10 +908,6 @@ void EnergyEverySecond(void) { \*********************************************************************************************/ void ResponseCmndEnergyTotalYesterdayToday(void) { - char value_chr[GUISZ]; // Used by EnergyFormatIndex - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - float energy_yesterday_kWh[3]; for (uint32_t i = 0; i < Energy->phase_count; i++) { energy_yesterday_kWh[i] = Energy->Settings.energy_yesterday_kWh[i]; @@ -898,16 +917,19 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { } } - Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), + Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s"), XdrvMailbox.command, - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution), - EnergyFormat(value3_chr, Energy->daily_kWh, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->total, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_kWh, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily_kWh, Settings->flag2.energy_resolution)); if (Energy->local_energy_active_export) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution)); } ResponseJsonEndEnd(); + EnergyFmtFree(); } void CmndEnergyDisplay(void) { @@ -1345,6 +1367,7 @@ void EnergyDrvInit(void) { EnergySettingsLoad(0); EnergyRtcSettingsLoad(); + EnergyFmtFree(); // Energy->voltage_common = false; // Energy->frequency_common = false; // Energy->use_overtemp = false; @@ -1399,17 +1422,19 @@ void EnergySnsInit(void) { } #ifdef USE_WEBSERVER -const char HTTP_ENERGY_SNS1[] PROGMEM = - "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}" - "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}" +const char HTTP_ENERGY_POWERUSAGE_APPARENT[] PROGMEM = + "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}"; +const char HTTP_ENERGY_POWERUSAGE_REACTIVE[] PROGMEM = + "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}"; +const char HTTP_ENERGY_POWER_FACTOR[] PROGMEM = "{s}" D_POWER_FACTOR "{m}%s{e}"; - -const char HTTP_ENERGY_SNS2[] PROGMEM = - "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" +const char HTTP_ENERGY_TODAY[] PROGMEM = + "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_ENERGY_YESTERDAY[] PROGMEM = + "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_ENERGY_TOTAL[] PROGMEM = "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; // {s} =
, {m} = , {e} =
Head1Head2Head3Head4{e} WSContentSend_P(PSTR("{t}{s}
, {s} = "), (no_label) ? "" : (label_o) ? "O" : "L", - (no_label) ? "" : itoa(relays[Energy->gui_offset +i], value_chr, 10)); + (no_label) ? "" : itoa(relays[Energy->gui_offset +i], number, 10)); } WSContentSend_P(PSTR(") #endif // USE_ENERGY_COLUMN_GUI if (Energy->voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (!Energy->type_dc) { if (!isnan(Energy->frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + WebEnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFmt(Energy->current, Settings->flag2.current_resolution)); } - WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value3_chr, power_factor, 2)); + WSContentSend_PD(HTTP_ENERGY_POWERUSAGE_APPARENT, WebEnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_ENERGY_POWERUSAGE_REACTIVE, WebEnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_ENERGY_POWER_FACTOR, WebEnergyFmt(power_factor, 2)); } } - WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_TODAY, WebEnergyFmt(Energy->daily_kWh, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_YESTERDAY, WebEnergyFmt(energy_yesterday_kWh, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_TOTAL, WebEnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; - WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + WSContentSend_PD(HTTP_ENERGY_EXPORT_ACTIVE, WebEnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); } #ifdef USE_ENERGY_COLUMN_GUI @@ -1710,6 +1737,7 @@ void EnergyShow(bool json) { #endif // USE_WEBSERVER } } + EnergyFmtFree(); } #ifdef USE_WEBSERVER diff --git a/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino b/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino index 5a02108eb..fd4e99cf7 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino @@ -60,6 +60,7 @@ #define D_CMND_I2CSTRETCH "I2CStretch" #define D_CMND_I2CCLOCK "I2CClock" #define D_CMND_SERBUFF "SerBufSize" +#define D_CMND_SOSET "SOSet" const char kDebugCommands[] PROGMEM = "|" // No prefix D_CMND_MEMDUMP "|" D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" @@ -77,8 +78,9 @@ const char kDebugCommands[] PROGMEM = "|" // No prefix #endif D_CMND_FLASHDUMP "|" D_CMND_FLASHMODE "|" D_CMND_FREEMEM"|" D_CMND_HELP "|" D_CMND_RTCDUMP "|" #ifdef USE_I2C - D_CMND_I2CWRITE "|" D_CMND_I2CREAD "|" D_CMND_I2CSTRETCH "|" D_CMND_I2CCLOCK + D_CMND_I2CWRITE "|" D_CMND_I2CREAD "|" D_CMND_I2CSTRETCH "|" D_CMND_I2CCLOCK "|" #endif + D_CMND_SOSET ; void (* const DebugCommand[])(void) PROGMEM = { @@ -97,8 +99,9 @@ void (* const DebugCommand[])(void) PROGMEM = { #endif &CmndFlashDump, &CmndFlashMode, &CmndFreemem, &CmndHelp, &CmndRtcDump, #ifdef USE_I2C - &CmndI2cWrite, &CmndI2cRead, &CmndI2cStretch, &CmndI2cClock + &CmndI2cWrite, &CmndI2cRead, &CmndI2cStretch, &CmndI2cClock, #endif + &CmndSoSet }; uint32_t CPU_loops = 0; @@ -209,23 +212,41 @@ extern "C" { extern cont_t* g_pcont; } -void DebugFreeMem(void) -{ +void DebugFreeMem(void) { register uint32_t *sp asm("a1"); AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_pcont->stack), XdrvMailbox.data); } +uint32_t FreeStack(void) { + register uint32_t *sp asm("a1"); + return 4 * (sp - g_pcont->stack); +} + +void AddLogMem(const char* function) { + register uint32_t *sp asm("a1"); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "== %s FreeRam %d, FreeStack %d"), function, ESP.getFreeHeap(), 4 * (sp - g_pcont->stack)); +} + #endif // ESP8266 #ifdef ESP32 -void DebugFreeMem(void) -{ +void DebugFreeMem(void) { register uint8_t *sp asm("a1"); AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), sp - pxTaskGetStackStart(NULL), XdrvMailbox.data); } +uint32_t FreeStack(void) { + register uint8_t *sp asm("a1"); + return sp - pxTaskGetStackStart(NULL); +} + +void AddLogMem(const char* function) { + register uint8_t *sp asm("a1"); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "== %s FreeRam %d, FreeStack %d"), function, ESP.getFreeHeap(), sp - pxTaskGetStackStart(NULL)); +} + #endif // ESP8266 - ESP32 /*******************************************************************************************/ @@ -724,6 +745,52 @@ void CmndI2cClock(void) } #endif // USE_I2C +void CmndSoSet(void) { + // Set option data as 32-bit hex value + // SoSet1 0x5400401B + if ((XdrvMailbox.index >= 1) && (XdrvMailbox.index <= 5)) { + uint32_t option = XdrvMailbox.index; + uint32_t data; + switch (option) { + case 1: + data = Settings->flag.data; // SetOption0 .. 31 + break; + case 2: + data = Settings->flag3.data; // SetOption50 .. 81 + break; + case 3: + data = Settings->flag4.data; // SetOption82 .. 113 + break; + case 4: + data = Settings->flag5.data; // SetOption114 .. 145 + break; + case 5: + data = Settings->flag6.data; // SetOption146 .. 177 + } + if (XdrvMailbox.data_len > 0) { + char *p; + data = strtoul(XdrvMailbox.data, &p, 0); // decimal, octal (0) or hex (0x) + switch (option) { + case 1: + Settings->flag.data = data; // SetOption0 .. 31 + break; + case 2: + Settings->flag3.data = data; // SetOption50 .. 81 + break; + case 3: + Settings->flag4.data = data; // SetOption82 .. 113 + break; + case 4: + Settings->flag5.data = data; // SetOption114 .. 145 + break; + case 5: Settings->flag6.data = data; // SetOption146 .. 177 + } +// TasmotaGlobal.restart_flag = 2; // Activate some SetOptions + } + Response_P(PSTR("{\"%s%d\":\"%08X\"}"), XdrvMailbox.command, XdrvMailbox.index, data); + } +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino b/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino index 66dc60856..b13ad4fbd 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino @@ -2300,14 +2300,12 @@ void SSPMEnergyShow(bool json) { WSContentSend_PD(HTTP_SNS_VOLTAGE, SSPMEnergyFormat(value_chr, Sspm->voltage[0], Settings->flag2.voltage_resolution, indirect, offset, count)); WSContentSend_PD(HTTP_SNS_CURRENT, SSPMEnergyFormat(value_chr, Sspm->current[0], Settings->flag2.current_resolution, indirect, offset, count)); WSContentSend_PD(HTTP_SNS_POWER, SSPMEnergyFormat(value_chr, Sspm->active_power[0], Settings->flag2.wattage_resolution, indirect, offset, count)); - char valu2_chr[SSPM_SIZE]; - char valu3_chr[SSPM_SIZE]; - WSContentSend_PD(HTTP_ENERGY_SNS1, SSPMEnergyFormat(value_chr, Sspm->apparent_power[0], Settings->flag2.wattage_resolution, indirect, offset, count), - SSPMEnergyFormat(valu2_chr, Sspm->reactive_power[0], Settings->flag2.wattage_resolution, indirect, offset, count), - SSPMEnergyFormat(valu3_chr, Sspm->power_factor[0], 2, indirect, offset, count)); - WSContentSend_PD(HTTP_ENERGY_SNS2, SSPMEnergyFormat(value_chr, Sspm->energy_today[0], Settings->flag2.energy_resolution, indirect, offset, count), - SSPMEnergyFormat(valu2_chr, Sspm->Settings.energy_yesterday[0], Settings->flag2.energy_resolution, indirect, offset, count), - SSPMEnergyFormat(valu3_chr, Sspm->energy_total[0], Settings->flag2.energy_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_ENERGY_POWERUSAGE_APPARENT, SSPMEnergyFormat(value_chr, Sspm->apparent_power[0], Settings->flag2.wattage_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_ENERGY_POWERUSAGE_REACTIVE, SSPMEnergyFormat(value_chr, Sspm->reactive_power[0], Settings->flag2.wattage_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_ENERGY_POWER_FACTOR, SSPMEnergyFormat(value_chr, Sspm->power_factor[0], 2, indirect, offset, count)); + WSContentSend_PD(HTTP_ENERGY_TODAY, SSPMEnergyFormat(value_chr, Sspm->energy_today[0], Settings->flag2.energy_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_ENERGY_YESTERDAY, SSPMEnergyFormat(value_chr, Sspm->Settings.energy_yesterday[0], Settings->flag2.energy_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_ENERGY_TOTAL, SSPMEnergyFormat(value_chr, Sspm->energy_total[0], Settings->flag2.energy_resolution, indirect, offset, count)); WSContentSend_P(PSTR("
) bool no_label = (1 == Energy->phase_count); + char number[4]; for (uint32_t i = 0; i < Energy->gui_count; i++) { WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR } #endif // USE_WEBSERVER diff --git a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino index e3c5b9b76..99b5b0804 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino @@ -204,55 +204,32 @@ void Sdm220Reset(void) } #ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM220[] PROGMEM = - "{s}" D_IMPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - "{s}" D_EXPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" +const char HTTP_ENERGY_SDM220_IMPORT_REACTIVE[] PROGMEM = + "{s}" D_IMPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}"; +const char HTTP_ENERGY_SDM220_EXPORT_REACTIVE[] PROGMEM = + "{s}" D_EXPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}"; +const char HTTP_ENERGY_SDM220_PHASE_ANGLE[] PROGMEM = "{s}" D_PHASE_ANGLE "{m}%s " D_UNIT_ANGLE "{e}"; #endif // USE_WEBSERVER -/* void Sdm220Show(bool json) { if (isnan(Sdm120.import_active)) { return; } - char import_active_chr[FLOATSZ]; - dtostrfd(Sdm120.import_active, Settings->flag2.energy_resolution, import_active_chr); - char import_reactive_chr[FLOATSZ]; - dtostrfd(Sdm120.import_reactive, Settings->flag2.energy_resolution, import_reactive_chr); - char export_reactive_chr[FLOATSZ]; - dtostrfd(Sdm120.export_reactive, Settings->flag2.energy_resolution, export_reactive_chr); - char phase_angle_chr[FLOATSZ]; - dtostrfd(Sdm120.phase_angle, 2, phase_angle_chr); - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s,\"" D_JSON_IMPORT_REACTIVE "\":%s,\"" D_JSON_EXPORT_REACTIVE "\":%s,\"" D_JSON_PHASE_ANGLE "\":%s"), - import_active_chr, import_reactive_chr, export_reactive_chr, phase_angle_chr); + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), + EnergyFmt(&Sdm120.import_active, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_REACTIVE "\":%s"), + EnergyFmt(&Sdm120.import_reactive, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_REACTIVE "\":%s"), + EnergyFmt(&Sdm120.export_reactive, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s"), + EnergyFmt(&Sdm120.phase_angle, 2)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_SDM220, import_reactive_chr, export_reactive_chr, phase_angle_chr); -#endif // USE_WEBSERVER - } -} -*/ + WSContentSend_PD(HTTP_ENERGY_SDM220_IMPORT_REACTIVE, WebEnergyFmt(&Sdm120.import_reactive, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_SDM220_EXPORT_REACTIVE, WebEnergyFmt(&Sdm120.export_reactive, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_ENERGY_SDM220_PHASE_ANGLE, WebEnergyFmt(&Sdm120.phase_angle, 2)); -void Sdm220Show(bool json) { - if (isnan(Sdm120.import_active)) { return; } - - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - char value4_chr[GUISZ]; - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s,\"" D_JSON_IMPORT_REACTIVE "\":%s,\"" D_JSON_EXPORT_REACTIVE "\":%s,\"" D_JSON_PHASE_ANGLE "\":%s"), - EnergyFormat(value_chr, &Sdm120.import_active, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, &Sdm120.import_reactive, Settings->flag2.energy_resolution), - EnergyFormat(value3_chr, &Sdm120.export_reactive, Settings->flag2.energy_resolution), - EnergyFormat(value4_chr, &Sdm120.phase_angle, 2)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_SDM220, WebEnergyFormat(value_chr, &Sdm120.import_reactive, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value2_chr, &Sdm120.export_reactive, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, &Sdm120.phase_angle, 2)); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino index 5be6cc2b2..d68bd6a9b 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino @@ -237,43 +237,22 @@ void FifLEReset(void) } #ifdef USE_WEBSERVER -const char HTTP_ENERGY_LE01MR[] PROGMEM = - "{s}" D_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_TOTAL_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - ; +const char HTTP_ENERGY_LE01MR_TOTAL_ACTIVE[] PROGMEM = + "{s}" D_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_ENERGY_LE01MR_TOTAL_REACTIVE[] PROGMEM = + "{s}" D_TOTAL_REACTIVE "{m}%s " D_UNIT_KWARH "{e}"; #endif // USE_WEBSERVER -/* void FifLEShow(bool json) { - char total_reactive_chr[FLOATSZ]; - dtostrfd(Le01mr.total_reactive, Settings->flag2.energy_resolution, total_reactive_chr); - char total_active_chr[FLOATSZ]; - dtostrfd(Le01mr.total_active, Settings->flag2.energy_resolution, total_active_chr); - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_ACTIVE "\":%s,\"" D_JSON_TOTAL_REACTIVE "\":%s"), - total_active_chr, total_reactive_chr); + ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_ACTIVE "\":%s"), + EnergyFmt(&Le01mr.total_active, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_REACTIVE "\":%s"), + EnergyFmt(&Le01mr.total_reactive, Settings->flag2.energy_resolution)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_LE01MR, total_active_chr, total_reactive_chr); -#endif // USE_WEBSERVER - } -} -*/ - -void FifLEShow(bool json) { - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_ACTIVE "\":%s,\"" D_JSON_TOTAL_REACTIVE "\":%s"), - EnergyFormat(value_chr, &Le01mr.total_active, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, &Le01mr.total_reactive, Settings->flag2.energy_resolution)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_LE01MR, WebEnergyFormat(value_chr, &Le01mr.total_active, Settings->flag2.energy_resolution), - WebEnergyFormat(value2_chr, &Le01mr.total_reactive, Settings->flag2.energy_resolution)); - + WSContentSend_PD(HTTP_ENERGY_LE01MR_TOTAL_ACTIVE, WebEnergyFmt(&Le01mr.total_active, Settings->flag2.energy_resolution)); + WSContentSend_PD(HTTP_ENERGY_LE01MR_TOTAL_REACTIVE, WebEnergyFmt(&Le01mr.total_reactive, Settings->flag2.energy_resolution)); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino index b058b09c0..69095ad81 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino @@ -177,26 +177,24 @@ void Sdm72Show(bool json) { */ #ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM72[] PROGMEM = - "{s}" D_EXPORT_POWER "{m}%s" D_UNIT_WATT "{e}" +const char HTTP_ENERGY_SDM72_EXPORT_POWER[] PROGMEM = + "{s}" D_EXPORT_POWER "{m}%s" D_UNIT_WATT "{e}"; +const char HTTP_ENERGY_SDM72_IMPORT_POWER[] PROGMEM = "{s}" D_IMPORT_POWER "{m}%s" D_UNIT_WATT "{e}"; #endif // USE_WEBSERVER void Sdm72Show(bool json) { if (isnan(Sdm72.total_active)) { return; } - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_POWER "\":%s,\"" D_JSON_IMPORT_POWER "\":%s"), - EnergyFormat(value_chr, &Sdm72.export_power, Settings->flag2.wattage_resolution), - EnergyFormat(value2_chr, &Sdm72.import_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_POWER "\":%s"), + EnergyFmt(&Sdm72.export_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_POWER "\":%s"), + EnergyFmt(&Sdm72.import_power, Settings->flag2.wattage_resolution)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_SDM72, WebEnergyFormat(value_chr, &Sdm72.export_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value2_chr, &Sdm72.import_power, Settings->flag2.wattage_resolution)); - + WSContentSend_PD(HTTP_ENERGY_SDM72_EXPORT_POWER, WebEnergyFmt(&Sdm72.export_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_ENERGY_SDM72_IMPORT_POWER, WebEnergyFmt(&Sdm72.import_power, Settings->flag2.wattage_resolution)); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino index f851b8110..c8c166d46 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino @@ -217,47 +217,27 @@ void Sdm230Reset(void) #ifdef SDM230_MORE_REGS #ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM230[] PROGMEM = - "{s}" D_PHASE_ANGLE "{m}%s " D_UNIT_ANGLE "{e}" - "{s}" D_MAX_POWER "{m}%s " D_UNIT_WATT "{e}" +const char HTTP_ENERGY_SDM230_PHASE_ANGLE[] PROGMEM = + "{s}" D_PHASE_ANGLE "{m}%s " D_UNIT_ANGLE "{e}"; +const char HTTP_ENERGY_SDM230_MAX_POWER[] PROGMEM = + "{s}" D_MAX_POWER "{m}%s " D_UNIT_WATT "{e}"; +const char HTTP_ENERGY_SDM230_RESETTABLE_TOTAL_ACTIVE[] PROGMEM = "{s}" D_RESETTABLE_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; #endif // USE_WEBSERVER -/* void Sdm230Show(bool json) { - char phase_angle_chr[FLOATSZ]; - dtostrfd(Sdm230.phase_angle, 2, phase_angle_chr); - char maximum_demand_chr[FLOATSZ]; - dtostrfd(Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution, maximum_demand_chr); - char resettable_energy_chr[FLOATSZ]; - dtostrfd(Sdm230.resettable_total_energy, Settings->flag2.energy_resolution, resettable_energy_chr); - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s,\"" D_JSON_POWERMAX "\":%s,\"" D_JSON_RESETTABLE_TOTAL_ACTIVE "\":%s"), - phase_angle_chr, maximum_demand_chr, resettable_energy_chr); + ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s"), + EnergyFmt(&Sdm230.phase_angle, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_POWERMAX "\":%s"), + EnergyFmt(&Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_RESETTABLE_TOTAL_ACTIVE "\":%s"), + EnergyFmt(&Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_SDM230, phase_angle_chr, maximum_demand_chr, resettable_energy_chr); -#endif // USE_WEBSERVER - } -} -*/ - -void Sdm230Show(bool json) { - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s,\"" D_JSON_POWERMAX "\":%s,\"" D_JSON_RESETTABLE_TOTAL_ACTIVE "\":%s"), - EnergyFormat(value_chr, &Sdm230.phase_angle, 2), - EnergyFormat(value2_chr, &Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution), - EnergyFormat(value3_chr, &Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_SDM230, WebEnergyFormat(value_chr, &Sdm230.phase_angle, 2), - WebEnergyFormat(value2_chr, &Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution), - WebEnergyFormat(value3_chr, &Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); + WSContentSend_PD(HTTP_ENERGY_SDM230_PHASE_ANGLE, WebEnergyFmt(&Sdm230.phase_angle, 2)); + WSContentSend_PD(HTTP_ENERGY_SDM230_MAX_POWER, WebEnergyFmt(&Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_ENERGY_SDM230_RESETTABLE_TOTAL_ACTIVE, WebEnergyFmt(&Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino index 0a6cdac0a..0c1f688fb 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino @@ -746,14 +746,13 @@ const char HTTP_ADE7880_CURRENT[] PROGMEM = "{s}" D_CURRENT_NEUTRAL "{m}%s " D_U #endif // USE_WEBSERVER void Ade7880Show(bool json) { - char value_chr[GUISZ]; if (json) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT_NEUTRAL "\":%s"), - EnergyFormat(value_chr, &Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); + EnergyFmt(&Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ADE7880_CURRENT, WebEnergyFormat(value_chr, &Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); + WSContentSend_PD(HTTP_ADE7880_CURRENT, WebEnergyFmt(&Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 8dde49a5a..29b4eaf10 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -799,7 +799,6 @@ uint32_t EnergyModbusResolution(uint32_t resolution) { } void EnergyModbusShow(bool json) { - char value_chr[GUISZ]; float values[ENERGY_MAX_PHASES]; for (uint32_t i = 0; i < NrgMbsParam.user_adds; i++) { uint32_t reg_index = NRG_MBS_MAX_REGS + i; @@ -829,15 +828,14 @@ void EnergyModbusShow(bool json) { #ifdef ENERGY_MODBUS_DEBUG_SHOW AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: resolution %d -> %d"), NrgMbsUser[i].resolution, resolution); #endif - if (json) { - ResponseAppend_P(PSTR(",\"%s\":%s"), NrgMbsUser[i].json_name, EnergyFormat(value_chr, values, resolution, single)); + ResponseAppend_P(PSTR(",\"%s\":%s"), NrgMbsUser[i].json_name, EnergyFmt(values, resolution, single)); #ifdef USE_WEBSERVER } else { if (strlen(NrgMbsUser[i].gui_name)) { // Skip empty GUI names WSContentSend_PD(PSTR("{s}%s{m}%s %s{e}"), NrgMbsUser[i].gui_name, - WebEnergyFormat(value_chr, values, resolution, single), + WebEnergyFmt(values, resolution, single), NrgMbsUser[i].gui_unit); } #endif // USE_WEBSERVER