Extending Laptop Battery Life

Lithium-Ion Batteries

Lithium-ion batteries should not be fully discharged or fully charged. This means you should not let them drain completely to the point of shutting down the device, and you should not keep them plugged in after they reach full charge.

Ideally, a lithium-ion battery should not be charged above 80% or discharged below 20%.

Since most of us today use our laptops primarily while plugged in and rarely need to run on battery alone, it is recommended to keep the charge around 60% to extend battery lifespan.

Most modern laptop brands provide official tools on Windows to control the charge threshold.

Setting the threshold

The Linux kernel, since version V4.17 and more specifically with this patch, introduced a userspace interface module for controlling battery charge thresholds. It was initially enabled experimentally for a few Lenovo ThinkPad series and has since expanded support to more devices.

There are several ways to check whether your laptop supports this. The simplest is to look for a file that controls the battery threshold behavior under the power management sysfs path. This file is typically named charge_control_{start,end}_threshold and located at /sys/class/power_supply/BAT[0-9].

If you manually change the value in this file, you will see that battery charging stops at your defined threshold. Use the echo and tee commands to do this — root access is required.

Using TLP

Charge threshold support for laptop brands other than ThinkPad has also been added to TLP and will be available in repositories soon. The following brands are currently supported:

  • ASUS Laptops
  • Huawei MateBooks
  • Lenovo Ideapads
  • Samsung Laptops

For more information, refer to this link.

You can also use TLP to control the battery charge threshold. If the tool does not yet support your system but you are sure your device has this capability, you can follow the instructions in this comment, create a gist, and post the link under #issue321 so the developers can add support for your device in a future release. Make sure your device specs have not already been submitted to avoid duplicates.

Sample output will look like this:

$ sudo tlp-stat -s -b
--- TLP 1.3.1 --------------------------------------------

+++ System Info
System         = ASUSTeK COMPUTER INC. 1.0        ZenBook 14 UX410UFR
BIOS           = UX410UFR.201
Kernel         = 5.5.3-arch1-1 #1 SMP PREEMPT Tue, 11 Feb 2020 15:35:41 +0000 x86_64
/proc/cmdline  = BOOT_IMAGE=/vmlinuz-linux root=UUID=805eb372-94c7-4e8c-87b4-54b0414fa84a rw loglevel=3 quiet
Init system    = systemd
Boot mode      = UEFI

+++ TLP Status
State          = enabled
RDW state      = enabled
Last run       = 09:11:45 PM,   1613 sec(s) ago
Mode           = AC
Power source   = AC

Notice: systemd-rfkill.service is not masked -- invoke "systemctl mask systemd-rfkill.service" to correct this!
Notice: systemd-rfkill.socket is not masked -- invoke "systemctl mask systemd-rfkill.socket" to correct this!

+++ Battery Features: Charge Thresholds and Recalibrate
natacpi    = inactive (laptop not supported)
tpacpi-bat = inactive (laptop not supported)
tp-smapi   = inactive (laptop not supported)

+++ Battery Status: BAT0
/sys/class/power_supply/BAT0/manufacturer                   = ASUSTeK
/sys/class/power_supply/BAT0/model_name                     = ASUS Battery
/sys/class/power_supply/BAT0/cycle_count                    =     35
/sys/class/power_supply/BAT0/energy_full_design             =  48336 [mWh]
/sys/class/power_supply/BAT0/energy_full                    =  45474 [mWh]
/sys/class/power_supply/BAT0/energy_now                     =  31327 [mWh]
/sys/class/power_supply/BAT0/power_now                      =      0 [mW]
/sys/class/power_supply/BAT0/status                         = Not charging

Charge                                                      =   68.9 [%]
Capacity                                                    =   94.1 [%]

# **NOTE**
# (I manually set the charge_control_end_threshold t0 60)

$ grep '.*' /sys/class/power_supply/BAT?/*
/sys/class/power_supply/BAT0/alarm:4833000
/sys/class/power_supply/BAT0/capacity:68
/sys/class/power_supply/BAT0/capacity_level:Normal
/sys/class/power_supply/BAT0/charge_control_end_threshold:60
/sys/class/power_supply/BAT0/cycle_count:35
/sys/class/power_supply/BAT0/energy_full:45474000
/sys/class/power_supply/BAT0/energy_full_design:48336000
/sys/class/power_supply/BAT0/energy_now:31327000
/sys/class/power_supply/BAT0/manufacturer:ASUSTeK
/sys/class/power_supply/BAT0/model_name:ASUS Battery
/sys/class/power_supply/BAT0/power_now:0
/sys/class/power_supply/BAT0/present:1
/sys/class/power_supply/BAT0/serial_number:
/sys/class/power_supply/BAT0/status:Not charging
/sys/class/power_supply/BAT0/technology:Li-ion
/sys/class/power_supply/BAT0/type:Battery
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_NAME=BAT0
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_STATUS=Not charging
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_PRESENT=1
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_TECHNOLOGY=Li-ion
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_CYCLE_COUNT=35
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_VOLTAGE_MIN_DESIGN=11400000
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_VOLTAGE_NOW=11400000
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_POWER_NOW=0
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_ENERGY_FULL_DESIGN=48336000
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_ENERGY_FULL=45474000
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_ENERGY_NOW=31327000
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_CAPACITY=68
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_CAPACITY_LEVEL=Normal
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_MODEL_NAME=ASUS Battery
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_MANUFACTURER=ASUSTeK
/sys/class/power_supply/BAT0/uevent:POWER_SUPPLY_SERIAL_NUMBER=
/sys/class/power_supply/BAT0/voltage_min_design:11400000
/sys/class/power_supply/BAT0/voltage_now:11400000

And for udevadm test:

$ udevadm test /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:19/PNP0C09:01/PNP0C0A:03/power_supply/BAT0
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.
...
BAT0: /etc/udev/rules.d/99_battery_threshold.rules:1 Failed to write ATTR{...}, ignoring: Permission denied
DEVPATH=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:19/PNP0C09:01/PNP0C0A:03/power_supply/BAT0
POWER_SUPPLY_NAME=BAT0
POWER_SUPPLY_STATUS=Not charging
...

Setting the Charge Threshold with udev

If you want the charge threshold to be set automatically every time the system boots, you can add a udev rule to apply the threshold value at boot time.

To do this, create a new file with a .rules extension in /etc/udev/rules.d.

My configuration looks like this:

$ cat /etc/udev/rules.d/99_battery_threshold.rules
KERNEL=="BAT[0-9]", SUBSYSTEM=="power_supply", ATTR{charge_control_end_threshold}="60"

For a deeper understanding of udev and how to use it to interact with kernel modules, refer to this page on the Arch Linux Wiki.

Setting the Charge Threshold with a systemd Service

For ASUS laptops, you can use this program to control the battery charge threshold. To persist the threshold across reboots, it creates a systemd service:

[Unit]
Description=Persist the battery charging threshold between restarts
After=multi-user.target
StartLimitBurst=0

[Service]
Type=oneshot
Restart=on-failure
ExecStart=/bin/bash -c 'echo %s > /sys/class/power_supply/BAT?/charge_control_end_threshold'

[Install]
WantedBy=multi-user.target

Comments

You can view the comments for this post on Mastodon here . Click the link below to write a comment.

Write a comment

View comments