ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
bq27220.cpp
Go to the documentation of this file.
1#include "bq27220.h"
2
3#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6
7#include <cmath>
8
9namespace esphome::bq27220 {
10
11ESPHOME_LOG_TAG(TAG, "bq27220");
12
13// Standard command registers (16-bit, little-endian), SLUUBD4A
14static constexpr uint8_t REG_CONTROL = 0x00;
15static constexpr uint8_t REG_TEMPERATURE = 0x06; // 0.1 K
16static constexpr uint8_t REG_VOLTAGE = 0x08; // mV
17static constexpr uint8_t REG_CURRENT = 0x0C; // mA, signed
18static constexpr uint8_t REG_REMAINING_CAPACITY = 0x10; // mAh
19static constexpr uint8_t REG_FULL_CHARGE_CAPACITY = 0x12; // mAh
20static constexpr uint8_t REG_TIME_TO_EMPTY = 0x16; // min, 0xFFFF when not discharging
21static constexpr uint8_t REG_STATE_OF_CHARGE = 0x2C; // %
22static constexpr uint8_t REG_STATE_OF_HEALTH = 0x2E; // %
23// The DEVICE_NUMBER subcommand (0x0001, SLUUBD4A §2.2.2) answers through the MAC data buffer
24static constexpr uint8_t REG_MAC_DATA = 0x40;
25static constexpr uint16_t DEVICE_NUMBER = 0x0220;
26static constexpr uint16_t TIME_TO_EMPTY_NOT_APPLICABLE = 0xFFFF;
27
28bool BQ27220Component::read_word_(uint8_t reg, uint16_t &value) {
29 uint8_t data[2];
30 if (this->read_register(reg, data, 2) != i2c::ERROR_OK) {
31 return false;
32 }
33 value = encode_uint16(data[1], data[0]);
34 return true;
35}
36
38 const uint8_t device_number_cmd[2] = {0x01, 0x00}; // DEVICE_NUMBER subcommand, little-endian
39 if (this->write_register(REG_CONTROL, device_number_cmd, 2) != i2c::ERROR_OK) {
40 this->mark_failed(LOG_STR("Failed to communicate with BQ27220"));
41 return;
42 }
43 delay(2); // SLUUBD4A §5.3: the subcommand result needs a moment before it can be read
44 uint16_t device_number = 0;
45 if (!this->read_word_(REG_MAC_DATA, device_number)) {
46 this->mark_failed(LOG_STR("Failed to read device number from BQ27220"));
47 return;
48 }
49 if (device_number != DEVICE_NUMBER) {
50 ESP_LOGE(TAG, "Unexpected device number 0x%04X (expected 0x%04X)", device_number, DEVICE_NUMBER);
51 this->mark_failed(LOG_STR("Unexpected device number"));
52 }
53}
54
55void BQ27220Component::update() {
56 bool ok = true;
57 this->publish_(this->voltage_sensor_, REG_VOLTAGE, ok, [](uint16_t raw) { return raw * 0.001f; });
58 this->publish_(this->current_sensor_, REG_CURRENT, ok,
59 [](uint16_t raw) { return static_cast<int16_t>(raw) * 0.001f; });
60 this->publish_(this->battery_level_sensor_, REG_STATE_OF_CHARGE, ok, [](uint16_t raw) { return float(raw); });
61 this->publish_(this->temperature_sensor_, REG_TEMPERATURE, ok, [](uint16_t raw) { return raw * 0.1f - 273.15f; });
62 this->publish_(this->remaining_capacity_sensor_, REG_REMAINING_CAPACITY, ok, [](uint16_t raw) { return float(raw); });
63 this->publish_(this->full_charge_capacity_sensor_, REG_FULL_CHARGE_CAPACITY, ok,
64 [](uint16_t raw) { return float(raw); });
65 this->publish_(this->time_to_empty_sensor_, REG_TIME_TO_EMPTY, ok,
66 [](uint16_t raw) { return raw == TIME_TO_EMPTY_NOT_APPLICABLE ? NAN : float(raw); });
67 this->publish_(this->state_of_health_sensor_, REG_STATE_OF_HEALTH, ok, [](uint16_t raw) { return float(raw); });
68
69 if (ok) {
71 } else {
72 this->status_set_warning(LOG_STR("Failed to read one or more registers from BQ27220"));
73 }
74}
75
76void BQ27220Component::dump_config() {
77 ESP_LOGCONFIG(TAG, "BQ27220 Battery Fuel Gauge:");
78 LOG_I2C_DEVICE(this);
79 LOG_UPDATE_INTERVAL(this);
80 LOG_SENSOR(" ", "Voltage", this->voltage_sensor_);
81 LOG_SENSOR(" ", "Current", this->current_sensor_);
82 LOG_SENSOR(" ", "Battery Level", this->battery_level_sensor_);
83 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
84 LOG_SENSOR(" ", "Remaining Capacity", this->remaining_capacity_sensor_);
85 LOG_SENSOR(" ", "Full Charge Capacity", this->full_charge_capacity_sensor_);
86 LOG_SENSOR(" ", "Time To Empty", this->time_to_empty_sensor_);
87 LOG_SENSOR(" ", "State Of Health", this->state_of_health_sensor_);
88}
89
90} // namespace esphome::bq27220
uint8_t raw[35]
Definition bl0939.h:0
void mark_failed()
Mark this component as failed.
virtual void setup()
Where the component's initialization should happen.
Definition component.cpp:84
void status_clear_warning()
Definition component.h:291
bool read_word_(uint8_t reg, uint16_t &value)
Definition bq27220.cpp:28
void publish_(sensor::Sensor *sensor, uint8_t reg, bool &ok, F convert)
Read a standard command register and publish it through the sensor, if one is configured.
Definition bq27220.h:31
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len) const
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:34
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:25
ESPHOME_LOG_TAG(TAG, "bq27220")
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:15
FLAG_HAS_TRANSITION float
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:980
void HOT delay(uint32_t ms)
Definition hal.cpp:85