diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f0c7ce11..14f5895fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,10 @@ All notable changes to this project will be documented in this file. ## [12.3.1.5] ### Added -- ESP32 Prep support for eigth energy phases/channels +- ESP32 support for eigth energy phases/channels +- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns +- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation +- support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) ### Breaking Changed - Berry energy_ctypes changed with new energy driver diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e11f17dcb..d9421ff0b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -117,11 +117,15 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Support for IPv6 only networks on Ethernet (not yet Wifi) - Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594) - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557) +- support for SEN5X gas and air quality sensor by Tyeth Gundry [#17736](https://github.com/arendst/Tasmota/issues/17736) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) - Berry crypto add ``random`` to generate series of random bytes - Berry crypto add ``HKDF_HMAC_SHA256`` - Berry crypto add ``SPAKE2P_Matter`` for Matter support +- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns +- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation +- ESP32 support for eigth energy phases/channels - ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643) ### Breaking Changed diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index 8cb8a5da1..c3df48348 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -454,6 +454,8 @@ #define D_CMND_VOLTAGEHIGH "VoltageHigh" #define D_CMND_CURRENTLOW "CurrentLow" #define D_CMND_CURRENTHIGH "CurrentHigh" +#define D_CMND_ENERGYDISPLAY "EnergyDisplay" +#define D_CMND_ENERGYCOLS "EnergyCols" #define D_CMND_ENERGYTODAY "EnergyToday" #define D_CMND_ENERGYYESTERDAY "EnergyYesterday" #define D_CMND_ENERGYTOTAL "EnergyTotal" diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index e3d1e271c..cf218d91c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -38,6 +38,9 @@ #undef ENERGY_MAX_PHASES #define ENERGY_MAX_PHASES 8 // Support max eight phases/channels +#define ENERGY_GUI_MAX_COLS 4 // [EnergyCols] Number of GUI data columns - Preffered 4 +#define ENERGY_GUI_DISPLAY_MODE 3 // [EnergyDisplay] 1 = Rotate if over EnergyCols, 2 = Rotate only powered on if over EnergyCols, 3 = Use tabs if over EnergyCols + #include #define D_CMND_POWERCAL "PowerCal" @@ -47,6 +50,11 @@ #define D_CMND_TARIFF "Tariff" #define D_CMND_MODULEADDRESS "ModuleAddress" +enum EnergyDisplayModes { + ENERGY_DISPLAY_MIN_OPTION, + ENERGY_DISPLAY_ROTATE, ENERGY_DISPLAY_ROTATE_POWERED_ON, ENERGY_DISPLAY_TABS, + ENERGY_DISPLAY_MAX_OPTION }; + enum EnergyCalibration { ENERGY_POWER_CALIBRATION, ENERGY_VOLTAGE_CALIBRATION, ENERGY_CURRENT_CALIBRATION, ENERGY_FREQUENCY_CALIBRATION }; @@ -61,7 +69,8 @@ const char kEnergyCommands[] PROGMEM = "|" // No prefix D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|" D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW "|" - D_CMND_ENERGYTODAY "|" D_CMND_ENERGYYESTERDAY "|" D_CMND_ENERGYTOTAL "|" D_CMND_ENERGYEXPORTACTIVE "|" D_CMND_ENERGYUSAGE "|" D_CMND_ENERGYEXPORT "|" D_CMND_TARIFF; + D_CMND_ENERGYTODAY "|" D_CMND_ENERGYYESTERDAY "|" D_CMND_ENERGYTOTAL "|" D_CMND_ENERGYEXPORTACTIVE "|" D_CMND_ENERGYUSAGE "|" D_CMND_ENERGYEXPORT "|" + D_CMND_TARIFF "|" D_CMND_ENERGYDISPLAY "|" D_CMND_ENERGYCOLS ; void (* const EnergyCommand[])(void) PROGMEM = { &CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal, &CmndFrequencyCal, @@ -70,7 +79,8 @@ void (* const EnergyCommand[])(void) PROGMEM = { &CmndMaxEnergy, &CmndMaxEnergyStart, &CmndMaxPower, &CmndMaxPowerHold, &CmndMaxPowerWindow, &CmndSafePower, &CmndSafePowerHold, &CmndSafePowerWindow, - &CmndEnergyToday, &CmndEnergyYesterday, &CmndEnergyTotal, &CmndEnergyExportActive, &CmndEnergyUsage, &CmndEnergyExport, &CmndTariff}; + &CmndEnergyToday, &CmndEnergyYesterday, &CmndEnergyTotal, &CmndEnergyExportActive, &CmndEnergyUsage, &CmndEnergyExport, + &CmndTariff, &CmndEnergyDisplay, &CmndEnergyCols }; /********************************************************************************************/ @@ -81,16 +91,40 @@ typedef struct { float last_usage_total_kWh; } tEnergyUsage; +typedef union { + uint16_t data; + struct { + uint16_t spare00 : 1; // bit 0 + uint16_t spare01 : 1; // bit 1 + uint16_t spare02 : 1; // bit 2 + uint16_t spare03 : 1; // bit 3 + uint16_t spare04 : 1; // bit 4 + uint16_t spare05 : 1; // bit 5 + uint16_t spare06 : 1; // bit 6 + uint16_t spare07 : 1; // bit 7 + uint16_t spare08 : 1; // bit 8 + uint16_t spare09 : 1; // bit 9 + uint16_t spare10 : 1; // bit 10 + uint16_t spare11 : 1; // bit 11 + uint16_t spare12 : 1; // bit 12 + uint16_t spare13 : 1; // bit 13 + uint16_t spare14 : 1; // bit 14 + uint16_t spare15 : 1; // bit 15 + }; +} tEnergyBitfield; + typedef struct { - uint32_t crc32; // To detect file changes - uint16_t version; // To detect driver function changes + uint32_t crc32; // To detect file changes + uint16_t version; // To detect driver function changes uint16_t energy_kWhdoy; uint32_t energy_kWhtotal_time; - uint32_t spare1; - uint32_t spare2; - uint32_t spare3; - uint32_t spare4; - uint32_t spare5; + tEnergyBitfield flag; + uint8_t gui_display; // EnergyDisplay - GUI display all relays (0), only powered on relays (1) or user selected relays (2) + uint8_t gui_cols; // EnergyCols + uint32_t spare32_1; + uint32_t spare32_2; + uint32_t spare32_3; + uint32_t spare32_4; uint32_t power_calibration[ENERGY_MAX_PHASES]; uint32_t voltage_calibration[ENERGY_MAX_PHASES]; @@ -137,36 +171,39 @@ typedef struct { float daily_sum_import_balanced; // 123.123 kWh float daily_sum_export_balanced; // 123.123 kWh + uint16_t power_history[ENERGY_MAX_PHASES][3]; + uint16_t mplh_counter; + uint16_t mplw_counter; + + uint8_t data_valid[ENERGY_MAX_PHASES]; + uint8_t phase_count; // Number of phases active uint8_t fifth_second; uint8_t command_code; - uint8_t data_valid[ENERGY_MAX_PHASES]; + uint8_t power_steady_counter; // Allow for power on stabilization + uint8_t mplr_counter; + uint8_t max_energy_state; + + uint8_t gui_indirect[ENERGY_MAX_PHASES]; + uint8_t gui_rotate; + uint8_t gui_count; + uint8_t gui_offset; - uint8_t phase_count; // Number of phases active bool voltage_common; // Use common voltage bool frequency_common; // Use common frequency bool use_overtemp; // Use global temperature as overtemp trigger on internal energy monitor hardware bool kWhtoday_offset_init; - bool voltage_available; // Enable if voltage is measured bool current_available; // Enable if current is measured bool local_energy_active_export; // Enable if support for storing energy_active - bool type_dc; bool power_on; - uint16_t power_history[ENERGY_MAX_PHASES][3]; - uint8_t power_steady_counter; // Allow for power on stabilization bool min_power_flag; bool max_power_flag; bool min_voltage_flag; bool max_voltage_flag; bool min_current_flag; bool max_current_flag; - - uint16_t mplh_counter; - uint16_t mplw_counter; - uint8_t mplr_counter; - uint8_t max_energy_state; } tEnergy; tEnergy *Energy = nullptr; @@ -240,7 +277,7 @@ bool EnergyRtcSettingsValid(void) { * Driver Settings load and save using filesystem \*********************************************************************************************/ -const uint32_t XDRV_03_VERSION = 0x0101; // Latest driver version (See settings deltas below) +const uint32_t XDRV_03_VERSION = 0x0102; // Latest driver version (See settings deltas below) void EnergySettingsLoad(void) { // *** Start init default values in case file is not found *** @@ -270,6 +307,11 @@ void EnergySettingsLoad(void) { Energy->Settings.power_delta[i] = (float)(Settings->energy_power_delta[i]); } + + // v0102 additions + Energy->Settings.gui_display = ENERGY_GUI_DISPLAY_MODE; + Energy->Settings.gui_cols = ENERGY_GUI_MAX_COLS; + // *** End Init default values *** #ifndef USE_UFILESYS @@ -283,6 +325,10 @@ void EnergySettingsLoad(void) { if (Energy->Settings.version != XDRV_03_VERSION) { // Fix version dependent changes // *** Start fix possible setting deltas *** + if (Energy->Settings.version < 0x0102) { + Energy->Settings.gui_display = ENERGY_GUI_DISPLAY_MODE; + Energy->Settings.gui_cols = ENERGY_GUI_MAX_COLS; + } // *** End setting deltas *** @@ -346,7 +392,7 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin } result[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(result, GUISZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); } return result; } @@ -372,20 +418,20 @@ 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 - if ((Energy->phase_count > 1) && single) { // Need to set colspan so need new columns + if ((Energy->gui_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]); + result, (Energy->gui_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[Energy->gui_indirect[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++) { + for (uint32_t i = 0; i < Energy->gui_count; i++) { ext_snprintf_P(result, GUISZ, PSTR("%s%*_f "), - result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); + result, (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"), result); @@ -665,7 +711,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]; + char value_chr[GUISZ]; ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); } @@ -833,9 +879,9 @@ void EnergyEverySecond(void) { \*********************************************************************************************/ void ResponseCmndEnergyTotalYesterdayToday(void) { - char value_chr[TOPSZ]; // Used by EnergyFormatIndex - char value2_chr[TOPSZ]; - char value3_chr[TOPSZ]; + 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++) { @@ -858,6 +904,26 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { ResponseJsonEndEnd(); } +void CmndEnergyDisplay(void) { + // Select either all relays, only powered on relays or user selected relay group + // EnergyDisplay 1, EnergyDisplay 2 or EnergyDisplay 3 + if ((XdrvMailbox.payload > ENERGY_DISPLAY_MIN_OPTION) && (XdrvMailbox.payload < ENERGY_DISPLAY_MAX_OPTION)) { + Energy->Settings.gui_display = XdrvMailbox.payload; + Energy->gui_rotate = 0; + } + ResponseCmndNumber(Energy->Settings.gui_display); +} + +void CmndEnergyCols(void) { + // Select number of columns + // EnergyCols 1..8 + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= ENERGY_MAX_PHASES)) { + Energy->Settings.gui_cols = XdrvMailbox.payload; + Energy->gui_rotate = 0; + } + ResponseCmndNumber(Energy->Settings.gui_cols); +} + void CmndEnergyTotal(void) { uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); @@ -1536,55 +1602,114 @@ void EnergyShow(bool json) { #ifdef USE_WEBSERVER } else { #ifdef USE_ENERGY_COLUMN_GUI - // Need a new table supporting more columns using empty columns (with   in data rows) as easy column spacing - // {s}Head1{e} - // {s}Head1Head2{e} - // {s}Head1Head2Head3{e} - // {s}Head1Head2Head3Head4{e} - 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)); + uint8_t relays[ENERGY_MAX_PHASES]; + uint32_t relay_show = 0; + power_t power = TasmotaGlobal.power; + for (uint32_t i = 0; i < Energy->phase_count; i++) { // Init relays and gui_indirect tables based on EnergyDisplay + if ((ENERGY_DISPLAY_ROTATE == Energy->Settings.gui_display) || + ((ENERGY_DISPLAY_ROTATE_POWERED_ON == Energy->Settings.gui_display) && (power >> i) &1) || + (ENERGY_DISPLAY_TABS == Energy->Settings.gui_display)) { + relays[relay_show] = i +1; + Energy->gui_indirect[relay_show] = i; + relay_show++; + } } - WSContentSend_P(PSTR(") + + if (relay_show) { + if (Energy->Settings.gui_display != ENERGY_DISPLAY_TABS) { + if (relay_show > Energy->Settings.gui_cols) { + Energy->gui_rotate++; + } else { + Energy->gui_rotate = 0; + } + } + if (Energy->gui_rotate >= relay_show) { + Energy->gui_rotate = 0; + } + Energy->gui_offset = (Energy->gui_rotate / Energy->Settings.gui_cols) * Energy->Settings.gui_cols; + Energy->gui_count = relay_show - Energy->gui_offset; + if (Energy->gui_count > Energy->Settings.gui_cols) { Energy->gui_count = Energy->Settings.gui_cols; } + + WSContentSend_P(PSTR("
) - bool label_o = Energy->voltage_common; - bool no_label = (1 == Energy->phase_count); - for (uint32_t i = 0; i < Energy->phase_count; i++) { - WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =

")); // Close current table as we will use different column count + bool label_o = Energy->voltage_common; + if (ENERGY_DISPLAY_TABS == Energy->Settings.gui_display) { + uint32_t tabs = (relay_show -1 + Energy->Settings.gui_cols) / Energy->Settings.gui_cols; + if (tabs > 1) { + WSContentSend_P(PSTR("{t}")); // {t} = + uint32_t cols_width = 100 / tabs; + uint32_t current_tab = Energy->gui_rotate / Energy->Settings.gui_cols; + for (uint32_t idx = 0; idx < tabs; idx++) { + WSContentSend_P(PSTR(""), // &k03 is related to WebGetArg("k", tmp, sizeof(tmp)); + cols_width, + (current_tab == idx) ? WebColor(COL_BACKGROUND) : WebColor(COL_FORM), + (current_tab == idx) ? "bold" : "normal", + idx, + (label_o) ? "O" : "L", (idx *Energy->Settings.gui_cols) +1); + } + WSContentSend_P(PSTR("
")); // Close current table as we will use different column count + } + } + // {s}Head1{e} + // {s}Head1Head2{e} + // {s}Head1Head2Head3{e} + // {s}Head1Head2Head3Head4{e} + WSContentSend_P(PSTR("{t}{s}")); // First column is empty ({t} = , {s} = "), + (no_label) ? "" : (label_o) ? "O" : "L", + (no_label) ? "" : itoa(relays[Energy->gui_offset +i], value_chr, 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, Energy->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, Energy->frequency_common)); + if (Energy->voltage_available) { + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); } - } - if (Energy->current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); - } - WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, 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)); + 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, Energy->frequency_common)); + } } - } - 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)); - 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)); - } + if (Energy->current_available) { + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + } + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, 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_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)); + 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)); + } + #ifdef USE_ENERGY_COLUMN_GUI - XnrgCall(FUNC_WEB_COL_SENSOR); - WSContentSend_P(PSTR("
) + bool no_label = (1 == Energy->phase_count); + 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 + XnrgCall(FUNC_WEB_COL_SENSOR); + WSContentSend_P(PSTR("

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR #endif // USE_ENERGY_COLUMN_GUI - XnrgCall(FUNC_WEB_SENSOR); + XnrgCall(FUNC_WEB_SENSOR); #endif // USE_WEBSERVER + } } } +#ifdef USE_WEBSERVER + +void EnergyWebGetArg(void) { + char tmp[8]; // WebGetArg numbers only + WebGetArg(PSTR("k03"), tmp, sizeof(tmp)); // relay gtoups + if (strlen(tmp)) { Energy->gui_rotate = atoi(tmp) * Energy->Settings.gui_cols; } +} + +#endif // USE_WEBSERVER + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -1650,6 +1775,9 @@ bool Xsns03(uint32_t function) case FUNC_WEB_SENSOR: EnergyShow(false); break; + case FUNC_WEB_GET_ARG: + EnergyWebGetArg(); + break; #endif // USE_WEBSERVER case FUNC_SAVE_BEFORE_RESTART: EnergySaveState(); diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 3c55df525..0eda31567 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -660,7 +660,7 @@ void Ade7953DrvInit(void) { if (PinUsed(GPIO_ADE7953_IRQ, GPIO_ANY)) { // Irq is not supported... uint32_t pin_irq = Pin(GPIO_ADE7953_IRQ, GPIO_ANY); pinMode(pin_irq, INPUT); // Related to resetPins() - Must be set to input - // 0 (1 = Shelly 2.5), 1 (2 = Shelly EM), 2 (3 = Shelly Plus 2PM), 3 (4 = Shelly Pro 1PM), 4 (5 = Shelly Pro 2PM) + // 0 (1 = Shelly 2.5), 1 (2 = Shelly EM), 2 (3 = Shelly Plus 2PM), 3 (4 = Shelly Pro 1PM), 4 (5 = Shelly Pro 2PM), 5 (6 = Shelly Pro 4PM) Ade7953.model = GetPin(pin_irq) - AGPIO(GPIO_ADE7953_IRQ); int pin_reset = Pin(GPIO_ADE7953_RST); // -1 if not defined