ESPHome  2024.3.1
atm90e32.cpp
Go to the documentation of this file.
1 #include "atm90e32.h"
2 #include "atm90e32_reg.h"
3 #include "esphome/core/log.h"
4 #include <cinttypes>
5 
6 namespace esphome {
7 namespace atm90e32 {
8 
9 static const char *const TAG = "atm90e32";
11  if (this->get_publish_interval_flag_()) {
12  this->set_publish_interval_flag_(false);
13  for (uint8_t phase = 0; phase < 3; phase++) {
14  if (this->phase_[phase].voltage_sensor_ != nullptr) {
15  this->phase_[phase].voltage_ = this->get_phase_voltage_(phase);
16  }
17  }
18  for (uint8_t phase = 0; phase < 3; phase++) {
19  if (this->phase_[phase].current_sensor_ != nullptr) {
20  this->phase_[phase].current_ = this->get_phase_current_(phase);
21  }
22  }
23  for (uint8_t phase = 0; phase < 3; phase++) {
24  if (this->phase_[phase].power_sensor_ != nullptr) {
25  this->phase_[phase].active_power_ = this->get_phase_active_power_(phase);
26  }
27  }
28  for (uint8_t phase = 0; phase < 3; phase++) {
29  if (this->phase_[phase].power_factor_sensor_ != nullptr) {
30  this->phase_[phase].power_factor_ = this->get_phase_power_factor_(phase);
31  }
32  }
33  for (uint8_t phase = 0; phase < 3; phase++) {
34  if (this->phase_[phase].reactive_power_sensor_ != nullptr) {
35  this->phase_[phase].reactive_power_ = this->get_phase_reactive_power_(phase);
36  }
37  }
38  for (uint8_t phase = 0; phase < 3; phase++) {
39  if (this->phase_[phase].forward_active_energy_sensor_ != nullptr) {
41  }
42  }
43  for (uint8_t phase = 0; phase < 3; phase++) {
44  if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr) {
46  }
47  }
48  for (uint8_t phase = 0; phase < 3; phase++) {
49  if (this->phase_[phase].phase_angle_sensor_ != nullptr) {
50  this->phase_[phase].phase_angle_ = this->get_phase_angle_(phase);
51  }
52  }
53  for (uint8_t phase = 0; phase < 3; phase++) {
54  if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) {
56  }
57  }
58  for (uint8_t phase = 0; phase < 3; phase++) {
59  if (this->phase_[phase].peak_current_sensor_ != nullptr) {
60  this->phase_[phase].peak_current_ = this->get_phase_peak_current_(phase);
61  }
62  }
63  // After the local store in collected we can publish them trusting they are withing +-1 haardware sampling
64  for (uint8_t phase = 0; phase < 3; phase++) {
65  if (this->phase_[phase].voltage_sensor_ != nullptr) {
67  }
68  }
69  for (uint8_t phase = 0; phase < 3; phase++) {
70  if (this->phase_[phase].current_sensor_ != nullptr) {
72  }
73  }
74  for (uint8_t phase = 0; phase < 3; phase++) {
75  if (this->phase_[phase].power_sensor_ != nullptr) {
77  }
78  }
79  for (uint8_t phase = 0; phase < 3; phase++) {
80  if (this->phase_[phase].power_factor_sensor_ != nullptr) {
82  }
83  }
84  for (uint8_t phase = 0; phase < 3; phase++) {
85  if (this->phase_[phase].reactive_power_sensor_ != nullptr) {
87  }
88  }
89  for (uint8_t phase = 0; phase < 3; phase++) {
90  if (this->phase_[phase].forward_active_energy_sensor_ != nullptr) {
93  }
94  }
95  for (uint8_t phase = 0; phase < 3; phase++) {
96  if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr) {
99  }
100  }
101  for (uint8_t phase = 0; phase < 3; phase++) {
102  if (this->phase_[phase].phase_angle_sensor_ != nullptr) {
104  }
105  }
106  for (uint8_t phase = 0; phase < 3; phase++) {
107  if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) {
110  }
111  }
112  for (uint8_t phase = 0; phase < 3; phase++) {
113  if (this->phase_[phase].peak_current_sensor_ != nullptr) {
115  }
116  }
117  if (this->freq_sensor_ != nullptr) {
118  this->freq_sensor_->publish_state(this->get_frequency_());
119  }
120  if (this->chip_temperature_sensor_ != nullptr) {
122  }
123  }
124 }
125 
127  if (this->read16_(ATM90E32_REGISTER_METEREN) != 1) {
128  this->status_set_warning();
129  return;
130  }
131  this->set_publish_interval_flag_(true);
132  this->status_clear_warning();
133 }
134 
136  ESP_LOGCONFIG(TAG, "Setting up ATM90E32 Component...");
137  this->spi_setup();
138 
139  uint16_t mmode0 = 0x87; // 3P4W 50Hz
140  if (line_freq_ == 60) {
141  mmode0 |= 1 << 12; // sets 12th bit to 1, 60Hz
142  }
143 
144  if (current_phases_ == 2) {
145  mmode0 |= 1 << 8; // sets 8th bit to 1, 3P3W
146  mmode0 |= 0 << 1; // sets 1st bit to 0, phase b is not counted into the all-phase sum energy/power (P/Q/S)
147  }
148 
149  this->write16_(ATM90E32_REGISTER_SOFTRESET, 0x789A); // Perform soft reset
150  delay(6); // Wait for the minimum 5ms + 1ms
151  this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA); // enable register config access
152  if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != 0x55AA) {
153  ESP_LOGW(TAG, "Could not initialize ATM90E32 IC, check SPI settings");
154  this->mark_failed();
155  return;
156  }
157 
158  this->write16_(ATM90E32_REGISTER_METEREN, 0x0001); // Enable Metering
159  this->write16_(ATM90E32_REGISTER_SAGPEAKDETCFG, 0xFF3F); // Peak Detector time ms (15:8), Sag Period ms (7:0)
160  this->write16_(ATM90E32_REGISTER_PLCONSTH, 0x0861); // PL Constant MSB (default) = 140625000
161  this->write16_(ATM90E32_REGISTER_PLCONSTL, 0xC468); // PL Constant LSB (default)
162  this->write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654); // ZX2, ZX1, ZX0 pin config
163  this->write16_(ATM90E32_REGISTER_MMODE0, mmode0); // Mode Config (frequency set in main program)
164  this->write16_(ATM90E32_REGISTER_MMODE1, pga_gain_); // PGA Gain Configuration for Current Channels
165  this->write16_(ATM90E32_REGISTER_PSTARTTH, 0x1D4C); // All Active Startup Power Threshold - 0.02A/0.00032 = 7500
166  this->write16_(ATM90E32_REGISTER_QSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
167  this->write16_(ATM90E32_REGISTER_SSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
168  this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750
169  this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10%
170  // Setup voltage and current calibration offsets for PHASE A
172  this->write16_(ATM90E32_REGISTER_UOFFSETA, this->phase_[PHASEA].voltage_offset_); // A Voltage offset
174  this->write16_(ATM90E32_REGISTER_IOFFSETA, this->phase_[PHASEA].current_offset_); // A Current offset
175  // Setup voltage and current gain for PHASE A
176  this->write16_(ATM90E32_REGISTER_UGAINA, this->phase_[PHASEA].voltage_gain_); // A Voltage rms gain
177  this->write16_(ATM90E32_REGISTER_IGAINA, this->phase_[PHASEA].ct_gain_); // A line current gain
178  // Setup voltage and current calibration offsets for PHASE B
180  this->write16_(ATM90E32_REGISTER_UOFFSETB, this->phase_[PHASEB].voltage_offset_); // B Voltage offset
182  this->write16_(ATM90E32_REGISTER_IOFFSETB, this->phase_[PHASEB].current_offset_); // B Current offset
183  // Setup voltage and current gain for PHASE B
184  this->write16_(ATM90E32_REGISTER_UGAINB, this->phase_[PHASEB].voltage_gain_); // B Voltage rms gain
185  this->write16_(ATM90E32_REGISTER_IGAINB, this->phase_[PHASEB].ct_gain_); // B line current gain
186  // Setup voltage and current calibration offsets for PHASE C
188  this->write16_(ATM90E32_REGISTER_UOFFSETC, this->phase_[PHASEC].voltage_offset_); // C Voltage offset
190  this->write16_(ATM90E32_REGISTER_IOFFSETC, this->phase_[PHASEC].current_offset_); // C Current offset
191  // Setup voltage and current gain for PHASE C
192  this->write16_(ATM90E32_REGISTER_UGAINC, this->phase_[PHASEC].voltage_gain_); // C Voltage rms gain
193  this->write16_(ATM90E32_REGISTER_IGAINC, this->phase_[PHASEC].ct_gain_); // C line current gain
194  this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000); // end configuration
195 }
196 
198  ESP_LOGCONFIG("", "ATM90E32:");
199  LOG_PIN(" CS Pin: ", this->cs_);
200  if (this->is_failed()) {
201  ESP_LOGE(TAG, "Communication with ATM90E32 failed!");
202  }
203  LOG_UPDATE_INTERVAL(this);
204  LOG_SENSOR(" ", "Voltage A", this->phase_[PHASEA].voltage_sensor_);
205  LOG_SENSOR(" ", "Current A", this->phase_[PHASEA].current_sensor_);
206  LOG_SENSOR(" ", "Power A", this->phase_[PHASEA].power_sensor_);
207  LOG_SENSOR(" ", "Reactive Power A", this->phase_[PHASEA].reactive_power_sensor_);
208  LOG_SENSOR(" ", "PF A", this->phase_[PHASEA].power_factor_sensor_);
209  LOG_SENSOR(" ", "Active Forward Energy A", this->phase_[PHASEA].forward_active_energy_sensor_);
210  LOG_SENSOR(" ", "Active Reverse Energy A", this->phase_[PHASEA].reverse_active_energy_sensor_);
211  LOG_SENSOR(" ", "Harmonic Power A", this->phase_[PHASEA].harmonic_active_power_sensor_);
212  LOG_SENSOR(" ", "Phase Angle A", this->phase_[PHASEA].phase_angle_sensor_);
213  LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEA].peak_current_sensor_);
214  LOG_SENSOR(" ", "Voltage B", this->phase_[PHASEB].voltage_sensor_);
215  LOG_SENSOR(" ", "Current B", this->phase_[PHASEB].current_sensor_);
216  LOG_SENSOR(" ", "Power B", this->phase_[PHASEB].power_sensor_);
217  LOG_SENSOR(" ", "Reactive Power B", this->phase_[PHASEB].reactive_power_sensor_);
218  LOG_SENSOR(" ", "PF B", this->phase_[PHASEB].power_factor_sensor_);
219  LOG_SENSOR(" ", "Active Forward Energy B", this->phase_[PHASEB].forward_active_energy_sensor_);
220  LOG_SENSOR(" ", "Active Reverse Energy B", this->phase_[PHASEB].reverse_active_energy_sensor_);
221  LOG_SENSOR(" ", "Harmonic Power A", this->phase_[PHASEB].harmonic_active_power_sensor_);
222  LOG_SENSOR(" ", "Phase Angle A", this->phase_[PHASEB].phase_angle_sensor_);
223  LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEB].peak_current_sensor_);
224  LOG_SENSOR(" ", "Voltage C", this->phase_[PHASEC].voltage_sensor_);
225  LOG_SENSOR(" ", "Current C", this->phase_[PHASEC].current_sensor_);
226  LOG_SENSOR(" ", "Power C", this->phase_[PHASEC].power_sensor_);
227  LOG_SENSOR(" ", "Reactive Power C", this->phase_[PHASEC].reactive_power_sensor_);
228  LOG_SENSOR(" ", "PF C", this->phase_[PHASEC].power_factor_sensor_);
229  LOG_SENSOR(" ", "Active Forward Energy C", this->phase_[PHASEC].forward_active_energy_sensor_);
230  LOG_SENSOR(" ", "Active Reverse Energy C", this->phase_[PHASEC].reverse_active_energy_sensor_);
231  LOG_SENSOR(" ", "Harmonic Power A", this->phase_[PHASEC].harmonic_active_power_sensor_);
232  LOG_SENSOR(" ", "Phase Angle A", this->phase_[PHASEC].phase_angle_sensor_);
233  LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEC].peak_current_sensor_);
234  LOG_SENSOR(" ", "Frequency", this->freq_sensor_);
235  LOG_SENSOR(" ", "Chip Temp", this->chip_temperature_sensor_);
236 }
237 
239 
240 // R/C registers can conly be cleared after the LastSPIData register is updated (register 78H)
241 // Peakdetect period: 05H. Bit 15:8 are PeakDet_period in ms. 7:0 are Sag_period
242 // Default is 143FH (20ms, 63ms)
243 uint16_t ATM90E32Component::read16_(uint16_t a_register) {
244  uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
245  uint8_t addrl = (a_register & 0xFF);
246  uint8_t data[2];
247  uint16_t output;
248  this->enable();
250  this->write_byte(addrh);
251  this->write_byte(addrl);
252  this->read_array(data, 2);
253  this->disable();
254 
255  output = (uint16_t(data[0] & 0xFF) << 8) | (data[1] & 0xFF);
256  ESP_LOGVV(TAG, "read16_ 0x%04" PRIX16 " output 0x%04" PRIX16, a_register, output);
257  return output;
258 }
259 
260 int ATM90E32Component::read32_(uint16_t addr_h, uint16_t addr_l) {
261  const uint16_t val_h = this->read16_(addr_h);
262  const uint16_t val_l = this->read16_(addr_l);
263  const int32_t val = (val_h << 16) | val_l;
264 
265  ESP_LOGVV(TAG,
266  "read32_ addr_h 0x%04" PRIX16 " val_h 0x%04" PRIX16 " addr_l 0x%04" PRIX16 " val_l 0x%04" PRIX16
267  " = %" PRId32,
268  addr_h, val_h, addr_l, val_l, val);
269 
270  return val;
271 }
272 
273 void ATM90E32Component::write16_(uint16_t a_register, uint16_t val) {
274  ESP_LOGVV(TAG, "write16_ 0x%04" PRIX16 " val 0x%04" PRIX16, a_register, val);
275  this->enable();
276  this->write_byte16(a_register);
277  this->write_byte16(val);
278  this->disable();
279  if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != val)
280  ESP_LOGW(TAG, "SPI write error 0x%04X val 0x%04X", a_register, val);
281 }
282 
283 float ATM90E32Component::get_local_phase_voltage_(uint8_t phase) { return this->phase_[phase].voltage_; }
284 
285 float ATM90E32Component::get_local_phase_current_(uint8_t phase) { return this->phase_[phase].current_; }
286 
287 float ATM90E32Component::get_local_phase_active_power_(uint8_t phase) { return this->phase_[phase].active_power_; }
288 
289 float ATM90E32Component::get_local_phase_reactive_power_(uint8_t phase) { return this->phase_[phase].reactive_power_; }
290 
291 float ATM90E32Component::get_local_phase_power_factor_(uint8_t phase) { return this->phase_[phase].power_factor_; }
292 
294  return this->phase_[phase].forward_active_energy_;
295 }
296 
298  return this->phase_[phase].reverse_active_energy_;
299 }
300 
301 float ATM90E32Component::get_local_phase_angle_(uint8_t phase) { return this->phase_[phase].phase_angle_; }
302 
304  return this->phase_[phase].harmonic_active_power_;
305 }
306 
307 float ATM90E32Component::get_local_phase_peak_current_(uint8_t phase) { return this->phase_[phase].peak_current_; }
308 
310  const uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMS + phase);
311  if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != voltage)
312  ESP_LOGW(TAG, "SPI URMS voltage register read error.");
313  return (float) voltage / 100;
314 }
315 
317  const uint8_t reads = 10;
318  uint32_t accumulation = 0;
319  uint16_t voltage = 0;
320  for (uint8_t i = 0; i < reads; i++) {
321  voltage = this->read16_(ATM90E32_REGISTER_URMS + phase);
322  if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != voltage)
323  ESP_LOGW(TAG, "SPI URMS voltage register read error.");
324  accumulation += voltage;
325  }
326  voltage = accumulation / reads;
327  this->phase_[phase].voltage_ = (float) voltage / 100;
328  return this->phase_[phase].voltage_;
329 }
330 
332  const uint8_t reads = 10;
333  uint32_t accumulation = 0;
334  uint16_t current = 0;
335  for (uint8_t i = 0; i < reads; i++) {
336  current = this->read16_(ATM90E32_REGISTER_IRMS + phase);
337  if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != current)
338  ESP_LOGW(TAG, "SPI IRMS current register read error.");
339  accumulation += current;
340  }
341  current = accumulation / reads;
342  this->phase_[phase].current_ = (float) current / 1000;
343  return this->phase_[phase].current_;
344 }
345 
347  const uint16_t current = this->read16_(ATM90E32_REGISTER_IRMS + phase);
348  if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != current)
349  ESP_LOGW(TAG, "SPI IRMS current register read error.");
350  return (float) current / 1000;
351 }
352 
354  const int val = this->read32_(ATM90E32_REGISTER_PMEAN + phase, ATM90E32_REGISTER_PMEANLSB + phase);
355  return val * 0.00032f;
356 }
357 
359  const int val = this->read32_(ATM90E32_REGISTER_QMEAN + phase, ATM90E32_REGISTER_QMEANLSB + phase);
360  return val * 0.00032f;
361 }
362 
364  const int16_t powerfactor = this->read16_(ATM90E32_REGISTER_PFMEAN + phase);
365  if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != powerfactor)
366  ESP_LOGW(TAG, "SPI power factor read error.");
367  return (float) powerfactor / 1000;
368 }
369 
371  const uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGY + phase);
372  if ((UINT32_MAX - this->phase_[phase].cumulative_forward_active_energy_) > val) {
374  } else {
376  }
377  return ((float) this->phase_[phase].cumulative_forward_active_energy_ * 10 / 3200);
378 }
379 
381  const uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGY);
382  if (UINT32_MAX - this->phase_[phase].cumulative_reverse_active_energy_ > val) {
384  } else {
386  }
387  return ((float) this->phase_[phase].cumulative_reverse_active_energy_ * 10 / 3200);
388 }
389 
391  int val = this->read32_(ATM90E32_REGISTER_PMEANH + phase, ATM90E32_REGISTER_PMEANHLSB + phase);
392  return val * 0.00032f;
393 }
394 
396  uint16_t val = this->read16_(ATM90E32_REGISTER_PANGLE + phase) / 10.0;
397  return (float) (val > 180) ? val - 360.0 : val;
398 }
399 
401  int16_t val = (float) this->read16_(ATM90E32_REGISTER_IPEAK + phase);
402  if (!this->peak_current_signed_)
403  val = abs(val);
404  // phase register * phase current gain value / 1000 * 2^13
405  return (float) (val * this->phase_[phase].ct_gain_ / 8192000.0);
406 }
407 
409  const uint16_t freq = this->read16_(ATM90E32_REGISTER_FREQ);
410  return (float) freq / 100;
411 }
412 
414  const uint16_t ctemp = this->read16_(ATM90E32_REGISTER_TEMP);
415  return (float) ctemp;
416 }
417 
419  const uint8_t num_reads = 5;
420  uint64_t total_value = 0;
421  for (int i = 0; i < num_reads; ++i) {
422  const uint32_t measurement_value = read32_(ATM90E32_REGISTER_URMS + phase, ATM90E32_REGISTER_URMSLSB + phase);
423  total_value += measurement_value;
424  }
425  const uint32_t average_value = total_value / num_reads;
426  const uint32_t shifted_value = average_value >> 7;
427  const uint32_t voltage_offset = ~shifted_value + 1;
428  return voltage_offset & 0xFFFF; // Take the lower 16 bits
429 }
430 
432  const uint8_t num_reads = 5;
433  uint64_t total_value = 0;
434  for (int i = 0; i < num_reads; ++i) {
435  const uint32_t measurement_value = read32_(ATM90E32_REGISTER_IRMS + phase, ATM90E32_REGISTER_IRMSLSB + phase);
436  total_value += measurement_value;
437  }
438  const uint32_t average_value = total_value / num_reads;
439  const uint32_t current_offset = ~average_value + 1;
440  return current_offset & 0xFFFF; // Take the lower 16 bits
441 }
442 
443 } // namespace atm90e32
444 } // namespace esphome
float get_local_phase_active_power_(uint8_t)
Definition: atm90e32.cpp:287
float get_setup_priority() const override
Definition: atm90e32.cpp:238
void write16_(uint16_t a_register, uint16_t val)
Definition: atm90e32.cpp:273
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:146
int read32_(uint16_t addr_h, uint16_t addr_l)
Definition: atm90e32.cpp:260
mopeka_std_values val[4]
GPIOPin * cs_
Definition: spi.h:395
void delay_microseconds_safe(uint32_t us)
Delay for the given amount of microseconds, possibly yielding to other processes during the wait...
Definition: helpers.cpp:601
static const uint8_t PHASEC
Definition: atm90e32.h:17
static const uint8_t PHASEB
Definition: atm90e32.h:16
float get_phase_forward_active_energy_(uint8_t)
Definition: atm90e32.cpp:370
static const uint8_t PHASEA
Definition: atm90e32.h:15
void status_clear_warning()
Definition: component.cpp:161
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
struct esphome::atm90e32::ATM90E32Component::ATM90E32Phase phase_[3]
float get_local_phase_forward_active_energy_(uint8_t)
Definition: atm90e32.cpp:293
uint16_t calibrate_voltage_offset_phase(uint8_t)
Definition: atm90e32.cpp:418
float get_phase_reverse_active_energy_(uint8_t)
Definition: atm90e32.cpp:380
float get_local_phase_peak_current_(uint8_t)
Definition: atm90e32.cpp:307
float get_phase_harmonic_active_power_(uint8_t)
Definition: atm90e32.cpp:390
uint16_t read16_(uint16_t a_register)
Definition: atm90e32.cpp:243
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:113
const float IO
For components that represent GPIO pins like PCF8573.
Definition: component.cpp:17
sensor::Sensor * chip_temperature_sensor_
Definition: atm90e32.h:118
float get_local_phase_reverse_active_energy_(uint8_t)
Definition: atm90e32.cpp:297
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
uint16_t calibrate_current_offset_phase(uint8_t)
Definition: atm90e32.cpp:431
float get_local_phase_harmonic_active_power_(uint8_t)
Definition: atm90e32.cpp:303
float get_local_phase_power_factor_(uint8_t)
Definition: atm90e32.cpp:291
void set_publish_interval_flag_(bool flag)
Definition: atm90e32.h:85
float get_local_phase_reactive_power_(uint8_t)
Definition: atm90e32.cpp:289
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26