mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 18:56:38 +00:00
Add command `PowerDelta1
to
PowerDelta3
`
- Bump version to 8.4.0.3 - Add command ``PowerDelta1`` to ``PowerDelta3`` to trigger on up to three phases (#9134)
This commit is contained in:
parent
6e111477a0
commit
0f1e4fc917
@ -53,7 +53,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
|
||||
|
||||
## Changelog
|
||||
|
||||
### Version 8.4.0.2
|
||||
### Version 8.4.0.3
|
||||
|
||||
- Remove support for 1-step upgrade from versions before 6.6.0.11 to versions after 8.4.0.1
|
||||
- Change White blend mode moved to using ``SetOption 105`` instead of ``RGBWWTable``
|
||||
@ -63,6 +63,8 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
|
||||
- Add command ``Restart 2`` to halt system. Needs hardware reset or power cycle to restart (#9046)
|
||||
- Add ESP32 Analog input support for GPIO32 to GPIO39
|
||||
- Add Zigbee options to ``ZbSend`` ``Config`` and ``ReadCondig``
|
||||
- Add Zigbee web gui widget for Temp/Humidity/Pressure sensors
|
||||
- Add better config corruption recovery (#9046)
|
||||
- Add virtual CT for 4 channels lights, emulating a 5th channel
|
||||
- Add support for DYP ME007 ultrasonic distance sensor by Janusz Kostorz (#9113)
|
||||
- Add command ``PowerDelta1`` to ``PowerDelta3`` to trigger on up to three phases (#9134)
|
||||
|
@ -1,5 +1,9 @@
|
||||
## Unreleased (development)
|
||||
|
||||
### 8.4.0.3 20200823
|
||||
|
||||
- Add command ``PowerDelta1`` to ``PowerDelta3`` to trigger on up to three phases (#9134)
|
||||
|
||||
### 8.4.0.2 20200813
|
||||
|
||||
- Remove support for 1-step upgrade from versions before 6.6.0.11 to versions after 8.4.0.1
|
||||
|
@ -127,7 +127,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
|
||||
uint32_t white_blend_mode : 1; // bit 23 (v8.4.0.1) - SetOption105 - White Blend Mode - used to be `RGBWWTable` last value `0`, now deprecated in favor of this option
|
||||
uint32_t virtual_ct : 1; // bit 24 (v8.4.0.1) - SetOption106 - Virtual CT - Creates a virtual White ColorTemp for RGBW lights
|
||||
uint32_t virtual_ct_cw : 1; // bit 25 (v8.4.0.1) - SetOption107 - Virtual CT Channel - signals whether the hardware white is cold CW (true) or warm WW (false)
|
||||
uint32_t teleinfo_rawdata : 1; // bit 21 (v8.4.0.2) - SetOption108 - enable Teleinfo + Tasmota Energy device (0) or Teleinfo raw data only (1)
|
||||
uint32_t teleinfo_rawdata : 1; // bit 21 (v8.4.0.2) - SetOption108 - enable Teleinfo + Tasmota Energy device (0) or Teleinfo raw data only (1)
|
||||
uint32_t spare27 : 1;
|
||||
uint32_t spare28 : 1; // bit 28
|
||||
uint32_t spare29 : 1; // bit 29
|
||||
@ -557,7 +557,7 @@ struct {
|
||||
uint16_t dimmer_hw_min; // E90
|
||||
uint16_t dimmer_hw_max; // E92
|
||||
uint32_t deepsleep; // E94
|
||||
uint16_t energy_power_delta; // E98
|
||||
uint16_t ex2_energy_power_delta; // E98 - Free since 8.4.0.3
|
||||
uint8_t shutter_motordelay[MAX_SHUTTERS]; // E9A
|
||||
int8_t temp_comp; // E9E
|
||||
uint8_t weight_change; // E9F
|
||||
@ -610,10 +610,14 @@ struct {
|
||||
uint8_t tcp_baudrate; // F41
|
||||
uint8_t fallback_module; // F42
|
||||
|
||||
uint8_t free_f43[113]; // F43 - Decrement if adding new Setting variables just above and below
|
||||
uint8_t free_f43[1]; // F43
|
||||
|
||||
uint16_t energy_power_delta[3]; // F44
|
||||
|
||||
uint8_t free_f4e[106]; // F4A - Decrement if adding new Setting variables just above and below
|
||||
|
||||
// Only 32 bit boundary variables below
|
||||
SysBitfield5 flag5; // EB4
|
||||
SysBitfield5 flag5; // FB4
|
||||
uint16_t pulse_counter_debounce_low; // FB8
|
||||
uint16_t pulse_counter_debounce_high; // FBA
|
||||
uint32_t keeloq_master_msb; // FBC
|
||||
|
@ -935,7 +935,9 @@ void SettingsDefaultSet2(void)
|
||||
flag3.dds2382_model |= ENERGY_DDS2382_MODE;
|
||||
flag3.hardware_energy_total |= ENERGY_HARDWARE_TOTALS;
|
||||
Settings.param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY;
|
||||
// Settings.energy_power_delta = 0;
|
||||
// Settings.energy_power_delta[0] = 0;
|
||||
// Settings.energy_power_delta[1] = 0;
|
||||
// Settings.energy_power_delta[2] = 0;
|
||||
Settings.energy_power_calibration = HLW_PREF_PULSE;
|
||||
Settings.energy_voltage_calibration = HLW_UREF_PULSE;
|
||||
Settings.energy_current_calibration = HLW_IREF_PULSE;
|
||||
@ -1346,7 +1348,7 @@ void SettingsDelta(void)
|
||||
Settings.ex_sbaudrate = 0;
|
||||
*/
|
||||
Settings.flag3.fast_power_cycle_disable = 0;
|
||||
Settings.energy_power_delta = Settings.ex_energy_power_delta;
|
||||
Settings.ex2_energy_power_delta = Settings.ex_energy_power_delta;
|
||||
Settings.ex_energy_power_delta = 0;
|
||||
}
|
||||
if (Settings.version < 0x06060015) {
|
||||
@ -1503,6 +1505,11 @@ void SettingsDelta(void)
|
||||
if (Settings.version < 0x08030106) {
|
||||
Settings.fallback_module = FALLBACK_MODULE;
|
||||
}
|
||||
if (Settings.version < 0x08040003) {
|
||||
Settings.energy_power_delta[0] = Settings.ex2_energy_power_delta;
|
||||
Settings.energy_power_delta[1] = 0;
|
||||
Settings.energy_power_delta[2] = 0;
|
||||
}
|
||||
|
||||
Settings.version = VERSION;
|
||||
SettingsSave(1);
|
||||
|
@ -538,9 +538,9 @@ void CmndStatus(void)
|
||||
#if defined(USE_ENERGY_SENSOR) && defined(USE_ENERGY_MARGIN_DETECTION)
|
||||
if (energy_flg) {
|
||||
if ((0 == payload) || (9 == payload)) {
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":%d,\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\""
|
||||
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, Settings.energy_min_power, Settings.energy_max_power,
|
||||
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);
|
||||
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "9"));
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
#ifndef _TASMOTA_VERSION_H_
|
||||
#define _TASMOTA_VERSION_H_
|
||||
|
||||
const uint32_t VERSION = 0x08040002;
|
||||
const uint32_t VERSION = 0x08040003;
|
||||
|
||||
// Lowest compatible version
|
||||
const uint32_t VERSION_COMPATIBLE = 0x07010006;
|
||||
|
@ -108,7 +108,7 @@ struct ENERGY {
|
||||
bool power_on = true;
|
||||
|
||||
#ifdef USE_ENERGY_MARGIN_DETECTION
|
||||
uint16_t power_history[3] = { 0 };
|
||||
uint16_t power_history[3][3] = {{ 0 }, { 0 }, { 0 }};
|
||||
uint8_t power_steady_counter = 8; // Allow for power on stabilization
|
||||
bool min_power_flag = false;
|
||||
bool max_power_flag = false;
|
||||
@ -130,6 +130,31 @@ Ticker ticker_energy;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
char* EnergyFormatIndex(char* result, char* input, bool json, uint32_t index, bool single = false)
|
||||
{
|
||||
char layout[16];
|
||||
GetTextIndexed(layout, sizeof(layout), (index -1) + (3 * json), kEnergyPhases);
|
||||
switch (index) {
|
||||
case 2:
|
||||
snprintf_P(result, FLOATSZ *3, layout, input, input + FLOATSZ); // Dirty
|
||||
break;
|
||||
case 3:
|
||||
snprintf_P(result, FLOATSZ *3, layout, input, input + FLOATSZ, input + FLOATSZ + FLOATSZ); // Even dirtier
|
||||
break;
|
||||
default:
|
||||
snprintf_P(result, FLOATSZ *3, input);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char* EnergyFormat(char* result, char* input, bool json, bool single = false)
|
||||
{
|
||||
uint8_t index = (single) ? 1 : Energy.phase_count; // 1,2,3
|
||||
return EnergyFormatIndex(result, input, json, index, single);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
bool EnergyTariff1Active() // Off-Peak hours
|
||||
{
|
||||
uint8_t dst = 0;
|
||||
@ -303,38 +328,53 @@ void EnergyMarginCheck(void)
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t energy_power_u = (uint16_t)(Energy.active_power[0]);
|
||||
|
||||
bool jsonflg = false;
|
||||
Response_P(PSTR("{\"" D_RSLT_MARGINS "\":{"));
|
||||
|
||||
if (Settings.energy_power_delta) {
|
||||
int16_t power_diff = energy_power_u - Energy.power_history[0];
|
||||
uint16_t delta = abs(power_diff);
|
||||
if (delta > 0) {
|
||||
if (Settings.energy_power_delta < 101) { // 1..100 = Percentage
|
||||
uint16_t min_power = (Energy.power_history[0] > energy_power_u) ? energy_power_u : Energy.power_history[0];
|
||||
if (0 == min_power) { min_power++; } // Fix divide by 0 exception (#6741)
|
||||
delta = (delta * 100) / min_power;
|
||||
if (delta > Settings.energy_power_delta) {
|
||||
jsonflg = true;
|
||||
}
|
||||
} else { // 101..32000 = Absolute
|
||||
if (delta > (Settings.energy_power_delta -100)) {
|
||||
jsonflg = true;
|
||||
int16_t power_diff[3] = { 0 };
|
||||
for (uint32_t phase = 0; phase < Energy.phase_count; phase++) {
|
||||
uint16_t active_power = (uint16_t)(Energy.active_power[phase]);
|
||||
|
||||
if (Settings.energy_power_delta[phase]) {
|
||||
power_diff[phase] = active_power - Energy.power_history[phase][0];
|
||||
uint16_t delta = abs(power_diff[phase]);
|
||||
bool threshold_met = false;
|
||||
if (delta > 0) {
|
||||
if (Settings.energy_power_delta[phase] < 101) { // 1..100 = Percentage
|
||||
uint16_t min_power = (Energy.power_history[phase][0] > active_power) ? active_power : Energy.power_history[phase][0];
|
||||
if (0 == min_power) { min_power++; } // Fix divide by 0 exception (#6741)
|
||||
delta = (delta * 100) / min_power;
|
||||
if (delta > Settings.energy_power_delta[phase]) {
|
||||
threshold_met = true;
|
||||
}
|
||||
} else { // 101..32000 = Absolute
|
||||
if (delta > (Settings.energy_power_delta[phase] -100)) {
|
||||
threshold_met = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jsonflg) {
|
||||
Energy.power_history[1] = Energy.active_power[0]; // We only want one report so reset history
|
||||
Energy.power_history[2] = Energy.active_power[0];
|
||||
|
||||
ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%d"), power_diff);
|
||||
if (threshold_met) {
|
||||
Energy.power_history[phase][1] = active_power; // We only want one report so reset history
|
||||
Energy.power_history[phase][2] = active_power;
|
||||
jsonflg = true;
|
||||
} else {
|
||||
power_diff[phase] = 0;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
Energy.power_history[0] = Energy.power_history[1]; // Shift in history every second allowing power changes to settle for up to three seconds
|
||||
Energy.power_history[1] = Energy.power_history[2];
|
||||
Energy.power_history[2] = energy_power_u;
|
||||
if (jsonflg) {
|
||||
char power_diff_chr[Energy.phase_count][FLOATSZ];
|
||||
for (uint32_t phase = 0; phase < Energy.phase_count; phase++) {
|
||||
dtostrfd(power_diff[phase], 0, power_diff_chr[phase]);
|
||||
}
|
||||
char value_chr[FLOATSZ *3];
|
||||
ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_chr[0], 1));
|
||||
}
|
||||
|
||||
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]);
|
||||
@ -725,10 +765,12 @@ void CmndModuleAddress(void)
|
||||
#ifdef USE_ENERGY_MARGIN_DETECTION
|
||||
void CmndPowerDelta(void)
|
||||
{
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32000)) {
|
||||
Settings.energy_power_delta = XdrvMailbox.payload;
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 3)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32000)) {
|
||||
Settings.energy_power_delta[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Settings.energy_power_delta[XdrvMailbox.index -1]);
|
||||
}
|
||||
ResponseCmndNumber(Settings.energy_power_delta);
|
||||
}
|
||||
|
||||
void CmndPowerLow(void)
|
||||
@ -881,29 +923,6 @@ const char HTTP_ENERGY_SNS3[] PROGMEM =
|
||||
"{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}";
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
char* EnergyFormatIndex(char* result, char* input, bool json, uint32_t index, bool single = false)
|
||||
{
|
||||
char layout[16];
|
||||
GetTextIndexed(layout, sizeof(layout), (index -1) + (3 * json), kEnergyPhases);
|
||||
switch (index) {
|
||||
case 2:
|
||||
snprintf_P(result, FLOATSZ *3, layout, input, input + FLOATSZ); // Dirty
|
||||
break;
|
||||
case 3:
|
||||
snprintf_P(result, FLOATSZ *3, layout, input, input + FLOATSZ, input + FLOATSZ + FLOATSZ); // Even dirtier
|
||||
break;
|
||||
default:
|
||||
snprintf_P(result, FLOATSZ *3, input);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char* EnergyFormat(char* result, char* input, bool json, bool single = false)
|
||||
{
|
||||
uint8_t index = (single) ? 1 : Energy.phase_count; // 1,2,3
|
||||
return EnergyFormatIndex(result, input, json, index, single);
|
||||
}
|
||||
|
||||
void EnergyShow(bool json)
|
||||
{
|
||||
for (uint32_t i = 0; i < Energy.phase_count; i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user