Add Energy command ``PowerSet 60,230`` to calibrate both Current and Power with known resistive load of 60W at 230V using calibrated Voltage

This commit is contained in:
Theo Arends 2024-08-20 13:08:56 +02:00
parent c5b92d3ab1
commit ab2d6c1169
4 changed files with 112 additions and 10 deletions

View File

@ -6,10 +6,13 @@ All notable changes to this project will be documented in this file.
## [14.2.0.1] ## [14.2.0.1]
### Added ### Added
- Energy Log level 4 message when (Calculated) Apparent Power is less than Active Power indicating wrong calibration (#20653) - Energy Log level 4 message when (Calculated) Apparent Power is less than Active Power indicating wrong calibration (#20653)
- Energy command ``PowerSet 60,230`` to calibrate both Current and Power with known resistive load of 60W at 230V using calibrated Voltage
- Energy command ``CurrentSet 60,230`` to calibrate both Power and Current with known resistive load of 60W at 230V using calibrated Voltage
### Breaking Changed ### Breaking Changed
### Changed ### Changed
- Energy force Apparent Power equals Active Power when (Calculated) Apparent Power is less than Active Power (#20653)
### Fixed ### Fixed
- Shutter timing registers overflow (#21966) - Shutter timing registers overflow (#21966)
@ -18,8 +21,6 @@ All notable changes to this project will be documented in this file.
### Removed ### Removed
- ESP8266 Analog input support using energy driver as only one channel is available - ESP8266 Analog input support using energy driver as only one channel is available
- Energy force Active Power equals Apparent Power when (Calculated) Apparent Power is less than Active Power (#20653)
- Energy force Power Factor to be always 1 or lower (#20653)
## [Released] ## [Released]

View File

@ -121,11 +121,14 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
## Changelog v14.2.0.1 ## Changelog v14.2.0.1
### Added ### Added
- Energy command ``PowerSet 60,230`` to calibrate both Current and Power with known resistive load of 60W at 230V using calibrated Voltage
- Energy command ``CurrentSet 60,230`` to calibrate both Power and Current with known resistive load of 60W at 230V using calibrated Voltage
- Energy Log level 4 message when (Calculated) Apparent Power is less than Active Power indicating wrong calibration [#20653](https://github.com/arendst/Tasmota/issues/20653) - Energy Log level 4 message when (Calculated) Apparent Power is less than Active Power indicating wrong calibration [#20653](https://github.com/arendst/Tasmota/issues/20653)
### Breaking Changed ### Breaking Changed
### Changed ### Changed
- Energy force Apparent Power equals Active Power when (Calculated) Apparent Power is less than Active Power [#20653](https://github.com/arendst/Tasmota/issues/20653)
### Fixed ### Fixed
- Energy calculation [#20653](https://github.com/arendst/Tasmota/issues/20653) - Energy calculation [#20653](https://github.com/arendst/Tasmota/issues/20653)
@ -133,6 +136,4 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
- PZEM continue energy monitoring when one phase fails [#21968](https://github.com/arendst/Tasmota/issues/21968) - PZEM continue energy monitoring when one phase fails [#21968](https://github.com/arendst/Tasmota/issues/21968)
### Removed ### Removed
- Energy force Active Power equals Apparent Power when (Calculated) Apparent Power is less than Active Power [#20653](https://github.com/arendst/Tasmota/issues/20653)
- Energy force Power Factor to be always 1 or lower [#20653](https://github.com/arendst/Tasmota/issues/20653)
- ESP8266 Analog input support using energy driver as only one channel is available - ESP8266 Analog input support using energy driver as only one channel is available

View File

@ -974,14 +974,56 @@ void EnergyCommandSetCalResponse(uint32_t cal_type) {
} }
} }
void EnergyCommandSetCal(uint32_t cal_type) {
if (XdrvMailbox.data_len) {
// PowerSet 61.2
// CurrentSet 263
if (ArgC() > 1) {
// Calibrate current and power using calibrated voltage and known resistive load voltage and power
// PowerSet 60.0,230
// CurrentSet 60.0,230
char argument[32];
float Pgoal = CharToFloat(ArgV(argument, 1)); // 60.0 W
float Ugoal = CharToFloat(ArgV(argument, 2)); // 230 V
float Igoal = Pgoal / Ugoal; // 0.26087 A
float R = Ugoal / Igoal; // 881,666 Ohm
uint32_t channel = XdrvMailbox.index;
if (channel > Energy->phase_count) { channel = 1; }
channel--;
float Umeas = Energy->voltage[channel]; // 232.0
// Calculate current and power based on measured voltage
float Ical = Umeas / R; // 0.26306 A
float Pcal = Umeas * Ical; // 61.03 W
Ical *= 1000; // A to mA
uint32_t cal_type1 = ENERGY_CURRENT_CALIBRATION;
float cal1 = Ical;
float cal2 = Pcal;
if (ENERGY_CURRENT_CALIBRATION == cal_type) {
cal_type1 = ENERGY_POWER_CALIBRATION;
cal1 = Pcal;
cal2 = Ical;
}
XdrvMailbox.data = argument;
ext_snprintf_P(argument, sizeof(argument), PSTR("%5_f"), &cal1);
XdrvMailbox.data_len = strlen(argument);
EnergyCommandSetCalResponse(cal_type1);
ext_snprintf_P(argument, sizeof(argument), PSTR("%5_f"), &cal2);
XdrvMailbox.data_len = strlen(argument);
}
}
EnergyCommandSetCalResponse(cal_type);
}
void CmndPowerSet(void) { void CmndPowerSet(void) {
EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); EnergyCommandSetCal(ENERGY_POWER_CALIBRATION);
} }
void CmndVoltageSet(void) { void CmndVoltageSet(void) {
EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION);
} }
void CmndCurrentSet(void) { void CmndCurrentSet(void) {
EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); EnergyCommandSetCal(ENERGY_CURRENT_CALIBRATION);
} }
void CmndFrequencySet(void) { void CmndFrequencySet(void) {
EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION);
@ -1184,6 +1226,10 @@ void EnergyShow(bool json) {
if (!Energy->type_dc) { if (!Energy->type_dc) {
if (Energy->current_available && Energy->voltage_available) { if (Energy->current_available && Energy->voltage_available) {
for (uint32_t i = 0; i < Energy->phase_count; i++) { for (uint32_t i = 0; i < Energy->phase_count; i++) {
if (0 == Energy->current[i]) {
Energy->active_power[i] = 0;
}
apparent_power[i] = Energy->apparent_power[i]; apparent_power[i] = Energy->apparent_power[i];
if (isnan(apparent_power[i])) { if (isnan(apparent_power[i])) {
apparent_power[i] = Energy->voltage[i] * Energy->current[i]; apparent_power[i] = Energy->voltage[i] * Energy->current[i];
@ -1209,11 +1255,15 @@ void EnergyShow(bool json) {
} }
if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible
if (apparent_power[i]) { if (apparent_power[i]) {
if ((power_factor[i] > 1.005) && (power_factor[i] < 2.0f)) { // Skip below 0.5% and don't expect 50% differences if ((power_factor[i] >= 1.02f) && (power_factor[i] < 2.0f)) { // Skip below 2% and don't expect 50% differences
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Calibrate as Active %3_fW > Apparent %3_fVA (PF = %4_f)"), AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Calibrate as Active %3_fW > Apparent %3_fVA (PF = %4_f)"),
&Energy->active_power[i], &apparent_power[i], &power_factor[i]); &Energy->active_power[i], &apparent_power[i], &power_factor[i]);
} }
} }
apparent_power[i] = Energy->active_power[i]; // Force apparent equal to active as mis-calibrated
if (power_factor[i] > 1) { // Should not happen (Active > Apparent)
power_factor[i] = 1;
}
} }
reactive_power[i] = Energy->reactive_power[i]; reactive_power[i] = Energy->reactive_power[i];

View File

@ -1285,14 +1285,56 @@ void EnergyCommandSetCalResponse(uint32_t cal_type) {
} }
} }
void EnergyCommandSetCal(uint32_t cal_type) {
if (XdrvMailbox.data_len && (XdrvMailbox.index > 0)) {
// PowerSet 61.2
// CurrentSet 263
if (ArgC() > 1) {
// Calibrate current and power using calibrated voltage and known resistive load voltage and power
// PowerSet 60.0,230
// CurrentSet 60.0,230
char argument[32];
float Pgoal = CharToFloat(ArgV(argument, 1)); // 60.0 W
float Ugoal = CharToFloat(ArgV(argument, 2)); // 230 V
float Igoal = Pgoal / Ugoal; // 0.26087 A
float R = Ugoal / Igoal; // 881,666 Ohm
uint32_t channel = XdrvMailbox.index;
if (channel > Energy->phase_count) { channel = 1; }
channel--;
float Umeas = Energy->voltage[channel]; // 232.0
// Calculate current and power based on measured voltage
float Ical = Umeas / R; // 0.26306 A
float Pcal = Umeas * Ical; // 61.03 W
Ical *= 1000; // A to mA
uint32_t cal_type1 = ENERGY_CURRENT_CALIBRATION;
float cal1 = Ical;
float cal2 = Pcal;
if (ENERGY_CURRENT_CALIBRATION == cal_type) {
cal_type1 = ENERGY_POWER_CALIBRATION;
cal1 = Pcal;
cal2 = Ical;
}
XdrvMailbox.data = argument;
ext_snprintf_P(argument, sizeof(argument), PSTR("%5_f"), &cal1);
XdrvMailbox.data_len = strlen(argument);
EnergyCommandSetCalResponse(cal_type1);
ext_snprintf_P(argument, sizeof(argument), PSTR("%5_f"), &cal2);
XdrvMailbox.data_len = strlen(argument);
}
}
EnergyCommandSetCalResponse(cal_type);
}
void CmndPowerSet(void) { void CmndPowerSet(void) {
EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); EnergyCommandSetCal(ENERGY_POWER_CALIBRATION);
} }
void CmndVoltageSet(void) { void CmndVoltageSet(void) {
EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION);
} }
void CmndCurrentSet(void) { void CmndCurrentSet(void) {
EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); EnergyCommandSetCal(ENERGY_CURRENT_CALIBRATION);
} }
void CmndFrequencySet(void) { void CmndFrequencySet(void) {
EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION);
@ -1526,6 +1568,10 @@ void EnergyShow(bool json) {
if (!Energy->type_dc) { if (!Energy->type_dc) {
if (Energy->current_available && Energy->voltage_available) { if (Energy->current_available && Energy->voltage_available) {
for (uint32_t i = 0; i < Energy->phase_count; i++) { for (uint32_t i = 0; i < Energy->phase_count; i++) {
if (0 == Energy->current[i]) {
Energy->active_power[i] = 0;
}
apparent_power[i] = Energy->apparent_power[i]; apparent_power[i] = Energy->apparent_power[i];
if (isnan(apparent_power[i])) { if (isnan(apparent_power[i])) {
apparent_power[i] = Energy->voltage[i] * Energy->current[i]; apparent_power[i] = Energy->voltage[i] * Energy->current[i];
@ -1551,11 +1597,15 @@ void EnergyShow(bool json) {
} }
if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible
if (apparent_power[i]) { if (apparent_power[i]) {
if ((power_factor[i] > 1.005) && (power_factor[i] < 2.0f)) { // Skip below 0.5% and don't expect 50% differences if ((power_factor[i] >= 1.02f) && (power_factor[i] < 2.0f)) { // Skip below 2% and don't expect 50% differences
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Calibrate as Active %3_fW > Apparent %3_fVA (PF = %4_f)"), AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Calibrate as Active %3_fW > Apparent %3_fVA (PF = %4_f)"),
&Energy->active_power[i], &apparent_power[i], &power_factor[i]); &Energy->active_power[i], &apparent_power[i], &power_factor[i]);
} }
} }
apparent_power[i] = Energy->active_power[i]; // Force apparent equal to active as mis-calibrated
if (power_factor[i] > 1) { // Should not happen (Active > Apparent)
power_factor[i] = 1;
}
} }
reactive_power[i] = Energy->reactive_power[i]; reactive_power[i] = Energy->reactive_power[i];