2017-12-16 14:51:45 +00:00
/*
2019-10-27 10:13:24 +00:00
xdrv_03_energy . ino - Energy sensor support for Tasmota
2017-12-16 14:51:45 +00:00
2021-01-01 12:44:04 +00:00
Copyright ( C ) 2021 Theo Arends
2017-12-16 14:51:45 +00:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2023-01-28 10:03:14 +00:00
# ifdef ESP8266
2017-12-16 14:51:45 +00:00
# ifdef USE_ENERGY_SENSOR
/*********************************************************************************************\
2023-01-27 15:41:55 +00:00
* Energy for ESP8266 and legacy ESP32 with max three phases / channels using Settings from flash
2017-12-16 14:51:45 +00:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-08-27 16:01:12 +01:00
# define XDRV_03 3
# define XSNS_03 3
2018-11-06 16:33:51 +00:00
2019-08-01 14:46:12 +01:00
//#define USE_ENERGY_MARGIN_DETECTION
// #define USE_ENERGY_POWER_LIMIT
2017-12-16 14:51:45 +00:00
2023-08-24 14:17:04 +01:00
# ifndef MQTT_TELE_RETAIN
# define MQTT_TELE_RETAIN 0
# endif
2019-08-27 16:01:12 +01:00
# define ENERGY_NONE 0
# define ENERGY_WATCHDOG 4 // Allow up to 4 seconds before deciding no valid data present
2023-01-25 16:05:48 +00:00
# undef ENERGY_MAX_PHASES
2021-04-06 14:23:07 +01:00
# define ENERGY_MAX_PHASES 3
2019-05-14 16:46:40 +01:00
2018-11-20 14:00:24 +00:00
# include <Ticker.h>
2019-01-05 14:39:56 +00:00
# define D_CMND_POWERCAL "PowerCal"
# define D_CMND_VOLTAGECAL "VoltageCal"
# define D_CMND_CURRENTCAL "CurrentCal"
2021-03-21 16:51:57 +00:00
# define D_CMND_FREQUENCYCAL "FrequencyCal"
2019-08-27 16:01:12 +01:00
# define D_CMND_TARIFF "Tariff"
2019-09-16 15:56:16 +01:00
# define D_CMND_MODULEADDRESS "ModuleAddress"
2019-01-05 14:39:56 +00:00
2022-10-30 10:15:17 +00:00
enum EnergyCalibration {
ENERGY_POWER_CALIBRATION , ENERGY_VOLTAGE_CALIBRATION , ENERGY_CURRENT_CALIBRATION , ENERGY_FREQUENCY_CALIBRATION } ;
2017-12-16 14:51:45 +00:00
enum EnergyCommands {
2021-03-21 16:51:57 +00:00
CMND_POWERCAL , CMND_VOLTAGECAL , CMND_CURRENTCAL , CMND_FREQUENCYCAL ,
2021-04-09 08:49:33 +01:00
CMND_POWERSET , CMND_VOLTAGESET , CMND_CURRENTSET , CMND_FREQUENCYSET , CMND_MODULEADDRESS , CMND_ENERGYCONFIG } ;
2019-08-01 14:46:12 +01:00
2019-08-11 17:12:18 +01:00
const char kEnergyCommands [ ] PROGMEM = " | " // No prefix
2021-03-21 16:51:57 +00:00
D_CMND_POWERCAL " | " D_CMND_VOLTAGECAL " | " D_CMND_CURRENTCAL " | " D_CMND_FREQUENCYCAL " | "
2021-04-09 08:49:33 +01:00
D_CMND_POWERSET " | " D_CMND_VOLTAGESET " | " D_CMND_CURRENTSET " | " D_CMND_FREQUENCYSET " | " D_CMND_MODULEADDRESS " | " D_CMND_ENERGYCONFIG " | "
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_MARGIN_DETECTION
D_CMND_POWERDELTA " | " D_CMND_POWERLOW " | " D_CMND_POWERHIGH " | " D_CMND_VOLTAGELOW " | " D_CMND_VOLTAGEHIGH " | " D_CMND_CURRENTLOW " | " D_CMND_CURRENTHIGH " | "
# ifdef USE_ENERGY_POWER_LIMIT
D_CMND_MAXENERGY " | " D_CMND_MAXENERGYSTART " | "
2017-12-16 14:51:45 +00:00
D_CMND_MAXPOWER " | " D_CMND_MAXPOWERHOLD " | " D_CMND_MAXPOWERWINDOW " | "
2019-08-01 14:46:12 +01:00
D_CMND_SAFEPOWER " | " D_CMND_SAFEPOWERHOLD " | " D_CMND_SAFEPOWERWINDOW " | "
# endif // USE_ENERGY_POWER_LIMIT
# endif // USE_ENERGY_MARGIN_DETECTION
2022-04-16 15:07:42 +01:00
D_CMND_ENERGYTODAY " | " D_CMND_ENERGYYESTERDAY " | " D_CMND_ENERGYTOTAL " | " D_CMND_ENERGYEXPORTACTIVE " | " D_CMND_ENERGYUSAGE " | " D_CMND_ENERGYEXPORT " | " D_CMND_TARIFF ;
2019-08-01 14:46:12 +01:00
void ( * const EnergyCommand [ ] ) ( void ) PROGMEM = {
2021-03-21 16:51:57 +00:00
& CmndPowerCal , & CmndVoltageCal , & CmndCurrentCal , & CmndFrequencyCal ,
2021-04-09 08:49:33 +01:00
& CmndPowerSet , & CmndVoltageSet , & CmndCurrentSet , & CmndFrequencySet , & CmndModuleAddress , & CmndEnergyConfig ,
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_MARGIN_DETECTION
& CmndPowerDelta , & CmndPowerLow , & CmndPowerHigh , & CmndVoltageLow , & CmndVoltageHigh , & CmndCurrentLow , & CmndCurrentHigh ,
# ifdef USE_ENERGY_POWER_LIMIT
& CmndMaxEnergy , & CmndMaxEnergyStart ,
& CmndMaxPower , & CmndMaxPowerHold , & CmndMaxPowerWindow ,
& CmndSafePower , & CmndSafePowerHold , & CmndSafePowerWindow ,
# endif // USE_ENERGY_POWER_LIMIT
# endif // USE_ENERGY_MARGIN_DETECTION
2022-04-16 15:07:42 +01:00
& CmndEnergyToday , & CmndEnergyYesterday , & CmndEnergyTotal , & CmndEnergyExportActive , & CmndEnergyUsage , & CmndEnergyExport , & CmndTariff } ;
2017-12-16 14:51:45 +00:00
2023-01-24 15:54:03 +00:00
typedef struct {
2021-04-06 14:23:07 +01:00
float voltage [ ENERGY_MAX_PHASES ] ; // 123.1 V
float current [ ENERGY_MAX_PHASES ] ; // 123.123 A
float active_power [ ENERGY_MAX_PHASES ] ; // 123.1 W
float apparent_power [ ENERGY_MAX_PHASES ] ; // 123.1 VA
float reactive_power [ ENERGY_MAX_PHASES ] ; // 123.1 VAr
float power_factor [ ENERGY_MAX_PHASES ] ; // 0.12
float frequency [ ENERGY_MAX_PHASES ] ; // 123.1 Hz
float import_active [ ENERGY_MAX_PHASES ] ; // 123.123 kWh
float export_active [ ENERGY_MAX_PHASES ] ; // 123.123 kWh
2021-09-29 14:33:58 +01:00
float start_energy [ ENERGY_MAX_PHASES ] ; // 12345.12345 kWh total previous
float daily [ ENERGY_MAX_PHASES ] ; // 123.123 kWh
float total [ ENERGY_MAX_PHASES ] ; // 12345.12345 kWh total energy
float daily_sum ; // 123.123 kWh
float total_sum ; // 12345.12345 kWh total energy
float yesterday_sum ; // 123.123 kWh
2022-08-26 13:35:52 +01:00
float daily_sum_import_balanced ; // 123.123 kWh
float daily_sum_export_balanced ; // 123.123 kWh
2021-09-29 14:33:58 +01:00
2023-01-24 15:54:03 +00:00
int32_t kWhtoday_delta [ ENERGY_MAX_PHASES ] ; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy->kWhtoday (HLW and CSE only)
int32_t kWhtoday_offset [ ENERGY_MAX_PHASES ] ; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily
int32_t kWhtoday [ ENERGY_MAX_PHASES ] ; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily
2023-04-18 14:34:19 +01:00
int32_t kWhtoday_export [ ENERGY_MAX_PHASES ] ; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily
2023-01-24 15:54:03 +00:00
int32_t period [ ENERGY_MAX_PHASES ] ; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily
2019-08-16 13:41:02 +01:00
2023-03-17 20:05:51 +00:00
char * value ;
2021-04-06 14:23:07 +01:00
uint8_t fifth_second ;
uint8_t command_code ;
uint8_t data_valid [ ENERGY_MAX_PHASES ] ;
2019-08-16 13:41:02 +01:00
2021-04-06 14:23:07 +01:00
uint8_t phase_count ; // Number of phases active
2021-10-29 07:51:21 +01:00
bool voltage_common ; // Use common voltage
bool frequency_common ; // Use common frequency
2021-04-09 09:04:37 +01:00
bool use_overtemp ; // Use global temperature as overtemp trigger on internal energy monitor hardware
2021-04-06 14:23:07 +01:00
bool kWhtoday_offset_init ;
2019-09-15 12:10:32 +01:00
2021-04-06 14:23:07 +01:00
bool voltage_available ; // Enable if voltage is measured
bool current_available ; // Enable if current is measured
2022-04-16 15:07:42 +01:00
bool local_energy_active_export ; // Enable if support for storing energy_active
2019-08-16 13:41:02 +01:00
2021-04-06 14:23:07 +01:00
bool type_dc ;
bool power_on ;
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_MARGIN_DETECTION
2021-04-06 14:23:07 +01:00
uint16_t power_history [ ENERGY_MAX_PHASES ] [ 3 ] ;
uint8_t power_steady_counter ; // Allow for power on stabilization
2023-05-11 17:10:52 +01:00
uint8_t margin_stable ;
2021-04-06 14:23:07 +01:00
bool min_power_flag ;
bool max_power_flag ;
bool min_voltage_flag ;
bool max_voltage_flag ;
bool min_current_flag ;
bool max_current_flag ;
2017-12-16 14:51:45 +00:00
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_POWER_LIMIT
2021-04-06 14:23:07 +01:00
uint16_t mplh_counter ;
uint16_t mplw_counter ;
uint8_t mplr_counter ;
uint8_t max_energy_state ;
2019-08-01 14:46:12 +01:00
# endif // USE_ENERGY_POWER_LIMIT
# endif // USE_ENERGY_MARGIN_DETECTION
2023-01-24 15:54:03 +00:00
} tEnergy ;
tEnergy * Energy = nullptr ;
2017-12-16 14:51:45 +00:00
Ticker ticker_energy ;
2018-02-04 17:09:09 +00:00
/********************************************************************************************/
2023-03-17 20:05:51 +00:00
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 ) {
2023-03-17 20:17:53 +00:00
// free(Energy->value); // Let's keep it for future use reducing heap fragmentation
// Energy->value = nullptr;
2023-03-17 20:05:51 +00:00
}
char * EnergyFmt ( float * input , uint32_t resolution , uint32_t single = 0 ) ;
char * EnergyFmt ( float * input , uint32_t resolution , uint32_t single ) {
2023-01-24 15:54:03 +00:00
// 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]
2022-03-15 14:43:23 +00:00
// single = 5 - single &0x03 = 1 - xx
// single = 6 - single &0x03 = 2 - [xx,xx] - used by tarriff
// single = 7 - single &0x03 = 3 - [xx,xx,xx]
2023-03-17 20:05:51 +00:00
if ( ! EnergyFmtMalloc ( ) ) { return EmptyStr ; }
2023-01-24 15:54:03 +00:00
uint32_t index = ( single > 3 ) ? single & 0x03 : ( 0 = = single ) ? Energy - > phase_count : 1 ; // 1,2,3
2022-03-15 14:43:23 +00:00
if ( single > 2 ) { single = 0 ; } // 0,1,2
2022-04-19 14:44:53 +01:00
float input_sum = 0.0f ;
2022-03-15 14:43:23 +00:00
if ( single > 1 ) {
if ( ! Settings - > flag5 . energy_phase ) { // SetOption129 - (Energy) Show phase information
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
2023-01-02 16:48:51 +00:00
if ( ! isnan ( input [ i ] ) ) {
input_sum + = input [ i ] ;
}
2022-03-15 14:43:23 +00:00
}
input = & input_sum ;
2022-03-15 16:36:25 +00:00
} else {
2023-01-24 15:54:03 +00:00
index = Energy - > phase_count ;
2022-03-15 14:43:23 +00:00
}
}
2023-03-17 20:05:51 +00:00
Energy - > value [ 0 ] = ' \0 ' ;
2022-03-15 14:43:23 +00:00
for ( uint32_t i = 0 ; i < index ; i + + ) {
2023-03-17 20:05:51 +00:00
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 ) ? " " : " ] " : " " ) ;
2020-08-23 17:29:16 +01:00
}
2023-03-17 20:05:51 +00:00
return Energy - > value ;
2020-08-23 17:29:16 +01:00
}
2022-03-15 14:43:23 +00:00
# ifdef USE_WEBSERVER
2023-03-17 20:05:51 +00:00
char * WebEnergyFmt ( float * input , uint32_t resolution , uint32_t single = 0 ) ;
char * WebEnergyFmt ( float * input , uint32_t resolution , uint32_t single ) {
2023-01-24 15:54:03 +00:00
// 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
2023-10-13 12:56:04 +01:00
// single = 3 - Sum of Energy->phase_count xx or single column using colspan (if needed)
2023-03-17 20:05:51 +00:00
if ( ! EnergyFmtMalloc ( ) ) { return EmptyStr ; }
2022-04-19 14:44:53 +01:00
float input_sum = 0.0f ;
2023-10-13 12:56:04 +01:00
if ( single > 1 ) { // Sum and/or Single column
if ( ( 3 = = single ) | | ! Settings - > flag5 . energy_phase ) { // SetOption129 - (Energy) Show phase information
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
2023-01-02 16:48:51 +00:00
if ( ! isnan ( input [ i ] ) ) {
input_sum + = input [ i ] ;
}
2022-03-15 14:43:23 +00:00
}
input = & input_sum ;
} else {
single = 0 ;
}
}
2023-10-13 12:56:04 +01:00
ext_snprintf_P ( Energy - > value , GUISZ , PSTR ( " </td> " ) ) ; // Skip first column
if ( ( Energy - > phase_count > 1 ) & & single ) { // Need to set colspan so need new columns
2022-04-12 09:22:32 +01:00
// </td><td colspan='3' style='text-align:right'>1.23</td><td> </td><td>
// </td><td colspan='5' style='text-align:right'>1.23</td><td> </td><td>
// </td><td colspan='7' style='text-align:right'>1.23</td><td> </td><td>
2023-03-17 20:05:51 +00:00
ext_snprintf_P ( Energy - > value , GUISZ , PSTR ( " %s<td colspan='%d' style='text-align:%s'>%*_f</td><td> </td> " ) ,
Energy - > value , ( Energy - > phase_count * 2 ) - 1 , ( Settings - > flag5 . gui_table_align ) ? PSTR ( " right " ) : PSTR ( " center " ) , resolution , & input [ 0 ] ) ;
2022-03-15 14:43:23 +00:00
} else {
2022-04-12 09:22:32 +01:00
// </td><td style='text-align:right'>1.23</td><td> </td><td>
// </td><td style='text-align:right'>1.23</td><td> </td><td style='text-align:right'>1.23</td><td> </td><td>
// </td><td style='text-align:right'>1.23</td><td> </td><td style='text-align:right'>1.23</td><td> </td><td style='text-align:right'>1.23</td><td> </td><td>
// </td><td style='text-align:right'>1.23</td><td> </td><td style='text-align:right'>1.23</td><td> </td><td style='text-align:right'>1.23</td><td> </td><td style='text-align:right'>1.23</td><td> </td><td>
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
2023-03-17 20:05:51 +00:00
ext_snprintf_P ( Energy - > value , GUISZ , PSTR ( " %s<td style='text-align:%s'>%*_f</td><td> </td> " ) ,
Energy - > value , ( Settings - > flag5 . gui_table_align ) ? PSTR ( " right " ) : PSTR ( " left " ) , resolution , & input [ i ] ) ;
2021-09-29 14:33:58 +01:00
}
}
2023-03-17 20:05:51 +00:00
ext_snprintf_P ( Energy - > value , GUISZ , PSTR ( " %s<td> " ) , Energy - > value ) ;
return Energy - > value ;
2020-08-23 17:29:16 +01:00
}
2022-03-15 14:43:23 +00:00
# endif // USE_WEBSERVER
2020-08-23 17:29:16 +01:00
/********************************************************************************************/
2023-01-27 14:53:40 +00:00
bool EnergyTariff1Active ( ) { // Off-Peak hours
2023-03-04 20:58:03 +00:00
if ( Settings - > mbflag2 . tariff_forced ) {
return 1 = = Settings - > mbflag2 . tariff_forced ;
}
2019-09-25 13:24:49 +01:00
uint8_t dst = 0 ;
2021-06-11 17:14:12 +01:00
if ( IsDst ( ) & & ( Settings - > tariff [ 0 ] [ 1 ] ! = Settings - > tariff [ 1 ] [ 1 ] ) ) {
2019-09-25 13:24:49 +01:00
dst = 1 ;
}
2021-06-11 17:14:12 +01:00
if ( Settings - > tariff [ 0 ] [ dst ] ! = Settings - > tariff [ 1 ] [ dst ] ) {
if ( Settings - > flag3 . energy_weekend & & ( ( RtcTime . day_of_week = = 1 ) | | // CMND_TARIFF
2019-09-29 11:18:09 +01:00
( RtcTime . day_of_week = = 7 ) ) ) {
return true ;
}
2019-09-25 13:24:49 +01:00
uint32_t minutes = MinutesPastMidnight ( ) ;
2021-06-11 17:14:12 +01:00
if ( Settings - > tariff [ 0 ] [ dst ] > Settings - > tariff [ 1 ] [ dst ] ) {
2019-09-29 11:18:09 +01:00
// {"Tariff":{"Off-Peak":{"STD":"22:00","DST":"23:00"},"Standard":{"STD":"06:00","DST":"07:00"},"Weekend":"OFF"}}
2021-06-11 17:14:12 +01:00
return ( ( minutes > = Settings - > tariff [ 0 ] [ dst ] ) | | ( minutes < Settings - > tariff [ 1 ] [ dst ] ) ) ;
2019-09-29 11:18:09 +01:00
} else {
// {"Tariff":{"Off-Peak":{"STD":"00:29","DST":"01:29"},"Standard":{"STD":"07:29","DST":"08:29"},"Weekend":"OFF"}}
2021-06-11 17:14:12 +01:00
return ( ( minutes > = Settings - > tariff [ 0 ] [ dst ] ) & & ( minutes < Settings - > tariff [ 1 ] [ dst ] ) ) ;
2019-09-29 11:18:09 +01:00
}
2019-09-10 15:18:23 +01:00
} else {
return false ;
}
}
2021-09-29 14:33:58 +01:00
void EnergyUpdateToday ( void ) {
2023-01-24 15:54:03 +00:00
Energy - > total_sum = 0.0f ;
Energy - > yesterday_sum = 0.0f ;
Energy - > daily_sum = 0.0f ;
2022-08-26 13:35:52 +01:00
int32_t delta_sum_balanced = 0 ;
2021-10-02 17:29:05 +01:00
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
if ( abs ( Energy - > kWhtoday_delta [ i ] ) > 1000 ) {
int32_t delta = Energy - > kWhtoday_delta [ i ] / 1000 ;
2022-08-26 13:35:52 +01:00
delta_sum_balanced + = delta ;
2023-01-24 15:54:03 +00:00
Energy - > kWhtoday_delta [ i ] - = ( delta * 1000 ) ;
Energy - > kWhtoday [ i ] + = delta ;
2022-04-16 15:07:42 +01:00
if ( delta < 0 ) { // Export energy
2023-04-18 14:34:19 +01:00
Energy - > kWhtoday_export [ i ] + = ( delta * - 1 ) ;
if ( Energy - > kWhtoday_export [ i ] > 100 ) {
int32_t delta_export = Energy - > kWhtoday_export [ i ] / 100 ;
Energy - > kWhtoday_export [ i ] - = ( delta_export * 100 ) ;
RtcSettings . energy_kWhexport_ph [ i ] + = delta_export ;
}
2022-04-16 15:07:42 +01:00
}
2021-09-29 14:33:58 +01:00
}
2019-08-27 16:01:12 +01:00
2023-01-24 15:54:03 +00:00
RtcSettings . energy_kWhtoday_ph [ i ] = Energy - > kWhtoday_offset [ i ] + Energy - > kWhtoday [ i ] ;
Energy - > daily [ i ] = ( float ) ( RtcSettings . energy_kWhtoday_ph [ i ] ) / 100000 ;
Energy - > total [ i ] = ( ( float ) ( RtcSettings . energy_kWhtotal_ph [ i ] ) / 1000 ) + ( ( float ) ( RtcSettings . energy_kWhtoday_ph [ i ] ) / 100000 ) ;
if ( Energy - > local_energy_active_export ) {
Energy - > export_active [ i ] = ( float ) ( RtcSettings . energy_kWhexport_ph [ i ] ) / 1000 ;
2022-04-20 11:04:18 +01:00
}
2021-09-29 14:33:58 +01:00
2023-01-24 15:54:03 +00:00
Energy - > total_sum + = Energy - > total [ i ] ;
Energy - > yesterday_sum + = ( float ) Settings - > energy_kWhyesterday_ph [ i ] / 100000 ;
Energy - > daily_sum + = Energy - > daily [ i ] ;
2021-09-29 14:33:58 +01:00
}
2021-09-29 13:53:23 +01:00
2022-08-26 13:35:52 +01:00
if ( delta_sum_balanced > 0 ) {
2023-01-24 15:54:03 +00:00
Energy - > daily_sum_import_balanced + = ( float ) delta_sum_balanced / 100000 ;
2022-08-26 13:35:52 +01:00
} else {
2023-01-24 15:54:03 +00:00
Energy - > daily_sum_export_balanced + = ( float ) abs ( delta_sum_balanced ) / 100000 ;
2022-08-26 13:35:52 +01:00
}
2019-09-20 21:35:56 +01:00
if ( RtcTime . valid ) { // We calc the difference only if we have a valid RTC time.
2023-01-24 15:54:03 +00:00
uint32_t energy_diff = ( uint32_t ) ( Energy - > total_sum * 1000 ) - RtcSettings . energy_usage . last_usage_kWhtotal ;
RtcSettings . energy_usage . last_usage_kWhtotal = ( uint32_t ) ( Energy - > total_sum * 1000 ) ;
2019-09-20 21:35:56 +01:00
uint32_t return_diff = 0 ;
2023-01-24 15:54:03 +00:00
if ( ! isnan ( Energy - > export_active [ 0 ] ) ) {
// return_diff = (uint32_t)(Energy->export_active * 1000) - RtcSettings.energy_usage.last_return_kWhtotal;
// RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy->export_active * 1000);
2020-05-22 16:48:21 +01:00
2022-04-19 14:44:53 +01:00
float export_active = 0.0f ;
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
if ( ! isnan ( Energy - > export_active [ i ] ) ) {
export_active + = Energy - > export_active [ i ] ;
2020-05-22 16:48:21 +01:00
}
}
2023-01-01 10:32:30 +00:00
return_diff = ( uint32_t ) ( export_active * 1000 ) - RtcSettings . energy_usage . last_return_kWhtotal ;
RtcSettings . energy_usage . last_return_kWhtotal = ( uint32_t ) ( export_active * 1000 ) ;
2019-09-20 21:35:56 +01:00
}
2019-09-20 13:37:55 +01:00
if ( EnergyTariff1Active ( ) ) { // Tarrif1 = Off-Peak
RtcSettings . energy_usage . usage1_kWhtotal + = energy_diff ;
RtcSettings . energy_usage . return1_kWhtotal + = return_diff ;
} else {
RtcSettings . energy_usage . usage2_kWhtotal + = energy_diff ;
RtcSettings . energy_usage . return2_kWhtotal + = return_diff ;
}
2019-08-27 16:01:12 +01:00
}
2018-02-04 17:09:09 +00:00
}
2021-10-02 17:29:05 +01:00
void EnergyUpdateTotal ( void ) {
2023-01-24 15:54:03 +00:00
// Provide total import active energy as float Energy->import_active[phase] in kWh: 98Wh = 0.098kWh
2019-09-06 17:02:31 +01:00
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " NRG: EnergyTotal[%d] %4_f kWh " ) , i , & Energy - > import_active [ i ] ) ;
2019-09-03 20:53:20 +01:00
2023-01-14 14:39:54 +00:00
// Try to fix instable input by verifying allowed bandwidth (#17659)
2023-01-24 15:54:03 +00:00
if ( ( Energy - > start_energy [ i ] ! = 0 ) & &
2023-01-14 14:39:54 +00:00
( Settings - > param [ P_CSE7766_INVALID_POWER ] > 0 ) & &
( Settings - > param [ P_CSE7766_INVALID_POWER ] < 128 ) ) { // SetOption39 1..127 kWh
2023-01-24 15:54:03 +00:00
int total = abs ( ( int ) Energy - > total [ i ] ) ; // We only use kWh
int import_active = abs ( ( int ) Energy - > import_active [ i ] ) ;
2023-01-14 14:39:54 +00:00
if ( ( import_active < ( total - Settings - > param [ P_CSE7766_INVALID_POWER ] ) ) | |
( import_active > ( total + Settings - > param [ P_CSE7766_INVALID_POWER ] ) ) ) {
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " NRG: Outside bandwidth " ) ) ;
continue ; // No valid energy value received
}
}
2023-01-24 15:54:03 +00:00
if ( 0 = = Energy - > start_energy [ i ] | | ( Energy - > import_active [ i ] < Energy - > start_energy [ i ] ) ) {
Energy - > start_energy [ i ] = Energy - > import_active [ i ] ; // Init after restart and handle roll-over if any
2021-10-02 17:29:05 +01:00
}
2023-01-24 15:54:03 +00:00
else if ( Energy - > import_active [ i ] ! = Energy - > start_energy [ i ] ) {
Energy - > kWhtoday [ i ] = ( int32_t ) ( ( Energy - > import_active [ i ] - Energy - > start_energy [ i ] ) * 100000 ) ;
2021-10-02 17:29:05 +01:00
}
2019-09-18 10:42:28 +01:00
2023-01-24 15:54:03 +00:00
if ( ( Energy - > total [ i ] < ( Energy - > import_active [ i ] - 0.01f ) ) & & // We subtract a little offset of 10Wh to avoid continuous updates
2023-01-01 10:32:30 +00:00
Settings - > flag3 . hardware_energy_total ) { // SetOption72 - Enable hardware energy total counter as reference (#6561)
2023-01-24 15:54:03 +00:00
// The following calculation allows total usage (Energy->import_active[i]) up to +/-2147483.647 kWh
RtcSettings . energy_kWhtotal_ph [ i ] = ( int32_t ) ( ( Energy - > import_active [ i ] * 1000 ) - ( ( Energy - > kWhtoday_offset [ i ] + Energy - > kWhtoday [ i ] ) / 100 ) ) ;
2021-10-02 17:29:05 +01:00
Settings - > energy_kWhtotal_ph [ i ] = RtcSettings . energy_kWhtotal_ph [ i ] ;
2023-01-24 15:54:03 +00:00
Energy - > total [ i ] = Energy - > import_active [ i ] ;
Settings - > energy_kWhtotal_time = ( ! Energy - > kWhtoday_offset [ i ] ) ? LocalTime ( ) : Midnight ( ) ;
2021-10-02 17:29:05 +01:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Energy Total updated with hardware value"));
}
2019-09-18 10:42:28 +01:00
}
2021-10-02 17:29:05 +01:00
2019-09-03 20:53:20 +01:00
EnergyUpdateToday ( ) ;
}
2018-05-10 16:21:26 +01:00
/*********************************************************************************************/
2023-01-27 14:53:40 +00:00
void Energy200ms ( void ) {
2023-01-24 15:54:03 +00:00
Energy - > power_on = ( TasmotaGlobal . power ! = 0 ) | Settings - > flag . no_power_on_check ; // SetOption21 - Show voltage even if powered off
2018-09-17 19:32:38 +01:00
2023-01-24 15:54:03 +00:00
Energy - > fifth_second + + ;
if ( 5 = = Energy - > fifth_second ) {
Energy - > fifth_second = 0 ;
2017-12-16 14:51:45 +00:00
2019-04-15 17:12:42 +01:00
XnrgCall ( FUNC_ENERGY_EVERY_SECOND ) ;
2018-02-03 22:25:05 +00:00
2017-12-16 14:51:45 +00:00
if ( RtcTime . valid ) {
2023-05-29 15:19:55 +01:00
if ( ! Settings - > energy_kWhtotal_time ) {
Settings - > energy_kWhtotal_time = LocalTime ( ) ;
}
2020-05-10 11:59:13 +01:00
2023-01-24 15:54:03 +00:00
if ( ! Energy - > kWhtoday_offset_init & & ( RtcTime . day_of_year = = Settings - > energy_kWhdoy ) ) {
Energy - > kWhtoday_offset_init = true ;
2021-09-29 14:33:58 +01:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
2023-01-24 15:54:03 +00:00
Energy - > kWhtoday_offset [ i ] = Settings - > energy_kWhtoday_ph [ i ] ;
2022-11-14 16:11:38 +00:00
// RtcSettings.energy_kWhtoday_ph[i] = 0;
2021-09-29 14:33:58 +01:00
}
2020-05-10 11:59:13 +01:00
}
2023-01-26 14:26:10 +00:00
bool midnight = ( LocalTime ( ) = = Midnight ( ) ) ;
if ( midnight | | ( RtcTime . day_of_year > Settings - > energy_kWhdoy ) ) {
2023-01-24 15:54:03 +00:00
Energy - > kWhtoday_offset_init = true ;
2023-01-03 11:24:34 +00:00
Settings - > energy_kWhdoy = RtcTime . day_of_year ;
2021-09-29 14:33:58 +01:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
Settings - > energy_kWhyesterday_ph [ i ] = RtcSettings . energy_kWhtoday_ph [ i ] ;
2019-08-27 16:01:12 +01:00
2023-01-01 10:32:30 +00:00
RtcSettings . energy_kWhtotal_ph [ i ] + = ( RtcSettings . energy_kWhtoday_ph [ i ] / 100 ) ;
2021-09-29 14:33:58 +01:00
Settings - > energy_kWhtotal_ph [ i ] = RtcSettings . energy_kWhtotal_ph [ i ] ;
2020-10-13 23:30:01 +01:00
2022-04-16 15:07:42 +01:00
Settings - > energy_kWhexport_ph [ i ] = RtcSettings . energy_kWhexport_ph [ i ] ;
2023-01-24 15:54:03 +00:00
Energy - > period [ i ] - = RtcSettings . energy_kWhtoday_ph [ i ] ; // this becomes a large unsigned, effectively a negative for EnergyShow calculation
Energy - > kWhtoday [ i ] = 0 ;
Energy - > kWhtoday_offset [ i ] = 0 ;
2021-09-29 14:33:58 +01:00
RtcSettings . energy_kWhtoday_ph [ i ] = 0 ;
2022-11-17 13:58:16 +00:00
Settings - > energy_kWhtoday_ph [ i ] = 0 ;
2023-01-24 15:54:03 +00:00
Energy - > start_energy [ i ] = 0 ;
// Energy->kWhtoday_delta = 0; // dont zero this, we need to carry the remainder over to tomorrow
Energy - > daily_sum_import_balanced = 0.0 ;
Energy - > daily_sum_export_balanced = 0.0 ;
2021-09-29 14:33:58 +01:00
}
2018-02-06 09:06:22 +00:00
EnergyUpdateToday ( ) ;
2023-01-26 14:26:10 +00:00
}
2019-08-01 14:46:12 +01:00
# if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT)
2023-01-26 14:26:10 +00:00
if ( midnight ) {
2023-01-24 15:54:03 +00:00
Energy - > max_energy_state = 3 ;
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
if ( ( RtcTime . hour = = Settings - > energy_max_energy_start ) & & ( 3 = = Energy - > max_energy_state ) ) {
Energy - > max_energy_state = 0 ;
2017-12-16 14:51:45 +00:00
}
2019-08-01 14:46:12 +01:00
# endif // USE_ENERGY_POWER_LIMIT
2017-12-16 14:51:45 +00:00
}
}
2019-09-07 15:31:39 +01:00
XnrgCall ( FUNC_EVERY_200_MSECOND ) ;
2017-12-16 14:51:45 +00:00
}
2023-01-27 14:53:40 +00:00
void EnergySaveState ( void ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_kWhdoy = ( RtcTime . valid ) ? RtcTime . day_of_year : 0 ;
2019-08-27 16:01:12 +01:00
2021-09-29 14:33:58 +01:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
Settings - > energy_kWhtoday_ph [ i ] = RtcSettings . energy_kWhtoday_ph [ i ] ;
Settings - > energy_kWhtotal_ph [ i ] = RtcSettings . energy_kWhtotal_ph [ i ] ;
2022-04-16 15:07:42 +01:00
Settings - > energy_kWhexport_ph [ i ] = RtcSettings . energy_kWhexport_ph [ i ] ;
2021-09-29 14:33:58 +01:00
}
2019-08-27 16:01:12 +01:00
2021-06-11 17:14:12 +01:00
Settings - > energy_usage = RtcSettings . energy_usage ;
2017-12-16 14:51:45 +00:00
}
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_MARGIN_DETECTION
2023-01-27 14:53:40 +00:00
bool EnergyMargin ( bool type , uint16_t margin , uint16_t value , bool & flag , bool & save_flag ) {
2019-01-28 13:08:33 +00:00
bool change ;
2017-12-16 14:51:45 +00:00
2018-02-06 09:06:22 +00:00
if ( ! margin ) return false ;
2017-12-16 14:51:45 +00:00
change = save_flag ;
if ( type ) {
flag = ( value > margin ) ;
} else {
flag = ( value < margin ) ;
}
save_flag = flag ;
return ( change ! = save_flag ) ;
}
2022-10-31 14:02:29 +00:00
void EnergyMarginCheck ( void ) {
2023-01-24 15:54:03 +00:00
if ( ! Energy - > phase_count | | ( TasmotaGlobal . uptime < 8 ) ) { return ; }
if ( Energy - > power_steady_counter ) {
Energy - > power_steady_counter - - ;
2017-12-16 14:51:45 +00:00
return ;
}
2020-07-20 15:26:32 +01:00
bool jsonflg = false ;
2020-07-20 15:41:05 +01:00
Response_P ( PSTR ( " { \" " D_RSLT_MARGINS " \" :{ " ) ) ;
2020-07-20 15:26:32 +01:00
2021-04-06 14:23:07 +01:00
int16_t power_diff [ ENERGY_MAX_PHASES ] = { 0 } ;
2023-01-24 15:54:03 +00:00
for ( uint32_t phase = 0 ; phase < Energy - > phase_count ; phase + + ) {
uint16_t active_power = ( uint16_t ) ( Energy - > active_power [ phase ] ) ;
2020-08-23 17:29:16 +01:00
2023-01-24 15:54:03 +00:00
// AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: APower %d, HPower0 %d, HPower1 %d, HPower2 %d"), active_power, Energy->power_history[phase][0], Energy->power_history[phase][1], Energy->power_history[phase][2]);
2020-10-28 16:32:07 +00:00
2021-06-11 17:14:12 +01:00
if ( Settings - > energy_power_delta [ phase ] ) {
2023-01-24 15:54:03 +00:00
power_diff [ phase ] = active_power - Energy - > power_history [ phase ] [ 0 ] ;
2020-08-23 17:29:16 +01:00
uint16_t delta = abs ( power_diff [ phase ] ) ;
bool threshold_met = false ;
if ( delta > 0 ) {
2021-06-11 17:14:12 +01:00
if ( Settings - > energy_power_delta [ phase ] < 101 ) { // 1..100 = Percentage
2023-01-24 15:54:03 +00:00
uint16_t min_power = ( Energy - > power_history [ phase ] [ 0 ] > active_power ) ? active_power : Energy - > power_history [ phase ] [ 0 ] ;
2020-08-23 17:29:16 +01:00
if ( 0 = = min_power ) { min_power + + ; } // Fix divide by 0 exception (#6741)
delta = ( delta * 100 ) / min_power ;
2022-02-07 21:33:09 +00:00
if ( delta > = Settings - > energy_power_delta [ phase ] ) {
2020-08-23 17:29:16 +01:00
threshold_met = true ;
}
} else { // 101..32000 = Absolute
2022-02-07 21:33:09 +00:00
if ( delta > = ( Settings - > energy_power_delta [ phase ] - 100 ) ) {
2020-08-23 17:29:16 +01:00
threshold_met = true ;
}
2020-01-17 09:12:57 +00:00
}
}
2020-08-23 17:29:16 +01:00
if ( threshold_met ) {
2023-01-24 15:54:03 +00:00
Energy - > power_history [ phase ] [ 1 ] = active_power ; // We only want one report so reset history
Energy - > power_history [ phase ] [ 2 ] = active_power ;
2020-08-23 17:29:16 +01:00
jsonflg = true ;
} else {
power_diff [ phase ] = 0 ;
2019-10-25 17:16:09 +01:00
}
2018-03-15 16:33:35 +00:00
}
2023-01-24 15:54:03 +00:00
Energy - > power_history [ phase ] [ 0 ] = Energy - > power_history [ phase ] [ 1 ] ; // Shift in history every second allowing power changes to settle for up to three seconds
Energy - > power_history [ phase ] [ 1 ] = Energy - > power_history [ phase ] [ 2 ] ;
Energy - > power_history [ phase ] [ 2 ] = active_power ;
2020-08-23 17:29:16 +01:00
}
if ( jsonflg ) {
2023-01-24 15:54:03 +00:00
float power_diff_f [ Energy - > phase_count ] ;
for ( uint32_t phase = 0 ; phase < Energy - > phase_count ; phase + + ) {
2021-09-29 14:33:58 +01:00
power_diff_f [ phase ] = power_diff [ phase ] ;
}
2023-03-17 20:05:51 +00:00
ResponseAppend_P ( PSTR ( " \" " D_CMND_POWERDELTA " \" :%s " ) , EnergyFmt ( power_diff_f , 0 ) ) ;
2018-03-15 16:33:35 +00:00
}
2020-08-23 17:29:16 +01:00
2023-01-24 15:54:03 +00:00
uint16_t energy_power_u = ( uint16_t ) ( Energy - > active_power [ 0 ] ) ;
2018-03-15 16:33:35 +00:00
2023-01-24 15:54:03 +00:00
if ( Energy - > power_on & & ( Settings - > energy_min_power | | Settings - > energy_max_power | | Settings - > energy_min_voltage | | Settings - > energy_max_voltage | | Settings - > energy_min_current | | Settings - > energy_max_current ) ) {
uint16_t energy_voltage_u = ( uint16_t ) ( Energy - > voltage [ 0 ] ) ;
uint16_t energy_current_u = ( uint16_t ) ( Energy - > current [ 0 ] * 1000 ) ;
2017-12-16 14:51:45 +00:00
2019-08-08 15:24:11 +01:00
DEBUG_DRIVER_LOG ( PSTR ( " NRG: W %d, U %d, I %d " ) , energy_power_u , energy_voltage_u , energy_current_u ) ;
2017-12-16 14:51:45 +00:00
2019-10-18 15:53:30 +01:00
bool flag ;
2023-01-24 15:54:03 +00:00
if ( EnergyMargin ( false , Settings - > energy_min_power , energy_power_u , flag , Energy - > min_power_flag ) ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s \" " D_CMND_POWERLOW " \" : \" %s \" " ) , ( jsonflg ) ? " , " : " " , GetStateText ( flag ) ) ;
2019-01-28 13:08:33 +00:00
jsonflg = true ;
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
if ( EnergyMargin ( true , Settings - > energy_max_power , energy_power_u , flag , Energy - > max_power_flag ) ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s \" " D_CMND_POWERHIGH " \" : \" %s \" " ) , ( jsonflg ) ? " , " : " " , GetStateText ( flag ) ) ;
2019-01-28 13:08:33 +00:00
jsonflg = true ;
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
if ( EnergyMargin ( false , Settings - > energy_min_voltage , energy_voltage_u , flag , Energy - > min_voltage_flag ) ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s \" " D_CMND_VOLTAGELOW " \" : \" %s \" " ) , ( jsonflg ) ? " , " : " " , GetStateText ( flag ) ) ;
2019-01-28 13:08:33 +00:00
jsonflg = true ;
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
if ( EnergyMargin ( true , Settings - > energy_max_voltage , energy_voltage_u , flag , Energy - > max_voltage_flag ) ) {
2019-03-23 16:00:59 +00:00
ResponseAppend_P ( PSTR ( " %s \" " D_CMND_VOLTAGEHIGH " \" : \" %s \" " ) , ( jsonflg ) ? " , " : " " , GetStateText ( flag ) ) ;
2019-01-28 13:08:33 +00:00
jsonflg = true ;
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
if ( EnergyMargin ( false , Settings - > energy_min_current , energy_current_u , flag , Energy - > min_current_flag ) ) {
2019-10-06 10:28:57 +01:00
ResponseAppend_P ( PSTR ( " %s \" " D_CMND_CURRENTLOW " \" : \" %s \" " ) , ( jsonflg ) ? " , " : " " , GetStateText ( flag ) ) ;
2019-01-28 13:08:33 +00:00
jsonflg = true ;
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
if ( EnergyMargin ( true , Settings - > energy_max_current , energy_current_u , flag , Energy - > max_current_flag ) ) {
2019-10-06 10:28:57 +01:00
ResponseAppend_P ( PSTR ( " %s \" " D_CMND_CURRENTHIGH " \" : \" %s \" " ) , ( jsonflg ) ? " , " : " " , GetStateText ( flag ) ) ;
2019-01-28 13:08:33 +00:00
jsonflg = true ;
2017-12-16 14:51:45 +00:00
}
2020-07-20 15:26:32 +01:00
}
if ( jsonflg ) {
2020-07-20 15:41:05 +01:00
ResponseJsonEndEnd ( ) ;
2020-07-20 16:24:51 +01:00
MqttPublishPrefixTopicRulesProcess_P ( TELE , PSTR ( D_RSLT_MARGINS ) , MQTT_TELE_RETAIN ) ;
2023-08-27 09:53:04 +01:00
EnergyMqttShow ( ) ;
2023-05-11 17:10:52 +01:00
Energy - > margin_stable = 3 ; // Allow 2 seconds to stabilize before reporting
2017-12-16 14:51:45 +00:00
}
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_POWER_LIMIT
2017-12-16 14:51:45 +00:00
// Max Power
2021-06-11 17:14:12 +01:00
if ( Settings - > energy_max_power_limit ) {
2023-01-24 15:54:03 +00:00
if ( Energy - > active_power [ 0 ] > Settings - > energy_max_power_limit ) {
if ( ! Energy - > mplh_counter ) {
Energy - > mplh_counter = Settings - > energy_max_power_limit_hold ;
2017-12-16 14:51:45 +00:00
} else {
2023-01-24 15:54:03 +00:00
Energy - > mplh_counter - - ;
if ( ! Energy - > mplh_counter ) {
2019-10-22 17:34:41 +01:00
ResponseTime_P ( PSTR ( " , \" " D_JSON_MAXPOWERREACHED " \" :%d} " ) , energy_power_u ) ;
2021-04-07 14:07:05 +01:00
MqttPublishPrefixTopicRulesProcess_P ( STAT , S_RSLT_WARNING ) ;
2017-12-16 14:51:45 +00:00
EnergyMqttShow ( ) ;
2024-04-08 11:03:11 +01:00
SetAllPower ( POWER_OFF_FORCE , SRC_MAXPOWER ) ;
2023-01-24 15:54:03 +00:00
if ( ! Energy - > mplr_counter ) {
Energy - > mplr_counter = Settings - > param [ P_MAX_POWER_RETRY ] + 1 ; // SetOption33 - Max Power Retry count
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
Energy - > mplw_counter = Settings - > energy_max_power_limit_window ;
2017-12-16 14:51:45 +00:00
}
}
}
2021-06-11 17:14:12 +01:00
else if ( TasmotaGlobal . power & & ( energy_power_u < = Settings - > energy_max_power_limit ) ) {
2023-01-24 15:54:03 +00:00
Energy - > mplh_counter = 0 ;
Energy - > mplr_counter = 0 ;
Energy - > mplw_counter = 0 ;
2017-12-16 14:51:45 +00:00
}
2020-10-28 18:03:39 +00:00
if ( ! TasmotaGlobal . power ) {
2023-01-24 15:54:03 +00:00
if ( Energy - > mplw_counter ) {
Energy - > mplw_counter - - ;
2017-12-16 14:51:45 +00:00
} else {
2023-01-24 15:54:03 +00:00
if ( Energy - > mplr_counter ) {
Energy - > mplr_counter - - ;
if ( Energy - > mplr_counter ) {
2019-09-04 17:06:34 +01:00
ResponseTime_P ( PSTR ( " , \" " D_JSON_POWERMONITOR " \" : \" %s \" } " ) , GetStateText ( 1 ) ) ;
2021-04-07 14:07:05 +01:00
MqttPublishPrefixTopicRulesProcess_P ( RESULT_OR_STAT , PSTR ( D_JSON_POWERMONITOR ) ) ;
2019-09-04 11:20:04 +01:00
RestorePower ( true , SRC_MAXPOWER ) ;
2017-12-16 14:51:45 +00:00
} else {
2019-09-04 17:06:34 +01:00
ResponseTime_P ( PSTR ( " , \" " D_JSON_MAXPOWERREACHEDRETRY " \" : \" %s \" } " ) , GetStateText ( 0 ) ) ;
2021-04-07 14:07:05 +01:00
MqttPublishPrefixTopicRulesProcess_P ( STAT , S_RSLT_WARNING ) ;
2017-12-16 14:51:45 +00:00
EnergyMqttShow ( ) ;
2024-04-08 11:03:11 +01:00
SetAllPower ( POWER_OFF_FORCE , SRC_MAXPOWER ) ;
2017-12-16 14:51:45 +00:00
}
}
}
}
}
// Max Energy
2021-06-11 17:14:12 +01:00
if ( Settings - > energy_max_energy ) {
2023-01-24 15:54:03 +00:00
uint16_t energy_daily_u = ( uint16_t ) ( Energy - > daily_sum * 1000 ) ;
if ( ! Energy - > max_energy_state & & ( RtcTime . hour = = Settings - > energy_max_energy_start ) ) {
Energy - > max_energy_state = 1 ;
2019-09-04 17:06:34 +01:00
ResponseTime_P ( PSTR ( " , \" " D_JSON_ENERGYMONITOR " \" : \" %s \" } " ) , GetStateText ( 1 ) ) ;
2021-04-07 14:07:05 +01:00
MqttPublishPrefixTopicRulesProcess_P ( RESULT_OR_STAT , PSTR ( D_JSON_ENERGYMONITOR ) ) ;
2019-09-04 11:20:04 +01:00
RestorePower ( true , SRC_MAXENERGY ) ;
2017-12-16 14:51:45 +00:00
}
2023-01-24 15:54:03 +00:00
else if ( ( 1 = = Energy - > max_energy_state ) & & ( energy_daily_u > = Settings - > energy_max_energy ) ) {
Energy - > max_energy_state = 2 ;
ResponseTime_P ( PSTR ( " , \" " D_JSON_MAXENERGYREACHED " \" :%3_f} " ) , & Energy - > daily_sum ) ;
2021-04-07 14:07:05 +01:00
MqttPublishPrefixTopicRulesProcess_P ( STAT , S_RSLT_WARNING ) ;
2017-12-16 14:51:45 +00:00
EnergyMqttShow ( ) ;
2024-04-08 11:03:11 +01:00
SetAllPower ( POWER_OFF_FORCE , SRC_MAXENERGY ) ;
2017-12-16 14:51:45 +00:00
}
}
2019-08-01 14:46:12 +01:00
# endif // USE_ENERGY_POWER_LIMIT
2023-03-17 20:05:51 +00:00
EnergyFmtFree ( ) ;
2017-12-16 14:51:45 +00:00
}
2023-01-27 14:53:40 +00:00
void EnergyMqttShow ( void ) {
2017-12-16 14:51:45 +00:00
// {"Time":"2017-12-16T11:48:55","ENERGY":{"Total":0.212,"Yesterday":0.000,"Today":0.014,"Period":2.0,"Power":22.0,"Factor":1.00,"Voltage":213.6,"Current":0.100}}
2020-10-29 12:37:09 +00:00
int tele_period_save = TasmotaGlobal . tele_period ;
TasmotaGlobal . tele_period = 2 ;
2020-10-30 11:29:48 +00:00
ResponseClear ( ) ;
2019-09-04 17:06:34 +01:00
ResponseAppendTime ( ) ;
2019-01-28 13:08:33 +00:00
EnergyShow ( true ) ;
2020-10-29 12:37:09 +00:00
TasmotaGlobal . tele_period = tele_period_save ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
ResponseJsonEnd ( ) ;
2019-11-10 16:40:37 +00:00
MqttPublishTeleSensor ( ) ;
2017-12-16 14:51:45 +00:00
}
2019-08-01 14:46:12 +01:00
# endif // USE_ENERGY_MARGIN_DETECTION
2017-12-16 14:51:45 +00:00
2023-01-27 14:53:40 +00:00
void EnergyEverySecond ( void ) {
2019-09-21 16:10:52 +01:00
// Overtemp check
2023-01-24 15:54:03 +00:00
if ( Energy - > use_overtemp & & TasmotaGlobal . global_update ) {
2021-06-11 17:14:12 +01:00
if ( TasmotaGlobal . power & & ! isnan ( TasmotaGlobal . temperature_celsius ) & & ( TasmotaGlobal . temperature_celsius > ( float ) Settings - > param [ P_OVER_TEMP ] ) ) { // SetOption42 Device overtemp, turn off relays
2020-06-12 15:51:21 +01:00
2021-03-06 14:04:16 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " NRG: Temperature %1_f " ) , & TasmotaGlobal . temperature_celsius ) ;
2020-06-12 15:51:21 +01:00
2024-04-08 11:03:11 +01:00
SetAllPower ( POWER_OFF_FORCE , SRC_OVERTEMP ) ;
2019-05-14 16:46:40 +01:00
}
}
2019-09-21 16:10:52 +01:00
// Invalid data reset
2021-03-06 14:04:16 +00:00
if ( TasmotaGlobal . uptime > ENERGY_WATCHDOG ) {
2023-01-24 15:54:03 +00:00
uint32_t data_valid = Energy - > phase_count ;
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
if ( Energy - > data_valid [ i ] < = ENERGY_WATCHDOG ) {
Energy - > data_valid [ i ] + + ;
if ( Energy - > data_valid [ i ] > ENERGY_WATCHDOG ) {
2021-03-05 17:28:07 +00:00
// Reset energy registers
2023-01-24 15:54:03 +00:00
Energy - > voltage [ i ] = 0 ;
Energy - > current [ i ] = 0 ;
Energy - > active_power [ i ] = 0 ;
if ( ! isnan ( Energy - > apparent_power [ i ] ) ) { Energy - > apparent_power [ i ] = 0 ; }
if ( ! isnan ( Energy - > reactive_power [ i ] ) ) { Energy - > reactive_power [ i ] = 0 ; }
2024-02-03 11:37:57 +00:00
if ( ! isnan ( Energy - > frequency [ i ] ) ) { Energy - > frequency [ i ] = 0 ; }
if ( ! isnan ( Energy - > power_factor [ i ] ) ) { Energy - > power_factor [ i ] = 0 ; }
if ( ! isnan ( Energy - > export_active [ i ] ) ) { Energy - > export_active [ i ] = 0 ; }
2021-03-05 17:28:07 +00:00
data_valid - - ;
}
2019-09-21 16:10:52 +01:00
}
2019-05-30 11:45:02 +01:00
}
2021-03-05 17:28:07 +00:00
if ( ! data_valid ) {
2023-01-24 15:54:03 +00:00
//Energy->start_energy = 0;
2021-03-06 14:04:16 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " NRG: Energy reset by invalid data " ) ) ;
2019-09-21 16:10:52 +01:00
2021-03-05 17:28:07 +00:00
XnrgCall ( FUNC_ENERGY_RESET ) ;
}
2019-09-21 16:10:52 +01:00
}
# ifdef USE_ENERGY_MARGIN_DETECTION
EnergyMarginCheck ( ) ;
2023-05-11 17:10:52 +01:00
if ( Energy - > margin_stable ) {
Energy - > margin_stable - - ;
if ( ! Energy - > margin_stable ) {
EnergyMqttShow ( ) ;
}
}
2019-09-21 16:10:52 +01:00
# endif // USE_ENERGY_MARGIN_DETECTION
2019-05-14 16:46:40 +01:00
}
2017-12-16 14:51:45 +00:00
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-10-02 17:29:05 +01:00
void ResponseCmndEnergyTotalYesterdayToday ( void ) {
2021-09-29 14:33:58 +01:00
float energy_yesterday_ph [ 3 ] ;
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
2021-09-29 14:33:58 +01:00
energy_yesterday_ph [ i ] = ( float ) Settings - > energy_kWhyesterday_ph [ i ] / 100000 ;
2023-01-24 15:54:03 +00:00
Energy - > total [ i ] = ( ( float ) ( RtcSettings . energy_kWhtotal_ph [ i ] ) / 1000 ) + ( ( float ) ( Energy - > kWhtoday_offset [ i ] + Energy - > kWhtoday [ i ] ) / 100000 ) ;
if ( Energy - > local_energy_active_export ) {
Energy - > export_active [ i ] = ( float ) ( RtcSettings . energy_kWhexport_ph [ i ] ) / 1000 ;
2022-04-16 15:07:42 +01:00
}
2021-09-29 14:33:58 +01:00
}
2023-03-17 20:05:51 +00:00
Response_P ( PSTR ( " { \" %s \" :{ \" " D_JSON_TOTAL " \" :%s " ) ,
2021-09-29 14:33:58 +01:00
XdrvMailbox . command ,
2023-03-17 20:05:51 +00:00
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 ) ) ;
2023-01-24 15:54:03 +00:00
if ( Energy - > local_energy_active_export ) {
2022-04-16 15:07:42 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_EXPORT_ACTIVE " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( Energy - > export_active , Settings - > flag2 . energy_resolution ) ) ;
2022-04-16 15:07:42 +01:00
}
ResponseJsonEndEnd ( ) ;
2023-03-17 20:05:51 +00:00
EnergyFmtFree ( ) ;
2021-09-29 14:33:58 +01:00
}
void CmndEnergyTotal ( void ) {
uint32_t values [ 2 ] = { 0 } ;
uint32_t params = ParseParameters ( 2 , values ) ;
2023-01-24 15:54:03 +00:00
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = Energy - > phase_count ) & & ( params > 0 ) ) {
2021-09-29 14:33:58 +01:00
uint32_t phase = XdrvMailbox . index - 1 ;
// Reset Energy Total
2023-02-17 09:53:07 +00:00
RtcSettings . energy_kWhtotal_ph [ phase ] = ( int32_t ) values [ 0 ] ;
2021-09-29 14:33:58 +01:00
Settings - > energy_kWhtotal_ph [ phase ] = RtcSettings . energy_kWhtotal_ph [ phase ] ;
if ( params > 1 ) {
Settings - > energy_kWhtotal_time = values [ 1 ] ;
} else {
2023-01-24 15:54:03 +00:00
Settings - > energy_kWhtotal_time = ( ! Energy - > kWhtoday_offset [ phase ] ) ? LocalTime ( ) : Midnight ( ) ;
2021-09-29 14:33:58 +01:00
}
2023-01-24 15:54:03 +00:00
RtcSettings . energy_usage . last_usage_kWhtotal = ( uint32_t ) ( Energy - > total [ phase ] * 1000 ) ;
2021-09-29 14:33:58 +01:00
}
2021-10-02 17:29:05 +01:00
ResponseCmndEnergyTotalYesterdayToday ( ) ;
2021-09-29 14:33:58 +01:00
}
void CmndEnergyYesterday ( void ) {
uint32_t values [ 2 ] = { 0 } ;
uint32_t params = ParseParameters ( 2 , values ) ;
2023-01-24 15:54:03 +00:00
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = Energy - > phase_count ) & & ( params > 0 ) ) {
2021-09-29 14:33:58 +01:00
uint32_t phase = XdrvMailbox . index - 1 ;
// Reset Energy Yesterday
2023-02-17 09:53:07 +00:00
Settings - > energy_kWhyesterday_ph [ phase ] = ( int32_t ) values [ 0 ] * 100 ;
2021-09-29 14:33:58 +01:00
if ( params > 1 ) {
Settings - > energy_kWhtotal_time = values [ 1 ] ;
}
}
2021-10-02 17:29:05 +01:00
ResponseCmndEnergyTotalYesterdayToday ( ) ;
2021-09-29 14:33:58 +01:00
}
2022-04-16 15:07:42 +01:00
2021-09-29 14:33:58 +01:00
void CmndEnergyToday ( void ) {
2023-01-27 14:53:40 +00:00
// EnergyToday 22 = 0.022 kWh
2021-09-29 14:33:58 +01:00
uint32_t values [ 2 ] = { 0 } ;
uint32_t params = ParseParameters ( 2 , values ) ;
2023-01-24 15:54:03 +00:00
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = Energy - > phase_count ) & & ( params > 0 ) ) {
2021-09-29 14:33:58 +01:00
uint32_t phase = XdrvMailbox . index - 1 ;
// Reset Energy Today
2023-02-17 09:53:07 +00:00
Energy - > kWhtoday_offset [ phase ] = ( int32_t ) values [ 0 ] * 100 ;
2023-01-24 15:54:03 +00:00
Energy - > kWhtoday [ phase ] = 0 ;
Energy - > kWhtoday_delta [ phase ] = 0 ;
Energy - > start_energy [ phase ] = 0 ;
Energy - > period [ phase ] = Energy - > kWhtoday_offset [ phase ] ;
Settings - > energy_kWhtoday_ph [ phase ] = Energy - > kWhtoday_offset [ phase ] ;
RtcSettings . energy_kWhtoday_ph [ phase ] = Energy - > kWhtoday_offset [ phase ] ;
Energy - > daily [ phase ] = ( float ) Energy - > kWhtoday_offset [ phase ] / 100000 ;
2021-09-29 14:33:58 +01:00
if ( params > 1 ) {
Settings - > energy_kWhtotal_time = values [ 1 ] ;
}
2023-01-24 15:54:03 +00:00
else if ( ! RtcSettings . energy_kWhtotal_ph [ phase ] & & ! Energy - > kWhtoday_offset [ phase ] ) {
2021-10-02 17:29:05 +01:00
Settings - > energy_kWhtotal_time = LocalTime ( ) ;
2021-09-29 14:33:58 +01:00
}
}
2021-10-02 17:29:05 +01:00
ResponseCmndEnergyTotalYesterdayToday ( ) ;
}
2022-04-16 15:07:42 +01:00
void CmndEnergyExportActive ( void ) {
2023-01-24 15:54:03 +00:00
if ( Energy - > local_energy_active_export ) {
2022-04-16 15:07:42 +01:00
// EnergyExportActive1 24
// EnergyExportActive1 24,1650111291
uint32_t values [ 2 ] = { 0 } ;
uint32_t params = ParseParameters ( 2 , values ) ;
2023-01-24 15:54:03 +00:00
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = Energy - > phase_count ) & & ( params > 0 ) ) {
2022-04-16 15:07:42 +01:00
uint32_t phase = XdrvMailbox . index - 1 ;
// Reset Energy Export Active
2023-02-17 09:53:07 +00:00
RtcSettings . energy_kWhexport_ph [ phase ] = ( int32_t ) values [ 0 ] ;
2022-04-16 15:07:42 +01:00
Settings - > energy_kWhexport_ph [ phase ] = RtcSettings . energy_kWhexport_ph [ phase ] ;
if ( params > 1 ) {
Settings - > energy_kWhtotal_time = values [ 1 ] ;
}
}
ResponseCmndEnergyTotalYesterdayToday ( ) ;
}
}
2021-10-02 17:29:05 +01:00
void ResponseCmndEnergyUsageExport ( void ) {
2023-01-01 10:32:30 +00:00
float usage1_kWhtotal = ( float ) Settings - > energy_usage . usage1_kWhtotal / 1000 ;
float usage2_kWhtotal = ( float ) Settings - > energy_usage . usage2_kWhtotal / 1000 ;
float return1_kWhtotal = ( float ) Settings - > energy_usage . return1_kWhtotal / 1000 ;
float return2_kWhtotal = ( float ) Settings - > energy_usage . return2_kWhtotal / 1000 ;
2021-10-02 17:29:05 +01:00
Response_P ( PSTR ( " { \" %s \" :{ \" " D_JSON_USAGE " \" :[%*_f,%*_f], \" " D_JSON_EXPORT " \" :[%*_f,%*_f]}} " ) ,
XdrvMailbox . command ,
Settings - > flag2 . energy_resolution , & usage1_kWhtotal ,
Settings - > flag2 . energy_resolution , & usage2_kWhtotal ,
Settings - > flag2 . energy_resolution , & return1_kWhtotal ,
Settings - > flag2 . energy_resolution , & return2_kWhtotal ) ;
}
void CmndEnergyUsage ( void ) {
uint32_t values [ 2 ] = { 0 } ;
uint32_t params = ParseParameters ( 2 , values ) ;
if ( params > 0 ) {
// Reset energy_usage.usage totals
2023-02-17 09:53:07 +00:00
RtcSettings . energy_usage . usage1_kWhtotal = ( int32_t ) values [ 0 ] ;
2021-10-02 17:29:05 +01:00
if ( params > 1 ) {
2023-02-17 09:53:07 +00:00
RtcSettings . energy_usage . usage2_kWhtotal = ( int32_t ) values [ 1 ] ;
2021-10-02 17:29:05 +01:00
}
Settings - > energy_usage . usage1_kWhtotal = RtcSettings . energy_usage . usage1_kWhtotal ;
Settings - > energy_usage . usage2_kWhtotal = RtcSettings . energy_usage . usage2_kWhtotal ;
}
ResponseCmndEnergyUsageExport ( ) ;
}
void CmndEnergyExport ( void ) {
uint32_t values [ 2 ] = { 0 } ;
uint32_t params = ParseParameters ( 2 , values ) ;
if ( params > 0 ) {
// Reset energy_usage.return totals
2023-02-17 09:53:07 +00:00
RtcSettings . energy_usage . return1_kWhtotal = ( int32_t ) values [ 0 ] * 100 ;
2021-10-02 17:29:05 +01:00
if ( params > 1 ) {
2023-02-17 09:53:07 +00:00
RtcSettings . energy_usage . return2_kWhtotal = ( int32_t ) values [ 1 ] * 100 ;
2021-10-02 17:29:05 +01:00
}
Settings - > energy_usage . return1_kWhtotal = RtcSettings . energy_usage . return1_kWhtotal ;
Settings - > energy_usage . return2_kWhtotal = RtcSettings . energy_usage . return2_kWhtotal ;
}
ResponseCmndEnergyUsageExport ( ) ;
2021-09-29 14:33:58 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndTariff ( void ) {
2019-09-25 13:24:49 +01:00
// Tariff1 22:00,23:00 - Tariff1 start hour for Standard Time and Daylight Savings Time
// Tariff2 6:00,7:00 - Tariff2 start hour for Standard Time and Daylight Savings Time
// Tariffx 1320, 1380 = minutes and also 22:00, 23:00
// Tariffx 22, 23 = hours and also 22:00, 23:00
2019-09-10 15:18:23 +01:00
// Tariff9 0/1
2019-09-10 17:04:56 +01:00
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = 2 ) ) {
2019-09-25 13:24:49 +01:00
uint32_t tariff = XdrvMailbox . index - 1 ;
2019-09-10 17:04:56 +01:00
uint32_t time_type = 0 ;
2019-09-25 13:24:49 +01:00
char * p ;
2023-03-04 20:58:03 +00:00
if ( POWER_OFF = = XdrvMailbox . payload )
Settings - > mbflag2 . tariff_forced = 0 ;
else if ( POWER_ON = = XdrvMailbox . payload )
Settings - > mbflag2 . tariff_forced = tariff + 1 ;
else {
char * str = strtok_r ( XdrvMailbox . data , " , " , & p ) ; // 23:15, 22:30
while ( ( str ! = nullptr ) & & ( time_type < 2 ) ) {
char * q ;
uint32_t value = strtol ( str , & q , 10 ) ; // 23 or 22
Settings - > tariff [ tariff ] [ time_type ] = value ;
if ( value < 24 ) { // Below 24 is hours
Settings - > tariff [ tariff ] [ time_type ] * = 60 ; // Multiply hours by 60 minutes
char * minute = strtok_r ( nullptr , " : " , & q ) ;
if ( minute ) {
value = strtol ( minute , nullptr , 10 ) ; // 15 or 30
if ( value > 59 ) {
value = 59 ;
}
Settings - > tariff [ tariff ] [ time_type ] + = value ;
2019-09-25 13:24:49 +01:00
}
}
2023-03-04 20:58:03 +00:00
if ( Settings - > tariff [ tariff ] [ time_type ] > 1439 ) {
Settings - > tariff [ tariff ] [ time_type ] = 1439 ; // Max is 23:59
}
str = strtok_r ( nullptr , " , " , & p ) ;
time_type + + ;
2019-09-25 13:24:49 +01:00
}
2019-08-27 16:01:12 +01:00
}
}
2019-09-10 15:18:23 +01:00
else if ( XdrvMailbox . index = = 9 ) {
2021-06-11 17:14:12 +01:00
Settings - > flag3 . energy_weekend = XdrvMailbox . payload & 1 ; // CMND_TARIFF
2019-08-27 16:01:12 +01:00
}
2023-03-04 20:58:03 +00:00
Response_P ( PSTR ( " { \" %s \" :{ \" Off-Peak \" :{ \" STD \" : \" %s \" , \" DST \" : \" %s \" }, \" Standard \" :{ \" STD \" : \" %s \" , \" DST \" : \" %s \" }, \" Weekend \" : \" %s \" , \" Forced \" : \" %d \" }} " ) ,
2019-09-10 15:18:23 +01:00
XdrvMailbox . command ,
2021-06-11 17:14:12 +01:00
GetMinuteTime ( Settings - > tariff [ 0 ] [ 0 ] ) . c_str ( ) , GetMinuteTime ( Settings - > tariff [ 0 ] [ 1 ] ) . c_str ( ) ,
GetMinuteTime ( Settings - > tariff [ 1 ] [ 0 ] ) . c_str ( ) , GetMinuteTime ( Settings - > tariff [ 1 ] [ 1 ] ) . c_str ( ) ,
2023-03-04 20:58:03 +00:00
GetStateText ( Settings - > flag3 . energy_weekend ) , // Tariff9
Settings - > mbflag2 . tariff_forced ) ; // Tariff<x> ON|OFF
2019-08-27 16:01:12 +01:00
}
2023-01-25 16:05:48 +00:00
uint32_t EnergyGetCalibration ( uint32_t cal_type , uint32_t chan = 0 ) {
2023-01-24 15:54:03 +00:00
uint32_t channel = ( ( 1 = = chan ) & & ( 2 = = Energy - > phase_count ) ) ? 1 : 0 ;
2022-10-30 10:15:17 +00:00
if ( channel ) {
switch ( cal_type ) {
case ENERGY_POWER_CALIBRATION : return Settings - > energy_power_calibration2 ;
case ENERGY_VOLTAGE_CALIBRATION : return Settings - > energy_voltage_calibration2 ;
case ENERGY_CURRENT_CALIBRATION : return Settings - > energy_current_calibration2 ;
}
} else {
switch ( cal_type ) {
case ENERGY_POWER_CALIBRATION : return Settings - > energy_power_calibration ;
case ENERGY_VOLTAGE_CALIBRATION : return Settings - > energy_voltage_calibration ;
case ENERGY_CURRENT_CALIBRATION : return Settings - > energy_current_calibration ;
}
}
return Settings - > energy_frequency_calibration ;
}
2023-01-25 16:05:48 +00:00
void EnergySetCalibration ( uint32_t cal_type , uint32_t value , uint32_t chan = 0 ) {
uint32_t channel = ( ( 1 = = chan ) & & ( 2 = = Energy - > phase_count ) ) ? 1 : 0 ;
if ( channel ) {
switch ( cal_type ) {
case ENERGY_POWER_CALIBRATION : Settings - > energy_power_calibration2 = value ; return ;
case ENERGY_VOLTAGE_CALIBRATION : Settings - > energy_voltage_calibration2 = value ; return ;
case ENERGY_CURRENT_CALIBRATION : Settings - > energy_current_calibration2 = value ; return ;
case ENERGY_FREQUENCY_CALIBRATION : Settings - > energy_frequency_calibration = value ; return ;
}
} else {
switch ( cal_type ) {
case ENERGY_POWER_CALIBRATION : Settings - > energy_power_calibration = value ; return ;
case ENERGY_VOLTAGE_CALIBRATION : Settings - > energy_voltage_calibration = value ; return ;
case ENERGY_CURRENT_CALIBRATION : Settings - > energy_current_calibration = value ; return ;
case ENERGY_FREQUENCY_CALIBRATION : Settings - > energy_frequency_calibration = value ; return ;
}
}
}
2022-10-29 18:08:06 +01:00
void EnergyCommandCalSetResponse ( uint32_t cal_type ) {
2022-10-30 11:20:56 +00:00
if ( XdrvMailbox . payload > 99 ) {
2023-01-25 16:05:48 +00:00
EnergySetCalibration ( cal_type , XdrvMailbox . payload , XdrvMailbox . index - 1 ) ;
2022-10-29 18:08:06 +01:00
}
2022-10-30 10:15:17 +00:00
if ( ENERGY_FREQUENCY_CALIBRATION = = cal_type ) {
2022-10-29 18:08:06 +01:00
ResponseAppend_P ( PSTR ( " %d} " ) , Settings - > energy_frequency_calibration ) ;
} else {
2023-01-24 15:54:03 +00:00
if ( 2 = = Energy - > phase_count ) {
2023-01-25 16:05:48 +00:00
ResponseAppend_P ( PSTR ( " [%d,%d]} " ) , EnergyGetCalibration ( cal_type ) , EnergyGetCalibration ( cal_type , 1 ) ) ;
2022-10-29 18:08:06 +01:00
} else {
2023-01-25 16:05:48 +00:00
ResponseAppend_P ( PSTR ( " %d} " ) , EnergyGetCalibration ( cal_type ) ) ;
2022-10-29 18:08:06 +01:00
}
}
}
void EnergyCommandCalResponse ( uint32_t cal_type ) {
2023-02-12 13:05:33 +00:00
Energy - > command_code = cal_type ; // Is XxxCal command too
if ( XnrgCall ( FUNC_COMMAND ) ) { // XxxCal
2024-01-22 15:57:59 +00:00
ResponseCmnd ( ) ;
2023-02-12 13:05:33 +00:00
EnergyCommandCalSetResponse ( cal_type ) ;
}
2022-10-29 18:08:06 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndPowerCal ( void ) {
2023-02-12 13:05:33 +00:00
EnergyCommandCalResponse ( ENERGY_POWER_CALIBRATION ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndVoltageCal ( void ) {
2023-02-12 13:05:33 +00:00
EnergyCommandCalResponse ( ENERGY_VOLTAGE_CALIBRATION ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndCurrentCal ( void ) {
2023-02-12 13:05:33 +00:00
EnergyCommandCalResponse ( ENERGY_CURRENT_CALIBRATION ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndFrequencyCal ( void ) {
2023-02-12 13:05:33 +00:00
EnergyCommandCalResponse ( ENERGY_FREQUENCY_CALIBRATION ) ;
2021-03-21 16:51:57 +00:00
}
2023-02-12 13:05:33 +00:00
void EnergyCommandSetCalResponse ( uint32_t cal_type ) {
Energy - > command_code = CMND_POWERSET + cal_type ; // Adjust for XxxSet command
if ( XnrgCall ( FUNC_COMMAND ) ) { // XxxSet
Response_P ( PSTR ( " { \" %sCal \" : " ) , XdrvMailbox . command ) ;
EnergyCommandCalSetResponse ( cal_type ) ;
2019-01-05 14:39:56 +00:00
}
2019-08-01 14:46:12 +01:00
}
2023-02-12 13:05:33 +00:00
void CmndPowerSet ( void ) {
EnergyCommandSetCalResponse ( ENERGY_POWER_CALIBRATION ) ;
}
2021-03-21 16:51:57 +00:00
void CmndVoltageSet ( void ) {
2023-02-12 13:05:33 +00:00
EnergyCommandSetCalResponse ( ENERGY_VOLTAGE_CALIBRATION ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndCurrentSet ( void ) {
2023-02-12 13:05:33 +00:00
EnergyCommandSetCalResponse ( ENERGY_CURRENT_CALIBRATION ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndFrequencySet ( void ) {
2023-02-12 13:05:33 +00:00
EnergyCommandSetCalResponse ( ENERGY_FREQUENCY_CALIBRATION ) ;
2019-08-01 14:46:12 +01:00
}
2018-02-03 22:25:05 +00:00
2021-03-21 16:51:57 +00:00
void CmndModuleAddress ( void ) {
2023-01-24 15:54:03 +00:00
if ( ( XdrvMailbox . payload > 0 ) & & ( XdrvMailbox . payload < 4 ) & & ( 1 = = Energy - > phase_count ) ) {
Energy - > command_code = CMND_MODULEADDRESS ;
2019-09-16 15:56:16 +01:00
if ( XnrgCall ( FUNC_COMMAND ) ) { // Module address
ResponseCmndDone ( ) ;
}
}
}
2021-04-08 21:59:44 +01:00
void CmndEnergyConfig ( void ) {
2023-01-24 15:54:03 +00:00
Energy - > command_code = CMND_ENERGYCONFIG ;
2022-03-26 15:02:50 +00:00
ResponseClear ( ) ;
2021-04-08 21:59:44 +01:00
if ( XnrgCall ( FUNC_COMMAND ) ) {
2022-03-08 17:11:52 +00:00
if ( ! ResponseLength ( ) ) {
ResponseCmndDone ( ) ;
}
2021-04-08 21:59:44 +01:00
}
}
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_MARGIN_DETECTION
2023-01-26 14:26:10 +00:00
/*********************************************************************************************\
* USE_ENERGY_MARGIN_DETECTION and USE_ENERGY_POWER_LIMIT
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void EnergyMarginStatus ( void ) {
Response_P ( PSTR ( " { \" " D_CMND_STATUS D_STATUS9_MARGIN " \" :{ \" " D_CMND_POWERDELTA " \" :[%d,%d,%d], \" " D_CMND_POWERLOW " \" :%d, \" " D_CMND_POWERHIGH " \" :%d, \" "
D_CMND_VOLTAGELOW " \" :%d, \" " D_CMND_VOLTAGEHIGH " \" :%d, \" " D_CMND_CURRENTLOW " \" :%d, \" " D_CMND_CURRENTHIGH " \" :%d}} " ) ,
Settings - > energy_power_delta [ 0 ] , Settings - > energy_power_delta [ 1 ] , Settings - > energy_power_delta [ 2 ] , Settings - > energy_min_power , Settings - > energy_max_power ,
Settings - > energy_min_voltage , Settings - > energy_max_voltage , Settings - > energy_min_current , Settings - > energy_max_current ) ;
}
2021-03-21 16:51:57 +00:00
void CmndPowerDelta ( void ) {
2021-04-06 14:23:07 +01:00
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = ENERGY_MAX_PHASES ) ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 32000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_power_delta [ XdrvMailbox . index - 1 ] = XdrvMailbox . payload ;
2020-08-23 17:29:16 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndIdxNumber ( Settings - > energy_power_delta [ XdrvMailbox . index - 1 ] ) ;
2017-12-16 14:51:45 +00:00
}
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndPowerLow ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_min_power = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_min_power ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndPowerHigh ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_power = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_power ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndVoltageLow ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 500 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_min_voltage = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_min_voltage ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndVoltageHigh ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 500 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_voltage = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_voltage ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndCurrentLow ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 25000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_min_current = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_min_current ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndCurrentHigh ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 25000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_current = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_current ) ;
2019-08-01 14:46:12 +01:00
}
# ifdef USE_ENERGY_POWER_LIMIT
2021-03-21 16:51:57 +00:00
void CmndMaxPower ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_power_limit = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_power_limit ) ;
2019-08-01 14:46:12 +01:00
}
2018-05-09 09:49:43 +01:00
2021-03-21 16:51:57 +00:00
void CmndMaxPowerHold ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_power_limit_hold = ( 1 = = XdrvMailbox . payload ) ? MAX_POWER_HOLD : XdrvMailbox . payload ;
2019-08-01 14:46:12 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_power_limit_hold ) ;
2019-08-01 14:46:12 +01:00
}
2018-09-22 14:09:53 +01:00
2021-03-21 16:51:57 +00:00
void CmndMaxPowerWindow ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_power_limit_window = ( 1 = = XdrvMailbox . payload ) ? MAX_POWER_WINDOW : XdrvMailbox . payload ;
2019-08-01 14:46:12 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_power_limit_window ) ;
2019-08-01 14:46:12 +01:00
}
2018-09-22 14:09:53 +01:00
2021-03-21 16:51:57 +00:00
void CmndSafePower ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_power_safe_limit = XdrvMailbox . payload ;
2017-12-16 14:51:45 +00:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_power_safe_limit ) ;
2019-08-01 14:46:12 +01:00
}
2018-05-09 09:49:43 +01:00
2021-03-21 16:51:57 +00:00
void CmndSafePowerHold ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_power_safe_limit_hold = ( 1 = = XdrvMailbox . payload ) ? SAFE_POWER_HOLD : XdrvMailbox . payload ;
2019-08-01 14:46:12 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_power_safe_limit_hold ) ;
2017-12-16 14:51:45 +00:00
}
2021-03-21 16:51:57 +00:00
void CmndSafePowerWindow ( void ) {
2019-08-01 14:46:12 +01:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < 1440 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_power_safe_limit_window = ( 1 = = XdrvMailbox . payload ) ? SAFE_POWER_WINDOW : XdrvMailbox . payload ;
2019-08-01 14:46:12 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_power_safe_limit_window ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndMaxEnergy ( void ) {
2022-12-04 11:25:17 +00:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 6000 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_energy = XdrvMailbox . payload ;
2023-01-24 15:54:03 +00:00
Energy - > max_energy_state = 3 ;
2019-08-01 14:46:12 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_energy ) ;
2019-08-01 14:46:12 +01:00
}
2021-03-21 16:51:57 +00:00
void CmndMaxEnergyStart ( void ) {
2019-08-01 14:46:12 +01:00
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < 24 ) ) {
2021-06-11 17:14:12 +01:00
Settings - > energy_max_energy_start = XdrvMailbox . payload ;
2019-08-01 14:46:12 +01:00
}
2021-06-11 17:14:12 +01:00
ResponseCmndNumber ( Settings - > energy_max_energy_start ) ;
2019-08-01 14:46:12 +01:00
}
# endif // USE_ENERGY_POWER_LIMIT
# endif // USE_ENERGY_MARGIN_DETECTION
2023-01-26 14:26:10 +00:00
/********************************************************************************************/
2021-04-06 14:23:07 +01:00
void EnergyDrvInit ( void ) {
2024-05-05 17:26:21 +01:00
Energy = ( tEnergy * ) calloc ( 1 , sizeof ( tEnergy ) ) ; // Need calloc to reset registers to 0/false
2023-01-24 15:54:03 +00:00
if ( ! Energy ) { return ; }
2023-03-17 20:17:53 +00:00
Energy - > value = nullptr ;
2023-01-24 15:54:03 +00:00
// Energy->voltage_common = false;
// Energy->frequency_common = false;
// Energy->use_overtemp = false;
2021-04-06 14:23:07 +01:00
for ( uint32_t phase = 0 ; phase < ENERGY_MAX_PHASES ; phase + + ) {
2023-01-24 15:54:03 +00:00
Energy - > apparent_power [ phase ] = NAN ;
Energy - > reactive_power [ phase ] = NAN ;
Energy - > power_factor [ phase ] = NAN ;
Energy - > frequency [ phase ] = NAN ;
Energy - > export_active [ phase ] = NAN ;
2021-04-06 14:23:07 +01:00
}
2023-01-24 15:54:03 +00:00
Energy - > phase_count = 1 ; // Number of phases active
Energy - > voltage_available = true ; // Enable if voltage is measured
Energy - > current_available = true ; // Enable if current is measured
Energy - > power_on = true ;
2021-04-06 14:23:07 +01:00
TasmotaGlobal . energy_driver = ENERGY_NONE ;
2022-08-05 14:25:39 +01:00
XnrgCall ( FUNC_PRE_INIT ) ; // Find first energy driver
2022-10-06 22:27:43 +01:00
if ( TasmotaGlobal . energy_driver ) {
AddLog ( LOG_LEVEL_INFO , PSTR ( " NRG: Init driver %d " ) , TasmotaGlobal . energy_driver ) ;
}
2021-04-06 14:23:07 +01:00
}
2018-11-14 13:32:09 +00:00
void EnergySnsInit ( void )
2018-02-03 22:25:05 +00:00
{
2018-09-04 15:22:34 +01:00
XnrgCall ( FUNC_INIT ) ;
2018-02-13 13:30:30 +00:00
2020-10-30 11:29:48 +00:00
if ( TasmotaGlobal . energy_driver ) {
2022-12-22 15:09:41 +00:00
/*
2022-11-14 16:11:38 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " NRG: Rtc valid %d, kWhtoday_ph Rtc %d/%d/%d, Set %d/%d/%d " ) ,
RtcSettingsValid ( ) ,
RtcSettings . energy_kWhtoday_ph [ 0 ] , RtcSettings . energy_kWhtoday_ph [ 1 ] , RtcSettings . energy_kWhtoday_ph [ 2 ] ,
Settings - > energy_kWhtoday_ph [ 0 ] , Settings - > energy_kWhtoday_ph [ 1 ] , Settings - > energy_kWhtoday_ph [ 2 ]
) ;
2022-12-22 15:09:41 +00:00
*/
2022-08-05 14:25:39 +01:00
for ( uint32_t i = 0 ; i < 3 ; i + + ) {
2023-01-24 15:54:03 +00:00
// Energy->kWhtoday_offset[i] = 0; // Reset by EnergyDrvInit()
2022-08-05 14:25:39 +01:00
// 20220805 - Change from https://github.com/arendst/Tasmota/issues/16118
if ( RtcSettingsValid ( ) ) {
2023-01-24 15:54:03 +00:00
Energy - > kWhtoday_offset [ i ] = RtcSettings . energy_kWhtoday_ph [ i ] ;
2022-08-05 14:25:39 +01:00
RtcSettings . energy_kWhtoday_ph [ i ] = 0 ;
2023-01-24 15:54:03 +00:00
Energy - > kWhtoday_offset_init = true ;
2021-09-29 14:33:58 +01:00
}
2023-01-24 15:54:03 +00:00
// Energy->kWhtoday_ph[i] = 0; // Reset by EnergyDrvInit()
// Energy->kWhtoday_delta[i] = 0; // Reset by EnergyDrvInit()
Energy - > period [ i ] = Energy - > kWhtoday_offset [ i ] ;
if ( Energy - > local_energy_active_export ) {
Energy - > export_active [ i ] = 0 ; // Was set to NAN by EnergyDrvInit()
2022-04-16 15:07:42 +01:00
}
2021-09-29 14:33:58 +01:00
}
2018-02-04 17:09:09 +00:00
EnergyUpdateToday ( ) ;
2019-09-07 15:31:39 +01:00
ticker_energy . attach_ms ( 200 , Energy200ms ) ;
2017-12-16 14:51:45 +00:00
}
}
2021-09-29 14:33:58 +01:00
void EnergyShow ( bool json ) {
2023-01-31 21:30:50 +00:00
bool voltage_common = ( Settings - > flag6 . no_voltage_common ) ? false : Energy - > voltage_common ;
bool frequency_common = ( Settings - > flag6 . no_voltage_common ) ? false : Energy - > frequency_common ;
if ( voltage_common ) {
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
Energy - > voltage [ i ] = Energy - > voltage [ 0 ] ;
2019-09-15 12:10:32 +01:00
}
}
2023-01-24 15:54:03 +00:00
float apparent_power [ Energy - > phase_count ] ;
float reactive_power [ Energy - > phase_count ] ;
float power_factor [ Energy - > phase_count ] ;
if ( ! Energy - > type_dc ) {
if ( Energy - > current_available & & Energy - > voltage_available ) {
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
apparent_power [ i ] = Energy - > apparent_power [ i ] ;
2021-09-29 14:33:58 +01:00
if ( isnan ( apparent_power [ i ] ) ) {
2023-01-24 15:54:03 +00:00
apparent_power [ i ] = Energy - > voltage [ i ] * Energy - > current [ i ] ;
2019-09-15 12:10:32 +01:00
}
2023-02-28 09:17:30 +00:00
else if ( 0 = = Energy - > current [ i ] ) {
apparent_power [ i ] = 0 ;
}
2023-01-24 15:54:03 +00:00
if ( apparent_power [ i ] < Energy - > active_power [ i ] ) { // Should be impossible
Energy - > active_power [ i ] = apparent_power [ i ] ;
2019-09-15 12:10:32 +01:00
}
2018-09-28 14:48:42 +01:00
2023-01-24 15:54:03 +00:00
power_factor [ i ] = Energy - > power_factor [ i ] ;
2021-09-29 14:33:58 +01:00
if ( isnan ( power_factor [ i ] ) ) {
2023-01-24 15:54:03 +00:00
power_factor [ i ] = ( Energy - > active_power [ i ] & & apparent_power [ i ] ) ? Energy - > active_power [ i ] / apparent_power [ i ] : 0 ;
2021-09-29 14:33:58 +01:00
if ( power_factor [ i ] > 1 ) {
power_factor [ i ] = 1 ;
2019-09-15 12:10:32 +01:00
}
}
2023-01-24 15:54:03 +00:00
reactive_power [ i ] = Energy - > reactive_power [ i ] ;
2021-09-29 14:33:58 +01:00
if ( isnan ( reactive_power [ i ] ) ) {
reactive_power [ i ] = 0 ;
2023-01-24 15:54:03 +00:00
uint32_t difference = ( ( uint32_t ) ( apparent_power [ i ] * 100 ) - ( uint32_t ) ( Energy - > active_power [ i ] * 100 ) ) / 10 ;
if ( ( Energy - > current [ i ] > 0.005f ) & & ( ( difference > 15 ) | | ( difference > ( uint32_t ) ( apparent_power [ i ] * 100 / 1000 ) ) ) ) {
2019-09-15 12:10:32 +01:00
// calculating reactive power only if current is greater than 0.005A and
// difference between active and apparent power is greater than 1.5W or 1%
2023-01-24 15:54:03 +00:00
//reactive_power[i] = (float)(RoundSqrtInt((uint64_t)(apparent_power[i] * apparent_power[i] * 100) - (uint64_t)(Energy->active_power[i] * Energy->active_power[i] * 100))) / 10;
float power_diff = apparent_power [ i ] * apparent_power [ i ] - Energy - > active_power [ i ] * Energy - > active_power [ i ] ;
2021-05-16 17:09:53 +01:00
if ( power_diff < 10737418 ) // 2^30 / 100 (RoundSqrtInt is limited to 2^30-1)
2022-04-19 14:44:53 +01:00
reactive_power [ i ] = ( float ) ( RoundSqrtInt ( ( uint32_t ) ( power_diff * 100.0f ) ) ) / 10.0f ;
2021-05-16 17:09:53 +01:00
else
2021-09-29 14:33:58 +01:00
reactive_power [ i ] = ( float ) ( SqrtInt ( ( uint32_t ) ( power_diff ) ) ) ;
2019-09-15 12:10:32 +01:00
}
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2023-02-28 09:17:30 +00:00
else if ( 0 = = Energy - > current [ i ] ) {
reactive_power [ i ] = 0 ;
}
2018-09-28 14:48:42 +01:00
2019-09-15 12:10:32 +01:00
}
2018-09-28 14:48:42 +01:00
}
}
2023-01-24 15:54:03 +00:00
float energy_yesterday_ph [ Energy - > phase_count ] ;
2023-10-13 12:56:04 +01:00
float active_power_sum = 0.0f ;
int negative_phases = 0 ;
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
2021-09-29 14:33:58 +01:00
energy_yesterday_ph [ i ] = ( float ) Settings - > energy_kWhyesterday_ph [ i ] / 100000 ;
2023-01-24 15:54:03 +00:00
active_power_sum + = Energy - > active_power [ i ] ;
2023-10-13 12:56:04 +01:00
negative_phases + = ( Energy - > active_power [ i ] < 0 ) ? - 1 : 1 ;
2021-09-29 14:33:58 +01:00
}
2021-09-29 13:53:23 +01:00
2020-05-22 16:48:21 +01:00
bool energy_tariff = false ;
2021-09-29 14:33:58 +01:00
float energy_usage [ 2 ] ;
float energy_return [ 2 ] ;
2023-03-04 20:58:03 +00:00
if ( Settings - > mbflag2 . tariff_forced | | ( Settings - > tariff [ 0 ] [ 0 ] ! = Settings - > tariff [ 1 ] [ 0 ] ) ) {
2023-01-01 10:32:30 +00:00
energy_usage [ 0 ] = ( float ) RtcSettings . energy_usage . usage1_kWhtotal / 1000 ; // Tariff1
energy_usage [ 1 ] = ( float ) RtcSettings . energy_usage . usage2_kWhtotal / 1000 ; // Tariff2
energy_return [ 0 ] = ( float ) RtcSettings . energy_usage . return1_kWhtotal / 1000 ; // Tariff1
energy_return [ 1 ] = ( float ) RtcSettings . energy_usage . return2_kWhtotal / 1000 ; // Tariff2
2020-05-22 16:48:21 +01:00
energy_tariff = true ;
2019-09-15 17:05:23 +01:00
}
2017-12-16 14:51:45 +00:00
if ( json ) {
2020-10-29 12:37:09 +00:00
bool show_energy_period = ( 0 = = TasmotaGlobal . tele_period ) ;
2019-09-10 11:31:08 +01:00
2020-05-22 16:48:21 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_RSLT_ENERGY " \" :{ \" " D_JSON_TOTAL_START_TIME " \" : \" %s \" , \" " D_JSON_TOTAL " \" :%s " ) ,
2023-04-14 16:42:31 +01:00
GetDT ( Settings - > energy_kWhtotal_time ) . c_str ( ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( Energy - > total , Settings - > flag2 . energy_resolution , 2 ) ) ;
2020-05-22 16:48:21 +01:00
if ( energy_tariff ) {
ResponseAppend_P ( PSTR ( " , \" " D_JSON_TOTAL D_CMND_TARIFF " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( energy_usage , Settings - > flag2 . energy_resolution , 6 ) ) ;
2020-05-22 16:48:21 +01:00
}
2023-03-17 20:05:51 +00:00
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 ) ) ;
2019-09-15 17:05:23 +01:00
2021-10-02 17:29:05 +01:00
/*
2021-02-09 15:13:40 +00:00
# if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP)
2023-01-24 15:54:03 +00:00
if ( ! isnan ( Energy - > import_active [ 0 ] ) ) {
2020-08-18 21:09:33 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_IMPORT_ACTIVE " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( Energy - > import_active , Settings - > flag2 . energy_resolution ) ) ;
2020-08-18 21:09:33 +01:00
if ( energy_tariff ) {
ResponseAppend_P ( PSTR ( " , \" " D_JSON_IMPORT D_CMND_TARIFF " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( energy_return , Settings - > flag2 . energy_resolution , 6 ) ) ;
2020-08-18 21:09:33 +01:00
}
}
2021-02-09 15:13:40 +00:00
# endif // SDM630_IMPORT || SDM72_IMPEXP
2021-10-02 17:29:05 +01:00
*/
2020-08-18 21:09:33 +01:00
2023-01-24 15:54:03 +00:00
if ( ! isnan ( Energy - > export_active [ 0 ] ) ) {
uint32_t single = ( ! isnan ( Energy - > export_active [ 1 ] ) & & ! isnan ( Energy - > export_active [ 2 ] ) ) ? 0 : 1 ;
2023-03-17 20:05:51 +00:00
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 ) ) ;
2020-05-22 16:48:21 +01:00
if ( energy_tariff ) {
2020-05-22 17:31:14 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_EXPORT D_CMND_TARIFF " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( energy_return , Settings - > flag2 . energy_resolution , 6 ) ) ;
2020-05-22 16:48:21 +01:00
}
2019-09-10 11:31:08 +01:00
}
2019-09-15 17:05:23 +01:00
2019-09-10 11:31:08 +01:00
if ( show_energy_period ) {
2023-01-24 15:54:03 +00:00
float energy_period [ Energy - > phase_count ] ;
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
2023-03-11 16:01:43 +00:00
energy_period [ i ] = ( float ) ( RtcSettings . energy_kWhtoday_ph [ i ] - Energy - > period [ i ] ) / 100 ; // Wh
2023-01-24 15:54:03 +00:00
Energy - > period [ i ] = RtcSettings . energy_kWhtoday_ph [ i ] ;
2021-09-29 14:33:58 +01:00
}
ResponseAppend_P ( PSTR ( " , \" " D_JSON_PERIOD " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( energy_period , Settings - > flag2 . wattage_resolution ) ) ;
2019-09-10 11:31:08 +01:00
}
2021-09-29 14:33:58 +01:00
2019-09-15 12:10:32 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_POWERUSAGE " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( Energy - > active_power , Settings - > flag2 . wattage_resolution ) ) ;
2023-01-24 15:54:03 +00:00
if ( ! Energy - > type_dc ) {
if ( Energy - > current_available & & Energy - > voltage_available ) {
2023-03-17 20:05:51 +00:00
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 ) ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2024-01-21 10:37:04 +00:00
}
if ( ! isnan ( Energy - > frequency [ 0 ] ) ) {
ResponseAppend_P ( PSTR ( " , \" " D_JSON_FREQUENCY " \" :%s " ) ,
EnergyFmt ( Energy - > frequency , Settings - > flag2 . frequency_resolution , frequency_common ) ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2023-01-24 15:54:03 +00:00
if ( Energy - > voltage_available ) {
2019-09-15 12:10:32 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_VOLTAGE " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( Energy - > voltage , Settings - > flag2 . voltage_resolution , voltage_common ) ) ;
2018-09-28 14:48:42 +01:00
}
2023-01-24 15:54:03 +00:00
if ( Energy - > current_available ) {
2019-09-15 12:10:32 +01:00
ResponseAppend_P ( PSTR ( " , \" " D_JSON_CURRENT " \" :%s " ) ,
2023-03-17 20:05:51 +00:00
EnergyFmt ( Energy - > current , Settings - > flag2 . current_resolution ) ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2019-09-01 16:51:25 +01:00
XnrgCall ( FUNC_JSON_APPEND ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
ResponseJsonEnd ( ) ;
2018-09-28 14:48:42 +01:00
2017-12-16 14:51:45 +00:00
# ifdef USE_DOMOTICZ
if ( show_energy_period ) { // Only send if telemetry
2021-09-29 14:33:58 +01:00
char temp_chr [ FLOATSZ ] ;
2023-01-24 15:54:03 +00:00
if ( Energy - > voltage_available ) {
dtostrfd ( Energy - > voltage [ 0 ] , Settings - > flag2 . voltage_resolution , temp_chr ) ;
2021-09-29 14:33:58 +01:00
DomoticzSensor ( DZ_VOLTAGE , temp_chr ) ; // Voltage
}
2023-01-24 15:54:03 +00:00
if ( Energy - > current_available ) {
dtostrfd ( Energy - > current [ 0 ] , Settings - > flag2 . current_resolution , temp_chr ) ;
2021-09-29 14:33:58 +01:00
DomoticzSensor ( DZ_CURRENT , temp_chr ) ; // Current
}
2023-01-24 15:54:03 +00:00
dtostrfd ( Energy - > total_sum * 1000 , 1 , temp_chr ) ;
2021-09-29 14:33:58 +01:00
DomoticzSensorPowerEnergy ( ( int ) active_power_sum , temp_chr ) ; // PowerUsage, EnergyToday
2019-08-27 16:01:12 +01:00
2021-09-29 14:33:58 +01:00
char energy_usage_chr [ 2 ] [ FLOATSZ ] ;
char energy_return_chr [ 2 ] [ FLOATSZ ] ;
2023-01-01 10:32:30 +00:00
dtostrfd ( ( float ) RtcSettings . energy_usage . usage1_kWhtotal , 1 , energy_usage_chr [ 0 ] ) ; // Tariff1
dtostrfd ( ( float ) RtcSettings . energy_usage . usage2_kWhtotal , 1 , energy_usage_chr [ 1 ] ) ; // Tariff2
dtostrfd ( ( float ) RtcSettings . energy_usage . return1_kWhtotal , 1 , energy_return_chr [ 0 ] ) ;
dtostrfd ( ( float ) RtcSettings . energy_usage . return2_kWhtotal , 1 , energy_return_chr [ 1 ] ) ;
2021-09-29 14:33:58 +01:00
DomoticzSensorP1SmartMeter ( energy_usage_chr [ 0 ] , energy_usage_chr [ 1 ] , energy_return_chr [ 0 ] , energy_return_chr [ 1 ] , ( int ) active_power_sum ) ;
2019-08-27 16:01:12 +01:00
2017-12-16 14:51:45 +00:00
}
# endif // USE_DOMOTICZ
2018-05-17 05:44:46 +01:00
# ifdef USE_KNX
if ( show_energy_period ) {
2023-01-24 15:54:03 +00:00
if ( Energy - > voltage_available ) {
KnxSensor ( KNX_ENERGY_VOLTAGE , Energy - > voltage [ 0 ] ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2023-01-24 15:54:03 +00:00
if ( Energy - > current_available ) {
KnxSensor ( KNX_ENERGY_CURRENT , Energy - > current [ 0 ] ) ;
2019-09-15 12:10:32 +01:00
}
2021-09-29 14:33:58 +01:00
KnxSensor ( KNX_ENERGY_POWER , active_power_sum ) ;
2023-01-24 15:54:03 +00:00
if ( ! Energy - > type_dc ) {
2021-09-29 14:33:58 +01:00
KnxSensor ( KNX_ENERGY_POWERFACTOR , power_factor [ 0 ] ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2023-01-24 15:54:03 +00:00
KnxSensor ( KNX_ENERGY_DAILY , Energy - > daily_sum ) ;
KnxSensor ( KNX_ENERGY_TOTAL , Energy - > total_sum ) ;
KnxSensor ( KNX_ENERGY_YESTERDAY , Energy - > yesterday_sum ) ;
2018-05-17 05:44:46 +01:00
}
# endif // USE_KNX
2017-12-16 14:51:45 +00:00
# ifdef USE_WEBSERVER
} else {
2022-04-12 09:22:32 +01:00
// Need a new table supporting more columns using empty columns (with in data rows) as easy column spacing
2022-04-11 17:33:57 +01:00
// {s}</th><th></th><th>Head1</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><td>{e}
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><th>Head3</th><th></th><td>{e}
2022-04-12 09:22:32 +01:00
// {s}</th><th></th><th>Head1</th><th></th><th>Head2</th><th></th><th>Head3</th><th></th><th>Head4</th><th></th><td>{e}
2024-01-15 14:36:59 +00:00
WSContentSend_P ( PSTR ( " </table>{t}{s}</th><th></th> " ) ) ; // First column is empty ({t} = <table style='width:100%'>, {s} = <tr><th>)
2023-01-31 21:30:50 +00:00
bool label_o = voltage_common ;
2023-01-27 14:53:40 +00:00
bool no_label = ( 1 = = Energy - > phase_count ) ;
2023-03-17 20:05:51 +00:00
char number [ 4 ] ;
2023-01-24 15:54:03 +00:00
for ( uint32_t i = 0 ; i < Energy - > phase_count ; i + + ) {
2023-03-17 20:05:51 +00:00
WSContentSend_P ( PSTR ( " <th style='text-align:center'>%s%s<th></th> " ) , ( no_label ) ? " " : ( label_o ) ? " O " : " L " , ( no_label ) ? " " : itoa ( i + 1 , number , 10 ) ) ;
2022-03-15 14:43:23 +00:00
}
2022-04-11 17:33:57 +01:00
WSContentSend_P ( PSTR ( " <td>{e} " ) ) ; // Last column is units ({e} = </td></tr>)
2023-01-24 15:54:03 +00:00
if ( Energy - > voltage_available ) {
2023-03-17 20:05:51 +00:00
WSContentSend_PD ( HTTP_SNS_VOLTAGE , WebEnergyFmt ( Energy - > voltage , Settings - > flag2 . voltage_resolution , voltage_common ) ) ;
2021-09-29 14:33:58 +01:00
}
2024-01-21 10:37:04 +00:00
if ( ! isnan ( Energy - > frequency [ 0 ] ) ) {
WSContentSend_PD ( PSTR ( " {s} " D_FREQUENCY " {m}%s " D_UNIT_HERTZ " {e} " ) ,
WebEnergyFmt ( Energy - > frequency , Settings - > flag2 . frequency_resolution , frequency_common ) ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2023-01-24 15:54:03 +00:00
if ( Energy - > current_available ) {
2023-03-17 20:05:51 +00:00
WSContentSend_PD ( HTTP_SNS_CURRENT , WebEnergyFmt ( Energy - > current , Settings - > flag2 . current_resolution ) ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2023-03-17 20:05:51 +00:00
WSContentSend_PD ( HTTP_SNS_POWER , WebEnergyFmt ( Energy - > active_power , Settings - > flag2 . wattage_resolution ) ) ;
2023-01-24 15:54:03 +00:00
if ( ! Energy - > type_dc ) {
if ( Energy - > current_available & & Energy - > voltage_available ) {
2023-03-18 17:26:43 +00:00
WSContentSend_PD ( HTTP_SNS_POWERUSAGE_APPARENT , WebEnergyFmt ( apparent_power , Settings - > flag2 . wattage_resolution ) ) ;
WSContentSend_PD ( HTTP_SNS_POWERUSAGE_REACTIVE , WebEnergyFmt ( reactive_power , Settings - > flag2 . wattage_resolution ) ) ;
WSContentSend_PD ( HTTP_SNS_POWER_FACTOR , WebEnergyFmt ( power_factor , 2 ) ) ;
Add support for Shelly 1PM Template
Add support for Shelly 1PM Template {"NAME":"Shelly 1PM","GPIO":[56,0,0,0,82,134,0,0,0,0,0,21,0],"FLAG":2,"BASE":18} (#5716)
2019-05-13 17:26:07 +01:00
}
2018-09-28 14:48:42 +01:00
}
2023-10-13 12:56:04 +01:00
if ( abs ( negative_phases ) ! = Energy - > phase_count ) { // Provide total power if producing power (PV) and multi phase
WSContentSend_PD ( HTTP_SNS_POWER_TOTAL , WebEnergyFmt ( Energy - > active_power , Settings - > flag2 . wattage_resolution , 3 ) ) ;
}
2023-03-18 17:26:43 +00:00
WSContentSend_PD ( HTTP_SNS_ENERGY_TODAY , WebEnergyFmt ( Energy - > daily , Settings - > flag2 . energy_resolution , 2 ) ) ;
WSContentSend_PD ( HTTP_SNS_ENERGY_YESTERDAY , WebEnergyFmt ( energy_yesterday_ph , Settings - > flag2 . energy_resolution , 2 ) ) ;
WSContentSend_PD ( HTTP_SNS_ENERGY_TOTAL , WebEnergyFmt ( Energy - > total , Settings - > flag2 . energy_resolution , 2 ) ) ;
2023-01-24 15:54:03 +00:00
if ( ! isnan ( Energy - > export_active [ 0 ] ) ) {
uint32_t single = ( ! isnan ( Energy - > export_active [ 1 ] ) & & ! isnan ( Energy - > export_active [ 2 ] ) ) ? 2 : 1 ;
2023-03-18 17:26:43 +00:00
WSContentSend_PD ( HTTP_SNS_EXPORT_ACTIVE , WebEnergyFmt ( Energy - > export_active , Settings - > flag2 . energy_resolution , single ) ) ;
2019-09-10 11:31:08 +01:00
}
2022-03-15 14:43:23 +00:00
XnrgCall ( FUNC_WEB_COL_SENSOR ) ;
2024-01-15 14:36:59 +00:00
WSContentSend_P ( PSTR ( " </table>{t} " ) ) ; // {t} = <table style='width:100%'> - Define for next FUNC_WEB_SENSOR
2019-09-01 16:51:25 +01:00
XnrgCall ( FUNC_WEB_SENSOR ) ;
2017-12-16 14:51:45 +00:00
# endif // USE_WEBSERVER
}
2023-03-17 20:05:51 +00:00
EnergyFmtFree ( ) ;
2017-12-16 14:51:45 +00:00
}
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-11-11 09:44:56 +00:00
bool Xdrv03 ( uint32_t function )
2018-01-05 11:26:19 +00:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2018-01-05 11:26:19 +00:00
2018-09-04 15:22:34 +01:00
if ( FUNC_PRE_INIT = = function ) {
2021-04-06 14:23:07 +01:00
EnergyDrvInit ( ) ;
2018-09-04 15:22:34 +01:00
}
2020-10-30 11:29:48 +00:00
else if ( TasmotaGlobal . energy_driver ) {
2018-01-05 11:26:19 +00:00
switch ( function ) {
2019-03-30 12:03:45 +00:00
case FUNC_LOOP :
2022-11-12 14:57:46 +00:00
case FUNC_SLEEP_LOOP :
2019-03-30 12:03:45 +00:00
XnrgCall ( FUNC_LOOP ) ;
break ;
2019-09-07 15:31:39 +01:00
case FUNC_EVERY_250_MSECOND :
2020-10-30 11:45:34 +00:00
if ( TasmotaGlobal . uptime > 4 ) {
XnrgCall ( FUNC_EVERY_250_MSECOND ) ;
}
2019-09-07 15:31:39 +01:00
break ;
2020-06-13 14:10:12 +01:00
case FUNC_EVERY_SECOND :
XnrgCall ( FUNC_EVERY_SECOND ) ;
break ;
2019-09-08 15:57:56 +01:00
case FUNC_SERIAL :
result = XnrgCall ( FUNC_SERIAL ) ;
break ;
2019-08-01 14:46:12 +01:00
# ifdef USE_ENERGY_MARGIN_DETECTION
2018-01-05 11:26:19 +00:00
case FUNC_SET_POWER :
2023-01-24 15:54:03 +00:00
Energy - > power_steady_counter = 2 ;
2018-01-05 11:26:19 +00:00
break ;
2019-08-01 14:46:12 +01:00
# endif // USE_ENERGY_MARGIN_DETECTION
case FUNC_COMMAND :
result = DecodeCommand ( kEnergyCommands , EnergyCommand ) ;
break ;
2022-11-11 10:15:05 +00:00
case FUNC_NETWORK_UP :
XnrgCall ( FUNC_NETWORK_UP ) ;
break ;
case FUNC_NETWORK_DOWN :
XnrgCall ( FUNC_NETWORK_DOWN ) ;
break ;
2023-12-27 21:03:56 +00:00
case FUNC_ACTIVE :
result = true ;
break ;
2018-01-05 11:26:19 +00:00
}
}
return result ;
}
2022-11-11 09:44:56 +00:00
bool Xsns03 ( uint32_t function )
2017-12-16 14:51:45 +00:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2017-12-16 14:51:45 +00:00
2020-10-30 11:29:48 +00:00
if ( TasmotaGlobal . energy_driver ) {
2017-12-16 14:51:45 +00:00
switch ( function ) {
2017-12-25 16:41:12 +00:00
case FUNC_EVERY_SECOND :
2019-09-21 16:10:52 +01:00
EnergyEverySecond ( ) ;
2017-12-16 14:51:45 +00:00
break ;
2017-12-25 16:41:12 +00:00
case FUNC_JSON_APPEND :
2019-01-28 13:08:33 +00:00
EnergyShow ( true ) ;
2017-12-16 14:51:45 +00:00
break ;
# ifdef USE_WEBSERVER
2019-03-19 16:31:43 +00:00
case FUNC_WEB_SENSOR :
2019-01-28 13:08:33 +00:00
EnergyShow ( false ) ;
2017-12-16 14:51:45 +00:00
break ;
# endif // USE_WEBSERVER
2017-12-25 16:41:12 +00:00
case FUNC_SAVE_BEFORE_RESTART :
2017-12-16 14:51:45 +00:00
EnergySaveState ( ) ;
break ;
2019-09-08 15:57:56 +01:00
case FUNC_INIT :
EnergySnsInit ( ) ;
break ;
2017-12-16 14:51:45 +00:00
}
}
return result ;
}
2023-02-05 15:22:18 +00:00
# endif // USE_ENERGY_SENSOR
# endif // ESP8266