Linux 系统中配置 T470s 的电源管理及充放电阈值

虽然多数时候我的笔记本都是插着电源在用的,但是也有不少时候只能工作在电池情况下。一旦工作在只有电池的情况下,希望电池能够提供尽量长时间的工作就成为理所当然的需求了。而 ThinkPad 笔记本电池还有个独特的设置充放电阈值的特性,使用适当的话可以延长电池的使用寿命。所以安装 openSUSE Tumbleweed 之后就开始琢磨着实现这两个目的。

节电是为了延长一次充电后的电池放电时间;设置充放电阈值是为了延长电池的服务年限。

节电这样的目的在 Windows 下是非常容易实现的,因为硬件厂商的支持,Windows 系统的智能节电设置很完善,但是在 Linux 上就相对麻烦一些,因为硬件厂商的支持力度不够大,而且一些私有的软件或代码也不能直接用在 openSUSE 这样的开源项目上。

作为笔记本,系统在电池供电情况下的省电设置——电源管理——是个很重要的特性。也正是因为其重要性,开源社区也积累了不少笔记本上的电源管理应用。Linux 上的电源管理应用有 Laptop Mode Tools (LMT)、TLP、pm-utils、Powertop,以及 thermald 等。

根据 Reddit 上 2015 年的这个讨论贴,似乎一般人比较倾向于 Powertop + TLP 的组合。于是我就按照这个思路配置了自己的电脑。不过具体效果怎么样就不知道了,也不想费时费力去测试。如果有朋友测试了,还请分享一下。

TLP

主页在这里

TLP 一般使用

openSUSE Tumbleweed 的官方软件源就有这个软件。安装很简单,

$ sudo zypper install tlp tlp-rdw

其中 tlp 是管节能的,而 tlp-rdw 是可选的,主要是无线设备管理用的。

现在查看 TLP 的状态,

$ sudo tlp-stat -s
...
Notice: tlp.service is not enabled -- invoke "systemctl enable tlp.service" to correct this!
Notice: tlp-sleep.service is not enabled -- invoke "systemctl enable tlp-sleep.service" to correct this!
Notice: systemd-rfkill.service is not masked -- invoke "systemctl mask systemd-rfkill.service" to correct this!
...

提示需要启用两个服务,并屏蔽系统默认的 rfkill 服务。按照提示启用两个系统服务并屏蔽 systemd-rfkill 即可,

$ sudo systemctl enable tlp.service
$ sudo systemctl enable tlp-sleep.service
$ sudo systemctl mask systemd-rfkill.service

于是 TLP 就会在下次开机后自动运行。如果要即时运行 TLP,则执行,

$ sudo systemctl start tlp.service

TLP 默认情况下就已经设定为在外接电源时使用最高性能,在使用电池供电时尽量节能。基本不需要自己配置。具体可参考其网页上对配置的介绍。

另外,如果要取消屏蔽 systemd-rfkill,只需要删除系统服务里那个指向 /dev/null 的软连接即可,

$ sudo systemctl status systemd-rfkill
● systemd-rfkill.service
    Loaded: masked (/dev/null; bad)
    Active: inactive (dead)
$ sudo rm /etc/systemd/system/systemd-rfkill.service

实际起作用的是 /usr/lib/systemd/systemd-rfkill 这个文件。

TLP 例外设置

根据 ArchLinux Wiki 上的提醒,如果磁盘使用 Btrfs 系统,则需要**禁用** SATA 接口在电池供电情况下的节电模式以防止文件系统出问题。修改 TLP 配置文件,将其中的 SATA_LINKPWR_ON_BAT 改成如下配置,

SATA_LINKPWR_ON_BAT=max_performance

我不知道这个设置是否对基于 PCIe 的 NVMe 接口的 SSD 有效。但是开着也算是有备无患。但是根据 openSUSE 论坛上的这个帖子,该问题应该已经不存在了。

TLP 管理 ThinkPad 充电阈值

背景

ThinkPad 笔记本电池与别的笔记本电池最大的区别就在于提供了充电开始与结束阈值的设定。关于这个问题的背景在之前的帖子中已经总结得很详细了。有需要的话请参考「浅谈 ThinkPad 电源管理之电池维护」。

实际上,根据 Lenovo 支持论坛的一个帖子,联想现在也不提供原来那个大家很熟悉的电池管理软件给 Windows 10 用户了。因为现在的 ThinkPad 系统里面够包含了双模式的电池固件。这种双模式的电池固件自己就能根据用户的使用情况,比如电池连续几个星期都是满电状态(就是说用户**一直**都是用外接电源),自动降低相对的满电水平(相当于降低电池的充电停止阈值)来维持电池最大限度的健康。具体解释请看下面的引用文字。

There is not any Power Manager for Windows 10.  Lenovo does not provide any feature to manage battery charge thresholds on Windows 10.  The ThinkPad systems that are on the Windows 10 supported system list here all have dual-mode battery firmware.  The battery firmware itself will recognize the scenario where the battery is ALWAYS fully charged 100% (over a period of many weeks) and adjust the full charge capacity downwards in a way to maintain maximum battery health.  This is something that happens automatically in the battery firmware.  There is nothing that a user needs to do manually, to maximize battery health on these batteries.  For this reason, we don’t provide any utility to manually manage battery charge thresholds on Windows 10.

对于电池这样的消耗品,多数用户应该不会去自己设置充电阈值,甚至都不知道 ThinkPad 提供了这样的设置。从这个角度看,联想这种双模式固件的设计是非常人性化的,应该效果也很好。但是不知道这种双模式是否能够在非 Windows 10 的系统下正常发挥作用。勘误:经过实际查看,在 Windows 10 中的「Lenovo Settings」中是**提供了电池阈值的设置选项**的。

无论如何,像我们这些了解到这种设置对电池寿命的好处的用户,如果不去设置就会感觉对不起自己的电池了。况且,自动的设置毕竟没有用户自己更了解自己的使用习惯。再加上现在是双电池设计,就更有必要根据自己的使用习惯来对两块电池设置不同的充电模式。

对了,我的 T470s 的两块电池制造商也不一样(估计都是这样)。主电池(电池 1)是锂聚合物(Li-Polymer)电池,SMP 制造(可能是 FUJITSU SIEMENS 的品牌?);副电池(电池 1)是锂离子(Li-ion)电池,SANYO(三洋)制造。

需要的附加组件

TLP 使用 tpacpi-bat 来管理 ThinkPad 笔记本上的电池充电阈值设置。这个阈值写入电池固件后,除非重新设置,否则不会发生变化。所以如果仅仅是为了设置充电阈值的话,就不需要一直启用 TLP 服务。

但是依赖的软件包还是需要的,acpi_call 和/或 tp_smapi。一般只需要这两个中的一个,有的机型可能同时支持两个。一般新机型只要 acpi_call 就够了。因为我的系统里 tp_smapi 无法加载,所以没有安装。

openSUSE 的软件仓库里 revealed 维护了这两个软件包。地址见这里。先添加该软件源针对 openSUSE Tumbleweed 的地址,然后直接通过 zypper或者 YaST2 安装即可。

注意:使用软件仓库里的私人软件源的缺点之一就是其更新通常比常规的 openSUSE Tumbleweed 更新快照的发布要晚一些(如果需要更新的话),而使用 dkms 的软件包则必然需要在 kernel 更新的时候重新打包,所以在更新 oSTw 的时候如果发布了新的 Linux 内核则需要留意一下 dkms-acpi_call 是否已经重新打包了。当然,先升级 kernel,随后再升级 dkms-acpi_call 也是没问题的,只是在升级它之前该功能是失效状态。

更新:后来发现是因为我没有在系统里启用 dkms 服务,启用之后就会在系统更新内核之后自动重新编译安装 acpi_call 了,跟安装源里面是否更新了 dkms-acpi_call 软件包没有关系。

$ sudo zypper addrepo --refresh --priority 100 --name thinkpad http://download.opensuse.org/repositories/home:/revealed/openSUSE_Tumbleweed/ thinkpad
$ sudo zypper install dkms-acpi_call
$ sudo systemctl enable dkms.service

按照 TLP 上面的介绍,tp_smapi 的加载需要系统配置 UEFI 禁用 Secure Boot。但是我的系统明明是这样的还是无法启用 tp_smapi。具体原因未知,反正通过 acpi_call 也可以设置充电阈值,就没有再深究。(似乎是因为我确实启用了 Secure boot。)

tp-smapi   = inactive (kernel module 'tp_smapi' load error)
tpacpi-bat = active

但是既然 acpi_call 就够了,我也就没有再深究 tp_smapi 的问题。

设置方法

**注意:具体什么样的充电跟用户的使用习惯和需求有关。

比如说,有的人虽然也是基本上都有外接电源可用,但是一旦偶尔没有外接电源却还需要内置电池尽它们的最大可能提供更长的使用时间,那就需要让 2 块电池都经常性的处于满电状态;有的人虽然经常用内置电池,但是每次都是最多用几十分钟最多两个小时,那么主电池基本上就是闲置而副电池则尽量保持满电的 80% 电量即可。而水景一页的博主,我就是后面这种使用状态。

所以我的设置是让主电池(电池 1)在电量低于 40% 才开始充电(开始充电阈值),而在充到满电量的 50% 时停止充电(停止充电阈值);副电池(电池 2)就分别是 40% 和 80%。

另外,根据我的经验,在 Linux 上设置好了充电阈值后,如果启动了预装的 Windows 10,则充电阈值会被改写成出厂设置(96%,100%)。为了避免这种情况,需要在 Windows 10 里面也通过「Lenovo Settings」软件设置对应的充电阈值。

直接修改 TLP 配置文件然后使之生效即可应用设置的电池充电开始与停止阈值。修改配置文件 /etc/default/tlp,修改其中的电池设置部分中阈值后面的数字即可。修改后的这一部分见下面(我的阈值设置上面已经说过了,对于修改即可),

$ sudo vim /etc/default/tlp
 ...
 # Battery charge thresholds (ThinkPad only, tp-smapi or acpi-call kernel module
 # required). Charging starts when the remaining capacity falls below the
 # START_CHARGE_THRESH value and stops when exceeding the STOP_CHARGE_THRESH value.
 # Main / Internal battery (values in %)
 START_CHARGE_THRESH_BAT0=40
 STOP_CHARGE_THRESH_BAT0=50
 # Ultrabay / Slice / Replaceable battery (values in %)
 START_CHARGE_THRESH_BAT1=40
 STOP_CHARGE_THRESH_BAT1=80
 ...

修改了 TLP 的配置之后需要重启、改变供电来源或者直接运行一下指令,

$ sudo tlp start

即可。然后可以查看一下电池状态,

$ sudo tlp-stat -b
--- TLP 0.9 --------------------------------------------

+++ ThinkPad Extended Battery Functions
tp-smapi   = inactive (kernel module 'tp_smapi' load error)
tpacpi-bat = active

+++ ThinkPad Battery Status: BAT0 (Main / Internal)
/sys/class/power_supply/BAT0/manufacturer                   = SMP
/sys/class/power_supply/BAT0/model_name                     = 00HW023
/sys/class/power_supply/BAT0/cycle_count                    =      1
/sys/class/power_supply/BAT0/energy_full_design             =  23540 [mWh]
/sys/class/power_supply/BAT0/energy_full                    =  24230 [mWh]
/sys/class/power_supply/BAT0/energy_now                     =  22810 [mWh]
/sys/class/power_supply/BAT0/power_now                      =      0 [mW]
/sys/class/power_supply/BAT0/status                         = Unknown (threshold effective)

tpacpi-bat.BAT0.startThreshold                              =     40 [%]
tpacpi-bat.BAT0.stopThreshold                               =     50 [%]
tpacpi-bat.BAT0.forceDischarge                              =      0

Charge                                                      =   94.1 [%]
Capacity                                                    =  102.9 [%]

+++ ThinkPad Battery Status: BAT1 (Ultrabay / Slice / Replaceable)
/sys/class/power_supply/BAT1/manufacturer                   = SANYO
/sys/class/power_supply/BAT1/model_name                     = 01AV405
/sys/class/power_supply/BAT1/cycle_count                    =      5
/sys/class/power_supply/BAT1/energy_full_design             =  26330 [mWh]
/sys/class/power_supply/BAT1/energy_full                    =  27630 [mWh]
/sys/class/power_supply/BAT1/energy_now                     =  23010 [mWh]
/sys/class/power_supply/BAT1/power_now                      =      0 [mW]
/sys/class/power_supply/BAT1/status                         = Unknown (threshold effective)

tpacpi-bat.BAT1.startThreshold                              =     40 [%]
tpacpi-bat.BAT1.stopThreshold                               =     80 [%]
tpacpi-bat.BAT1.forceDischarge                              =      0

Charge                                                      =   83.3 [%]
Capacity                                                    =  104.9 [%]

因为kernel module 'tp_smapi' load error 的问题无法解决,又没看到什么影响,就给删除了。

需要注意的是,这样设置充放电阈值之后,Linux 任务栏的电池状态指示器可能会一直显示「正在充电 Charging」,但实际上并不一定在充电。这是因为这个显示电池电量的微件无法按照充电阈值的设定来处理。无碍。

PowerTop

严格来讲,PowerTop 并不是个电源管理软件,而是用于分析优化系统的节电设置的。

openSUSE Tumbleweed 官方安装源里有这个软件,直接安装即可,

$ sudo zypper install powertop

根据网上的介绍,可以直接通过命令行运行 `sudo powertop` 指令来查看系统的节电设置的状态。当然,需要运行在电池供电的情况下才能看到系统耗电情况及可以采取的优化措施。

$ sudo powertop
The battery reports a discharge rate of 7.11 W
The estimated remaining time is 6 hours, 22 minutes
...

使用 Tab 键即可在各个标签页之间切换。感觉我这个使用电池时候的 7 W 的电量消耗还可以优化。但是看 PowerTop 的优化提示,只有 USB 设备的休眠有问题。不过反正可以用六个小时了,也足够了。再说我还开着键盘背光呢。

PowerTop 还有自动优化功能。如果要它自动应用优化设置的话,需要自己创建一个系统服务来让它开机自动运行。

创建系统服务,

$ sudo touch /usr/lib/systemd/system/powertop.service
$ sudo vim /usr/lib/systemd/system/powertop.service

贴入如下代码即可,

[Unit]
Description=Powertop tunings

[Service]
Type=oneshot
ExecStart=/usr/bin/powertop --auto-tune

[Install]
WantedBy=multi-user.target

然后启用该服务并立即运行它,

$ sudo systemctl enable powertop # 启用服务
$ sudo systemctl start powertop # 运行服务

但是水景一页捣鼓了一阵子之后对这个东西感觉有些懵,于是就没有启用这个服务。不过 powertop 倒是留着了,需要的时候可以用来查看系统的节电情况。

ArchLinux Wiki 和 ThinkWiki 上的两篇关于使用电池状态下的节能的文章,

我都仔细看过了,也尝试着对照检查了自己的系统设置。结果是很多配置在 openSUSE Tumbleweed 里的 KDE 桌面环境下都已经是很优化的配置了,并不需要用户调整。

实际上节电什么的并不是我的目的。最主要的任务是设置电池的充电开始和结束阈值。现在目的已经达到了。

另外记录一个小插曲。有一天,我笔记本开机的状态下插下外接电源的接头到插线板上,结果插头那里噗的一阵弧光。这个应该是比较正常的,虽然需要尽量避免。当然最好能用那种带独立开关的配电盘,这样就可以在插好线之后再打开开关。但是我刚好又注意到笔记本电源线插口那里的那个绿色交流电源指示灯不亮了。我还以为是因为这个瞬时电流过大给烧坏了。但是电池电量低的那个桔黄色的灯还是正常。结果过几天之后,偶尔的情况下它又好了。于是才发现是因为进入了 Windows 10 系统一次,电池阈值被重置,也许跟这个有关。后来又觉得也许跟使用 tpacpi-bat 设置了充电阈值有关。绿灯坏的那时候应该是才使用 tpacpi-bat(我之前没用 TLP)来设置电池充放电阈值之后。随后的几天一有空就钻研这个。后来因为实验 TLP 而故意充放电电池,结果发现那个绿灯时好时坏。猜测是因为新的电池固件还有些参数大家还没有弄出来,无法正确设置(只能设置阈值,而不能设置辅助的参数)。具体的背后的问题就不准备再深究了,平常事情太多了,心累。©

本文发表于水景一页。永久链接:<https://cnzhx.net/blog/power-management-and-battery-threshold-in-linux-on-t470s/>。转载请保留此信息及相应链接。

3 条关于 “Linux 系统中配置 T470s 的电源管理及充放电阈值” 的评论

  1. 楼主,
    我以前留过言,并且希望的到回复,但是过了好久都没有收到。今天看到我的留言被回复了,希望楼主增加一个功能。在回复后,发送一条信息到填写的邮箱。
    谢谢

  2. 引用通告: 在 T470s 上折腾 Linux 滚动发行版 openSUSE Tumbleweed 记录汇总 | 水景一页

雁过留声,人过留名

电子邮件地址不会被公开。 必填项已用*标注

特别提示:与当前文章主题无关的讨论相关但需要较多讨论求助信息请发布到水景一页讨论区的相应版块,谢谢您的理解与合作!请参考本站互助指南
您可以在评论中使用如下的 HTML 标记来辅助表达: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>