ESPHome  2024.10.2
ina2xx_base.cpp
Go to the documentation of this file.
1 #include "ina2xx_base.h"
2 #include "esphome/core/log.h"
3 #include "esphome/core/hal.h"
4 #include "esphome/core/helpers.h"
5 #include <cinttypes>
6 #include <cmath>
7 
8 namespace esphome {
9 namespace ina2xx_base {
10 
11 static const char *const TAG = "ina2xx";
12 
13 #define OKFAILED(b) ((b) ? "OK" : "FAILED")
14 
15 static const uint16_t ADC_TIMES[8] = {50, 84, 150, 280, 540, 1052, 2074, 4120};
16 static const uint16_t ADC_SAMPLES[8] = {1, 4, 16, 64, 128, 256, 512, 1024};
17 
18 static const char *get_device_name(INAModel model) {
19  switch (model) {
20  case INAModel::INA_228:
21  return "INA228";
22  case INAModel::INA_229:
23  return "INA229";
24  case INAModel::INA_238:
25  return "INA238";
26  case INAModel::INA_239:
27  return "INA239";
28  case INAModel::INA_237:
29  return "INA237";
30  default:
31  return "UNKNOWN";
32  }
33 };
34 
35 static bool check_model_and_device_match(INAModel model, uint16_t dev_id) {
36  switch (model) {
37  case INAModel::INA_228:
38  return dev_id == 0x228;
39  case INAModel::INA_229:
40  return dev_id == 0x229;
41  case INAModel::INA_238:
42  return dev_id == 0x238;
43  case INAModel::INA_239:
44  return dev_id == 0x239;
45  case INAModel::INA_237:
46  return dev_id == 0x237;
47  default:
48  return false;
49  }
50 }
51 
52 void INA2XX::setup() {
53  ESP_LOGCONFIG(TAG, "Setting up INA2xx...");
54 
55  if (!this->reset_config_()) {
56  ESP_LOGE(TAG, "Reset failed, check connection");
57  this->mark_failed();
58  return;
59  }
60  delay(2);
61 
62  if (!this->check_device_model_()) {
63  ESP_LOGE(TAG, "Device not supported or model selected improperly in yaml file");
64  this->mark_failed();
65  return;
66  }
67  delay(1);
68 
69  this->configure_adc_range_();
70  delay(1);
71 
72  this->configure_adc_();
73  delay(1);
74 
75  this->configure_shunt_();
76  delay(1);
77 
79  delay(1);
80 
81  this->state_ = State::IDLE;
82 }
83 
85 
87  ESP_LOGD(TAG, "Updating");
88  if (this->is_ready() && this->state_ == State::IDLE) {
89  ESP_LOGD(TAG, "Initiating new data collection");
90  this->state_ = State::DATA_COLLECTION_1;
91  return;
92  }
93 }
94 
95 void INA2XX::loop() {
96  if (this->is_ready()) {
97  switch (this->state_) {
99  case State::IDLE:
100  break;
101 
103  this->full_loop_is_okay_ = true;
104 
105  if (this->shunt_voltage_sensor_ != nullptr) {
106  float shunt_voltage{0};
107  this->full_loop_is_okay_ &= this->read_shunt_voltage_mv_(shunt_voltage);
108  this->shunt_voltage_sensor_->publish_state(shunt_voltage);
109  }
110  this->state_ = State::DATA_COLLECTION_2;
111  break;
112 
114  if (this->bus_voltage_sensor_ != nullptr) {
115  float bus_voltage{0};
116  this->full_loop_is_okay_ &= this->read_bus_voltage_(bus_voltage);
117  this->bus_voltage_sensor_->publish_state(bus_voltage);
118  }
119  this->state_ = State::DATA_COLLECTION_3;
120  break;
121 
123  if (this->die_temperature_sensor_ != nullptr) {
124  float die_temperature{0};
125  this->full_loop_is_okay_ &= this->read_die_temp_c_(die_temperature);
126  this->die_temperature_sensor_->publish_state(die_temperature);
127  }
128  this->state_ = State::DATA_COLLECTION_4;
129  break;
130 
132  if (this->current_sensor_ != nullptr) {
133  float current{0};
134  this->full_loop_is_okay_ &= this->read_current_a_(current);
135  this->current_sensor_->publish_state(current);
136  }
137  this->state_ = State::DATA_COLLECTION_5;
138  break;
139 
141  if (this->power_sensor_ != nullptr) {
142  float power{0};
143  this->full_loop_is_okay_ &= this->read_power_w_(power);
144  this->power_sensor_->publish_state(power);
145  }
146  this->state_ = State::DATA_COLLECTION_6;
147  break;
148 
150  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
151  if (this->energy_sensor_j_ != nullptr || this->energy_sensor_wh_ != nullptr ||
152  this->charge_sensor_c_ != nullptr || this->charge_sensor_ah_ != nullptr) {
154  }
155  if (this->energy_sensor_j_ != nullptr || this->energy_sensor_wh_ != nullptr) {
156  double energy_j{0}, energy_wh{0};
157  this->full_loop_is_okay_ &= this->read_energy_(energy_j, energy_wh);
158  if (this->energy_sensor_j_ != nullptr)
159  this->energy_sensor_j_->publish_state(energy_j);
160  if (this->energy_sensor_wh_ != nullptr)
161  this->energy_sensor_wh_->publish_state(energy_wh);
162  }
163  }
164  this->state_ = State::DATA_COLLECTION_7;
165  break;
166 
168  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
169  if (this->charge_sensor_c_ != nullptr || this->charge_sensor_ah_ != nullptr) {
170  double charge_c{0}, charge_ah{0};
171  this->full_loop_is_okay_ &= this->read_charge_(charge_c, charge_ah);
172  if (this->charge_sensor_c_ != nullptr)
173  this->charge_sensor_c_->publish_state(charge_c);
174  if (this->charge_sensor_ah_ != nullptr)
175  this->charge_sensor_ah_->publish_state(charge_ah);
176  }
177  }
178  this->state_ = State::DATA_COLLECTION_8;
179  break;
180 
182  if (this->full_loop_is_okay_) {
183  this->status_clear_warning();
184  } else {
185  this->status_set_warning();
186  }
187  this->state_ = State::IDLE;
188  break;
189 
190  default:
191  ESP_LOGW(TAG, "Unknown state of the component, might be due to memory corruption");
192  break;
193  }
194  }
195 }
196 
198  ESP_LOGCONFIG(TAG, "INA2xx:");
199  ESP_LOGCONFIG(TAG, " Device model = %s", get_device_name(this->ina_model_));
200 
201  if (this->device_mismatch_) {
202  ESP_LOGE(TAG, " Device model mismatch. Found device with ID = %x. Please check your configuration.",
203  this->dev_id_);
204  }
205  if (this->is_failed()) {
206  ESP_LOGE(TAG, "Communication with INA2xx failed!");
207  }
208  LOG_UPDATE_INTERVAL(this);
209  ESP_LOGCONFIG(TAG, " Shunt resistance = %f Ohm", this->shunt_resistance_ohm_);
210  ESP_LOGCONFIG(TAG, " Max current = %f A", this->max_current_a_);
211  ESP_LOGCONFIG(TAG, " Shunt temp coeff = %d ppm/°C", this->shunt_tempco_ppm_c_);
212  ESP_LOGCONFIG(TAG, " ADCRANGE = %d (%s)", (uint8_t) this->adc_range_, this->adc_range_ ? "±40.96 mV" : "±163.84 mV");
213  ESP_LOGCONFIG(TAG, " CURRENT_LSB = %f", this->current_lsb_);
214  ESP_LOGCONFIG(TAG, " SHUNT_CAL = %d", this->shunt_cal_);
215 
216  ESP_LOGCONFIG(TAG, " ADC Samples = %d; ADC times: Bus = %d μs, Shunt = %d μs, Temp = %d μs",
217  ADC_SAMPLES[0b111 & (uint8_t) this->adc_avg_samples_],
218  ADC_TIMES[0b111 & (uint8_t) this->adc_time_bus_voltage_],
219  ADC_TIMES[0b111 & (uint8_t) this->adc_time_shunt_voltage_],
220  ADC_TIMES[0b111 & (uint8_t) this->adc_time_die_temperature_]);
221 
222  ESP_LOGCONFIG(TAG, " Device is %s", get_device_name(this->ina_model_));
223 
224  LOG_SENSOR(" ", "Shunt Voltage", this->shunt_voltage_sensor_);
225  LOG_SENSOR(" ", "Bus Voltage", this->bus_voltage_sensor_);
226  LOG_SENSOR(" ", "Die Temperature", this->die_temperature_sensor_);
227  LOG_SENSOR(" ", "Current", this->current_sensor_);
228  LOG_SENSOR(" ", "Power", this->power_sensor_);
229 
230  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
231  LOG_SENSOR(" ", "Energy J", this->energy_sensor_j_);
232  LOG_SENSOR(" ", "Energy Wh", this->energy_sensor_wh_);
233  LOG_SENSOR(" ", "Charge C", this->charge_sensor_c_);
234  LOG_SENSOR(" ", "Charge Ah", this->charge_sensor_ah_);
235  }
236 }
237 
239  if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) {
240  return false;
241  }
242  ESP_LOGV(TAG, "reset_energy_counters");
243 
244  ConfigurationRegister cfg{0};
245  auto ret = this->read_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16);
246  cfg.RSTACC = true;
247  cfg.ADCRANGE = this->adc_range_;
248  ret = ret && this->write_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16);
249 
250  this->energy_overflows_count_ = 0;
251  this->charge_overflows_count_ = 0;
252  return ret;
253 }
254 
256  ESP_LOGV(TAG, "Reset");
257  ConfigurationRegister cfg{0};
258  cfg.RST = true;
259  return this->write_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16);
260 }
261 
263  constexpr uint16_t manufacturer_ti = 0x5449; // "TI"
264 
265  uint16_t manufacturer_id{0}, rev_id{0};
266  this->read_unsigned_16_(RegisterMap::REG_MANUFACTURER_ID, manufacturer_id);
268  this->dev_id_ = 0;
269  ESP_LOGV(TAG, "Can't read device ID");
270  };
271  rev_id = this->dev_id_ & 0x0F;
272  this->dev_id_ >>= 4;
273  ESP_LOGI(TAG, "Manufacturer: 0x%04X, Device ID: 0x%04X, Revision: %d", manufacturer_id, this->dev_id_, rev_id);
274 
275  if (manufacturer_id != manufacturer_ti) {
276  ESP_LOGE(TAG, "Manufacturer ID doesn't match original 0x5449");
277  this->device_mismatch_ = true;
278  return false;
279  }
280 
281  if (this->dev_id_ == 0x228 || this->dev_id_ == 0x229) {
282  ESP_LOGI(TAG, "Supported device found: INA%x, 85-V, 20-Bit, Ultra-Precise Power/Energy/Charge Monitor",
283  this->dev_id_);
284  } else if (this->dev_id_ == 0x238 || this->dev_id_ == 0x239) {
285  ESP_LOGI(TAG, "Supported device found: INA%x, 85-V, 16-Bit, High-Precision Power Monitor", this->dev_id_);
286  } else if (this->dev_id_ == 0x0 || this->dev_id_ == 0xFF) {
287  ESP_LOGI(TAG, "We assume device is: INA237 85-V, 16-Bit, Precision Power Monitor");
288  this->dev_id_ = 0x237;
289  } else {
290  ESP_LOGE(TAG, "Unknown device ID %x.", this->dev_id_);
291  this->device_mismatch_ = true;
292  return false;
293  }
294 
295  // Check user-selected model agains what we have found. Mark as failed if selected model != found model
296  if (!check_model_and_device_match(this->ina_model_, this->dev_id_)) {
297  ESP_LOGE(TAG, "Selected model %s doesn't match found device INA%x", get_device_name(this->ina_model_),
298  this->dev_id_);
299  this->device_mismatch_ = true;
300  return false;
301  }
302 
303  // setup device coefficients
304  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
305  this->cfg_.vbus_lsb = 0.0001953125f;
306  this->cfg_.v_shunt_lsb_range0 = 0.0003125f;
307  this->cfg_.v_shunt_lsb_range1 = 0.000078125f;
308  this->cfg_.shunt_cal_scale = 13107.2f * 1000000.0f;
309  this->cfg_.current_lsb_scale_factor = -19;
310  this->cfg_.die_temp_lsb = 0.0078125f;
311  this->cfg_.power_coeff = 3.2f;
312  this->cfg_.energy_coeff = 16.0f * 3.2f;
313  } else {
314  this->cfg_.vbus_lsb = 0.0031250000f;
315  this->cfg_.v_shunt_lsb_range0 = 0.0050000f;
316  this->cfg_.v_shunt_lsb_range1 = 0.001250000f;
317  this->cfg_.shunt_cal_scale = 819.2f * 1000000.0f;
318  this->cfg_.current_lsb_scale_factor = -15;
319  this->cfg_.die_temp_lsb = 0.1250000f;
320  this->cfg_.power_coeff = 0.2f;
321  this->cfg_.energy_coeff = 0.0f; // N/A
322  }
323 
324  return true;
325 }
326 
328  ESP_LOGV(TAG, "Setting ADCRANGE = %d", (uint8_t) this->adc_range_);
329  ConfigurationRegister cfg{0};
330  auto ret = this->read_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16);
331  cfg.ADCRANGE = this->adc_range_;
332  ret = ret && this->write_unsigned_16_(RegisterMap::REG_CONFIG, cfg.raw_u16);
333 
334  return ret;
335 }
336 
338  bool ret{false};
339  AdcConfigurationRegister adc_cfg{0};
340  adc_cfg.MODE = 0x0F; // Fh = Continuous bus voltage, shunt voltage and temperature
341  adc_cfg.VBUSCT = this->adc_time_bus_voltage_;
342  adc_cfg.VSHCT = this->adc_time_shunt_voltage_;
343  adc_cfg.VTCT = this->adc_time_die_temperature_;
344  adc_cfg.AVG = this->adc_avg_samples_;
345  ret = this->write_unsigned_16_(RegisterMap::REG_ADC_CONFIG, adc_cfg.raw_u16);
346  return ret;
347 }
348 
350  this->current_lsb_ = ldexp(this->max_current_a_, this->cfg_.current_lsb_scale_factor);
351  this->shunt_cal_ = (uint16_t) (this->cfg_.shunt_cal_scale * this->current_lsb_ * this->shunt_resistance_ohm_);
352  if (this->adc_range_)
353  this->shunt_cal_ *= 4;
354 
355  if (this->shunt_cal_ & 0x8000) {
356  // cant be more than 15 bits
357  ESP_LOGW(TAG, "Shunt value too high");
358  }
359  this->shunt_cal_ &= 0x7FFF;
360  ESP_LOGV(TAG, "Given Rshunt=%f Ohm and Max_current=%.3f", this->shunt_resistance_ohm_, this->max_current_a_);
361  ESP_LOGV(TAG, "New CURRENT_LSB=%f, SHUNT_CAL=%u", this->current_lsb_, this->shunt_cal_);
363 }
364 
366  // Only for 228/229
367  // unsigned 14-bit value
368  // 0x0000 = 0 ppm/°C
369  // 0x3FFF = 16383 ppm/°C
370  if ((this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) &&
371  this->shunt_tempco_ppm_c_ > 0) {
373  }
374  return true;
375 }
376 
377 bool INA2XX::read_shunt_voltage_mv_(float &volt_out) {
378  // Two's complement value
379  // 228, 229 - 24bit: 20(23-4) + 4(3-0) res
380  // 237, 238, 239 - 16bit
381 
382  bool ret{false};
383  float volt_reading{0};
384  uint64_t raw{0};
385  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
386  ret = this->read_unsigned_(RegisterMap::REG_VSHUNT, 3, raw);
387  raw >>= 4;
388  volt_reading = this->two_complement_(raw, 20);
389  } else {
390  ret = this->read_unsigned_(RegisterMap::REG_VSHUNT, 2, raw);
391  volt_reading = this->two_complement_(raw, 16);
392  }
393 
394  if (ret) {
395  volt_out = (this->adc_range_ ? this->cfg_.v_shunt_lsb_range1 : this->cfg_.v_shunt_lsb_range0) * volt_reading;
396  }
397 
398  ESP_LOGV(TAG, "read_shunt_voltage_mv_ ret=%s, shunt_cal=%d, reading_lsb=%f", OKFAILED(ret), this->shunt_cal_,
399  volt_reading);
400 
401  return ret;
402 }
403 
404 bool INA2XX::read_bus_voltage_(float &volt_out) {
405  // Two's complement value
406  // 228, 229 - 24bit: 20(23-4) + 4(3-0) res
407  // 237, 238, 239 - 16bit
408 
409  bool ret{false};
410  float volt_reading{0};
411  uint64_t raw{0};
412  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
413  ret = this->read_unsigned_(RegisterMap::REG_VBUS, 3, raw);
414  raw >>= 4;
415  volt_reading = this->two_complement_(raw, 20);
416  } else {
417  ret = this->read_unsigned_(RegisterMap::REG_VBUS, 2, raw);
418  volt_reading = this->two_complement_(raw, 16);
419  }
420  if (ret) {
421  volt_out = this->cfg_.vbus_lsb * (float) volt_reading;
422  }
423 
424  ESP_LOGV(TAG, "read_bus_voltage_ ret=%s, reading_lsb=%f", OKFAILED(ret), volt_reading);
425  return ret;
426 }
427 
428 bool INA2XX::read_die_temp_c_(float &temp_out) {
429  // Two's complement value
430  // 228, 229 - 16bit
431  // 237, 238, 239 - 16bit: 12(15-4) + 4(3-0) res
432 
433  bool ret{false};
434  float temp_reading{0};
435  uint64_t raw{0};
436 
437  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
439  temp_reading = this->two_complement_(raw, 16);
440  } else {
442  raw >>= 4;
443  temp_reading = this->two_complement_(raw, 12);
444  }
445  if (ret) {
446  temp_out = this->cfg_.die_temp_lsb * (float) temp_reading;
447  }
448 
449  ESP_LOGV(TAG, "read_die_temp_c_ ret=%s, reading_lsb=%f", OKFAILED(ret), temp_reading);
450  return ret;
451 }
452 
453 bool INA2XX::read_current_a_(float &amps_out) {
454  // Two's complement value
455  // 228, 229 - 24bit: 20(23-4) + 4(3-0) res
456  // 237, 238, 239 - 16bit
457  bool ret{false};
458  float amps_reading{0};
459  uint64_t raw{0};
460 
461  if (this->ina_model_ == INAModel::INA_228 || this->ina_model_ == INAModel::INA_229) {
463  raw >>= 4;
464  amps_reading = this->two_complement_(raw, 20);
465  } else {
467  amps_reading = this->two_complement_(raw, 16);
468  }
469 
470  ESP_LOGV(TAG, "read_current_a_ ret=%s. current_lsb=%f. reading_lsb=%f", OKFAILED(ret), this->current_lsb_,
471  amps_reading);
472  if (ret) {
473  amps_out = this->current_lsb_ * (float) amps_reading;
474  }
475 
476  return ret;
477 }
478 
479 bool INA2XX::read_power_w_(float &power_out) {
480  // Unsigned value
481  // 228, 229 - 24bit
482  // 237, 238, 239 - 24bit
483  uint64_t power_reading{0};
484  auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_POWER, 3, power_reading);
485 
486  ESP_LOGV(TAG, "read_power_w_ ret=%s, reading_lsb=%" PRIu32, OKFAILED(ret), (uint32_t) power_reading);
487  if (ret) {
488  power_out = this->cfg_.power_coeff * this->current_lsb_ * (float) power_reading;
489  }
490 
491  return ret;
492 }
493 
494 bool INA2XX::read_energy_(double &joules_out, double &watt_hours_out) {
495  // Unsigned value
496  // 228, 229 - 40bit
497  // 237, 238, 239 - not available
498  if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) {
499  joules_out = 0;
500  return false;
501  }
502  uint64_t joules_reading = 0;
503  uint64_t previous_energy = this->energy_overflows_count_ * (((uint64_t) 1) << 40);
504  auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_ENERGY, 5, joules_reading);
505 
506  ESP_LOGV(TAG, "read_energy_j_ ret=%s, reading_lsb=0x%" PRIX64 ", current_lsb=%f, overflow_cnt=%" PRIu32,
507  OKFAILED(ret), joules_reading, this->current_lsb_, this->energy_overflows_count_);
508  if (ret) {
509  joules_out = this->cfg_.energy_coeff * this->current_lsb_ * (double) joules_reading + (double) previous_energy;
510  watt_hours_out = joules_out / 3600.0;
511  }
512  return ret;
513 }
514 
515 bool INA2XX::read_charge_(double &coulombs_out, double &amp_hours_out) {
516  // Two's complement value
517  // 228, 229 - 40bit
518  // 237, 238, 239 - not available
519  if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) {
520  coulombs_out = 0;
521  return false;
522  }
523 
524  // and what to do with this? datasheet doesnt tell us what if charge is negative
525  uint64_t previous_charge = this->charge_overflows_count_ * (((uint64_t) 1) << 39);
526  double coulombs_reading = 0;
527  uint64_t raw{0};
528  auto ret = this->read_unsigned_((uint8_t) RegisterMap::REG_CHARGE, 5, raw);
529  coulombs_reading = this->two_complement_(raw, 40);
530 
531  ESP_LOGV(TAG, "read_charge_c_ ret=%d, curr_charge=%f + 39-bit overflow_cnt=%" PRIu32, ret, coulombs_reading,
533  if (ret) {
534  coulombs_out = this->current_lsb_ * (double) coulombs_reading + (double) previous_charge;
535  amp_hours_out = coulombs_out / 3600.0;
536  }
537  return ret;
538 }
539 
541  if (this->ina_model_ != INAModel::INA_228 && this->ina_model_ != INAModel::INA_229) {
542  return false;
543  }
544 
545  DiagnosticRegister diag{0};
546  auto ret = this->read_unsigned_16_(RegisterMap::REG_DIAG_ALRT, diag.raw_u16);
547  ESP_LOGV(TAG, "read_diagnostics_and_act_ ret=%s, 0x%04X", OKFAILED(ret), diag.raw_u16);
548 
549  if (diag.ENERGYOF) {
550  this->energy_overflows_count_++; // 40-bit overflow
551  }
552 
553  if (diag.CHARGEOF) {
554  this->charge_overflows_count_++; // 39-bit overflow
555  }
556 
557  return ret;
558 }
559 
560 bool INA2XX::write_unsigned_16_(uint8_t reg, uint16_t val) {
561  uint16_t data_out = byteswap(val);
562  auto ret = this->write_ina_register(reg, (uint8_t *) &data_out, 2);
563  if (!ret) {
564  ESP_LOGV(TAG, "write_unsigned_16_ FAILED reg=0x%02X, val=0x%04X", reg, val);
565  }
566  return ret;
567 }
568 
569 bool INA2XX::read_unsigned_(uint8_t reg, uint8_t reg_size, uint64_t &data_out) {
570  static uint8_t rx_buf[5] = {0}; // max buffer size
571 
572  if (reg_size > 5) {
573  return false;
574  }
575 
576  auto ret = this->read_ina_register(reg, rx_buf, reg_size);
577 
578  // Combine bytes
579  data_out = rx_buf[0];
580  for (uint8_t i = 1; i < reg_size; i++) {
581  data_out = (data_out << 8) | rx_buf[i];
582  }
583  ESP_LOGV(TAG, "read_unsigned_ reg=0x%02X, ret=%s, len=%d, val=0x%" PRIX64, reg, OKFAILED(ret), reg_size, data_out);
584 
585  return ret;
586 }
587 
588 bool INA2XX::read_unsigned_16_(uint8_t reg, uint16_t &out) {
589  uint16_t data_in{0};
590  auto ret = this->read_ina_register(reg, (uint8_t *) &data_in, 2);
591  out = byteswap(data_in);
592  ESP_LOGV(TAG, "read_unsigned_16_ 0x%02X, ret= %s, val=0x%04X", reg, OKFAILED(ret), out);
593  return ret;
594 }
595 
596 int64_t INA2XX::two_complement_(uint64_t value, uint8_t bits) {
597  if (value > (1ULL << (bits - 1))) {
598  return (int64_t) (value - (1ULL << bits));
599  } else {
600  return (int64_t) value;
601  }
602 }
603 } // namespace ina2xx_base
604 } // namespace esphome
bool read_current_a_(float &amps_out)
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
uint8_t raw[35]
Definition: bl0939.h:19
bool read_unsigned_(uint8_t reg, uint8_t reg_size, uint64_t &data_out)
sensor::Sensor * charge_sensor_c_
Definition: ina2xx_base.h:195
virtual bool write_ina_register(uint8_t a_register, const uint8_t *data, size_t len)=0
int64_t two_complement_(uint64_t value, uint8_t bits)
bool read_shunt_voltage_mv_(float &volt_out)
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
bool read_power_w_(float &power_out)
bool read_energy_(double &joules_out, double &watt_hours_out)
sensor::Sensor * shunt_voltage_sensor_
Definition: ina2xx_base.h:188
float get_setup_priority() const override
Definition: ina2xx_base.cpp:84
bool is_failed() const
Definition: component.cpp:143
bool read_die_temp_c_(float &temp)
sensor::Sensor * charge_sensor_ah_
Definition: ina2xx_base.h:196
mopeka_std_values val[4]
sensor::Sensor * energy_sensor_j_
Definition: ina2xx_base.h:193
sensor::Sensor * die_temperature_sensor_
Definition: ina2xx_base.h:190
sensor::Sensor * power_sensor_
Definition: ina2xx_base.h:192
bool is_ready() const
Definition: component.cpp:144
AdcAvgSamples adc_avg_samples_
Definition: ina2xx_base.h:173
bool read_charge_(double &coulombs_out, double &amp_hours_out)
void status_clear_warning()
Definition: component.cpp:166
sensor::Sensor * current_sensor_
Definition: ina2xx_base.h:191
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
bool read_bus_voltage_(float &volt_out)
sensor::Sensor * bus_voltage_sensor_
Definition: ina2xx_base.h:189
constexpr14 T byteswap(T n)
Definition: helpers.h:129
bool read_unsigned_16_(uint8_t reg, uint16_t &out)
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
struct esphome::ina2xx_base::INA2XX::@87 cfg_
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
virtual bool read_ina_register(uint8_t a_register, uint8_t *data, size_t len)=0
sensor::Sensor * energy_sensor_wh_
Definition: ina2xx_base.h:194
bool write_unsigned_16_(uint8_t reg, uint16_t val)
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26