mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-25 19:56:30 +00:00
Change ESP32 support for energy margin checks, like `MaxPower2
` per phase (#21695)
- Add ESP32 support for power and energy limit checks, like ``MaxEnergy2`` per phase (#21695) - Bump version v14.1.0.3
This commit is contained in:
parent
20d0207890
commit
178d42c286
19
CHANGELOG.md
19
CHANGELOG.md
@ -3,7 +3,20 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased] - Development
|
||||
|
||||
## [14.1.0.2]
|
||||
## [14.1.0.3]
|
||||
### Added
|
||||
- ESP32 support for power and energy limit checks, like ``MaxEnergy2`` per phase (#21695)
|
||||
|
||||
### Breaking Changed
|
||||
|
||||
### Changed
|
||||
- ESP32 support for energy margin checks, like ``MaxPower2`` per phase (#21695)
|
||||
|
||||
### Fixed
|
||||
|
||||
### Removed
|
||||
|
||||
## [14.1.0.2] 20240627
|
||||
### Added
|
||||
- Support for Sonoff WTS01 temperature sensor using SerialBridge in ``SSerialMode 3``
|
||||
- Berry `classof` extended to class methods (#21615)
|
||||
@ -14,8 +27,6 @@ All notable changes to this project will be documented in this file.
|
||||
- Matter show event name in logs (#21649)
|
||||
- Matter full support of events (#21698)
|
||||
|
||||
### Breaking Changed
|
||||
|
||||
### Changed
|
||||
- SerialBridge command ``SSerialSend9`` replaced by ``SSerialMode``
|
||||
- SML replace vars in descriptor and line (#21622)
|
||||
@ -37,8 +48,6 @@ All notable changes to this project will be documented in this file.
|
||||
- Matter resumption final ack (#21673)
|
||||
- ESP32 allow use of UART0 with enabled USB_CDC_CONSOLE (#21496)
|
||||
|
||||
### Removed
|
||||
|
||||
## [14.1.0.1] 20240611
|
||||
### Added
|
||||
- Berry solidification of `bytes` instances (#21558)
|
||||
|
@ -119,11 +119,12 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
|
||||
|
||||
[Complete list](BUILDS.md) of available feature and sensors.
|
||||
|
||||
## Changelog v14.1.0.2
|
||||
## Changelog v14.1.0.3
|
||||
### Added
|
||||
- Support for QMP6988 temperature and pressure sensor
|
||||
- Support for Sonoff WTS01 temperature sensor using SerialBridge in ``SSerialMode 3``
|
||||
- Extend command ``SetOption147 1`` to disable publish of IRReceived MQTT messages [#21574](https://github.com/arendst/Tasmota/issues/21574)
|
||||
- ESP32 support for power and energy limit checks, like ``MaxEnergy2`` per phase [#21695](https://github.com/arendst/Tasmota/issues/21695)
|
||||
- Berry solidification of `bytes` instances [#21558](https://github.com/arendst/Tasmota/issues/21558)
|
||||
- Berry automatic rounding of float to int when calling C mapped functions [#21601](https://github.com/arendst/Tasmota/issues/21601)
|
||||
- Berry add `math.round` [#21602](https://github.com/arendst/Tasmota/issues/21602)
|
||||
@ -148,7 +149,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
|
||||
- SML replace vars in descriptor and line [#21622](https://github.com/arendst/Tasmota/issues/21622)
|
||||
- NeoPool using temperature as only frequently changing value for NPTeleperiod [#21628](https://github.com/arendst/Tasmota/issues/21628)
|
||||
- NeoPool make compiler setting available by `user_config_override.h` [#21645](https://github.com/arendst/Tasmota/issues/21645)
|
||||
- ESP32 Core3 platform update from 2024.05.13 to 2024.06.10 [#21569](https://github.com/arendst/Tasmota/issues/21569)
|
||||
- ESP32 support for energy margin checks, like ``MaxPower2`` per phase [#21695](https://github.com/arendst/Tasmota/issues/21695)
|
||||
- ESP32 MI32 refactoring, bugfixes, generic device scanning [#21603](https://github.com/arendst/Tasmota/issues/21603)
|
||||
- ESP32 MI32 improve parser [#21648](https://github.com/arendst/Tasmota/issues/21648)
|
||||
- Matter refactoring of bridged devices [#21575](https://github.com/arendst/Tasmota/issues/21575)
|
||||
|
@ -22,6 +22,6 @@
|
||||
|
||||
#define TASMOTA_SHA_SHORT // Filled by Github sed
|
||||
|
||||
const uint32_t TASMOTA_VERSION = 0x0E010002; // 14.1.0.2
|
||||
const uint32_t TASMOTA_VERSION = 0x0E010003; // 14.1.0.3
|
||||
|
||||
#endif // _TASMOTA_VERSION_H_
|
||||
|
@ -690,6 +690,7 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
|
||||
// state 2 = POWER_TOGGLE = Toggle relay
|
||||
// state 3 = POWER_BLINK = Blink relay
|
||||
// state 4 = POWER_BLINK_STOP = Stop blinking relay
|
||||
// state 5 = POWER_OFF_FORCE = Relay off even if locked
|
||||
// state 8 = POWER_OFF_NO_STATE = Relay Off and no publishPowerState
|
||||
// state 9 = POWER_ON_NO_STATE = Relay On and no publishPowerState
|
||||
// state 10 = POWER_TOGGLE_NO_STATE = Toggle relay and no publishPowerState
|
||||
@ -709,6 +710,12 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
|
||||
}
|
||||
#endif // USE_SONOFF_IFAN
|
||||
|
||||
bool force_power_off = false;
|
||||
if (POWER_OFF_FORCE == state) {
|
||||
force_power_off = true;
|
||||
state = POWER_OFF;
|
||||
}
|
||||
|
||||
bool publish_power = true;
|
||||
if ((state >= POWER_OFF_NO_STATE) && (state <= POWER_TOGGLE_NO_STATE)) {
|
||||
state &= 3; // POWER_OFF, POWER_ON or POWER_TOGGLE
|
||||
@ -720,7 +727,7 @@ void ExecuteCommandPower(uint32_t device, uint32_t state, uint32_t source)
|
||||
}
|
||||
TasmotaGlobal.active_device = device;
|
||||
|
||||
if (bitRead(Settings->power_lock, device -1)) {
|
||||
if (!force_power_off && bitRead(Settings->power_lock, device -1)) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("CMD: Power%d is LOCKED"), device);
|
||||
state = POWER_SHOW_STATE; // Only show state. Make no change
|
||||
}
|
||||
|
@ -107,6 +107,23 @@ typedef union {
|
||||
};
|
||||
} tEnergyBitfield;
|
||||
|
||||
typedef struct {
|
||||
uint16_t min_voltage; // VoltageLow
|
||||
uint16_t max_voltage; // VoltageHigh
|
||||
uint16_t min_current; // CurrentLow
|
||||
uint16_t max_current; // CurrentHigh
|
||||
uint16_t min_power; // PowerLow
|
||||
uint16_t max_power; // PowerHigh
|
||||
uint16_t max_power_limit; // MaxPowerLimit
|
||||
uint16_t max_power_limit_hold; // MaxPowerLimitHold
|
||||
uint16_t max_power_limit_window; // MaxPowerLimitWindow
|
||||
uint16_t max_power_safe_limit; // MaxSafePowerLimit
|
||||
uint16_t max_power_safe_limit_hold; // MaxSafePowerLimitHold
|
||||
uint16_t max_power_safe_limit_window; // MaxSafePowerLimitWindow
|
||||
uint16_t max_energy; // MaxEnergy
|
||||
uint16_t max_energy_start; // MaxEnergyStart
|
||||
} tPhase;
|
||||
|
||||
typedef struct {
|
||||
uint32_t crc32; // To detect file changes
|
||||
uint16_t version; // To detect driver function changes
|
||||
@ -134,6 +151,7 @@ typedef struct {
|
||||
|
||||
uint16_t tariff[4][2];
|
||||
tEnergyUsage energy_usage;
|
||||
tPhase phase[ENERGY_MAX_PHASES];
|
||||
} tEnergySettings;
|
||||
|
||||
typedef struct {
|
||||
@ -168,8 +186,8 @@ typedef struct {
|
||||
float daily_sum_export_balanced; // 123.123 kWh
|
||||
|
||||
uint16_t power_history[ENERGY_MAX_PHASES][3];
|
||||
uint16_t mplh_counter;
|
||||
uint16_t mplw_counter;
|
||||
uint16_t mplh_counter[ENERGY_MAX_PHASES];
|
||||
uint16_t mplw_counter[ENERGY_MAX_PHASES];
|
||||
|
||||
uint8_t data_valid[ENERGY_MAX_PHASES];
|
||||
uint8_t phase_count; // Number of phases active
|
||||
@ -177,8 +195,9 @@ typedef struct {
|
||||
uint8_t command_code;
|
||||
uint8_t power_steady_counter; // Allow for power on stabilization
|
||||
uint8_t margin_stable;
|
||||
uint8_t mplr_counter;
|
||||
uint8_t max_energy_state;
|
||||
uint8_t mplr_counter[ENERGY_MAX_PHASES];
|
||||
uint8_t max_energy_state[ENERGY_MAX_PHASES];
|
||||
uint8_t hour;
|
||||
|
||||
uint8_t gui_indirect[ENERGY_MAX_PHASES];
|
||||
uint8_t gui_rotate;
|
||||
@ -195,12 +214,12 @@ typedef struct {
|
||||
bool type_dc;
|
||||
bool power_on;
|
||||
|
||||
bool min_power_flag;
|
||||
bool max_power_flag;
|
||||
bool min_voltage_flag;
|
||||
bool max_voltage_flag;
|
||||
bool min_current_flag;
|
||||
bool max_current_flag;
|
||||
bool min_power_flag[ENERGY_MAX_PHASES];
|
||||
bool max_power_flag[ENERGY_MAX_PHASES];
|
||||
bool min_voltage_flag[ENERGY_MAX_PHASES];
|
||||
bool max_voltage_flag[ENERGY_MAX_PHASES];
|
||||
bool min_current_flag[ENERGY_MAX_PHASES];
|
||||
bool max_current_flag[ENERGY_MAX_PHASES];
|
||||
} tEnergy;
|
||||
|
||||
tEnergy *Energy = nullptr;
|
||||
@ -286,10 +305,26 @@ void EnergySettingsLoad(bool erase) {
|
||||
Energy->Settings.voltage_calibration[i] = Settings->energy_voltage_calibration;;
|
||||
Energy->Settings.current_calibration[i] = Settings->energy_current_calibration;;
|
||||
Energy->Settings.frequency_calibration[i] = Settings->energy_frequency_calibration;
|
||||
Energy->Settings.phase[i].min_voltage = Settings->energy_min_voltage;
|
||||
Energy->Settings.phase[i].max_voltage = Settings->energy_max_voltage;
|
||||
Energy->Settings.phase[i].min_current = Settings->energy_min_current;
|
||||
Energy->Settings.phase[i].max_current = Settings->energy_max_current;
|
||||
Energy->Settings.phase[i].min_power = Settings->energy_min_power;
|
||||
Energy->Settings.phase[i].max_power = Settings->energy_max_power;
|
||||
}
|
||||
Energy->Settings.power_calibration[1] = Settings->energy_power_calibration2;
|
||||
Energy->Settings.voltage_calibration[1] = Settings->energy_voltage_calibration2;
|
||||
Energy->Settings.current_calibration[1] = Settings->energy_current_calibration2;
|
||||
|
||||
// Only restore phase 1 for backward compatibility (all power off)
|
||||
Energy->Settings.phase[0].max_power_limit = Settings->energy_max_power_limit;
|
||||
Energy->Settings.phase[0].max_power_limit_hold = Settings->energy_max_power_limit_hold;
|
||||
Energy->Settings.phase[0].max_power_limit_window = Settings->energy_max_power_limit_window;
|
||||
Energy->Settings.phase[0].max_power_safe_limit = Settings->energy_max_power_safe_limit;
|
||||
Energy->Settings.phase[0].max_power_safe_limit_hold = Settings->energy_max_power_safe_limit_hold;
|
||||
Energy->Settings.phase[0].max_power_safe_limit_window = Settings->energy_max_power_safe_limit_window;
|
||||
Energy->Settings.phase[0].max_energy = Settings->energy_max_energy;
|
||||
Energy->Settings.phase[0].max_energy_start = Settings->energy_max_energy_start;
|
||||
/*
|
||||
RtcEnergySettings.energy_total_kWh[0] = 0;
|
||||
RtcEnergySettings.energy_total_kWh[1] = 0;
|
||||
@ -654,11 +689,19 @@ void Energy200ms(void) {
|
||||
}
|
||||
EnergyUpdateToday();
|
||||
}
|
||||
|
||||
if (midnight) {
|
||||
Energy->max_energy_state = 3;
|
||||
for (uint32_t phase = 0; phase < Energy->phase_count; phase++) {
|
||||
Energy->max_energy_state[phase] = 3;
|
||||
}
|
||||
}
|
||||
if (RtcTime.hour != Energy->hour) {
|
||||
Energy->hour = RtcTime.hour;
|
||||
for (uint32_t phase = 0; phase < Energy->phase_count; phase++) {
|
||||
if ((RtcTime.hour == Energy->Settings.phase[phase].max_energy_start) && (3 == Energy->max_energy_state[phase] )) {
|
||||
Energy->max_energy_state[phase] = 0;
|
||||
}
|
||||
}
|
||||
if ((RtcTime.hour == Settings->energy_max_energy_start) && (3 == Energy->max_energy_state )) {
|
||||
Energy->max_energy_state = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@ -747,86 +790,124 @@ void EnergyMarginCheck(void) {
|
||||
ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFmt(power_diff_f, 0));
|
||||
}
|
||||
|
||||
uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]);
|
||||
|
||||
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);
|
||||
uint16_t energy_power_u;
|
||||
if (Energy->power_on) {
|
||||
bool flag;
|
||||
for (uint32_t phase = 0; phase < Energy->phase_count; phase++) {
|
||||
energy_power_u = (uint16_t)(Energy->active_power[phase]);
|
||||
uint16_t energy_voltage_u = (uint16_t)(Energy->voltage[phase]);
|
||||
uint16_t energy_current_u = (uint16_t)(Energy->current[phase] * 1000);
|
||||
|
||||
DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u);
|
||||
|
||||
bool flag;
|
||||
if (EnergyMargin(false, Settings->energy_min_power, energy_power_u, flag, Energy->min_power_flag)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
if (Energy->Settings.phase[phase].min_power) {
|
||||
if (EnergyMargin(false, Energy->Settings.phase[phase].min_power, energy_power_u, flag, Energy->min_power_flag[phase])) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "%d\":\"%s\""), (jsonflg)?",":"", phase +1, GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
if (EnergyMargin(true, Settings->energy_max_power, energy_power_u, flag, Energy->max_power_flag)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
}
|
||||
if (Energy->Settings.phase[phase].max_power) {
|
||||
if (EnergyMargin(true, Energy->Settings.phase[phase].max_power, energy_power_u, flag, Energy->max_power_flag[phase])) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "%d\":\"%s\""), (jsonflg)?",":"", phase +1, GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
if (EnergyMargin(false, Settings->energy_min_voltage, energy_voltage_u, flag, Energy->min_voltage_flag)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
}
|
||||
if (Energy->Settings.phase[phase].min_voltage) {
|
||||
if (EnergyMargin(false, Energy->Settings.phase[phase].min_voltage, energy_voltage_u, flag, Energy->min_voltage_flag[phase])) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "%d\":\"%s\""), (jsonflg)?",":"", phase +1, GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
if (EnergyMargin(true, Settings->energy_max_voltage, energy_voltage_u, flag, Energy->max_voltage_flag)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
}
|
||||
if (Energy->Settings.phase[phase].max_voltage) {
|
||||
if (EnergyMargin(true, Energy->Settings.phase[phase].max_voltage, energy_voltage_u, flag, Energy->max_voltage_flag[phase])) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "%d\":\"%s\""), (jsonflg)?",":"", phase +1, GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
if (EnergyMargin(false, Settings->energy_min_current, energy_current_u, flag, Energy->min_current_flag)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
}
|
||||
if (Energy->Settings.phase[phase].min_current) {
|
||||
if (EnergyMargin(false, Energy->Settings.phase[phase].min_current, energy_current_u, flag, Energy->min_current_flag[phase])) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTLOW "%d\":\"%s\""), (jsonflg)?",":"", phase +1, GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
if (EnergyMargin(true, Settings->energy_max_current, energy_current_u, flag, Energy->max_current_flag)) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
}
|
||||
if (Energy->Settings.phase[phase].max_current) {
|
||||
if (EnergyMargin(true, Energy->Settings.phase[phase].max_current, energy_current_u, flag, Energy->max_current_flag[phase])) {
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "%d\":\"%s\""), (jsonflg)?",":"", phase +1, GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jsonflg) {
|
||||
ResponseJsonEndEnd();
|
||||
MqttPublishTele(PSTR(D_RSLT_MARGINS));
|
||||
EnergyMqttShow();
|
||||
Energy->margin_stable = 3; // Allow 2 seconds to stabilize before reporting
|
||||
}
|
||||
}
|
||||
|
||||
// Max Power
|
||||
if (Settings->energy_max_power_limit) {
|
||||
if (Energy->active_power[0] > Settings->energy_max_power_limit) {
|
||||
if (!Energy->mplh_counter) {
|
||||
Energy->mplh_counter = Settings->energy_max_power_limit_hold;
|
||||
bool set_all_power = true; // Use all power control for backward compatibility
|
||||
for (uint32_t phase = 1; phase < Energy->phase_count; phase++) {
|
||||
if (Energy->Settings.phase[phase].max_power_limit) {
|
||||
set_all_power = false; // If any other power limit is set use new selected power control
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (uint32_t phase = 0; phase < Energy->phase_count; phase++) {
|
||||
if (Energy->Settings.phase[phase].max_power_limit) {
|
||||
energy_power_u = (uint16_t)(Energy->active_power[phase]);
|
||||
bool power_on = (TasmotaGlobal.power & (1 << phase));
|
||||
if (Energy->active_power[phase] > Energy->Settings.phase[phase].max_power_limit) {
|
||||
if (!Energy->mplh_counter[phase]) {
|
||||
Energy->mplh_counter[phase] = Energy->Settings.phase[phase].max_power_limit_hold;
|
||||
} else {
|
||||
Energy->mplh_counter--;
|
||||
if (!Energy->mplh_counter) {
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHED "\":%d}"), energy_power_u);
|
||||
Energy->mplh_counter[phase]--;
|
||||
if (!Energy->mplh_counter[phase]) {
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHED "%d\":%d}"), phase +1, energy_power_u);
|
||||
MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING);
|
||||
EnergyMqttShow();
|
||||
if (set_all_power) {
|
||||
SetAllPower(POWER_OFF_FORCE, SRC_MAXPOWER);
|
||||
if (!Energy->mplr_counter) {
|
||||
Energy->mplr_counter = Settings->param[P_MAX_POWER_RETRY] +1; // SetOption33 - Max Power Retry count
|
||||
}
|
||||
Energy->mplw_counter = Settings->energy_max_power_limit_window;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (TasmotaGlobal.power && (energy_power_u <= Settings->energy_max_power_limit)) {
|
||||
Energy->mplh_counter = 0;
|
||||
Energy->mplr_counter = 0;
|
||||
Energy->mplw_counter = 0;
|
||||
}
|
||||
if (!TasmotaGlobal.power) {
|
||||
if (Energy->mplw_counter) {
|
||||
Energy->mplw_counter--;
|
||||
} else {
|
||||
if (Energy->mplr_counter) {
|
||||
Energy->mplr_counter--;
|
||||
if (Energy->mplr_counter) {
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1));
|
||||
ExecuteCommandPower(phase +1, POWER_OFF_FORCE, SRC_MAXPOWER);
|
||||
}
|
||||
if (!Energy->mplr_counter[phase]) {
|
||||
Energy->mplr_counter[phase] = Settings->param[P_MAX_POWER_RETRY] +1; // SetOption33 - Max Power Retry count
|
||||
}
|
||||
Energy->mplw_counter[phase] = Energy->Settings.phase[phase].max_power_limit_window;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (power_on && (energy_power_u <= Energy->Settings.phase[phase].max_power_limit)) {
|
||||
Energy->mplh_counter[phase] = 0;
|
||||
Energy->mplr_counter[phase] = 0;
|
||||
Energy->mplw_counter[phase] = 0;
|
||||
}
|
||||
|
||||
if (!power_on) {
|
||||
if (Energy->mplw_counter[phase]) {
|
||||
Energy->mplw_counter[phase]--;
|
||||
} else {
|
||||
if (Energy->mplr_counter[phase]) {
|
||||
Energy->mplr_counter[phase]--;
|
||||
if (Energy->mplr_counter[phase]) {
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_POWERMONITOR "%d\":\"%s\"}"), phase +1, GetStateText(1));
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR));
|
||||
if (set_all_power) {
|
||||
RestorePower(true, SRC_MAXPOWER);
|
||||
} else {
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0));
|
||||
ExecuteCommandPower(phase +1, POWER_ON, SRC_MAXPOWER);
|
||||
}
|
||||
} else {
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHEDRETRY "%d\":\"%s\"}"), phase +1, GetStateText(0));
|
||||
MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING);
|
||||
EnergyMqttShow();
|
||||
if (set_all_power) {
|
||||
SetAllPower(POWER_OFF_FORCE, SRC_MAXPOWER);
|
||||
} else {
|
||||
ExecuteCommandPower(phase +1, POWER_OFF_FORCE, SRC_MAXPOWER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -834,22 +915,44 @@ void EnergyMarginCheck(void) {
|
||||
}
|
||||
|
||||
// Max Energy
|
||||
if (Settings->energy_max_energy) {
|
||||
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;
|
||||
set_all_power = true; // Use all power control for backward compatibility
|
||||
for (uint32_t phase = 1; phase < Energy->phase_count; phase++) {
|
||||
if (Energy->Settings.phase[phase].max_energy) {
|
||||
set_all_power = false; // If any other max energy is set use new selected power control
|
||||
break;
|
||||
}
|
||||
}
|
||||
float daily_sum = Energy->daily_sum;
|
||||
for (uint32_t phase = 0; phase < Energy->phase_count; phase++) {
|
||||
if (Energy->Settings.phase[phase].max_energy) {
|
||||
if (!set_all_power) {
|
||||
daily_sum = Energy->daily_kWh[phase];
|
||||
}
|
||||
uint16_t energy_daily_u = (uint16_t)(daily_sum * 1000);
|
||||
if (!Energy->max_energy_state[phase] && (RtcTime.hour == Energy->Settings.phase[phase].max_energy_start)) {
|
||||
Energy->max_energy_state[phase] = 1;
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1));
|
||||
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR));
|
||||
if (set_all_power) {
|
||||
RestorePower(true, SRC_MAXENERGY);
|
||||
} else {
|
||||
ExecuteCommandPower(phase +1, POWER_ON, SRC_MAXENERGY);
|
||||
}
|
||||
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);
|
||||
}
|
||||
else if ((1 == Energy->max_energy_state[phase]) && (energy_daily_u >= Energy->Settings.phase[phase].max_energy)) {
|
||||
Energy->max_energy_state[phase] = 2;
|
||||
ResponseTime_P(PSTR(",\"" D_JSON_MAXENERGYREACHED "\":%3_f}"), &daily_sum);
|
||||
MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING);
|
||||
EnergyMqttShow();
|
||||
if (set_all_power) {
|
||||
SetAllPower(POWER_OFF_FORCE, SRC_MAXENERGY);
|
||||
} else {
|
||||
ExecuteCommandPower(phase +1, POWER_OFF_FORCE, SRC_MAXENERGY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EnergyFmtFree();
|
||||
}
|
||||
|
||||
@ -1251,13 +1354,34 @@ void CmndEnergyConfig(void) {
|
||||
|
||||
void EnergyMarginStatus(void) {
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":["));
|
||||
for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) {
|
||||
for (uint32_t i = 0; i < Energy->phase_count; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.power_delta[i]);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"" 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_min_power, Settings->energy_max_power,
|
||||
Settings->energy_min_voltage, Settings->energy_max_voltage, Settings->energy_min_current, Settings->energy_max_current);
|
||||
ResponseAppend_P(PSTR("],\"" D_CMND_POWERLOW "\":["));
|
||||
for (uint32_t i = 0; i < Energy->phase_count; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.phase[i].min_power);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"" D_CMND_POWERHIGH "\":["));
|
||||
for (uint32_t i = 0; i < Energy->phase_count; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.phase[i].max_power);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"" D_CMND_VOLTAGELOW "\":["));
|
||||
for (uint32_t i = 0; i < Energy->phase_count; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.phase[i].min_voltage);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"" D_CMND_VOLTAGEHIGH "\":["));
|
||||
for (uint32_t i = 0; i < Energy->phase_count; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.phase[i].max_voltage);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"" D_CMND_CURRENTLOW "\":["));
|
||||
for (uint32_t i = 0; i < Energy->phase_count; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.phase[i].min_current);
|
||||
}
|
||||
ResponseAppend_P(PSTR("],\"" D_CMND_CURRENTHIGH "\":["));
|
||||
for (uint32_t i = 0; i < Energy->phase_count; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.phase[i].max_current);
|
||||
}
|
||||
ResponseAppend_P(PSTR("]}}"));
|
||||
}
|
||||
|
||||
void CmndPowerDelta(void) {
|
||||
@ -1270,66 +1394,84 @@ void CmndPowerDelta(void) {
|
||||
}
|
||||
|
||||
void CmndPowerLow(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
|
||||
Settings->energy_min_power = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].min_power = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].min_power);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_min_power);
|
||||
}
|
||||
|
||||
void CmndPowerHigh(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
|
||||
Settings->energy_max_power = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_power = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_power);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_power);
|
||||
}
|
||||
|
||||
void CmndVoltageLow(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) {
|
||||
Settings->energy_min_voltage = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].min_voltage = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].min_voltage);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_min_voltage);
|
||||
}
|
||||
|
||||
void CmndVoltageHigh(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) {
|
||||
Settings->energy_max_voltage = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_voltage = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_voltage);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_voltage);
|
||||
}
|
||||
|
||||
void CmndCurrentLow(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) {
|
||||
Settings->energy_min_current = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].min_current = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].min_current);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_min_current);
|
||||
}
|
||||
|
||||
void CmndCurrentHigh(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) {
|
||||
Settings->energy_max_current = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_current = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_current);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_current);
|
||||
}
|
||||
|
||||
void CmndMaxPower(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
|
||||
Settings->energy_max_power_limit = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_power_limit = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_power_limit);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_power_limit);
|
||||
}
|
||||
|
||||
void CmndMaxPowerHold(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
|
||||
Settings->energy_max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_power_limit_hold);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_power_limit_hold);
|
||||
}
|
||||
|
||||
void CmndMaxPowerWindow(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
|
||||
Settings->energy_max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_power_limit_window);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_power_limit_window);
|
||||
}
|
||||
|
||||
void CmndSafePower(void) {
|
||||
@ -1354,18 +1496,22 @@ void CmndSafePowerWindow(void) {
|
||||
}
|
||||
|
||||
void CmndMaxEnergy(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
|
||||
Settings->energy_max_energy = XdrvMailbox.payload;
|
||||
Energy->max_energy_state = 3;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_energy = XdrvMailbox.payload;
|
||||
Energy->max_energy_state[XdrvMailbox.index -1] = 3;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_energy);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_energy);
|
||||
}
|
||||
|
||||
void CmndMaxEnergyStart(void) {
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 24)) {
|
||||
Settings->energy_max_energy_start = XdrvMailbox.payload;
|
||||
Energy->Settings.phase[XdrvMailbox.index -1].max_energy_start = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Energy->Settings.phase[XdrvMailbox.index -1].max_energy_start);
|
||||
}
|
||||
ResponseCmndNumber(Settings->energy_max_energy_start);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user