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