Add support for two phase power calibration

Add support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2``
This commit is contained in:
Theo Arends 2022-10-30 11:15:17 +01:00
parent cd14c15c41
commit 41b65fd6b7
8 changed files with 64 additions and 37 deletions

View File

@ -6,11 +6,12 @@ All notable changes to this project will be documented in this file.
## [12.2.0.2]
### Added
- Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk (#16938)
- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2``
### Breaking Changed
### Changed
- Prepare for two phase power calibration and move some persistent data (PowerLow)
- Move some persistent data (PowerLow)
- ESP32 Framework (Core) from v2.0.5 to v2.0.5.2
### Fixed

View File

@ -109,6 +109,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
## Changelog v12.2.0.2
### Added
- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2``
- Command NeoPool ``NPFiltration 2`` toggle [#16859](https://github.com/arendst/Tasmota/issues/16859)
- Support for Shelly Pro 1/1PM and 2/2PM [#16773](https://github.com/arendst/Tasmota/issues/16773)
- Support for up to four DS18x20 GPIOs by md5sum-as [#16833](https://github.com/arendst/Tasmota/issues/16833)

View File

@ -45,7 +45,7 @@ void RtcSettingsSave(void) {
if (RTC_MEM_VALID != RtcSettings.valid) {
memset(&RtcSettings, 0, sizeof(RtcSettings));
RtcSettings.valid = RTC_MEM_VALID;
// RtcSettings.ex_energy_kWhtoday = Settings->energy_power_calibration2;
// RtcSettings.ex_energy_kWhtoday = Settings->energy_power_calibration2; // = ex_energy_kWhtoday
// RtcSettings.ex_energy_kWhtotal = Settings->ex_energy_kWhtotal;
for (uint32_t i = 0; i < 3; i++) {
RtcSettings.energy_kWhtoday_ph[i] = Settings->energy_kWhtoday_ph[i];
@ -1535,8 +1535,8 @@ void SettingsDelta(void) {
memset(&Settings->energy_kWhtoday_ph, 0, 36);
memset(&RtcSettings.energy_kWhtoday_ph, 0, 24);
Settings->energy_kWhtotal_ph[0] = Settings->ex_energy_kWhtotal;
Settings->energy_kWhtoday_ph[0] = Settings->energy_power_calibration2;
Settings->energy_kWhyesterday_ph[0] = Settings->energy_voltage_calibration2;
Settings->energy_kWhtoday_ph[0] = Settings->energy_power_calibration2; // = ex_energy_kWhtoday
Settings->energy_kWhyesterday_ph[0] = Settings->energy_voltage_calibration2; // = ex_energy_kWhyesterday
RtcSettings.energy_kWhtoday_ph[0] = RtcSettings.ex_energy_kWhtoday;
RtcSettings.energy_kWhtotal_ph[0] = RtcSettings.ex_energy_kWhtotal;
}

View File

@ -41,6 +41,9 @@
#define D_CMND_TARIFF "Tariff"
#define D_CMND_MODULEADDRESS "ModuleAddress"
enum EnergyCalibration {
ENERGY_POWER_CALIBRATION, ENERGY_VOLTAGE_CALIBRATION, ENERGY_CURRENT_CALIBRATION, ENERGY_FREQUENCY_CALIBRATION };
enum EnergyCommands {
CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, CMND_FREQUENCYCAL,
CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS, CMND_ENERGYCONFIG };
@ -830,34 +833,50 @@ void CmndTariff(void) {
GetStateText(Settings->flag3.energy_weekend)); // CMND_TARIFF
}
uint32_t EnergyGetCalibration(uint32_t chan, uint32_t cal_type) {
uint32_t channel = ((1 == chan) && (2 == Energy.phase_count)) ? 1 : 0;
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;
}
void EnergyCommandCalSetResponse(uint32_t cal_type) {
if (XdrvMailbox.payload > 999) {
uint32_t channel = ((2 == XdrvMailbox.index) && (2 == Energy.phase_count)) ? 1 : 0;
if (channel) {
switch (cal_type) {
case 0: Settings->energy_power_calibration2 = XdrvMailbox.payload; break;
case 1: Settings->energy_voltage_calibration2 = XdrvMailbox.payload; break;
case 2: Settings->energy_current_calibration2 = XdrvMailbox.payload; break;
case 3: Settings->energy_frequency_calibration = XdrvMailbox.payload; break;
case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration2 = XdrvMailbox.payload; break;
case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration2 = XdrvMailbox.payload; break;
case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration2 = XdrvMailbox.payload; break;
case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break;
}
} else {
switch (cal_type) {
case 0: Settings->energy_power_calibration = XdrvMailbox.payload; break;
case 1: Settings->energy_voltage_calibration = XdrvMailbox.payload; break;
case 2: Settings->energy_current_calibration = XdrvMailbox.payload; break;
case 3: Settings->energy_frequency_calibration = XdrvMailbox.payload; break;
case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration = XdrvMailbox.payload; break;
case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration = XdrvMailbox.payload; break;
case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration = XdrvMailbox.payload; break;
case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break;
}
}
}
if (3 == cal_type) {
if (ENERGY_FREQUENCY_CALIBRATION == cal_type) {
ResponseAppend_P(PSTR("%d}"), Settings->energy_frequency_calibration);
} else {
uint32_t cal_array[2][3];
memcpy(&cal_array, &Settings->energy_power_calibration, 24);
if (2 == Energy.phase_count) {
ResponseAppend_P(PSTR("[%d,%d]}"), cal_array[0][cal_type], cal_array[1][cal_type]);
ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(0, cal_type), EnergyGetCalibration(1, cal_type));
} else {
ResponseAppend_P(PSTR("%d}"), cal_array[0][cal_type]);
ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(0, cal_type));
}
}
}
@ -875,56 +894,56 @@ void EnergyCommandSetCalResponse(uint32_t cal_type) {
void CmndPowerCal(void) {
Energy.command_code = CMND_POWERCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
EnergyCommandCalResponse(0);
EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION);
}
}
void CmndVoltageCal(void) {
Energy.command_code = CMND_VOLTAGECAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
EnergyCommandCalResponse(1);
EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION);
}
}
void CmndCurrentCal(void) {
Energy.command_code = CMND_CURRENTCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
EnergyCommandCalResponse(2);
EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION);
}
}
void CmndFrequencyCal(void) {
Energy.command_code = CMND_FREQUENCYCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
EnergyCommandCalResponse(3);
EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION);
}
}
void CmndPowerSet(void) {
Energy.command_code = CMND_POWERSET;
if (XnrgCall(FUNC_COMMAND)) { // Watt
EnergyCommandSetCalResponse(0);
EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION);
}
}
void CmndVoltageSet(void) {
Energy.command_code = CMND_VOLTAGESET;
if (XnrgCall(FUNC_COMMAND)) { // Volt
EnergyCommandSetCalResponse(1);
EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION);
}
}
void CmndCurrentSet(void) {
Energy.command_code = CMND_CURRENTSET;
if (XnrgCall(FUNC_COMMAND)) { // milliAmpere
EnergyCommandSetCalResponse(2);
EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION);
}
}
void CmndFrequencySet(void) {
Energy.command_code = CMND_FREQUENCYSET;
if (XnrgCall(FUNC_COMMAND)) { // Hz
EnergyCommandSetCalResponse(3);
EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION);
}
}

View File

@ -463,9 +463,9 @@ void Ade7953GetData(void) {
for (uint32_t channel = 0; channel < 2; channel++) {
Energy.data_valid[channel] = 0;
float power_calibration = ((channel) ? Settings->energy_power_calibration2 : Settings->energy_power_calibration) / 10;
float voltage_calibration = (channel) ? Settings->energy_voltage_calibration2 : Settings->energy_voltage_calibration;
float current_calibration = ((channel) ? Settings->energy_current_calibration2 : Settings->energy_current_calibration) * 10;
float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 10;
float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION);
float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) * 10;
Energy.frequency[channel] = 223750.0f / ((float)reg[channel][5] + 1);
divider = (Ade7953.calib_data[channel][ADE7953_CAL_VGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : voltage_calibration;

View File

@ -193,8 +193,8 @@ void Bl09XXUpdateEnergy() {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %2_f, T %2_f"), &Energy.voltage[0], &Bl09XX.temperature);
#endif
for (uint32_t chan = 0; chan < Energy.phase_count; chan++) {
uint32_t power_calibration = (chan) ? Settings->energy_power_calibration2 : Settings->energy_power_calibration;
uint32_t current_calibration = (chan) ? Settings->energy_current_calibration2 : Settings->energy_current_calibration;
uint32_t power_calibration = EnergyGetCalibration(chan, ENERGY_POWER_CALIBRATION);
uint32_t current_calibration = EnergyGetCalibration(chan, ENERGY_CURRENT_CALIBRATION);
if (Bl09XX.power[chan] > power_calibration) { // We need at least 1W
Energy.active_power[chan] = (float)Bl09XX.power[chan] / power_calibration;
Energy.current[chan] = (float)Bl09XX.current[chan] / current_calibration;

View File

@ -468,14 +468,14 @@ void Cse7761GetData(void) {
for (uint32_t channel = 0; channel < 2; channel++) {
Energy.data_valid[channel] = 0;
uint32_t power_calibration = (channel) ? Settings->energy_power_calibration2 : Settings->energy_power_calibration;
uint32_t power_calibration = EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION);
// Active power = PowerPA * PowerPAC * 1000 / 0x80000000
// Energy.active_power[channel] = (float)(((uint64_t)CSE7761Data.active_power[channel] * CSE7761Data.coefficient[PowerPAC + channel] * 1000) >> 31) / 1000; // W
Energy.active_power[channel] = (float)CSE7761Data.active_power[channel] / power_calibration; // W
if (0 == Energy.active_power[channel]) {
Energy.current[channel] = 0;
} else {
uint32_t current_calibration = (channel) ? Settings->energy_current_calibration2 : Settings->energy_current_calibration;
uint32_t current_calibration = EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION);
// Current = RmsIA * RmsIAC / 0x800000
// Energy.current[channel] = (float)(((uint64_t)CSE7761Data.current_rms[channel] * CSE7761Data.coefficient[RmsIAC + channel]) >> 23) / 1000; // A
Energy.current[channel] = (float)CSE7761Data.current_rms[channel] / current_calibration; // A

View File

@ -55,14 +55,20 @@ struct {
void NrgDummyEverySecond(void) {
if (Energy.power_on) { // Powered on
for (uint32_t channel = 0; channel < Energy.phase_count; channel++) {
Energy.voltage[channel] = ((float)Settings->energy_voltage_calibration / 100); // V
Energy.frequency[channel] = ((float)Settings->energy_frequency_calibration / 100); // Hz
if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on
Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : ((float)Settings->energy_power_calibration / 100); // W
float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 100;
float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION) / 100;
float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) / 100000;
float frequency_calibration = (float)EnergyGetCalibration(channel, ENERGY_FREQUENCY_CALIBRATION) / 100;
Energy.voltage[channel] = power_calibration; // V
Energy.frequency[channel] = frequency_calibration; // Hz
if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on
Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : voltage_calibration; // W
if (0 == Energy.active_power[channel]) {
Energy.current[channel] = 0;
} else {
Energy.current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : ((float)Settings->energy_current_calibration / 100000); // A
Energy.current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : current_calibration; // A
Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36;
}
Energy.data_valid[channel] = 0;