mirror of https://github.com/arendst/Tasmota.git
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:
parent
cd14c15c41
commit
41b65fd6b7
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue