macli battery 字段详解与诊断手册

macli battery 读取 macOS IOKit 的 AppleSmartBattery 服务,把电池、充电器、电源遥测等数据整理成可直接用 jq 处理的 JSON。它是 ioreg -n AppleSmartBattery -r严格超集:除了 IO 元数据,几乎所有标量、数组、嵌套对象都被保留,并且增加了单位换算、派生指标和二进制 blob 解码。

当前版本输出的是 完整/详细模式;以后会增加 --detail 开关,默认输出精简子集,但字段名和结构保持不变。


30 秒上手

# 核心状态
macli battery | jq '{status, stateOfCharge, healthPercent, cycleCount, temperature}'

# 功率流(电池输出功率、系统功耗、输入功率、瞬时功率)
macli battery | jq '{instantPowerWatts, batteryPower, systemPower, inputPower}'

# 电芯平衡(delta > 0.05 V 要留意)
macli battery | jq '{cellVoltages, cellVoltageDelta}'

# 解码后的每电芯内阻表
macli battery | jq '.raTableRaw'

# 导出 TSV 给 Excel / Numbers / R
macli battery --tsv > battery.tsv

为什么用 macli battery 而不是 ioreg

ioreg -n AppleSmartBattery -r -l 已经把几乎所有原始数据展示出来了,但它有几点不便:

能力 ioreg macli battery
输出格式 XML/Plist 风格文本 直接是 JSON
单位换算 原始数值,需手动除 100/1000 已换算好(温度 °C、电压 V、功率 W 等)
派生指标 healthPercentdesignWhcurrentWhcellVoltageDeltainstantPowerWatts
二进制 blob RaTableRawBatteryState 等是原始 <...> 数据 raTableRawbatteryStateBytesmfgDataAscii 等已解码
键名稳定性 不同 macOS 版本可能变化 macli 尽量保持稳定
脚本友好 需要 grep/awk/plist 解析 jq 直接取值
TSV 输出 macli battery --tsv
与 monitor 集成 macli monitor 可取电池功率流

所以:ioreg 能看原始数据,macli battery 帮你把数据变成可编程、可对比、可监控的格式。两者不是替代关系,而是分层:底层探查用 ioreg,脚本/监控/告警用 macli

system_profiler SPPowerDataType 的对比

system_profiler 只给出人类可读的摘要(循环次数、状态、最大容量百分比)。macli battery 则提供原始遥测:每个电芯电压、充电器状态、PD 适配器档位、电量计内部标志、生命周期数据等。


serialNumberbatterySerial 为什么会不同?

来源

JSON key IOKit 路径 含义
serialNumber AppleSmartBattery.Serial 系统层(AppleSmartBattery kext)报告的电池序列号
batterySerial AppleSmartBattery.BatteryData.Serial 电池管理芯片(gas gauge,如 BQ40Z651/BQ20Z451)内部序列号

为什么会不一样?

这两个序列号来自不同层级

  1. 根级 Serial 是 macOS 的 AppleSmartBattery 驱动从 SMC/PMU 侧读取或维护的标识,常用于 system_profiler SPPowerDataType 和系统设置。
  2. BatteryData.Serial 来自电池包内部的电量计芯片(gas gauge)数据闪存,是电池制造商写入的。

在大多数原装机器上,Apple 会把同一个序列号同步到两个位置,所以它们看起来一样。但在以下场景可能不同:

论据

怎么用

# 判断两者是否一致
macli battery | jq '{serialNumber, batterySerial, same: (.serialNumber == .batterySerial)}'

# 怀疑假电池时,优先检查 BatteryData 序列号格式
macli battery | jq '.batterySerial'

适配器电压:adapter.voltageadapter.adapterVoltage

IOKit 在不同机型/固件里用了两个键表示适配器电压:

JSON key IOKit key 说明
adapter.voltage AdapterDetails.Voltage 旧版键名,某些 Intel 机型仍使用
adapter.adapterVoltage AdapterDetails.AdapterVoltage Apple Silicon PD 适配器常用键名

macli 两个都读,所以你的输出里至少有一个存在。如果两个都有,它们应该是同一个值。

macli battery | jq '.adapter | {voltage, adapterVoltage}'

诊断脚本手册

下面这些脚本可以直接复制使用。它们展示了 macli battery 如何超越“查看信息”,变成真正的诊断工具。

1. 健康度与寿命

# 健康度低于 80% 时报警
macli battery | jq -e '.healthPercent < 80' && echo "考虑更换电池"

# 循环次数 + 设计寿命,算剩余寿命比例
macli battery | jq '{cycleCount, designCycleCount, lifeUsedPercent: (.cycleCount / .designCycleCount * 100)}'

# 温度换算成华氏度
macli battery | jq '{celsius: .temperature, fahrenheit: (.temperature * 9 / 5 + 32)}'

2. 功率与充电

# 当前系统/电池/输入功率全景
macli battery | jq '{instantPowerWatts, batteryPower, systemPower, inputPower, chargerPower: .charger.powerWatts}'

# 判断是否在“慢充”或“不充电”
macli battery | jq '{externalConnected, isCharging, fullyCharged, notChargingReason: .charger.notChargingReason, slowChargingReason: .charger.slowChargingReason}'

# 估算从当前电量到满电需要多少 Wh
macli battery | jq '{remainingWh: (.estimatedFullChargeWh - .currentWh), estimatedFullChargeWh, currentWh}'

3. 电芯平衡与内阻

# 电芯电压差
macli battery | jq '{cellVoltages, cellVoltageDelta}'

# 电压差大于 0.05 V 时高亮
macli battery | jq -e '.cellVoltageDelta > 0.05' && echo "电芯不平衡,建议校准或检查"

# 查看加权内阻(mΩ)
macli battery | jq '{weightedRa, chemicalWeightedRa, resScale, rss, iss}'

# 把 raTableRaw 画成每个电芯的电阻表
macli battery | jq '.raTableRaw | to_entries[] | {cell: .key, table: .value}'

4. 适配器与 USB-C PD

# 当前适配器能力
macli battery | jq '.adapter | {watts, voltage, current, description, isWireless}'

# PDO 档位(适配器支持的电压/电流组合)
macli battery | jq '.adapter.usbHvcMenu'

# 每个 USB-C 口接了什么设备
macli battery | jq '.fedDetails | map({vendorID, productID, externalConnected, remainingCapacity})'

5. 时间序列与监控

# 每隔 5 秒记录一条 CSV
while true; do
  macli battery | jq -r '[now, .stateOfCharge, .temperature, .instantPowerWatts, .cellVoltageDelta] | @csv'
  sleep 5
done >> battery.csv

# 用 macli monitor 流式监控电池功率(每秒一个样本,共 60 个)
macli monitor --metric battery_power --interval 1 --count 60

# 计算过去 N 次采样的平均功耗
macli monitor --metric battery_power --interval 1 --count 60 | awk -F'\t' 'NR>1 {sum+=$2; n++} END {print "avg:", sum/n, "W"}'

6. 可疑电池 / 身份核对

# 两个序列号是否一致
macli battery | jq '{serialNumber, batterySerial, same: (.serialNumber == .batterySerial)}'

# 制造商数据里的 ASCII 片段
macli battery | jq '{mfgDataAscii, manufacturerDataAscii, deviceName, manufactureDate}'

# 一次性输出所有可用于判断电池是否原生的字段
macli battery | jq '{serialNumber, batterySerial, deviceName, manufactureDate, cycleCount, designCycleCount, mfgDataAscii}'

二进制字段解析说明

ioreg 里有些字段是 NSData blob,macli battery 对它们做了不同处理:

字段 原始 IOKit 键 macli 处理方式 说明
raTableRaw BatteryData.RaTableRaw 解析为每电芯 uint16 数组 电量计内阻表,字节序为 big-endian
batteryState / batteryStateBytes BatteryData.BatteryState hex 字符串 + uint8 数组 gas gauge 扩展状态字节
mfgData / mfgDataAscii BatteryData.MfgData hex 字符串 + 可打印 ASCII 制造商原始数据,常含产线代码
manufacturerData / manufacturerDataAscii AppleSmartBattery.ManufacturerData hex 字符串 + 可打印 ASCII 顶层制造商数据
charger.status / charger.statusBytes ChargerData.ChargerStatus hex 字符串 + uint8 数组 充电器 IC 状态
iMaxAndSocSmoothTable BatteryData.iMaxAndSocSmoothTable hex 字符串 电流-电量平滑表,通常全 0
LifetimeData.Raw / TimeAtHighSoc 跳过 Apple 电量计私有生命周期日志,无公开格式
PortControllerEvtBuffer 跳过 USB-PD 控制器原始事件 buffer,无公开格式

关于 BatteryStateChargerStatus 的 bit 含义

SBS(Smart Battery System)规范定义了标准寄存器:

但 Apple 在 BatteryData.BatteryState 里放的是扩展状态 blob(常见 16~17 字节),ChargerData.ChargerStatus 新版本也是 NSData。前两个字节可能对应 SBS 标志,其余字节布局未公开。macli battery 只负责把它们以 hex/bytes 形式暴露出来,不推测未验证的 bit 语义

关于 RaTableRaw

每个电芯的内阻表是 32 字节,按 big-endian uint16 解析成 16 个整数。这些值与 ra00ra14 一起描述了电池在不同 SOC/温度点的内阻特征。跨机型、跨化学 ID 的具体映射由电量计算法决定,macli 只提供原始整数表,不发明物理含义。


字段速查表

状态

字段 类型 IOKit 来源 说明
ok bool 内部 是否成功读到电池
present bool 内部 电池是否在位
source string 固定 恒为 "IOKit"
status string 派生 "AC" / "Battery"
externalConnected bool ExternalConnected AC 是否插入
appleRawExternalConnected bool AppleRawExternalConnected 原始 AC 状态
externalChargeCapable bool ExternalChargeCapable 是否支持外接充电
isCharging bool IsCharging 是否正在充电
fullyCharged bool FullyCharged 是否已充满
builtIn bool built-in 是否为内置电池
batteryInstalled bool BatteryInstalled 电池是否安装
atCriticalLevel bool AtCriticalLevel 是否处于临界低电量
permanentFailureStatus int PermanentFailureStatus 永久故障码,非 0 需警惕
designCycleCount int DesignCycleCount9C 设计循环寿命,常见 1000
gasGaugeFirmwareVersion int GasGaugeFirmwareVersion 电量计固件版本

容量与能量

字段 单位 说明
designCapacity mAh 设计容量
maxCapacity mAh 当前最大可用容量
currentCapacity mAh 当前剩余容量
nominalChargeCapacity mAh gas gauge 标称容量
absoluteCapacity mAh 绝对容量
packReserve mAh 保留容量
healthPercent % maxCapacity / designCapacity * 100
designWh Wh 设计能量
currentWh Wh 当前剩余能量
estimatedFullChargeWh Wh 按当前电压与 maxCapacity 估算的满电能量

电压 / 电流

字段 单位 说明
voltage mV 电池包电压
amperage mA 平均电流
instantAmperage mA 瞬时电流
instantPowerWatts W voltage * instantAmperage / 1e6
appleRawBatteryVoltage mV 原始电池电压
bootVoltage mV 启动时电压

电量百分比

字段 说明
stateOfCharge 系统层电量百分比(CurrentCapacity
gaugeStateOfCharge gas gauge 电量百分比(BatteryData.StateOfCharge

两者通常接近,差 1% 属于正常。

温度

字段 单位 说明
temperature °C 物理传感器温度
virtualTemperature °C 电池模型估算温度

时间估算

字段 单位 说明
timeRemaining 分钟 系统估算剩余时间
avgTimeToEmpty 分钟 基于平均耗电的放空时间
avgTimeToFull 分钟 基于平均充电的充满时间

65535 表示无效/未知(常见于接 AC 未充电时)。

识别信息

字段 说明  
serialNumber 系统层序列号  
batterySerial gas gauge 序列号  
deviceName 电量计芯片型号,如 bq40z651  
manufactureDate 出厂日期码(芯片原生格式)  
manufacturerData hex 制造商原始数据
manufacturerDataAscii string ManufacturerData 中可打印的 ASCII 片段

电芯数据

字段 单位 说明
cellVoltages V 每个电芯电压
cellVoltageDelta V 最高电芯电压 - 最低电芯电压
qmax mAh 每个电芯最大化学容量
cellWom - cell wake-on-motion 标志
presentDOD - 当前放电深度
dod0 - 初始 DOD 校准值
weightedRa 加权内阻
cellCurrentAccumulator - 电芯电流累积器
raTableRaw [uint16] 每电芯内阻表(已从 RaTableRaw 解码)
iMaxAndSocSmoothTable hex 电流-电量平滑表(通常全 0)

电池数据诊断

字段 说明  
batteryDataFlags BatteryData 状态标志  
gaugeFlagRaw gas gauge 原始标志  
miscStatus miscellaneous 状态  
itMiscStatus IT misc 状态  
chemID 化学 ID  
algoChemID 算法化学 ID  
fccComp1 / fccComp2 满充补偿值  
resScale / rss / iss 内阻/缩放相关  
dataFlashWriteCount 数据闪存写入次数  
batteryHealthMetric 电池健康度指标  
chemicalWeightedRa 化学加权内阻  
pmuConfigured PMU 配置值  
soc1Voltage SoC=1% 时电压  
qmaxDisqualificationReason Qmax 失效原因码  
simRate / idealCRate 仿真/理想 C-rate  
packCurrentAccumulator 包电流累积器  
packCurrentAccumulatorCount 累积计数  
filteredCurrent 滤波后电流  
dateOfFirstUse 首次使用日期码  
gaugeCycleCount gas gauge 计循环数  
batteryState hex gas gauge 状态字节
batteryStateBytes [uint8] BatteryState 的 uint8 数组
mfgData hex 制造商数据
mfgDataAscii string MfgData 中可打印的 ASCII 片段

适配器

字段 说明
adapter.watts 额定功率(W)
adapter.current 额定电流(mA)
adapter.voltage 额定电压(mV,旧键名)
adapter.adapterVoltage 额定电压(mV,新键名)
adapter.description 描述,如 "pd charger"
adapter.isWireless 是否无线充电器
adapter.adapterID 适配器 ID
adapter.familyCode 家族码
adapter.adapterPowerTier 功率等级
adapter.usbHvcHvcIndex USB HVC 索引
adapter.pmuConfiguration PMU 配置
adapter.usbHvcMenu PDO 档位列表
inputPower adapter.watts 的平铺副本
rawAdapterDetails 每个 USB-C 口的原始适配器信息

充电器

字段 说明  
charger.voltage 当前充电电压(mV)  
charger.current 当前充电电流限制(mA)  
charger.powerWatts W charger.voltage * charger.current / 1e6
charger.status hex 充电器状态字节
charger.statusBytes [uint8] ChargerStatus 的 uint8 数组
charger.vacVoltageLimit VAC 电压限制  
charger.notChargingReason 不充电原因码  
charger.slowChargingReason 慢充原因码  
charger.resetCounter 充电器复位计数  
charger.chargerID 充电器 ID  
charger.timeChargingThermallyLimited 热限制充电时长  
charger.inhibitReason 抑制原因码  

系统电源遥测

字段 单位 说明
systemPower W 系统总功耗
batteryPower W 电池输出功率
systemVoltageIn mV 系统输入电压
systemCurrentIn mA 系统输入电流
systemLoad mW 系统负载
wallEnergyEstimate - 墙面能量估算
systemEnergyConsumed - 系统消耗能量
accumulatedSystemLoad - 累积系统负载
accumulatedSystemEnergyConsumed - 累积系统能耗
accumulatedWallEnergyEstimate - 累积墙面能量估算
accumulatedBatteryPower - 累积电池功率
accumulatedSystemPowerIn - 累积系统输入功率
accumulatedBatteryDischarge - 累积电池放电量
adapterEfficiencyLoss - 适配器效率损耗
accumulatedAdapterEfficiencyLoss - 累积适配器效率损耗
powerTelemetryErrorCount - 遥测错误计数
systemPowerInAccumulatorCount - 系统输入功率累积计数
systemLoadAccumulatorCount - 系统负载累积计数
adapterEfficiencyLossAccumulatorCount - 效率损耗累积计数
batteryPowerAccumulatorCount - 电池功率累积计数
batteryDischargeAccumulatorCount - 电池放电累积计数

USB-C PD 与端口诊断

字段 说明
fedDetails 每个 USB-C 口连接的 PD 设备信息
portControllerInfo 每个 USB-C 口控制器诊断

生命周期数据

字段 说明
lifetimeData.updateTime 数据更新时间戳
lifetimeData.totalOperatingTime 总运行时间
lifetimeData.temperatureSamples 温度采样次数
lifetimeData.averageTemperature 平均温度(0.1°C)
lifetimeData.minimumTemperature 最低温度(0.1°C)
lifetimeData.maximumTemperature 最高温度(0.1°C)
lifetimeData.maximumDischargeCurrent 最大放电电流
lifetimeData.maximumChargeCurrent 最大充电电流
lifetimeData.minimumPackVoltage 最小包电压
lifetimeData.maximumPackVoltage 最大包电压
lifetimeData.cycleCountLastQmax 上次 Qmax 校准时的循环数
lifetimeData.resistanceUpdatedDisabledCount 内阻更新禁用计数
lifetimeData.rdisCnt RDIS 计数

使用示例

# 只看最关心的状态
macli battery | jq '{status, stateOfCharge, currentCapacity, maxCapacity, healthPercent, cycleCount, temperature}'

# 判断健康度是否低于 80%
macli battery | jq -e '.healthPercent < 80' && echo "consider replacement"

# 计算真实充电功率(如果正在充电)
macli battery | jq '{watts: (.charger.voltage * .charger.current / 1000000)}'

# 检查两个序列号是否一致
macli battery | jq '{serialNumber, batterySerial, same: (.serialNumber == .batterySerial)}'

# 查看每个 USB-C 口接了什么
macli battery | jq '.fedDetails'

# 查看 PDO 供电档位
macli battery | jq '.adapter.usbHvcMenu'

# 导出为 TSV 在表格里打开
macli battery --tsv > battery.tsv

补充字段(进一步覆盖 ioreg)

以下字段是为了让 macli battery 成为 ioreg 的超集而补充的:

字段 来源 说明
batteryCellDisconnectCount BatteryCellDisconnectCount 电芯断开次数
skipperNEIgnoreAtCritical SkipperNEIgnoreAtCritical 临界电量忽略标志
maxCapacityPercent MaxCapacity 系统层最大容量百分比(常为 100)
chargerConfiguration ChargerConfiguration 充电器配置值
carrierMode CarrierMode 载体模式参数(低/高电压阈值、状态)
deadBatteryBootData DeadBatteryBootData 没电时启动记录的 payload
ocvData OCVData 开路电压数据(通常为空)
lpemData LPEMData LPEM 数据(通常为空)
batteryRsenseOpenCount BatteryData.BatteryRsenseOpenCount 电流采样电阻开路计数
cellCurrentAccumulatorCount BatteryData.CellCurrentAccumulatorCount 电芯电流累积计数
currentSenseMonitorStatus BatteryData.CurrentSenseMonitorStatus 电流采样监控状态
dod0AtQualifiedQmax BatteryData.Dod0AtQualifiedQmax Qmax 合格时的 DOD0
ra00 ~ ra14 BatteryData.Ra00 ~ Ra14 各温度点内阻表(mΩ)
raTableRaw BatteryData.RaTableRaw 每电芯内阻表原始字节解码为 uint16 数组
iMaxAndSocSmoothTable BatteryData.iMaxAndSocSmoothTable 电流-电量平滑表(hex)
batteryStateBytes BatteryData.BatteryState gas gauge 状态字节数组
mfgDataAscii BatteryData.MfgData 制造商数据中的可打印 ASCII
manufacturerDataAscii AppleSmartBattery.ManufacturerData 顶层制造商数据 ASCII
cellVoltageDelta BatteryData.CellVoltage 电芯最大最小电压差
estimatedFullChargeWh Voltage × AppleRawMaxCapacity 估算满电能量
instantPowerWatts Voltage × InstantAmperage 瞬时功率
charger.powerWatts ChargerData.ChargingVoltage × ChargingCurrent 当前充电功率
charger.statusBytes ChargerData.ChargerStatus 充电器状态字节数组
batteryDataSystemPower BatteryData.SystemPower gas gauge 原始系统功率
batteryDataAdapterPower BatteryData.AdapterPower gas gauge 原始适配器功率

故意不重复输出的字段

以下字段在 ioreg 里同时出现在根级和 BatteryData 里,macli 已经在根级输出,所以不再在 BatteryData 下重复:

ioreg 键 macli 已输出为
BatteryData.DesignCapacity designCapacity
BatteryData.MaxCapacity maxCapacityPercent
BatteryData.Voltage voltage
BatteryData.CycleCount gaugeCycleCount(同时根级有 cycleCount

跳过的字段

以下字段是 IO 元数据或大块二进制 blob,macli 故意不输出:

其余二进制字段(BatteryStateChargerStatusMfgDataManufacturerDataRaTableRawiMaxAndSocSmoothTable)已以 hex 或结构化形式输出。


控制充电:macli battery 只读,控制请用这些工具

macli battery观测/诊断工具,它只读取 IOKit 数据,不修改电池或充电行为。如果你需要限制充电、暂停充电或做自动校准,请使用以下方案。

1. 官方原生方式(最稳)

macOS 官方提供图形界面的充电控制,注意区分“学习型延迟充电”和“硬上限”:

功能 路径 机制 最终行为
Optimized Battery Charging Battery Health → Optimized Battery Charging 系统学习你的作息 先停到 80%,快用之前再充满到 100%
80% Limit Battery Health → 80% Limit 硬上限 永远只充到 80%
Charging Limit(80%–100% 可调) System Settings → Battery → 充电 → 充电上限 硬上限 永远只充到你选的值(如 80%、90%)

重要:Optimized Battery Charging 最终还是会充满到 100%,只是延迟最后 20% 的充电时间。如果你希望长期插电时电池停在 80% 或更低,必须开 80% Limit / Charging Limit,而不是 Optimized Battery Charging。

Charging Limit(80%–100% 可调)是 macOS 26.4 及更高版本新增的原生功能(据 charlie0129/batt 项目公告),无需第三方工具。

Optimized Battery Charging 的学习机制与决策

它是怎么学习的?

  1. macOS 会记录你每天的插电和拔电时间、使用时长。
  2. 当它发现你有规律(比如每晚 23:00 插电,早上 8:30 拔掉),它会:
    • 先快速充到 80%
    • 在 80% 处“暂停”;
    • 在你预计拔掉电源前不久(比如早上 7:30)再把最后 20% 充满。
  3. 这样既减少了电池在高电压下停留的时间,又能保证你拔电时电池是满的。

它的局限:

决策建议:

你的情况 推荐做法
每天固定时间插电、固定时间拔电 可以交给 Optimized Battery Charging 自动管理
作息不规律、经常出差、随时可能拔电 建议开 80% Limit / Charging Limit 硬上限
长期接显示器当台式机,几乎不带走 建议用 80% Limit 或第三方工具设到 60%–70%

临时需要充满时,可以点击电池菜单或系统通知里的 “Charge to Full Now”(立即充满),让系统跳过学习策略一次。

优点:Apple 官方支持,无需额外软件,系统升级不会失效。
缺点:依然没有 CLI;如果需要低于 80% 的限制,仍需第三方工具。

为什么有时要设到 60% 甚至更低?

80% 是大多数人的甜点,但不是所有人的最优解。

锂电池在高 SOC(高电压)下老化更快。80% 已经比 100% 好很多;如果你几乎 24 小时插电(比如 Mac 长期接显示器当台式机用),把上限进一步降到 60%–70% 可以减少化学应力、延缓容量衰减。代价是断电时的可用续航变少。

使用方式 推荐上限 理由
经常外出 / 移动办公 100% 或 80% 需要最大可用续航
偶尔移动, mostly 插电 80% 苹果官方甜点,续航与寿命平衡
长期当台式机用,几乎不带走 60%–70% 进一步延长电池寿命,但牺牲应急续航

macOS 原生只支持 80%–100% 的可调范围,所以想要 60%–70% 必须用 batt(Apple Silicon)或 AlDente 等第三方工具。

2. pmset — 原生命令,但只能看不能控

pmset 是 macOS 自带的电源管理工具,可以查看电池和电源状态:

pmset -g batt        # 当前电池状态
pmset -g ps         # 电源源状态
pmset -g rawlog     # 原始电池状态日志
pmset -g log        # 电源事件日志

但它没有充电限制功能。它管理的是睡眠、唤醒、显示器关闭、低电量模式等系统电源策略,不是电池充电阈值。

3. 第三方 CLI 控制工具(功能强,但非官方)

工具 适用平台 原理 特点
batt Apple Silicon 逆向 Apple 电源管理私有 API,通过守护进程控制充电 适合 macOS 26.4 之前,或需要低于 80% 的充电上限;功能丰富:上下限、定时校准、切电源、睡眠前停止充电
bclm Intel 通过 SMC 设置 BCLM 轻量,但 Apple Silicon 不支持
AlDente Apple Silicon / Intel 商业工具,使用 IOKit 私有 API 有 GUI,功能多,部分功能付费
# batt(Apple Silicon)设置 80% 上限
brew install batt
sudo batt limit 80

# bclm(Intel)设置 80% 上限
brew tap zackelia/formulae
brew install bclm
sudo bclm write 80

⚠️ 这些工具都依赖未公开的接口或私有 API。macOS 大版本更新后可能需要等待工具更新,且不在 Apple 官方支持范围内。

4. 和 macli battery 的配合

推荐组合:

  1. 日常充电策略用 System Settings(最稳)。
  2. macli battery 做遥测,验证策略是否生效:
    macli battery | jq '{stateOfCharge, isCharging, externalConnected, chargerPower: .charger.powerWatts}'
    
  3. 如果系统版本低于 macOS 26.4,或需要把上限设到 80% 以下,再考虑 batt / bclm,并接受它们是私有/非官方方案。

macli batterybatt / bclm 的关系

一句话:不是替代关系,是互补关系。

能力 macli battery batt bclm
核心目标 观测 / 诊断 / 遥测 控制充电(Apple Silicon) 控制充电(Intel)
能否设充电上限 ✅(macOS <26.4 或需 <80% 时用 batt limit 80 bclm write 80
能否暂停/恢复充电 batt adapter disable/enable
字段数量 ~150+ 仅状态所需(电量、是否充电、限制值等)
电芯级数据 cellVoltagescellVoltageDeltaqmaxraTableRaw
适配器/PD 诊断 adapter.usbHvcMenufedDetailsportControllerInfo
生命周期数据 lifetimeData.*
二进制 blob 解码 raTableRawbatteryStateBytesmfgDataAscii
是否需要守护进程
平台 Apple Silicon / Intel Apple Silicon Intel

为什么 batt 不能替代 macli battery

batt 的定位非常聚焦:把充电上限这件事做透。它的 batt status 只会输出控制充电所需的最小信息(当前电量、是否在充电、限制值等),不会给你:

反过来说,macli battery 永远也不会去控制充电——这是两个不同的问题域。

推荐搭配

# 1. 用 macli battery 做全面体检
macli battery | jq '{healthPercent, cycleCount, cellVoltageDelta, temperature}'

# 2. 如果需要,再用 batt 设置充电上限(Apple Silicon)
sudo batt limit 80

# 3. 用 macli battery 验证 batt 是否生效
macli battery | jq '{stateOfCharge, isCharging, externalConnected, chargerPower: .charger.powerWatts}'

电池保养、常见误区与决策参考

macli battery 给了一堆数字,但数字背后的决策更重要。下面是一些实用的电池知识,帮你判断该怎么用、该怎么设。

循环次数 vs 健康度

# 同时看循环次数和健康度
macli battery | jq '{cycleCount, designCycleCount, healthPercent, temperature}'

温度比循环次数更伤电池

锂电池最怕的是高温,其次是长期高电量

# 看看你的电池现在热不热
macli battery | jq '.temperature'

充电习惯:浅充浅放更好

长期存放

如果你要几周或几个月不用 Mac:

  1. 把电量充到 50% 左右
  2. 关机(不要只睡眠)。
  3. 放在阴凉、干燥的地方。

长期满电存放和长期亏电存放都会损伤电池。

需要手动校准电池吗?

现代 Mac 的电量计(gas gauge)会自动校准,大多数时候不需要你手动做完整充放电循环。

只在出现以下现象时考虑校准:

校准方法:用到接近自动关机,然后一次性充满到 100%,中间不要中断。

什么时候该考虑换电池

信号 说明
healthPercent < 80% 容量已明显衰减
cycleCount 接近或超过 designCycleCount 常见设计寿命是 1000 次
机身鼓包 立即停止使用并更换
意外关机 可能是电池内阻过大或保护板动作
系统显示 Service Recommended 官方建议维修
cellVoltageDelta 持续 > 0.05 V 电芯不平衡加剧

MagSafe 指示灯含义

颜色 含义
橙色 正在充电
绿色 已充满,或已达到充电上限

如果你开了 80% Limit,MagSafe 灯在 80% 时就会变绿,这是正常的。

常见误区


数据布局说明

macli battery 的输出布局遵循以下原则:

  1. 兼容优先:所有已有的顶层字段(designCapacitymaxCapacityhealthPercent 等)位置和名字不变。
  2. 一个 IOKit key 尽量对应一个 JSON key:新增字段不合并、不重新分组。
  3. 只有多实例或结构复杂的数据才嵌套
    • adapter 是对象,因为适配器信息包含多个子字段。
    • rawAdapterDetailsfedDetailsportControllerInfo 是数组,因为 macOS 按 USB-C 口提供多份数据。
    • lifetimeDatacarrierModedeadBatteryBootData 是对象,因为它们在 IOKit 里本身就是嵌套字典。
  4. 命名风格
    • 顶层历史字段和新增标量字段使用 camelCase。
    • 嵌套对象/数组内部保留 IOKit 原始 PascalCase 键名,避免 invent mapping。

优点jq '.healthPercent' 直接取值,不破坏旧脚本。
代价:顶层键很多(约 150 个),第一眼会比较 overwhelm。后续 --detail 开关会把默认输出精简到 15~20 个常用字段。


如何用 ioreg 查看 macli 未输出的字段

macli 为了兼容、体积和可读性,跳过了 IO 元数据和大块二进制 blob。如果你需要这些原始字段,直接用 ioreg

# 1. 查看完整原始快照
ioreg -n AppleSmartBattery -r -l

# 2. 保存为 plist 并用 plutil 查看(更结构化)
ioreg -n AppleSmartBattery -r -a -l > /tmp/battery.plist
plutil -p /tmp/battery.plist

# 3. 只看被 macli 跳过的二进制/大块字段
ioreg -n AppleSmartBattery -r -l | \
  grep -E -A2 'RaTableRaw|iMaxAndSocSmoothTable|"BatteryState"|"ChargerStatus"|TimeAtHighSoc|"Raw"|PortControllerEvtBuffer'

# 4. 查看 BatteryData 里被 macli 故意去重的字段
#    (它们已在根级输出为 designCapacity / maxCapacityPercent / voltage / gaugeCycleCount)
ioreg -n AppleSmartBattery -r -l | \
  grep -A40 '"BatteryData"' | \
  grep -E 'DesignCapacity|MaxCapacity|Voltage|CycleCount'

# 5. 查看所有 IO 元数据(IOObjectClass、IORegistryEntryID 等)
ioreg -n AppleSmartBattery -r -l | grep -E 'IO(Object|Registry|Report|Service)'

说明:


常见问题

Q:输出字段这么多,是不是 bug? A:不是。当前是完整模式,所有 IOKit 里有价值的数据都flatten/保留了出来。后续 --detail 开关会让默认输出变精简。

Q:nominalChargeCapacity 为什么比 designCapacity 大? A:它是 gas gauge 的标称校准值,会漂移,略大于设计值是正常的。

Q:timeRemaining 为什么是 65535? A:接电源且未充电时无法估算,Apple 用 65535 表示无效。

Q:batterySerialserialNumber 一样代表没问题吗? A:在原装机器上通常一样。如果你怀疑电池被更换或篡改,重点看 batterySerial 格式是否符合 Apple 正品规律,以及 manufactureDate 是否与机器年龄匹配。

Q:为什么 ioreg 就够了还要用 macli? A:ioreg 是原始探查工具;macli battery 把它变成结构化的 JSON、做了单位换算、加了派生指标,并且能被脚本和 macli monitor 复用。