Diagnóstico de batería de litio desde software

8 de diciembre de 2022 • fjbalon

La siguiente sección del cuaderno de bitácora detalla la investigación que he llevado a cabo para determinar el estado de salud de la batería de litio de mi ordenador portátil, la cual mantiene desde hace algo de tiempo un comportamiento extraño. Primero de todo, he querido omitir pruebas eléctricas directamente sobre el hardware, para detallar los pasos sobre el software y el sistema operativo que he seguido para determinar el diagnóstico.

La única información realmente útil para el lector es, entonces, que utilizo el sistema operativo GNU/Linux (con el kernel 6.0.11-arch1-1) en su distribución archlinux.

Para leer el porcentaje de batería utilizada uso ACPI (acpi 1.7), concretamente los valores que se encuentran en /sys/class/power_supply/BAT0/ (siendo BAT0 la interfaz de batería de mi equipo).

Concretamente, el fragmento del código que obtiene el valor de batería es:

int perc;
char path[PATH_MAX];

if (esnprintf(path, sizeof(path), "/sys/class/power_supply/BAT0/capacity", bat) < 0) {
    return NULL;
}

if (pscanf(path, "%d", &perc) != 1) {
    return NULL;
}

return bprintf("%d", perc);

Que recibe el valor del fichero capacity. Llegados a este punto, es necesario aclarar los distintos ficheros del directorio /sys/class/power_supply/BAT0/ (que se resumen en el fichero uevent):

POWER_SUPPLY_NAME=BAT0
POWER_SUPPLY_TYPE=Battery
POWER_SUPPLY_STATUS=Discharging
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_TECHNOLOGY=Li-ion
POWER_SUPPLY_CYCLE_COUNT=0
POWER_SUPPLY_VOLTAGE_MIN_DESIGN=11400000
POWER_SUPPLY_VOLTAGE_NOW=11759000
POWER_SUPPLY_CURRENT_NOW=1089000
POWER_SUPPLY_CHARGE_FULL_DESIGN=4100000
POWER_SUPPLY_CHARGE_FULL=900000
POWER_SUPPLY_CHARGE_NOW=675000
POWER_SUPPLY_CAPACITY=75
POWER_SUPPLY_CAPACITY_LEVEL=Normal
POWER_SUPPLY_MODEL_NAME=standard
POWER_SUPPLY_MANUFACTURER=OEM
POWER_SUPPLY_SERIAL_NUMBER=00001

Para un mayor detalle, es posible que desee ver cómo se define la clase del dispositivo power-supply en include/linux/power_supply.h. Sin embargo en esta entrada iré al grano.

Por lo que todos los valores charge_* (charge_full_design, charge_full y charge_now) se mide en microamperios/hora (µAh), mientras que current_now se mide en microamperios (µA).

POWER_SUPPLY_CHARGE_FULL_DESIGN=4100000
POWER_SUPPLY_CHARGE_FULL=900000
POWER_SUPPLY_CHARGE_NOW=675000

Cuando era nueva, la batería afirma haber tenido una capacidad de carga completa de 4,10Ah (charge_full_design), pero desde entonces se ha degradado dando lugar a una capacidad de carga completa actual de 0,9Ah. Actualmente, le quedan 0,675Ah de carga. Que realizando un simple cálculo de porcentaje:

100 0 , 675 0 , 9 = 75

Da como valor el porcentaje de batería restante, que también se obtiene de capacity:

cat /sys/class/power_supply/BAT0/capacity
75

Por otro lado, el voltaje mínimo de diseño (nunca debería descargarse por debajo de este voltaje) se mide en microvoltios (µV):

POWER_SUPPLY_VOLTAGE_MIN_DESIGN=11400000
POWER_SUPPLY_VOLTAGE_NOW=11759000

Siendo voltage_min_design 11400000µV, sea 11,4V. El voltaje actual según la medida en este momento es de 11,759V. La batería en este momento proporciona 1,089A de corriente:

POWER_SUPPLY_CURRENT_NOW=1089000

Como una simple estimación, con la corriente que está tomando de la batería en este momento:

0 , 675 A h 1 , 089 A = 0.62 h = 37 m

Le quedan unos 37 minutos de energía.

Sin embargo y como es evidente, no se puede diagnosticar por los valores concretos de un momento t en el tiempo, sin tener más valores estadísticos. Por lo que para ello, he implementado monitorización a través de un servidor Zabbix que gestione todos estos campos (concretamente para obtener una vez por minuto). Los UserParameters de Zabbix usados por el agente son:

UserParameter=ChargeNow,cat /sys/class/power_supply/BAT0/charge_now
UserParameter=ChargeFull,cat /sys/class/power_supply/BAT0/charge_full
UserParameter=ChargeFullDesign,cat /sys/class/power_supply/BAT0/charge_full_design
UserParameter=VoltageMin,cat /sys/class/power_supply/BAT0/voltage_min_design
UserParameter=VoltageNow,cat /sys/class/power_supply/BAT0/voltage_now
UserParameter=CurrentNow,cat /sys/class/power_supply/BAT0/current_now
UserParameter=Capacity,cat /sys/class/power_supply/BAT0/capacity
UserParameter=Status,if [ "$(cat /sys/class/power_supply/BAT0/status)" = "Charging" ]; then echo 1; else echo 0; fi

De tal forma, monitorizamos los valores de la batería, como el amperaje degradado y la corriente la corriente a través del tiempo:

Por otro lado, comprobamos la capacidad porcentual (y bruta). Esto nos muestra valores interesantes, como que la batería tarda en desgastarse prácticamente lo mismo que al rellenarse, sin embargo, al llegar al umbral de 8% de capacidad, ésta se vacía a una velocidad mucho más lenta hasta el 0%, lo que constituye un primer indicador del funcionamiento extraño de la batería:

Otro de los indicadores más extraños proviene al apagar el equipo durante unas horas. Éste al encenderse de nuevo, marca una batería que no se corresponde con el valor de apagado. En el ejemplo registrado, se observa como la batería se encontraba aproximadamente marcando un 10% de capacidad, pero tras 1,45h sin interacción de ningún tipo (lógicamente no estuvo conectado a la red eléctrica en este tiempo) vuelve a marcar un valor entre el 60-70% de capacidad:

Como sabemos, el valor mínimo establecido por diseño que indica la batería es de 11.4V. Sin embargo y tal como se ve, sólo excede el mínimo cuando está conectado a AC:

Por lo tanto y con toda la información recopilada, concretamente la pronunciada degradación de la batería (diferencia entre charge_full_design y charge_full) y la evidencia de que baja regularmente del voltaje mínimo establecido por diseño (voltage_min_design) sugiere que la batería probablemente esté en un estado crítico, y que podría fallar en cualquier momento.