10static const char *
const TAG =
"atm90e32";
12static const LogString *offset_calibration_name(
bool power_offsets) {
13 return power_offsets ? LOG_STR(
"Power offset") : LOG_STR(
"Offset");
16static uint32_t pref_hash(
const char *prefix,
const char *name_space) {
25 if (current_pref.
load(¤t)) {
37 for (uint8_t phase = 0; phase < 3; phase++) {
38 if (this->
phase_[phase].voltage_sensor_ !=
nullptr)
41 if (this->
phase_[phase].current_sensor_ !=
nullptr)
44 if (this->
phase_[phase].power_sensor_ !=
nullptr)
47 if (this->
phase_[phase].power_factor_sensor_ !=
nullptr)
50 if (this->
phase_[phase].reactive_power_sensor_ !=
nullptr)
53 if (this->
phase_[phase].apparent_power_sensor_ !=
nullptr)
56 if (this->
phase_[phase].forward_active_energy_sensor_ !=
nullptr)
59 if (this->
phase_[phase].reverse_active_energy_sensor_ !=
nullptr)
62 if (this->
phase_[phase].phase_angle_sensor_ !=
nullptr)
65 if (this->
phase_[phase].harmonic_active_power_sensor_ !=
nullptr)
68 if (this->
phase_[phase].peak_current_sensor_ !=
nullptr)
72 if (this->
phase_[phase].voltage_sensor_ !=
nullptr)
75 if (this->
phase_[phase].current_sensor_ !=
nullptr)
78 if (this->
phase_[phase].power_sensor_ !=
nullptr)
81 if (this->
phase_[phase].power_factor_sensor_ !=
nullptr)
84 if (this->
phase_[phase].reactive_power_sensor_ !=
nullptr)
87 if (this->
phase_[phase].apparent_power_sensor_ !=
nullptr)
90 if (this->
phase_[phase].forward_active_energy_sensor_ !=
nullptr) {
95 if (this->
phase_[phase].reverse_active_energy_sensor_ !=
nullptr) {
100 if (this->
phase_[phase].phase_angle_sensor_ !=
nullptr)
103 if (this->
phase_[phase].harmonic_active_power_sensor_ !=
nullptr) {
108 if (this->
phase_[phase].peak_current_sensor_ !=
nullptr)
120 if (this->
read16_(ATM90E32_REGISTER_METEREN) != 1) {
127#ifdef USE_TEXT_SENSOR
145 const bool has_distinct_legacy_namespace = strcmp(cs, legacy_cs) != 0;
147 uint16_t mmode0 = 0x87;
148 uint16_t high_thresh = 0;
149 uint16_t low_thresh = 0;
166 this->
write16_(ATM90E32_REGISTER_SOFTRESET, 0x789A,
false);
168 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
170 ESP_LOGW(TAG,
"Could not initialize ATM90E32 IC, check SPI settings");
175 this->
write16_(ATM90E32_REGISTER_METEREN, 0x0001);
176 this->
write16_(ATM90E32_REGISTER_SAGPEAKDETCFG, 0xFF3F);
177 this->
write16_(ATM90E32_REGISTER_PLCONSTH, 0x0861);
178 this->
write16_(ATM90E32_REGISTER_PLCONSTL, 0xC468);
179 this->
write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654);
180 this->
write16_(ATM90E32_REGISTER_MMODE0, mmode0);
182 this->
write16_(ATM90E32_REGISTER_FREQHITH, high_thresh);
183 this->
write16_(ATM90E32_REGISTER_FREQLOTH, low_thresh);
184 this->
write16_(ATM90E32_REGISTER_PSTARTTH, 0x1D4C);
185 this->
write16_(ATM90E32_REGISTER_QSTARTTH, 0x1D4C);
186 this->
write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C);
187 this->
write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE);
188 this->
write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE);
192 uint32_t o_hash = pref_hash(
"_offset_calibration_", cs);
194 bool migrated_offset =
false;
195 if (has_distinct_legacy_namespace) {
196 uint32_t legacy_o_hash = pref_hash(
"_offset_calibration_", legacy_cs);
199 int migration_status = migrate_legacy_pref_if_needed(this->
offset_pref_, legacy_offset_pref, &offset_data);
200 migrated_offset = migration_status > 0;
201 if (migration_status > 0) {
202 ESP_LOGI(TAG,
"[CALIBRATION][%s] Migrated offset calibrations from legacy storage.", cs);
203 }
else if (migration_status < 0) {
204 ESP_LOGW(TAG,
"[CALIBRATION][%s] Failed to migrate offset calibrations from legacy storage.", cs);
209 uint32_t po_hash = pref_hash(
"_power_offset_calibration_", cs);
211 bool migrated_power_offset =
false;
212 if (has_distinct_legacy_namespace) {
213 uint32_t legacy_po_hash = pref_hash(
"_power_offset_calibration_", legacy_cs);
216 int migration_status =
217 migrate_legacy_pref_if_needed(this->
power_offset_pref_, legacy_power_offset_pref, &power_offset_data);
218 migrated_power_offset = migration_status > 0;
219 if (migration_status > 0) {
220 ESP_LOGI(TAG,
"[CALIBRATION][%s] Migrated power offset calibrations from legacy storage.", cs);
221 }
else if (migration_status < 0) {
222 ESP_LOGW(TAG,
"[CALIBRATION][%s] Failed to migrate power offset calibrations from legacy storage.", cs);
226 if (migrated_offset || migrated_power_offset) {
233 ESP_LOGI(TAG,
"[CALIBRATION][%s] Power & Voltage/Current offset calibration is disabled. Using config file values.",
235 for (uint8_t phase = 0; phase < 3; ++phase) {
237 static_cast<uint16_t
>(this->
offset_phase_[phase].first_offset));
239 static_cast<uint16_t
>(this->
offset_phase_[phase].second_offset));
249 uint32_t g_hash = pref_hash(
"_gain_calibration_", cs);
251 bool migrated_gain =
false;
252 if (has_distinct_legacy_namespace) {
253 uint32_t legacy_g_hash = pref_hash(
"_gain_calibration_", legacy_cs);
256 int migration_status =
258 migrated_gain = migration_status > 0;
259 if (migration_status > 0) {
260 ESP_LOGI(TAG,
"[CALIBRATION][%s] Migrated gain calibrations from legacy storage.", cs);
261 }
else if (migration_status < 0) {
262 ESP_LOGW(TAG,
"[CALIBRATION][%s] Failed to migrate gain calibrations from legacy storage.", cs);
273 for (uint8_t phase = 0; phase < 3; ++phase) {
279 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration is disabled. Using config file values.", cs);
280 for (uint8_t phase = 0; phase < 3; ++phase) {
292 this->
write16_(ATM90E32_REGISTER_SAGTH, sagth);
293 this->
write16_(ATM90E32_REGISTER_OVTH, ovth);
295 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
301 bool offset_mismatch =
false;
302 bool power_mismatch =
false;
303 bool gain_mismatch =
false;
305 for (uint8_t phase = 0; phase < 3; ++phase) {
311 if (offset_mismatch) {
312 ESP_LOGW(TAG,
"[CALIBRATION][%s] ", cs);
314 "[CALIBRATION][%s] ===================== Offset mismatch: using flash values =====================", cs);
315 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
317 ESP_LOGW(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
318 ESP_LOGW(TAG,
"[CALIBRATION][%s] | | config | flash | config | flash |", cs);
319 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
321 for (uint8_t phase = 0; phase < 3; ++phase) {
322 ESP_LOGW(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d | %6d | %6d |", cs,
'A' + phase,
327 "[CALIBRATION][%s] ===============================================================================", cs);
329 if (power_mismatch) {
330 ESP_LOGW(TAG,
"[CALIBRATION][%s] ", cs);
332 "[CALIBRATION][%s] ================= Power offset mismatch: using flash values =================", cs);
333 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
335 ESP_LOGW(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power|offset_reactive_power|", cs);
336 ESP_LOGW(TAG,
"[CALIBRATION][%s] | | config | flash | config | flash |", cs);
337 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
339 for (uint8_t phase = 0; phase < 3; ++phase) {
340 ESP_LOGW(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d | %6d | %6d |", cs,
'A' + phase,
345 "[CALIBRATION][%s] ===============================================================================", cs);
348 ESP_LOGW(TAG,
"[CALIBRATION][%s] ", cs);
350 "[CALIBRATION][%s] ====================== Gain mismatch: using flash values =====================", cs);
351 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
353 ESP_LOGW(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
354 ESP_LOGW(TAG,
"[CALIBRATION][%s] | | config | flash | config | flash |", cs);
355 ESP_LOGW(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------------------",
357 for (uint8_t phase = 0; phase < 3; ++phase) {
358 ESP_LOGW(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u | %6u | %6u |", cs,
'A' + phase,
363 "[CALIBRATION][%s] ===============================================================================", cs);
366 ESP_LOGI(TAG,
"[CALIBRATION][%s] Power & Voltage/Current offset calibration is disabled. Using config file values.",
369 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
370 ESP_LOGI(TAG,
"[CALIBRATION][%s] ============== Restored offset calibration from memory ==============", cs);
371 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
372 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
373 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
374 for (uint8_t phase = 0; phase < 3; phase++) {
375 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
378 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==============================================================\\n", cs);
382 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
383 ESP_LOGI(TAG,
"[CALIBRATION][%s] ============ Restored power offset calibration from memory ============", cs);
384 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
385 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
386 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
387 for (uint8_t phase = 0; phase < 3; phase++) {
388 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
391 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
394 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration is disabled. Using config file values.", cs);
396 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
397 ESP_LOGI(TAG,
"[CALIBRATION][%s] ============ Restoring saved gain calibrations to registers ============", cs);
398 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
399 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
400 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
401 for (uint8_t phase = 0; phase < 3; phase++) {
402 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u |", cs,
'A' + phase,
405 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\\n", cs);
406 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration loaded and verified successfully.\n", cs);
412 ESP_LOGCONFIG(
"",
"ATM90E32:");
413 LOG_PIN(
" CS Pin: ", this->
cs_);
415 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
417 LOG_UPDATE_INTERVAL(
this);
418 LOG_SENSOR(
" ",
"Voltage A", this->
phase_[
PHASEA].voltage_sensor_);
419 LOG_SENSOR(
" ",
"Current A", this->
phase_[
PHASEA].current_sensor_);
420 LOG_SENSOR(
" ",
"Power A", this->
phase_[
PHASEA].power_sensor_);
421 LOG_SENSOR(
" ",
"Reactive Power A", this->
phase_[
PHASEA].reactive_power_sensor_);
422 LOG_SENSOR(
" ",
"Apparent Power A", this->
phase_[
PHASEA].apparent_power_sensor_);
423 LOG_SENSOR(
" ",
"PF A", this->
phase_[
PHASEA].power_factor_sensor_);
424 LOG_SENSOR(
" ",
"Active Forward Energy A", this->
phase_[
PHASEA].forward_active_energy_sensor_);
425 LOG_SENSOR(
" ",
"Active Reverse Energy A", this->
phase_[
PHASEA].reverse_active_energy_sensor_);
426 LOG_SENSOR(
" ",
"Harmonic Power A", this->
phase_[
PHASEA].harmonic_active_power_sensor_);
427 LOG_SENSOR(
" ",
"Phase Angle A", this->
phase_[
PHASEA].phase_angle_sensor_);
428 LOG_SENSOR(
" ",
"Peak Current A", this->
phase_[
PHASEA].peak_current_sensor_);
429 LOG_SENSOR(
" ",
"Voltage B", this->
phase_[
PHASEB].voltage_sensor_);
430 LOG_SENSOR(
" ",
"Current B", this->
phase_[
PHASEB].current_sensor_);
431 LOG_SENSOR(
" ",
"Power B", this->
phase_[
PHASEB].power_sensor_);
432 LOG_SENSOR(
" ",
"Reactive Power B", this->
phase_[
PHASEB].reactive_power_sensor_);
433 LOG_SENSOR(
" ",
"Apparent Power B", this->
phase_[
PHASEB].apparent_power_sensor_);
434 LOG_SENSOR(
" ",
"PF B", this->
phase_[
PHASEB].power_factor_sensor_);
435 LOG_SENSOR(
" ",
"Active Forward Energy B", this->
phase_[
PHASEB].forward_active_energy_sensor_);
436 LOG_SENSOR(
" ",
"Active Reverse Energy B", this->
phase_[
PHASEB].reverse_active_energy_sensor_);
437 LOG_SENSOR(
" ",
"Harmonic Power B", this->
phase_[
PHASEB].harmonic_active_power_sensor_);
438 LOG_SENSOR(
" ",
"Phase Angle B", this->
phase_[
PHASEB].phase_angle_sensor_);
439 LOG_SENSOR(
" ",
"Peak Current B", this->
phase_[
PHASEB].peak_current_sensor_);
440 LOG_SENSOR(
" ",
"Voltage C", this->
phase_[
PHASEC].voltage_sensor_);
441 LOG_SENSOR(
" ",
"Current C", this->
phase_[
PHASEC].current_sensor_);
442 LOG_SENSOR(
" ",
"Power C", this->
phase_[
PHASEC].power_sensor_);
443 LOG_SENSOR(
" ",
"Reactive Power C", this->
phase_[
PHASEC].reactive_power_sensor_);
444 LOG_SENSOR(
" ",
"Apparent Power C", this->
phase_[
PHASEC].apparent_power_sensor_);
445 LOG_SENSOR(
" ",
"PF C", this->
phase_[
PHASEC].power_factor_sensor_);
446 LOG_SENSOR(
" ",
"Active Forward Energy C", this->
phase_[
PHASEC].forward_active_energy_sensor_);
447 LOG_SENSOR(
" ",
"Active Reverse Energy C", this->
phase_[
PHASEC].reverse_active_energy_sensor_);
448 LOG_SENSOR(
" ",
"Harmonic Power C", this->
phase_[
PHASEC].harmonic_active_power_sensor_);
449 LOG_SENSOR(
" ",
"Phase Angle C", this->
phase_[
PHASEC].phase_angle_sensor_);
450 LOG_SENSOR(
" ",
"Peak Current C", this->
phase_[
PHASEC].peak_current_sensor_);
467 uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
468 uint8_t addrl = (a_register & 0xFF);
469 uint8_t data[4] = {addrh, addrl, 0x00, 0x00};
472 ESP_LOGVV(TAG,
"read16_ 0x%04" PRIX16
" output 0x%04" PRIX16, a_register, output);
480 const uint16_t val_h = this->
read16_(addr_h);
481 const uint16_t val_l = this->
read16_(addr_l);
482 const int32_t
val = (val_h << 16) | val_l;
485 "read32_ addr_h 0x%04" PRIX16
" val_h 0x%04" PRIX16
" addr_l 0x%04" PRIX16
" val_l 0x%04" PRIX16
487 addr_h, val_h, addr_l, val_l,
val);
493 ESP_LOGVV(TAG,
"write16_ 0x%04" PRIX16
" val 0x%04" PRIX16, a_register,
val);
494 uint8_t addrh = ((a_register >> 8) & 0x03);
495 uint8_t addrl = (a_register & 0xFF);
496 uint8_t data[4] = {addrh, addrl, uint8_t((
val >> 8) & 0xFF), uint8_t(
val & 0xFF)};
536 const uint16_t voltage = this->
read16_(ATM90E32_REGISTER_URMS + phase);
538 return (
float) voltage / 100;
542 const uint8_t reads = 10;
544 uint16_t voltage = 0;
545 for (uint8_t i = 0; i < reads; i++) {
546 voltage = this->
read16_(ATM90E32_REGISTER_URMS + phase);
548 accumulation += voltage;
550 voltage = accumulation / reads;
556 const uint8_t reads = 10;
558 uint16_t current = 0;
559 for (uint8_t i = 0; i < reads; i++) {
560 current = this->
read16_(ATM90E32_REGISTER_IRMS + phase);
562 accumulation += current;
564 current = accumulation / reads;
570 const uint16_t current = this->
read16_(ATM90E32_REGISTER_IRMS + phase);
572 return (
float) current / 1000;
576 const int val = this->
read32_(ATM90E32_REGISTER_PMEAN + phase, ATM90E32_REGISTER_PMEANLSB + phase);
577 return val * 0.00032f;
581 const int val = this->
read32_(ATM90E32_REGISTER_QMEAN + phase, ATM90E32_REGISTER_QMEANLSB + phase);
582 return val * 0.00032f;
586 const int val = this->
read32_(ATM90E32_REGISTER_SMEAN + phase, ATM90E32_REGISTER_SMEANLSB + phase);
587 return val * 0.00032f;
591 uint16_t powerfactor = this->
read16_(ATM90E32_REGISTER_PFMEAN + phase);
593 return (
float) ((int16_t) powerfactor) / 1000;
597 const uint16_t
val = this->
read16_(ATM90E32_REGISTER_APENERGY + phase);
598 if ((UINT32_MAX - this->
phase_[phase].cumulative_forward_active_energy_) >
val) {
604 return ((
float) this->
phase_[phase].cumulative_forward_active_energy_ * (10.0f / 3200.0f));
608 const uint16_t
val = this->
read16_(ATM90E32_REGISTER_ANENERGY + phase);
609 if (UINT32_MAX - this->
phase_[phase].cumulative_reverse_active_energy_ >
val) {
615 return ((
float) this->
phase_[phase].cumulative_reverse_active_energy_ * (10.0f / 3200.0f));
619 int val = this->
read32_(ATM90E32_REGISTER_PMEANH + phase, ATM90E32_REGISTER_PMEANHLSB + phase);
620 return val * 0.00032f;
624 float val = this->
read16_(ATM90E32_REGISTER_PANGLE + phase) / 10.0f;
625 return (
val > 180.0f) ?
val - 360.0f :
val;
629 int16_t
val = (float) this->
read16_(ATM90E32_REGISTER_IPEAK + phase);
633 return (
val * this->
phase_[phase].ct_gain_ / 8192000.0);
637 const uint16_t freq = this->
read16_(ATM90E32_REGISTER_FREQ);
638 return (
float) freq / 100;
642 const uint16_t ctemp = this->
read16_(ATM90E32_REGISTER_TEMP);
643 return (
float) ctemp;
649 ESP_LOGW(TAG,
"[CALIBRATION][%s] Gain calibration is disabled! Enable it first with enable_gain_calibration: true",
654 float ref_voltages[3] = {
662 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
663 ESP_LOGI(TAG,
"[CALIBRATION][%s] ========================= Gain Calibration =========================", cs);
664 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
667 "[CALIBRATION][%s] | Phase | V_meas (V) | I_meas (A) | V_ref | I_ref | V_gain (old→new) | I_gain (old→new) |",
669 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
671 for (uint8_t phase = 0; phase < 3; phase++) {
675 float ref_voltage = ref_voltages[phase];
676 float ref_current = ref_currents[phase];
681 bool did_voltage =
false;
682 bool did_current =
false;
685 if (ref_voltage <= 0.0f) {
686 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping voltage calibration: reference voltage is 0.", cs,
688 }
else if (measured_voltage == 0.0f) {
689 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping voltage calibration: measured voltage is 0.", cs,
692 uint32_t new_voltage_gain =
static_cast<uint32_t>((ref_voltage / measured_voltage) * current_voltage_gain);
693 if (new_voltage_gain == 0) {
694 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Voltage gain would be 0. Check reference and measured voltage.", cs,
697 if (new_voltage_gain >= 65535) {
699 "[CALIBRATION][%s] Phase %s - Voltage gain exceeds 65535. You may need a higher output voltage "
702 new_voltage_gain = 65535;
710 if (ref_current == 0.0f) {
711 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping current calibration: reference current is 0.", cs,
713 }
else if (measured_current == 0.0f) {
714 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Skipping current calibration: measured current is 0.", cs,
717 uint32_t new_current_gain =
static_cast<uint32_t>((ref_current / measured_current) * current_current_gain);
718 if (new_current_gain == 0) {
719 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Current gain would be 0. Check reference and measured current.", cs,
722 if (new_current_gain >= 65535) {
723 ESP_LOGW(TAG,
"[CALIBRATION][%s] Phase %s - Current gain exceeds 65535. You may need to turn up pga gain.",
725 new_current_gain = 65535;
733 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %9.2f | %9.4f | %5.2f | %6.4f | %5u → %-5u | %5u → %-5u |", cs,
734 'A' + phase, measured_voltage, measured_current, ref_voltage, ref_current, current_voltage_gain,
735 did_voltage ? this->
gain_phase_[phase].voltage_gain : current_voltage_gain, current_current_gain,
736 did_current ? this->
gain_phase_[phase].current_gain : current_current_gain);
739 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
752 ESP_LOGI(TAG,
"[CALIBRATION][%s] Gain calibration saved to memory.", cs);
755 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to save gain calibration to memory!", cs);
763 const LogString *name = offset_calibration_name(power_offsets);
774 if (writes_verified) {
775 saved = preference->
save(offsets);
779 if (writes_verified && saved && synced) {
783 for (uint8_t phase = 0; phase < 3; phase++)
784 mismatches[phase] =
false;
785 ESP_LOGI(TAG,
"[CALIBRATION][%s] %s calibration saved to memory. %s calibration completed and verified.", cs,
786 LOG_STR_ARG(name), LOG_STR_ARG(name));
790 if (writes_verified) {
791 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to save %s calibration to memory!", cs, LOG_STR_ARG(name));
794 for (uint8_t phase = 0; phase < 3; phase++) {
799 bool rollback_persisted =
false;
800 if (writes_verified) {
803 const bool rollback_saved = preference->
save(&rollback);
805 rollback_persisted = rollback_saved && rollback_synced;
806 if (!rollback_saved || !rollback_synced) {
807 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to persist restored %s calibration values!", cs, LOG_STR_ARG(name));
811 *restored = previous_restored;
812 if (rollback_persisted)
813 *has_stored = previous_restored;
815 if (!rollback_verified) {
816 ESP_LOGE(TAG,
"[CALIBRATION][%s] %s calibration failed; rollback readback verification failed.", cs,
820 ESP_LOGE(TAG,
"[CALIBRATION][%s] %s calibration failed; previous values restored.", cs, LOG_STR_ARG(name));
827 "[CALIBRATION][%s] Offset calibration is disabled! Enable it first with enable_offset_calibration: true",
832 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
833 ESP_LOGI(TAG,
"[CALIBRATION][%s] ======================== Offset Calibration ========================", cs);
834 ESP_LOGI(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------", cs);
835 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
836 ESP_LOGI(TAG,
"[CALIBRATION][%s] ------------------------------------------------------------------", cs);
842 for (uint8_t phase = 0; phase < 3; phase++) {
849 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, voltage_offset,
853 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==================================================================\n", cs);
864 "[CALIBRATION][%s] Offset power calibration is disabled! Enable it first with enable_offset_calibration: true",
869 ESP_LOGI(TAG,
"[CALIBRATION][%s] ", cs);
870 ESP_LOGI(TAG,
"[CALIBRATION][%s] ===================== Power Offset Calibration =====================", cs);
871 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
872 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
873 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
876 this->power_offset_phase_[2]};
880 for (uint8_t phase = 0; phase < 3; ++phase) {
887 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, active_offset,
890 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
897 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
899 for (
int phase = 0; phase < 3; phase++) {
904 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
922 const uint16_t *second_registers =
924 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA);
925 this->
write16_(first_registers[phase],
static_cast<uint16_t
>(first_offset));
926 this->
write16_(second_registers[phase],
static_cast<uint16_t
>(second_offset));
927 this->
write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000);
932 for (uint8_t i = 0; i < 3; ++i) {
941 bool all_zero =
true;
942 bool same_as_config =
true;
943 for (uint8_t phase = 0; phase < 3; ++phase) {
946 if (saved.voltage_gain != 0 || saved.current_gain != 0)
948 if (saved.voltage_gain != cfg.voltage_gain || saved.current_gain != cfg.current_gain)
949 same_as_config =
false;
952 if (!all_zero && !same_as_config) {
953 for (uint8_t phase = 0; phase < 3; ++phase) {
954 bool mismatch =
false;
974 ESP_LOGE(TAG,
"[CALIBRATION][%s] Gain verification failed! Calibration may not be applied correctly.", cs);
979 for (uint8_t i = 0; i < 3; ++i)
983 ESP_LOGW(TAG,
"[CALIBRATION][%s] No stored gain calibrations found. Using config file values.", cs);
989 const LogString *name = power_offsets ? LOG_STR(
"power offset") : LOG_STR(
"offset");
1001 for (uint8_t i = 0; i < 3; ++i)
1002 (*config_offsets)[i] = (*offsets)[i];
1004 const bool have_data = preference->
load(offsets);
1005 bool all_zero =
true;
1007 for (
const auto &phase : *offsets) {
1008 if (phase.first_offset != 0 || phase.second_offset != 0) {
1015 *has_stored = have_data && !all_zero;
1017 for (uint8_t phase = 0; phase < 3; phase++) {
1018 mismatches[phase] =
false;
1021 (has_first[phase] && (*offsets)[phase].first_offset != (*config_offsets)[phase].first_offset) ||
1022 (has_second[phase] && (*offsets)[phase].second_offset != (*config_offsets)[phase].second_offset);
1027 for (uint8_t phase = 0; phase < 3; phase++)
1028 (*offsets)[phase] = (*config_offsets)[phase];
1029 ESP_LOGW(TAG,
"[CALIBRATION][%s] No stored %s calibrations found. Using default values.", cs, LOG_STR_ARG(name));
1032 for (uint8_t phase = 0; phase < 3; phase++) {
1036 if (initial_values_verified) {
1038 *restored =
state.restored;
1039 ESP_LOGI(TAG,
"[CALIBRATION][%s] %s calibration values verified.", cs, LOG_STR_ARG(name));
1044 for (uint8_t phase = 0; phase < 3; phase++)
1045 mismatches[phase] =
false;
1046 for (uint8_t phase = 0; phase < 3; phase++) {
1047 (*offsets)[phase] = (*config_offsets)[phase];
1051 *restored =
state.restored;
1052 if (
state.values_verified) {
1053 ESP_LOGE(TAG,
"[CALIBRATION][%s] %s calibration restore failed verification; config values verified.", cs,
1056 ESP_LOGE(TAG,
"[CALIBRATION][%s] %s calibration restore and config fallback both failed verification.", cs,
1064 ESP_LOGI(TAG,
"[CALIBRATION][%s] No stored gain calibrations to clear. Current values:", cs);
1065 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
1066 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
1067 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
1068 for (
int phase = 0; phase < 3; phase++) {
1069 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u |", cs,
'A' + phase,
1072 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==========================================================\n", cs);
1076 ESP_LOGI(TAG,
"[CALIBRATION][%s] Clearing stored gain calibrations and restoring config-defined values", cs);
1077 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
1078 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | voltage_gain | current_gain |", cs);
1079 ESP_LOGI(TAG,
"[CALIBRATION][%s] ----------------------------------------------------------", cs);
1081 for (
int phase = 0; phase < 3; phase++) {
1090 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6u | %6u |", cs,
'A' + phase, voltage_gain, current_gain);
1092 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==========================================================\n", cs);
1104 ESP_LOGE(TAG,
"[CALIBRATION][%s] Failed to clear gain calibrations!", cs);
1113 ESP_LOGI(TAG,
"[CALIBRATION][%s] No stored offset calibrations to clear. Current values:", cs);
1114 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1115 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
1116 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1117 for (uint8_t phase = 0; phase < 3; phase++) {
1118 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
1121 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==============================================================\n", cs);
1125 ESP_LOGI(TAG,
"[CALIBRATION][%s] Clearing stored offset calibrations and restoring config-defined values", cs);
1126 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1127 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_voltage | offset_current |", cs);
1128 ESP_LOGI(TAG,
"[CALIBRATION][%s] --------------------------------------------------------------", cs);
1130 for (uint8_t phase = 0; phase < 3; phase++) {
1131 int16_t voltage_offset =
1133 int16_t current_offset =
1137 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, voltage_offset,
1140 ESP_LOGI(TAG,
"[CALIBRATION][%s] ==============================================================\n", cs);
1151 ESP_LOGI(TAG,
"[CALIBRATION][%s] Offsets cleared.", cs);
1157 ESP_LOGI(TAG,
"[CALIBRATION][%s] No stored power offsets to clear. Current values:", cs);
1158 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1159 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
1160 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1161 for (uint8_t phase = 0; phase < 3; phase++) {
1162 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase,
1165 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
1169 ESP_LOGI(TAG,
"[CALIBRATION][%s] Clearing stored power offsets and restoring config-defined values", cs);
1170 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1171 ESP_LOGI(TAG,
"[CALIBRATION][%s] | Phase | offset_active_power | offset_reactive_power |", cs);
1172 ESP_LOGI(TAG,
"[CALIBRATION][%s] ---------------------------------------------------------------------", cs);
1174 for (uint8_t phase = 0; phase < 3; phase++) {
1175 int16_t active_offset =
1177 int16_t reactive_offset =
1181 ESP_LOGI(TAG,
"[CALIBRATION][%s] | %c | %6d | %6d |", cs,
'A' + phase, active_offset,
1184 ESP_LOGI(TAG,
"[CALIBRATION][%s] =====================================================================\n", cs);
1195 ESP_LOGI(TAG,
"[CALIBRATION][%s] Power offsets cleared.", cs);
1199 const uint8_t num_reads = 5;
1200 uint64_t total_value = 0;
1202 for (uint8_t i = 0; i < num_reads; ++i) {
1203 uint32_t reading = voltage ? this->
read32_(ATM90E32_REGISTER_URMS + phase, ATM90E32_REGISTER_URMSLSB + phase)
1204 : this->
read32_(ATM90E32_REGISTER_IRMS + phase, ATM90E32_REGISTER_IRMSLSB + phase);
1205 total_value += reading;
1208 const uint32_t average_value = total_value / num_reads;
1209 const uint32_t shifted = average_value >> 7;
1210 const uint32_t offset = ~shifted + 1;
1211 return static_cast<int16_t
>(offset);
1215 const uint8_t num_reads = 5;
1216 int64_t total_value = 0;
1218 for (uint8_t i = 0; i < num_reads; ++i) {
1219 int32_t reading = reactive ? this->
read32_(ATM90E32_REGISTER_QMEAN + phase, ATM90E32_REGISTER_QMEANLSB + phase)
1220 : this->
read32_(ATM90E32_REGISTER_PMEAN + phase, ATM90E32_REGISTER_PMEANLSB + phase);
1221 total_value += reading;
1224 int32_t average_value = total_value / num_reads;
1225 int32_t power_offset = -average_value;
1226 return static_cast<int16_t
>(power_offset);
1231 bool success =
true;
1232 for (uint8_t phase = 0; phase < 3; phase++) {
1236 if (read_voltage != this->
gain_phase_[phase].voltage_gain ||
1237 read_current != this->
gain_phase_[phase].current_gain) {
1238 ESP_LOGE(TAG,
"[CALIBRATION][%s] Mismatch detected for Phase %s!", cs,
phase_labels[phase]);
1248 const LogString *name = offset_calibration_name(power_offsets);
1249 const LogString *first_name = power_offsets ? LOG_STR(
"active") : LOG_STR(
"voltage");
1250 const LogString *second_name = power_offsets ? LOG_STR(
"reactive") : LOG_STR(
"current");
1253 const uint16_t *second_registers =
1255 bool success =
true;
1256 for (uint8_t phase = 0; phase < 3; phase++) {
1257 const uint16_t first = this->
read16_(first_registers[phase]);
1258 const uint16_t
second = this->
read16_(second_registers[phase]);
1261 ESP_LOGE(TAG,
"[CALIBRATION][%s] %s readback failed for Phase %s: %s %d/%d, %s %d/%d.", cs, LOG_STR_ARG(name),
1262 phase_labels[phase], LOG_STR_ARG(first_name),
static_cast<int16_t
>(first), offsets[phase].first_offset,
1263 LOG_STR_ARG(second_name),
static_cast<int16_t
>(
second), offsets[phase].second_offset);
1270#ifdef USE_TEXT_SENSOR
1272 uint16_t state0 = this->
read16_(ATM90E32_REGISTER_EMMSTATE0);
1273 uint16_t state1 = this->
read16_(ATM90E32_REGISTER_EMMSTATE1);
1275 for (
int phase = 0; phase < 3; phase++) {
1279 status +=
"Over Voltage; ";
1281 status +=
"Voltage Sag; ";
1283 status +=
"Phase Loss; ";
1286 if (sensor ==
nullptr)
1292 ESP_LOGW(TAG,
"%s: %s", sensor->get_name().c_str(),
status.c_str());
1293 sensor->publish_state(
status);
1295 sensor->publish_state(
"Okay");
1301 uint16_t state1 = this->
read16_(ATM90E32_REGISTER_EMMSTATE1);
1303 std::string freq_status;
1305 if (state1 & ATM90E32_STATUS_S1_FREQHIST) {
1306 freq_status =
"HIGH";
1307 }
else if (state1 & ATM90E32_STATUS_S1_FREQLOST) {
1308 freq_status =
"LOW";
1310 freq_status =
"Normal";
1313 if (freq_status ==
"Normal") {
1314 ESP_LOGD(TAG,
"Frequency status: %s", freq_status.c_str());
1316 ESP_LOGW(TAG,
"Frequency status: %s", freq_status.c_str());
1323 constexpr float max_current_threshold = 65.53f;
1325 for (uint8_t phase = 0; phase < 3; phase++) {
1329 if (current_val > max_current_threshold) {
1330 ESP_LOGW(TAG,
"Over current detected on Phase %c: %.2f A",
'A' + phase, current_val);
1331 ESP_LOGW(TAG,
"You may need to half your gain_ct: value & multiply the current and power values by 2");
1343 float nominal_voltage = (line_freq == 60) ? 120.0f : 220.0f;
1344 float target_voltage = nominal_voltage * multiplier;
1346 float peak_01v = target_voltage * 100.0f * std::numbers::sqrt2_v<float>;
1347 float divider = (2.0f * ugain) / 32768.0f;
1349 float threshold = peak_01v / divider;
1351 return static_cast<uint16_t
>(threshold);
1355 uint16_t last = this->
read16_(ATM90E32_REGISTER_LASTSPIDATA);
1356 if (last != expected) {
1357 if (context !=
nullptr) {
1358 ESP_LOGW(TAG,
"[%s] SPI read mismatch: expected 0x%04X, got 0x%04X", context, expected, last);
1360 ESP_LOGW(TAG,
"SPI read mismatch: expected 0x%04X, got 0x%04X", expected, last);
void mark_failed()
Mark this component as failed.
void status_set_warning()
void status_clear_warning()
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]
OffsetCalibration config_power_offset_phase_[3]
bool has_config_active_power_offset_[3]
float get_phase_current_avg_(uint8_t phase)
bool has_stored_power_offset_calibration_
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]
text_sensor::TextSensor * freq_status_text_sensor_
ESPPreferenceObject power_offset_pref_
const uint16_t voltage_gain_registers[3]
void restore_offset_calibrations_(OffsetCalibrationType type)
float get_phase_voltage_avg_(uint8_t phase)
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)
const uint16_t reactive_power_offset_registers[3]
const uint16_t over_voltage_flags[3]
void clear_power_offset_calibrations()
bool has_stored_offset_calibration_
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 finish_offset_calibration_(const OffsetCalibration(&previous)[3], bool previous_restored, bool previous_using_saved, OffsetCalibrationType type)
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_
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_
static const uint8_t PHASEA
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)
void run_power_offset_calibrations()
const char * get_calibration_id_()
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)
const char * instance_id_
int read32_(uint16_t addr_h, uint16_t addr_l)
sensor::Sensor * chip_temperature_sensor_
void write_offsets_to_registers_(uint8_t phase, int16_t first_offset, int16_t second_offset, OffsetCalibrationType type)
float get_phase_power_factor_(uint8_t phase)
OffsetCalibration power_offset_phase_[3]
float get_local_phase_angle_(uint8_t phase)
const uint16_t voltage_offset_registers[3]
void save_gain_calibration_to_memory_()
OffsetCalibration offset_phase_[3]
bool has_config_voltage_offset_[3]
bool offset_calibration_mismatch_[3]
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]
bool verify_offset_writes_(OffsetCalibrationType type)
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)
OffsetRestoreState resolve_offset_restore_state(bool has_stored_values, bool initial_values_verified, bool fallback_values_verified)
bool offset_register_value_matches(uint16_t actual, int16_t expected)
@ OFFSET_CALIBRATION_TYPE_VOLTAGE_CURRENT
@ OFFSET_CALIBRATION_TYPE_POWER
void prepare_offset_rollback(const OffsetCalibration(&previous)[3], bool had_stored_values, OffsetCalibration(&rollback)[3])
constexpr float IO
For components that represent GPIO pins like PCF8573.
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 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 HOT delay(uint32_t ms)
ESPPreferenceObject make_preference(size_t, uint32_t, bool)
bool sync()
Commit pending writes to flash.
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_