Skip to content

Commit e74bab6

Browse files
committed
Merge branch 'feat/adc_battery_esti_add_charging_prognosis' into 'master'
feat(adc_battery): add software estimation for charging state See merge request ae_group/esp-iot-solution!1310
2 parents 61935c3 + f1cc4e1 commit e74bab6

File tree

6 files changed

+112
-11
lines changed

6 files changed

+112
-11
lines changed

components/sensors/battery_fuel_gauge/adc_battery_estimation/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# ChangeLog
22

3+
## v0.2.0 - 2025-6-18
4+
5+
* Add software estimation for charging state
6+
37
## v0.1.0 - 2025-5-16
48

59
### Enhancements:
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
idf_component_register(SRCS "adc_battery_estimation.c"
22
INCLUDE_DIRS include
3-
REQUIRES "esp_adc")
3+
REQUIRES "esp_adc" "esp_timer")
44

55
include(package_manager)
66
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})

components/sensors/battery_fuel_gauge/adc_battery_estimation/Kconfig

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,33 @@ menu "ADC Battery Estimation"
4040
Lower values provide more smoothing but slower response to changes.
4141
Higher values provide less smoothing but faster response to changes.
4242

43+
config BATTERY_STATE_SOFTWARE_ESTIMATION
44+
bool "Battery State Software Estimation"
45+
default y
46+
help
47+
Enable software-based estimation of the battery state to determine
48+
whether the battery is charging or discharging.
49+
50+
menu "Software Estimation Configuration"
51+
depends on BATTERY_STATE_SOFTWARE_ESTIMATION
52+
53+
config SOFTWARE_ESTIMATION_SAMPLE_COUNT
54+
int "Software Estimation Sample Count"
55+
range 10 15
56+
default 10
57+
help
58+
The number of samples to collect for software-based battery state estimation.
59+
A higher number of samples can provide more accurate estimation but may increase
60+
the time required for estimation.
61+
62+
config SOFTWARE_ESTIMATION_SAMPLE_INTERVAL
63+
int "Software Estimation Sample Interval (ms)"
64+
range 10000 100000
65+
default 20000
66+
help
67+
The interval in milliseconds between each sample for software-based battery state estimation.
68+
A shorter interval allows for quicker detection of changes in battery state but may consume
69+
more power.
70+
endmenu
4371

4472
endmenu

components/sensors/battery_fuel_gauge/adc_battery_estimation/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
1. Provides basic battery level information while ensuring consistency in the estimated capacity
66
2. Supports both user-provided external ADC Handle or automatic creation by the component internally
77
3. Supports filtering of collected ADC data and estimated battery capacity
8+
4. Provides a software-based charging state estimation method. If the user cannot provide a charging indicator pin and `BATTERY_STATE_SOFTWARE_ESTIMATION` is enabled in Kconfig, software charging state estimation will be activated
89

910
This component provides two OCV-SOC models, from [Ti](https://www.ti.com/lit/SLUAAR3) and [Analog Device](https://www.analog.com/en/resources/design-notes/characterizing-a-lithiumion-li-cell-for-use-with-an-opencircuitvoltage-ocv-based-fuel-gauge.html) respectively. Additionally, it supports user-defined custom OCV-SOC models.
1011

components/sensors/battery_fuel_gauge/adc_battery_estimation/adc_battery_estimation.c

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <math.h>
99
#include "esp_log.h"
1010
#include "esp_check.h"
11+
#include "esp_timer.h"
1112
#include "adc_battery_estimation.h"
1213

1314
static const char* TAG = "adc_battery_estimation";
@@ -22,11 +23,16 @@ typedef struct {
2223
size_t battery_points_count;
2324
adc_battery_charging_detect_cb_t charging_detect_cb;
2425
void *charging_detect_user_data;
25-
float last_capacity; /*!< Last calculated battery capacity in percentage */
26-
bool is_first_read; /*!< Flag for first capacity reading */
27-
bool last_charging_state; /*!< Last charging state */
28-
float voltage_divider_ratio; /*!< Voltage divider ratio */
29-
float filter_alpha; /*!< Low-pass filter coefficient (0 < alpha < 1) */
26+
float last_capacity; /*!< Last calculated battery capacity in percentage */
27+
bool is_first_read; /*!< Flag for first capacity reading */
28+
bool last_charging_state; /*!< Last charging state */
29+
float voltage_divider_ratio; /*!< Voltage divider ratio */
30+
float filter_alpha; /*!< Low-pass filter coefficient (0 < alpha < 1) */
31+
#if CONFIG_BATTERY_STATE_SOFTWARE_ESTIMATION
32+
uint64_t last_time_ms; /*!< Last time in milliseconds */
33+
int battery_state_estimation_buffer[CONFIG_SOFTWARE_ESTIMATION_SAMPLE_COUNT]; /*!< Buffer to store ADC readings */
34+
int battery_state_estimation_index; /*!< Current index in the buffer */
35+
#endif
3036
} adc_battery_estimation_ctx_t;
3137

3238
// Helper function to calculate battery capacity based on voltage
@@ -53,6 +59,32 @@ static float calculate_battery_capacity(float voltage, const battery_point_t *po
5359
}
5460
}
5561

62+
// Helper function to analyze battery trend
63+
static bool analyze_battery_trend(const int *buffer, int buffer_size, bool last_charging_state)
64+
{
65+
int increasing_count = 0;
66+
int decreasing_count = 0;
67+
68+
// Count increasing and decreasing points
69+
for (int i = 1; i < buffer_size; i++) {
70+
if (buffer[i] > buffer[i - 1]) {
71+
increasing_count++;
72+
} else if (buffer[i] < buffer[i - 1]) {
73+
decreasing_count++;
74+
}
75+
}
76+
77+
// Log the analysis results
78+
ESP_LOGD(TAG, "Trend analysis: increasing=%d, decreasing=%d", increasing_count, decreasing_count);
79+
80+
// If increasing and decreasing counts are equal, keep the last state
81+
if (increasing_count == decreasing_count) {
82+
return last_charging_state;
83+
}
84+
// Otherwise, determine by increasing/decreasing trend
85+
return increasing_count > decreasing_count;
86+
}
87+
5688
adc_battery_estimation_handle_t adc_battery_estimation_create(adc_battery_estimation_t *config)
5789
{
5890
ESP_RETURN_ON_FALSE(config, NULL, TAG, "Config is NULL");
@@ -127,6 +159,11 @@ adc_battery_estimation_handle_t adc_battery_estimation_create(adc_battery_estima
127159
ctx->voltage_divider_ratio = config->lower_resistor / total_resistance;
128160
ctx->filter_alpha = CONFIG_BATTERY_CAPACITY_LPF_COEFFICIENT / 10.0f;
129161

162+
#if CONFIG_BATTERY_STATE_SOFTWARE_ESTIMATION
163+
ctx->battery_state_estimation_index = 0;
164+
ctx->last_time_ms = 0;
165+
#endif
166+
130167
return (adc_battery_estimation_handle_t) ctx;
131168
}
132169

@@ -172,11 +209,19 @@ esp_err_t adc_battery_estimation_get_capacity(adc_battery_estimation_handle_t ha
172209

173210
adc_battery_estimation_ctx_t *ctx = (adc_battery_estimation_ctx_t *) handle;
174211
bool is_charging = false;
175-
212+
#if CONFIG_BATTERY_STATE_SOFTWARE_ESTIMATION
213+
uint64_t current_time_ms = esp_timer_get_time() / 1000;
214+
#endif
176215
// Check charging state if callback is provided
177216
if (ctx->charging_detect_cb) {
178217
is_charging = ctx->charging_detect_cb(ctx->charging_detect_user_data);
179218
}
219+
#if CONFIG_BATTERY_STATE_SOFTWARE_ESTIMATION
220+
else {
221+
// Use last charging state if no callback is provided
222+
is_charging = ctx->last_charging_state;
223+
}
224+
#endif
180225

181226
// Get ADC reading via filtering
182227
int vol[CONFIG_ADC_FILTER_WINDOW_SIZE] = {0};
@@ -215,9 +260,33 @@ esp_err_t adc_battery_estimation_get_capacity(adc_battery_estimation_handle_t ha
215260
filtered_result = filtered_vol / filtered_count;
216261
}
217262

263+
#if CONFIG_BATTERY_STATE_SOFTWARE_ESTIMATION
264+
// Record filtered_result every CONFIG_SOFTWARE_ESTIMATION_SAMPLE_INTERVAL ms
265+
if (current_time_ms - ctx->last_time_ms >= CONFIG_SOFTWARE_ESTIMATION_SAMPLE_INTERVAL) {
266+
// Store the new value at current index
267+
ctx->battery_state_estimation_buffer[ctx->battery_state_estimation_index] = filtered_result;
268+
// Update index, wrap around when reaching the end
269+
ctx->battery_state_estimation_index = (ctx->battery_state_estimation_index + 1) % CONFIG_SOFTWARE_ESTIMATION_SAMPLE_COUNT;
270+
271+
// If buffer is full (index is 0), analyze the trend
272+
if (ctx->battery_state_estimation_index == 0) {
273+
bool trend_is_charging = analyze_battery_trend(ctx->battery_state_estimation_buffer,
274+
CONFIG_SOFTWARE_ESTIMATION_SAMPLE_COUNT,
275+
ctx->last_charging_state);
276+
ESP_LOGD(TAG, "Battery trend analysis: %s", trend_is_charging ? "Charging" : "Discharging");
277+
278+
// Update last charging state
279+
ctx->last_charging_state = trend_is_charging;
280+
// If no charging detection callback is provided, use trend analysis
281+
if (!ctx->charging_detect_cb) {
282+
is_charging = trend_is_charging;
283+
}
284+
}
285+
ctx->last_time_ms = current_time_ms;
286+
}
287+
#endif
218288
// Convert ADC voltage (mV) to battery voltage (V)
219289
float battery_voltage = (float)filtered_result / 1000.0f / ctx->voltage_divider_ratio;
220-
ESP_LOGD(TAG, "Battery voltage: %.2fV", battery_voltage);
221290

222291
// Calculate battery capacity based on voltage
223292
float current_capacity = calculate_battery_capacity(battery_voltage, ctx->battery_points, ctx->battery_points_count);
@@ -265,8 +334,7 @@ esp_err_t adc_battery_estimation_get_charging_state(adc_battery_estimation_handl
265334
if (ctx->charging_detect_cb) {
266335
*is_charging = ctx->charging_detect_cb(ctx->charging_detect_user_data);
267336
} else {
268-
ESP_LOGE(TAG, "Charging detection callback is not set");
269-
return ESP_ERR_INVALID_STATE;
337+
*is_charging = ctx->last_charging_state;
270338
}
271339

272340
return ESP_OK;

components/sensors/battery_fuel_gauge/adc_battery_estimation/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: 0.1.0
1+
version: 0.2.0
22
description: Battery capacity estimation based on ADC
33
url: https://github.com/espressif/esp-iot-solution/tree/master/components/sensors/battery_fuel_gauge/adc_battery_estimation
44
repository: https://github.com/espressif/esp-iot-solution.git

0 commit comments

Comments
 (0)