9 namespace ina2xx_base {
11 static const char *
const TAG =
"ina2xx";
13 #define OKFAILED(b) ((b) ? "OK" : "FAILED") 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};
18 static const char *get_device_name(
INAModel model) {
35 static bool check_model_and_device_match(
INAModel model, uint16_t dev_id) {
38 return dev_id == 0x228;
40 return dev_id == 0x229;
42 return dev_id == 0x238;
44 return dev_id == 0x239;
46 return dev_id == 0x237;
53 ESP_LOGCONFIG(TAG,
"Setting up INA2xx...");
56 ESP_LOGE(TAG,
"Reset failed, check connection");
63 ESP_LOGE(TAG,
"Device not supported or model selected improperly in yaml file");
87 ESP_LOGD(TAG,
"Updating");
89 ESP_LOGD(TAG,
"Initiating new data collection");
97 switch (this->state_) {
106 float shunt_voltage{0};
115 float bus_voltage{0};
124 float die_temperature{0};
156 double energy_j{0}, energy_wh{0};
170 double charge_c{0}, charge_ah{0};
191 ESP_LOGW(TAG,
"Unknown state of the component, might be due to memory corruption");
198 ESP_LOGCONFIG(TAG,
"INA2xx:");
199 ESP_LOGCONFIG(TAG,
" Device model = %s", get_device_name(this->
ina_model_));
202 ESP_LOGE(TAG,
" Device model mismatch. Found device with ID = %x. Please check your configuration.",
206 ESP_LOGE(TAG,
"Communication with INA2xx failed!");
208 LOG_UPDATE_INTERVAL(
this);
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_);
216 ESP_LOGCONFIG(TAG,
" ADC Samples = %d; ADC times: Bus = %d μs, Shunt = %d μs, Temp = %d μs",
222 ESP_LOGCONFIG(TAG,
" Device is %s", get_device_name(this->
ina_model_));
242 ESP_LOGV(TAG,
"reset_energy_counters");
256 ESP_LOGV(TAG,
"Reset");
263 constexpr uint16_t manufacturer_ti = 0x5449;
265 uint16_t manufacturer_id{0}, rev_id{0};
269 ESP_LOGV(TAG,
"Can't read device ID");
273 ESP_LOGI(TAG,
"Manufacturer: 0x%04X, Device ID: 0x%04X, Revision: %d", manufacturer_id, this->
dev_id_, rev_id);
275 if (manufacturer_id != manufacturer_ti) {
276 ESP_LOGE(TAG,
"Manufacturer ID doesn't match original 0x5449");
282 ESP_LOGI(TAG,
"Supported device found: INA%x, 85-V, 20-Bit, Ultra-Precise Power/Energy/Charge Monitor",
285 ESP_LOGI(TAG,
"Supported device found: INA%x, 85-V, 16-Bit, High-Precision Power Monitor", this->
dev_id_);
287 ESP_LOGI(TAG,
"We assume device is: INA237 85-V, 16-Bit, Precision Power Monitor");
290 ESP_LOGE(TAG,
"Unknown device ID %x.", this->
dev_id_);
297 ESP_LOGE(TAG,
"Selected model %s doesn't match found device INA%x", get_device_name(this->
ina_model_),
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;
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;
328 ESP_LOGV(TAG,
"Setting ADCRANGE = %d", (uint8_t) this->
adc_range_);
351 this->
shunt_cal_ = (uint16_t) (this->
cfg_.shunt_cal_scale * this->current_lsb_ * this->shunt_resistance_ohm_);
357 ESP_LOGW(TAG,
"Shunt value too high");
383 float volt_reading{0};
395 volt_out = (this->
adc_range_ ? this->
cfg_.v_shunt_lsb_range1 : this->
cfg_.v_shunt_lsb_range0) * volt_reading;
398 ESP_LOGV(TAG,
"read_shunt_voltage_mv_ ret=%s, shunt_cal=%d, reading_lsb=%f", OKFAILED(ret), this->
shunt_cal_,
410 float volt_reading{0};
421 volt_out = this->
cfg_.vbus_lsb * (float) volt_reading;
424 ESP_LOGV(TAG,
"read_bus_voltage_ ret=%s, reading_lsb=%f", OKFAILED(ret), volt_reading);
434 float temp_reading{0};
446 temp_out = this->
cfg_.die_temp_lsb * (float) temp_reading;
449 ESP_LOGV(TAG,
"read_die_temp_c_ ret=%s, reading_lsb=%f", OKFAILED(ret), temp_reading);
458 float amps_reading{0};
470 ESP_LOGV(TAG,
"read_current_a_ ret=%s. current_lsb=%f. reading_lsb=%f", OKFAILED(ret), this->
current_lsb_,
483 uint64_t power_reading{0};
486 ESP_LOGV(TAG,
"read_power_w_ ret=%s, reading_lsb=%" PRIu32, OKFAILED(ret), (uint32_t) power_reading);
488 power_out = this->
cfg_.power_coeff * this->
current_lsb_ * (float) power_reading;
502 uint64_t joules_reading = 0;
506 ESP_LOGV(TAG,
"read_energy_j_ ret=%s, reading_lsb=0x%" PRIX64
", current_lsb=%f, overflow_cnt=%" PRIu32,
509 joules_out = this->
cfg_.energy_coeff * this->
current_lsb_ * (double) joules_reading + (
double) previous_energy;
510 watt_hours_out = joules_out / 3600.0;
526 double coulombs_reading = 0;
531 ESP_LOGV(TAG,
"read_charge_c_ ret=%d, curr_charge=%f + 39-bit overflow_cnt=%" PRIu32, ret, coulombs_reading,
534 coulombs_out = this->
current_lsb_ * (double) coulombs_reading + (
double) previous_charge;
535 amp_hours_out = coulombs_out / 3600.0;
547 ESP_LOGV(TAG,
"read_diagnostics_and_act_ ret=%s, 0x%04X", OKFAILED(ret), diag.raw_u16);
564 ESP_LOGV(TAG,
"write_unsigned_16_ FAILED reg=0x%02X, val=0x%04X", reg, val);
570 static uint8_t rx_buf[5] = {0};
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];
583 ESP_LOGV(TAG,
"read_unsigned_ reg=0x%02X, ret=%s, len=%d, val=0x%" PRIX64, reg, OKFAILED(ret), reg_size, data_out);
592 ESP_LOGV(TAG,
"read_unsigned_16_ 0x%02X, ret= %s, val=0x%04X", reg, OKFAILED(ret), out);
597 if (value > (1ULL << (bits - 1))) {
598 return (int64_t) (value - (1ULL << bits));
600 return (int64_t) value;
bool read_current_a_(float &s_out)
bool check_device_model_()
const float DATA
For components that import data from directly connected sensors like DHT.
bool read_unsigned_(uint8_t reg, uint8_t reg_size, uint64_t &data_out)
bool configure_shunt_tempco_()
sensor::Sensor * charge_sensor_c_
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")
bool read_power_w_(float &power_out)
bool read_energy_(double &joules_out, double &watt_hours_out)
sensor::Sensor * shunt_voltage_sensor_
float get_setup_priority() const override
uint16_t shunt_tempco_ppm_c_
void dump_config() override
bool read_die_temp_c_(float &temp)
bool read_diagnostics_and_act_()
sensor::Sensor * charge_sensor_ah_
bool configure_adc_range_()
sensor::Sensor * energy_sensor_j_
sensor::Sensor * die_temperature_sensor_
sensor::Sensor * power_sensor_
AdcTime adc_time_shunt_voltage_
AdcAvgSamples adc_avg_samples_
bool read_charge_(double &coulombs_out, double &_hours_out)
float shunt_resistance_ohm_
AdcTime adc_time_die_temperature_
void status_clear_warning()
sensor::Sensor * current_sensor_
void publish_state(float state)
Publish a new state to the front-end.
bool read_bus_voltage_(float &volt_out)
sensor::Sensor * bus_voltage_sensor_
bool reset_energy_counters()
constexpr14 T byteswap(T n)
bool read_unsigned_16_(uint8_t reg, uint16_t &out)
virtual void mark_failed()
Mark this component as failed.
struct esphome::ina2xx_base::INA2XX::@87 cfg_
Implementation of SPI Controller mode.
virtual bool read_ina_register(uint8_t a_register, uint8_t *data, size_t len)=0
uint32_t energy_overflows_count_
sensor::Sensor * energy_sensor_wh_
AdcTime adc_time_bus_voltage_
bool write_unsigned_16_(uint8_t reg, uint16_t val)
uint32_t charge_overflows_count_
void IRAM_ATTR HOT delay(uint32_t ms)