Skip to content

Commit

Permalink
feat: Add ability to fetch battery voltage.
Browse files Browse the repository at this point in the history
* To be able to use the Zephyr `voltage-divider` driver,
  add a mode for fetching raw voltage from the sensor
 and do state of charge calculation outside of the driver.
  • Loading branch information
petejohanson committed Mar 24, 2024
1 parent 931a36f commit 4435879
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
14 changes: 14 additions & 0 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,20 @@ config ZMK_BATTERY_REPORTING
select ZMK_LOW_PRIORITY_WORK_QUEUE
imply BT_BAS if ZMK_BLE

if ZMK_BATTERY_REPORTING

choice ZMK_BATTERY_REPORTING_FETCH_MODE
prompt "Battery Reporting Fetch Mode"

config ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE
bool "State of charge"

config ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE
bool "Lithium Voltage"

endchoice
endif

config ZMK_IDLE_TIMEOUT
int "Milliseconds of inactivity before entering idle state (OLED shutoff, etc)"
default 30000
Expand Down
42 changes: 41 additions & 1 deletion app/src/battery.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,29 @@ static const struct device *const battery = DEVICE_DT_GET(DT_CHOSEN(zmk_battery)
static const struct device *battery;
#endif

#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) {
// Simple linear approximation of a battery based off adafruit's discharge graph:
// https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages

if (bat_mv >= 4200) {
return 100;
} else if (bat_mv <= 3450) {
return 0;
}

return bat_mv * 2 / 15 - 459;
}

#endif // IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)

static int zmk_battery_update(const struct device *battery) {
struct sensor_value state_of_charge;
int rc;

int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE);
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE)

rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE);
if (rc != 0) {
LOG_DBG("Failed to fetch battery values: %d", rc);
return rc;
Expand All @@ -50,6 +68,28 @@ static int zmk_battery_update(const struct device *battery) {
LOG_DBG("Failed to get battery state of charge: %d", rc);
return rc;
}
#elif IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_VOLTAGE);
if (rc != 0) {
LOG_DBG("Failed to fetch battery values: %d", rc);
return rc;
}

struct sensor_value voltage;
rc = sensor_channel_get(battery, SENSOR_CHAN_VOLTAGE, &voltage);

if (rc != 0) {
LOG_DBG("Failed to get battery voltage: %d", rc);
return rc;
}

uint16_t mv = voltage.val1 * 1000 + (voltage.val2 / 1000);
state_of_charge.val1 = lithium_ion_mv_to_pct(mv);

LOG_DBG("State of change %d from %d mv", state_of_charge.val1, mv);
#else
#error "Not a supported reporting fetch mode"
#endif

if (last_state_of_charge != state_of_charge.val1) {
last_state_of_charge = state_of_charge.val1;
Expand Down

0 comments on commit 4435879

Please sign in to comment.