10static const char *
const TAG =
"atm90e32";
14 for (uint8_t phase = 0; phase < 3; phase++) {
15 if (this->
phase_[phase].voltage_sensor_ !=
nullptr)
18 if (this->
phase_[phase].current_sensor_ !=
nullptr)
21 if (this->
phase_[phase].power_sensor_ !=
nullptr)
24 if (this->
phase_[phase].power_factor_sensor_ !=
nullptr)
27 if (this->
phase_[phase].reactive_power_sensor_ !=
nullptr)
30 if (this->
phase_[phase].apparent_power_sensor_ !=
nullptr)
33 if (this->
phase_[phase].forward_active_energy_sensor_ !=
nullptr)
36 if (this->
phase_[phase].reverse_active_energy_sensor_ !=
nullptr)
39 if (this->
phase_[phase].phase_angle_sensor_ !=
nullptr)
42 if (this->
phase_[phase].harmonic_active_power_sensor_ !=
nullptr)
45 if (this->
phase_[phase].peak_current_sensor_ !=
nullptr)
49 if (this->
phase_[phase].voltage_sensor_ !=
nullptr)
52 if (this->
phase_[phase].current_sensor_ !=
nullptr)
55 if (this->
phase_[phase].power_sensor_ !=
nullptr)
58 if (this->
phase_[phase].power_factor_sensor_ !=
nullptr)
61 if (this->
phase_[phase].reactive_power_sensor_ !=
nullptr)
64 if (this->
phase_[phase].apparent_power_sensor_ !=
nullptr)
67 if (this->
phase_[phase].forward_active_energy_sensor_ !=
nullptr) {
72 if (this->
phase_[phase].reverse_active_energy_sensor_ !=
nullptr) {
77 if (this->
phase_[phase].phase_angle_sensor_ !=
nullptr)
80 if (this->
phase_[phase].harmonic_active_power_sensor_ !=
nullptr) {
85 if (this->
phase_[phase].peak_current_sensor_ !=
nullptr)
97 if (this->
read16_(ATM90E32_REGISTER_METEREN) != 1) {
104#ifdef USE_TEXT_SENSOR
120 uint16_t mmode0 = 0x87;
121 uint16_t high_thresh = 0;
122 uint16_t low_thresh = 0;
139 this->
write16_(ATM90E32_REGISTER_SOFTRESET, 0x789A,
false);
141 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
143 ESP_LOGW(TAG,
"Could not initialize ATM90E32 IC, check SPI settings");
148 this->
write16_(ATM90E32_REGISTER_METEREN, 0x0001);
149 this->
write16_(ATM90E32_REGISTER_SAGPEAKDETCFG, 0xFF3F);
150 this->
write16_(ATM90E32_REGISTER_PLCONSTH, 0x0861);
151 this->
write16_(ATM90E32_REGISTER_PLCONSTL, 0xC468);
152 this->
write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654);
153 this->
write16_(ATM90E32_REGISTER_MMODE0, mmode0);
155 this->
write16_(ATM90E32_REGISTER_FREQHITH, high_thresh);
156 this->
write16_(ATM90E32_REGISTER_FREQLOTH, low_thresh);
157 this->
write16_(ATM90E32_REGISTER_PSTARTTH, 0x1D4C);
158 this->
write16_(ATM90E32_REGISTER_QSTARTTH, 0x1D4C);
159 this->
write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C);
160 this->
write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE);
161 this->
write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE);
165 uint32_t o_hash =
fnv1_hash(
"_offset_calibration_");
171 uint32_t po_hash =
fnv1_hash(
"_power_offset_calibration_");
176 ESP_LOGI(TAG,
"[CALIBRATION][%s] Power & Voltage/Current offset calibration is disabled. Using config file values.",
178 for (uint8_t phase = 0; phase < 3; ++phase) {
180 static_cast<uint16_t
>(this->
offset_phase_[phase].voltage_offset_));
182 static_cast<uint16_t
>(this->
offset_phase_[phase].current_offset_));
192 uint32_t g_hash =
fnv1_hash(
"_gain_calibration_");
198 for (uint8_t phase = 0; phase < 3; ++phase) {
204 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration is disabled. Using config file values.", cs);
205 for (uint8_t phase = 0; phase < 3; ++phase) {
217 this->
write16_(ATM90E32_REGISTER_SAGTH, sagth);
218 this->
write16_(ATM90E32_REGISTER_OVTH, ovth);
220 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
227 bool offset_mismatch =
false;
228 bool power_mismatch =
false;
229 bool gain_mismatch =
false;
231 for (uint8_t phase = 0; phase < 3; ++phase) {
237 if (offset_mismatch) {
238 ESP_LOGW(TAG,
"[CALIBRATION][%s] ", cs);
240 "[CALIBRATION][%s] ===================== Offset mismatch: using flash values =====================", cs);
241 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
243 ESP_LOGW(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
244 ESP_LOGW(TAG,
"[CALIBRATION][%s] | | config | flash | config | flash |", cs);
245 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
247 for (uint8_t phase = 0; phase < 3; ++phase) {
248 ESP_LOGW(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d | %6d | %6d |", cs,
'A' + phase,
253 "[CALIBRATION][%s] ===============================================================================", cs);
255 if (power_mismatch) {
256 ESP_LOGW(TAG,
"[CALIBRATION][%s] ", cs);
258 "[CALIBRATION][%s] ================= Power offset mismatch: using flash values =================", cs);
259 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
261 ESP_LOGW(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power|offset_reactive_power|", cs);
262 ESP_LOGW(TAG,
"[CALIBRATION][%s] | | config | flash | config | flash |", cs);
263 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
265 for (uint8_t phase = 0; phase < 3; ++phase) {
266 ESP_LOGW(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d | %6d | %6d |", cs,
'A' + phase,
273 "[CALIBRATION][%s] ===============================================================================", cs);
276 ESP_LOGW(TAG,
"[CALIBRATION][%s] ", cs);
278 "[CALIBRATION][%s] ====================== Gain mismatch: using flash values =====================", cs);
279 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
281 ESP_LOGW(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
282 ESP_LOGW(TAG,
"[CALIBRATION][%s] | | config | flash | config | flash |", cs);
283 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
285 for (uint8_t phase = 0; phase < 3; ++phase) {
286 ESP_LOGW(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u | %6u | %6u |", cs,
'A' + phase,
291 "[CALIBRATION][%s] ===============================================================================", cs);
294 ESP_LOGI(TAG,
"[CALIBRATION][%s] Power & Voltage/Current offset calibration is disabled. Using config file values.",
297 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
298 ESP_LOGI(TAG,
"[CALIBRATION][%s] ============== Restored offset calibration from memory ==============", cs);
299 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
300 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
301 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
302 for (uint8_t phase = 0; phase < 3; phase++) {
303 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
306 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==============================================================\\n", cs);
310 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
311 ESP_LOGI(TAG,
"[CALIBRATION][%s] ============ Restored power offset calibration from memory ============", cs);
312 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
313 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
314 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
315 for (uint8_t phase = 0; phase < 3; phase++) {
316 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
320 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
323 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration is disabled. Using config file values.", cs);
325 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
326 ESP_LOGI(TAG,
"[CALIBRATION][%s] ============ Restoring saved gain calibrations to registers ============", cs);
327 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
328 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
329 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
330 for (uint8_t phase = 0; phase < 3; phase++) {
331 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u |", cs,
'A' + phase,
334 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\\n", cs);
335 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration loaded and verified successfully.\n", cs);
341 ESP_LOGCONFIG(
"",
"ATM90E32:");
342 LOG_PIN(
" CS Pin: ", this->
cs_);
344 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
346 LOG_UPDATE_INTERVAL(
this);
347 LOG_SENSOR(
" ",
"Voltage A", this->
phase_[
PHASEA].voltage_sensor_);
348 LOG_SENSOR(
" ",
"Current A", this->
phase_[
PHASEA].current_sensor_);
349 LOG_SENSOR(
" ",
"Power A", this->
phase_[
PHASEA].power_sensor_);
350 LOG_SENSOR(
" ",
"Reactive Power A", this->
phase_[
PHASEA].reactive_power_sensor_);
351 LOG_SENSOR(
" ",
"Apparent Power A", this->
phase_[
PHASEA].apparent_power_sensor_);
352 LOG_SENSOR(
" ",
"PF A", this->
phase_[
PHASEA].power_factor_sensor_);
353 LOG_SENSOR(
" ",
"Active Forward Energy A", this->
phase_[
PHASEA].forward_active_energy_sensor_);
354 LOG_SENSOR(
" ",
"Active Reverse Energy A", this->
phase_[
PHASEA].reverse_active_energy_sensor_);
355 LOG_SENSOR(
" ",
"Harmonic Power A", this->
phase_[
PHASEA].harmonic_active_power_sensor_);
356 LOG_SENSOR(
" ",
"Phase Angle A", this->
phase_[
PHASEA].phase_angle_sensor_);
357 LOG_SENSOR(
" ",
"Peak Current A", this->
phase_[
PHASEA].peak_current_sensor_);
358 LOG_SENSOR(
" ",
"Voltage B", this->
phase_[
PHASEB].voltage_sensor_);
359 LOG_SENSOR(
" ",
"Current B", this->
phase_[
PHASEB].current_sensor_);
360 LOG_SENSOR(
" ",
"Power B", this->
phase_[
PHASEB].power_sensor_);
361 LOG_SENSOR(
" ",
"Reactive Power B", this->
phase_[
PHASEB].reactive_power_sensor_);
362 LOG_SENSOR(
" ",
"Apparent Power B", this->
phase_[
PHASEB].apparent_power_sensor_);
363 LOG_SENSOR(
" ",
"PF B", this->
phase_[
PHASEB].power_factor_sensor_);
364 LOG_SENSOR(
" ",
"Active Forward Energy B", this->
phase_[
PHASEB].forward_active_energy_sensor_);
365 LOG_SENSOR(
" ",
"Active Reverse Energy B", this->
phase_[
PHASEB].reverse_active_energy_sensor_);
366 LOG_SENSOR(
" ",
"Harmonic Power B", this->
phase_[
PHASEB].harmonic_active_power_sensor_);
367 LOG_SENSOR(
" ",
"Phase Angle B", this->
phase_[
PHASEB].phase_angle_sensor_);
368 LOG_SENSOR(
" ",
"Peak Current B", this->
phase_[
PHASEB].peak_current_sensor_);
369 LOG_SENSOR(
" ",
"Voltage C", this->
phase_[
PHASEC].voltage_sensor_);
370 LOG_SENSOR(
" ",
"Current C", this->
phase_[
PHASEC].current_sensor_);
371 LOG_SENSOR(
" ",
"Power C", this->
phase_[
PHASEC].power_sensor_);
372 LOG_SENSOR(
" ",
"Reactive Power C", this->
phase_[
PHASEC].reactive_power_sensor_);
373 LOG_SENSOR(
" ",
"Apparent Power C", this->
phase_[
PHASEC].apparent_power_sensor_);
374 LOG_SENSOR(
" ",
"PF C", this->
phase_[
PHASEC].power_factor_sensor_);
375 LOG_SENSOR(
" ",
"Active Forward Energy C", this->
phase_[
PHASEC].forward_active_energy_sensor_);
376 LOG_SENSOR(
" ",
"Active Reverse Energy C", this->
phase_[
PHASEC].reverse_active_energy_sensor_);
377 LOG_SENSOR(
" ",
"Harmonic Power C", this->
phase_[
PHASEC].harmonic_active_power_sensor_);
378 LOG_SENSOR(
" ",
"Phase Angle C", this->
phase_[
PHASEC].phase_angle_sensor_);
379 LOG_SENSOR(
" ",
"Peak Current C", this->
phase_[
PHASEC].peak_current_sensor_);
396 uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
397 uint8_t addrl = (a_register & 0xFF);
398 uint8_t data[4] = {addrh, addrl, 0x00, 0x00};
401 ESP_LOGVV(TAG,
"read16_ 0x%04" PRIX16
" output 0x%04" PRIX16, a_register, output);
409 const uint16_t val_h = this->
read16_(addr_h);
410 const uint16_t val_l = this->
read16_(addr_l);
411 const int32_t
val = (val_h << 16) | val_l;
414 "read32_ addr_h 0x%04" PRIX16
" val_h 0x%04" PRIX16
" addr_l 0x%04" PRIX16
" val_l 0x%04" PRIX16
416 addr_h, val_h, addr_l, val_l,
val);
422 ESP_LOGVV(TAG,
"write16_ 0x%04" PRIX16
" val 0x%04" PRIX16, a_register,
val);
423 uint8_t addrh = ((a_register >> 8) & 0x03);
424 uint8_t addrl = (a_register & 0xFF);
425 uint8_t data[4] = {addrh, addrl, uint8_t((
val >> 8) & 0xFF), uint8_t(
val & 0xFF)};
465 const uint16_t voltage = this->
read16_(ATM90E32_REGISTER_URMS + phase);
467 return (
float) voltage / 100;
471 const uint8_t reads = 10;
472 uint32_t accumulation = 0;
473 uint16_t voltage = 0;
474 for (uint8_t i = 0; i < reads; i++) {
475 voltage = this->
read16_(ATM90E32_REGISTER_URMS + phase);
477 accumulation += voltage;
479 voltage = accumulation / reads;
485 const uint8_t reads = 10;
486 uint32_t accumulation = 0;
487 uint16_t current = 0;
488 for (uint8_t i = 0; i < reads; i++) {
489 current = this->
read16_(ATM90E32_REGISTER_IRMS + phase);
491 accumulation += current;
493 current = accumulation / reads;
499 const uint16_t current = this->
read16_(ATM90E32_REGISTER_IRMS + phase);
501 return (
float) current / 1000;
505 const int val = this->
read32_(ATM90E32_REGISTER_PMEAN + phase, ATM90E32_REGISTER_PMEANLSB + phase);
506 return val * 0.00032f;
510 const int val = this->
read32_(ATM90E32_REGISTER_QMEAN + phase, ATM90E32_REGISTER_QMEANLSB + phase);
511 return val * 0.00032f;
515 const int val = this->
read32_(ATM90E32_REGISTER_SMEAN + phase, ATM90E32_REGISTER_SMEANLSB + phase);
516 return val * 0.00032f;
520 uint16_t powerfactor = this->
read16_(ATM90E32_REGISTER_PFMEAN + phase);
522 return (
float) ((int16_t) powerfactor) / 1000;
526 const uint16_t
val = this->
read16_(ATM90E32_REGISTER_APENERGY + phase);
527 if ((UINT32_MAX - this->
phase_[phase].cumulative_forward_active_energy_) >
val) {
533 return ((
float) this->
phase_[phase].cumulative_forward_active_energy_ * (10.0f / 3200.0f));
537 const uint16_t
val = this->
read16_(ATM90E32_REGISTER_ANENERGY + phase);
538 if (UINT32_MAX - this->
phase_[phase].cumulative_reverse_active_energy_ >
val) {
544 return ((
float) this->
phase_[phase].cumulative_reverse_active_energy_ * (10.0f / 3200.0f));
548 int val = this->
read32_(ATM90E32_REGISTER_PMEANH + phase, ATM90E32_REGISTER_PMEANHLSB + phase);
549 return val * 0.00032f;
553 uint16_t
val = this->
read16_(ATM90E32_REGISTER_PANGLE + phase) / 10.0;
554 return (
val > 180) ? (float) (
val - 360.0f) : (float)
val;
558 int16_t
val = (float) this->
read16_(ATM90E32_REGISTER_IPEAK + phase);
562 return (
val * this->
phase_[phase].ct_gain_ / 8192000.0);
566 const uint16_t freq = this->
read16_(ATM90E32_REGISTER_FREQ);
567 return (
float) freq / 100;
571 const uint16_t ctemp = this->
read16_(ATM90E32_REGISTER_TEMP);
572 return (
float) ctemp;
579 ESP_LOGW(TAG,
"[CALIBRATION][%s] Gain calibration is disabled! Enable it first with enable_gain_calibration: true",
584 float ref_voltages[3] = {
592 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
593 ESP_LOGI(TAG,
"[CALIBRATION][%s] ========================= Gain Calibration =========================", cs);
594 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
597 "[CALIBRATION][%s] | Phase | V_meas (V) | I_meas (A) | V_ref | I_ref | V_gain (old→new) | I_gain (old→new) |",
599 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
601 for (uint8_t phase = 0; phase < 3; phase++) {
605 float ref_voltage = ref_voltages[phase];
606 float ref_current = ref_currents[phase];
611 bool did_voltage =
false;
612 bool did_current =
false;
615 if (ref_voltage <= 0.0f) {
616 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping voltage calibration: reference voltage is 0.", cs,
618 }
else if (measured_voltage == 0.0f) {
619 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping voltage calibration: measured voltage is 0.", cs,
622 uint32_t new_voltage_gain =
static_cast<uint16_t
>((ref_voltage / measured_voltage) * current_voltage_gain);
623 if (new_voltage_gain == 0) {
624 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Voltage gain would be 0. Check reference and measured voltage.", cs,
627 if (new_voltage_gain >= 65535) {
629 "[CALIBRATION][%s] Phase %s - Voltage gain exceeds 65535. You may need a higher output voltage "
632 new_voltage_gain = 65535;
640 if (ref_current == 0.0f) {
641 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping current calibration: reference current is 0.", cs,
643 }
else if (measured_current == 0.0f) {
644 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping current calibration: measured current is 0.", cs,
647 uint32_t new_current_gain =
static_cast<uint16_t
>((ref_current / measured_current) * current_current_gain);
648 if (new_current_gain == 0) {
649 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Current gain would be 0. Check reference and measured current.", cs,
652 if (new_current_gain >= 65535) {
653 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Current gain exceeds 65535. You may need to turn up pga gain.",
655 new_current_gain = 65535;
663 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %9.2f | %9.4f | %5.2f | %6.4f | %5u → %-5u | %5u → %-5u |", cs,
664 'A' + phase, measured_voltage, measured_current, ref_voltage, ref_current, current_voltage_gain,
665 did_voltage ? this->
gain_phase_[phase].voltage_gain : current_voltage_gain, current_current_gain,
666 did_current ? this->
gain_phase_[phase].current_gain : current_current_gain);
669 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
683 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration saved to memory.", cs);
686 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to save gain calibration to memory!", cs);
700 ESP_LOGI(TAG,
"[CALIBRATION][%s] Offset calibration saved to memory.", cs);
703 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to save offset calibration to memory!", cs);
717 ESP_LOGI(TAG,
"[CALIBRATION][%s] Power offset calibration saved to memory.", cs);
720 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to save power offset calibration to memory!", cs);
729 "[CALIBRATION][%s] Offset calibration is disabled! Enable it first with enable_offset_calibration: true",
734 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
735 ESP_LOGI(TAG,
"[CALIBRATION][%s] ======================== Offset Calibration ========================", cs);
736 ESP_LOGI(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------", cs);
737 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
738 ESP_LOGI(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------", cs);
740 for (uint8_t phase = 0; phase < 3; phase++) {
746 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, voltage_offset,
750 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==================================================================\n", cs);
761 "[CALIBRATION][%s] Offset power calibration is disabled! Enable it first with enable_offset_calibration: true",
766 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
767 ESP_LOGI(TAG,
"[CALIBRATION][%s] ===================== Power Offset Calibration =====================", cs);
768 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
769 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
770 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
772 for (uint8_t phase = 0; phase < 3; ++phase) {
778 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, active_offset,
781 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
787 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
789 for (
int phase = 0; phase < 3; phase++) {
794 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
807 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
810 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
823 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
826 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
832 for (uint8_t i = 0; i < 3; ++i) {
839 bool all_zero =
true;
840 bool same_as_config =
true;
841 for (uint8_t phase = 0; phase < 3; ++phase) {
844 if (saved.voltage_gain != 0 || saved.current_gain != 0)
846 if (saved.voltage_gain != cfg.voltage_gain || saved.current_gain != cfg.current_gain)
847 same_as_config =
false;
850 if (!all_zero && !same_as_config) {
851 for (uint8_t phase = 0; phase < 3; ++phase) {
852 bool mismatch =
false;
872 ESP_LOGE(TAG,
"[CALIBRATION][%s] Gain verification failed! Calibration may not be applied correctly.", cs);
877 for (uint8_t i = 0; i < 3; ++i)
881 ESP_LOGW(TAG,
"[CALIBRATION][%s] No stored gain calibrations found. Using config file values.", cs);
887 for (uint8_t i = 0; i < 3; ++i)
891 bool all_zero =
true;
894 if (phase.voltage_offset_ != 0 || phase.current_offset_ != 0) {
901 if (have_data && !all_zero) {
903 for (uint8_t phase = 0; phase < 3; phase++) {
905 bool mismatch =
false;
907 offset.voltage_offset_ != this->config_offset_phase_[phase].voltage_offset_)
910 offset.current_offset_ != this->config_offset_phase_[phase].current_offset_)
916 for (uint8_t phase = 0; phase < 3; phase++)
918 ESP_LOGW(TAG,
"[CALIBRATION][%s] No stored offset calibrations found. Using default values.", cs);
921 for (uint8_t phase = 0; phase < 3; phase++) {
930 for (uint8_t i = 0; i < 3; ++i)
934 bool all_zero =
true;
937 if (phase.active_power_offset != 0 || phase.reactive_power_offset != 0) {
944 if (have_data && !all_zero) {
946 for (uint8_t phase = 0; phase < 3; ++phase) {
948 bool mismatch =
false;
950 offset.active_power_offset != this->config_power_offset_phase_[phase].active_power_offset)
953 offset.reactive_power_offset != this->config_power_offset_phase_[phase].reactive_power_offset)
959 for (uint8_t phase = 0; phase < 3; ++phase)
961 ESP_LOGW(TAG,
"[CALIBRATION][%s] No stored power offsets found. Using default values.", cs);
964 for (uint8_t phase = 0; phase < 3; ++phase) {
974 ESP_LOGI(TAG,
"[CALIBRATION][%s] No stored gain calibrations to clear. Current values:", cs);
975 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
976 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
977 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
978 for (
int phase = 0; phase < 3; phase++) {
979 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u |", cs,
'A' + phase,
982 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==========================================================\n", cs);
986 ESP_LOGI(TAG,
"[CALIBRATION][%s] Clearing stored gain calibrations and restoring config-defined values", cs);
987 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
988 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
989 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
991 for (
int phase = 0; phase < 3; phase++) {
1000 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u |", cs,
'A' + phase, voltage_gain, current_gain);
1002 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==========================================================\n", cs);
1014 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to clear gain calibrations!", cs);
1024 ESP_LOGI(TAG,
"[CALIBRATION][%s] No stored offset calibrations to clear. Current values:", cs);
1025 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1026 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
1027 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1028 for (uint8_t phase = 0; phase < 3; phase++) {
1029 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
1032 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==============================================================\n", cs);
1036 ESP_LOGI(TAG,
"[CALIBRATION][%s] Clearing stored offset calibrations and restoring config-defined values", cs);
1037 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1038 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
1039 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1041 for (uint8_t phase = 0; phase < 3; phase++) {
1042 int16_t voltage_offset =
1044 int16_t current_offset =
1047 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, voltage_offset,
1050 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==============================================================\n", cs);
1060 ESP_LOGI(TAG,
"[CALIBRATION][%s] Offsets cleared.", cs);
1067 ESP_LOGI(TAG,
"[CALIBRATION][%s] No stored power offsets to clear. Current values:", cs);
1068 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1069 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
1070 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1071 for (uint8_t phase = 0; phase < 3; phase++) {
1072 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
1076 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
1080 ESP_LOGI(TAG,
"[CALIBRATION][%s] Clearing stored power offsets and restoring config-defined values", cs);
1081 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1082 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
1083 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1085 for (uint8_t phase = 0; phase < 3; phase++) {
1086 int16_t active_offset =
1092 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, active_offset,
1095 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
1105 ESP_LOGI(TAG,
"[CALIBRATION][%s] Power offsets cleared.", cs);
1109 const uint8_t num_reads = 5;
1110 uint64_t total_value = 0;
1112 for (uint8_t i = 0; i < num_reads; ++i) {
1113 uint32_t reading = voltage ? this->
read32_(ATM90E32_REGISTER_URMS + phase, ATM90E32_REGISTER_URMSLSB + phase)
1114 : this->
read32_(ATM90E32_REGISTER_IRMS + phase, ATM90E32_REGISTER_IRMSLSB + phase);
1115 total_value += reading;
1118 const uint32_t average_value = total_value / num_reads;
1119 const uint32_t shifted = average_value >> 7;
1120 const uint32_t offset = ~shifted + 1;
1121 return static_cast<int16_t
>(offset);
1125 const uint8_t num_reads = 5;
1126 int64_t total_value = 0;
1128 for (uint8_t i = 0; i < num_reads; ++i) {
1129 int32_t reading = reactive ? this->
read32_(ATM90E32_REGISTER_QMEAN + phase, ATM90E32_REGISTER_QMEANLSB + phase)
1130 : this->
read32_(ATM90E32_REGISTER_PMEAN + phase, ATM90E32_REGISTER_PMEANLSB + phase);
1131 total_value += reading;
1134 int32_t average_value = total_value / num_reads;
1135 int32_t power_offset = -average_value;
1136 return static_cast<int16_t
>(power_offset);
1142 bool success =
true;
1143 for (uint8_t phase = 0; phase < 3; phase++) {
1147 if (read_voltage != this->
gain_phase_[phase].voltage_gain ||
1148 read_current != this->
gain_phase_[phase].current_gain) {
1149 ESP_LOGE(TAG,
"[CALIBRATION][%s] Mismatch detected for Phase %s!", cs,
phase_labels[phase]);
1156#ifdef USE_TEXT_SENSOR
1158 uint16_t state0 = this->
read16_(ATM90E32_REGISTER_EMMSTATE0);
1159 uint16_t state1 = this->
read16_(ATM90E32_REGISTER_EMMSTATE1);
1161 for (
int phase = 0; phase < 3; phase++) {
1165 status +=
"Over Voltage; ";
1167 status +=
"Voltage Sag; ";
1169 status +=
"Phase Loss; ";
1172 if (sensor ==
nullptr)
1178 ESP_LOGW(TAG,
"%s: %s", sensor->get_name().c_str(),
status.c_str());
1179 sensor->publish_state(
status);
1181 sensor->publish_state(
"Okay");
1187 uint16_t state1 = this->
read16_(ATM90E32_REGISTER_EMMSTATE1);
1189 std::string freq_status;
1191 if (state1 & ATM90E32_STATUS_S1_FREQHIST) {
1192 freq_status =
"HIGH";
1193 }
else if (state1 & ATM90E32_STATUS_S1_FREQLOST) {
1194 freq_status =
"LOW";
1196 freq_status =
"Normal";
1199 if (freq_status ==
"Normal") {
1200 ESP_LOGD(TAG,
"Frequency status: %s", freq_status.c_str());
1202 ESP_LOGW(TAG,
"Frequency status: %s", freq_status.c_str());
1209 constexpr float max_current_threshold = 65.53f;
1211 for (uint8_t phase = 0; phase < 3; phase++) {
1215 if (current_val > max_current_threshold) {
1216 ESP_LOGW(TAG,
"Over current detected on Phase %c: %.2f A",
'A' + phase, current_val);
1217 ESP_LOGW(TAG,
"You may need to half your gain_ct: value & multiply the current and power values by 2");
1229 float nominal_voltage = (line_freq == 60) ? 120.0f : 220.0f;
1230 float target_voltage = nominal_voltage * multiplier;
1232 float peak_01v = target_voltage * 100.0f * std::numbers::sqrt2_v<float>;
1233 float divider = (2.0f * ugain) / 32768.0f;
1235 float threshold = peak_01v / divider;
1237 return static_cast<uint16_t
>(threshold);
1241 uint16_t last = this->
read16_(ATM90E32_REGISTER_LASTSPIDATA);
1242 if (last != expected) {
1243 if (context !=
nullptr) {
1244 ESP_LOGW(TAG,
"[%s] SPI read mismatch: expected 0x%04X, got 0x%04X", context, expected, last);
1246 ESP_LOGW(TAG,
"SPI read mismatch: expected 0x%04X, got 0x%04X", expected, last);
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
void status_clear_warning()
virtual bool sync()=0
Commit pending writes to flash.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
virtual size_t dump_summary(char *buffer, size_t len) const
Write a summary of this pin to the provided buffer.
bool enable_offset_calibration_
float get_local_phase_reactive_power_(uint8_t phase)
float get_phase_forward_active_energy_(uint8_t phase)
bool restored_gain_calibration_
bool has_config_voltage_gain_[3]
sensor::Sensor * freq_sensor_
void run_gain_calibrations()
bool gain_calibration_mismatch_[3]
bool has_config_active_power_offset_[3]
float get_phase_current_avg_(uint8_t phase)
float get_local_phase_apparent_power_(uint8_t phase)
void write16_(uint16_t a_register, uint16_t val, bool validate=true)
bool has_config_reactive_power_offset_[3]
void save_offset_calibration_to_memory_()
text_sensor::TextSensor * freq_status_text_sensor_
ESPPreferenceObject power_offset_pref_
const uint16_t voltage_gain_registers[3]
float get_phase_voltage_avg_(uint8_t phase)
void write_power_offsets_to_registers_(uint8_t phase, int16_t p_offset, int16_t q_offset)
const uint16_t current_gain_registers[3]
void run_offset_calibrations()
float get_reference_voltage(uint8_t phase)
struct esphome::atm90e32::ATM90E32Component::GainCalibration gain_phase_[3]
bool get_publish_interval_flag_()
const uint16_t current_offset_registers[3]
static const uint8_t PHASEB
float get_phase_reverse_active_energy_(uint8_t phase)
float get_local_phase_harmonic_active_power_(uint8_t phase)
void check_phase_status()
float get_phase_angle_(uint8_t phase)
float get_local_phase_current_(uint8_t phase)
bool validate_spi_read_(uint16_t expected, const char *context=nullptr)
void restore_offset_calibrations_()
const uint16_t reactive_power_offset_registers[3]
const uint16_t over_voltage_flags[3]
void clear_power_offset_calibrations()
float get_phase_voltage_(uint8_t phase)
float get_chip_temperature_()
GainCalibration config_gain_phase_[3]
bool restored_power_offset_calibration_
int16_t calibrate_offset(uint8_t phase, bool voltage)
float get_local_phase_reverse_active_energy_(uint8_t phase)
void dump_config() override
void restore_gain_calibrations_()
float get_local_phase_forward_active_energy_(uint8_t phase)
OffsetCalibration config_offset_phase_[3]
bool peak_current_signed_
struct esphome::atm90e32::ATM90E32Component::OffsetCalibration offset_phase_[3]
void restore_power_offset_calibrations_()
uint16_t calculate_voltage_threshold(int line_freq, uint16_t ugain, float multiplier)
float get_local_phase_power_factor_(uint8_t phase)
bool calibration_message_printed_
float get_phase_reactive_power_(uint8_t phase)
void clear_offset_calibrations()
bool has_config_current_offset_[3]
const uint16_t phase_loss_flags[3]
void log_calibration_status_()
float get_phase_apparent_power_(uint8_t phase)
void write_gains_to_registers_()
float get_local_phase_voltage_(uint8_t phase)
void check_over_current()
ESPPreferenceObject gain_calibration_pref_
void write_offsets_to_registers_(uint8_t phase, int16_t voltage_offset, int16_t current_offset)
static const uint8_t PHASEA
struct esphome::atm90e32::ATM90E32Component::PowerOffsetCalibration power_offset_phase_[3]
float get_reference_current(uint8_t phase)
bool verify_gain_writes_()
bool using_saved_calibrations_
float get_phase_peak_current_(uint8_t phase)
void clear_gain_calibrations()
float get_phase_harmonic_active_power_(uint8_t phase)
bool has_config_current_gain_[3]
const uint16_t voltage_sag_flags[3]
bool restored_offset_calibration_
float get_phase_active_power_(uint8_t phase)
PowerOffsetCalibration config_power_offset_phase_[3]
void run_power_offset_calibrations()
bool enable_gain_calibration_
void get_cs_summary_(std::span< char, GPIO_SUMMARY_MAX_LEN > buffer)
static const uint8_t PHASEC
bool power_offset_calibration_mismatch_[3]
const uint16_t power_offset_registers[3]
float get_setup_priority() const override
uint16_t read16_(uint16_t a_register)
int read32_(uint16_t addr_h, uint16_t addr_l)
sensor::Sensor * chip_temperature_sensor_
float get_phase_power_factor_(uint8_t phase)
float get_local_phase_angle_(uint8_t phase)
const uint16_t voltage_offset_registers[3]
void save_gain_calibration_to_memory_()
bool has_config_voltage_offset_[3]
bool offset_calibration_mismatch_[3]
void save_power_offset_calibration_to_memory_()
text_sensor::TextSensor * phase_status_text_sensor_[3]
float get_phase_current_(uint8_t phase)
float get_local_phase_peak_current_(uint8_t phase)
void set_publish_interval_flag_(bool flag)
int16_t calibrate_power_offset(uint8_t phase, bool reactive)
struct esphome::atm90e32::ATM90E32Component::ATM90E32Phase phase_[3]
const char * phase_labels[3]
ESPPreferenceObject offset_pref_
float get_local_phase_active_power_(uint8_t phase)
void publish_state(float state)
Publish a new state to the front-end.
float state
This member variable stores the last state that has passed through all filters.
void spi_setup() override
void transfer_array(uint8_t *data, size_t length)
void write_array(const uint8_t *data, size_t length)
void publish_state(const std::string &state)
const float IO
For components that represent GPIO pins like PCF8573.
Providing packet encoding functions for exchanging data with a remote host.
constexpr uint32_t fnv1_hash_extend(uint32_t hash, T value)
Extend a FNV-1 hash with an integer (hashes each byte).
ESPPreferences * global_preferences
uint32_t fnv1_hash(const char *str)
Calculate a FNV-1 hash of str.
void IRAM_ATTR HOT delay_microseconds_safe(uint32_t us)
Delay for the given amount of microseconds, possibly yielding to other processes during the wait.
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
constexpr size_t GPIO_SUMMARY_MAX_LEN
Maximum buffer size for dump_summary output.
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t cumulative_reverse_active_energy_
float reverse_active_energy_
int16_t active_power_offset_
sensor::Sensor * reactive_power_sensor_
sensor::Sensor * peak_current_sensor_
float forward_active_energy_
sensor::Sensor * power_factor_sensor_
sensor::Sensor * phase_angle_sensor_
sensor::Sensor * apparent_power_sensor_
sensor::Sensor * power_sensor_
sensor::Sensor * current_sensor_
sensor::Sensor * forward_active_energy_sensor_
sensor::Sensor * harmonic_active_power_sensor_
int16_t reactive_power_offset_
sensor::Sensor * reverse_active_energy_sensor_
float harmonic_active_power_
sensor::Sensor * voltage_sensor_
uint32_t cumulative_forward_active_energy_
int16_t reactive_power_offset
int16_t active_power_offset