写点什么

掌控 Apple Silicon MacBook 电池健康的神器

作者:qife122
  • 2025-11-21
    福建
  • 本文字数:3028 字

    阅读完需:约 10 分钟

batt - Apple Silicon MacBook 电池充电控制器

batt 是一款专为 Apple Silicon MacBook 设计的电池充电控制工具,能够有效延长电池寿命。通过智能限制充电阈值,防止电池长期处于满电状态,从而减缓电池老化过程。

功能特性

  • 智能充电限制:设置上下充电阈值(10%-100%),像 ThinkPad 一样保护电池健康

  • MagSafe LED 控制:根据充电状态自动控制 MagSafe LED 指示灯颜色

  • 睡眠保护机制:防止系统睡眠时电池过充,支持空闲睡眠和系统睡眠防护

  • 电源适配器控制:可手动启用或禁用电源适配器供电

  • 实时状态监控:提供详细的电池状态和电源信息监控

  • 图形化界面:提供直观的 GUI 界面,方便用户操作

安装指南

系统要求

  • macOS 11.0 或更高版本

  • Apple Silicon MacBook

  • 需要 root 权限进行系统级安装

快速安装

# 使用自动安装脚本curl -fsSL https://github.com/charlie0129/batt/raw/main/install.sh | bash
复制代码

手动安装

  1. GitHub Releases 下载最新版本

  2. 解压到系统目录:


sudo tar -xzf batt-*.tar.gz -C /usr/local/bin
复制代码


  1. 安装守护进程:


sudo batt install --allow-non-root-access
复制代码

Homebrew 安装

brew install battsudo brew services start batt
复制代码

使用说明

基础命令

设置充电上限为 80%:


batt limit 80
复制代码


禁用电池充电限制:


batt disable
复制代码


查看当前状态:


batt status
复制代码

高级功能

启用 MagSafe LED 控制:


batt magsafe-led enable
复制代码


防止空闲睡眠:


batt prevent-idle-sleep enable
复制代码


禁用充电前睡眠保护:


batt disable-charging-pre-sleep enable
复制代码

电源适配器控制

启用电源适配器:


batt adapter enable
复制代码


禁用电源适配器:


batt adapter disable
复制代码

核心代码

充电限制核心逻辑

// pkg/daemon/loop.gofunc maintainLoopInner(force bool) {    maintainLoopInnerLock.Lock()    defer maintainLoopInnerLock.Unlock()
charge, err := smcConn.GetBatteryCharge() if err != nil { logrus.Errorf("failed to get battery charge: %v", err) return }
pluggedIn, err := smcConn.IsPluggedIn() if err != nil { logrus.Errorf("failed to check if plugged in: %v", err) return }
// 根据充电状态和配置决定是否充电 if pluggedIn && conf.UpperLimit() < 100 && charge >= conf.UpperLimit() { // 达到上限,停止充电 if err := smcConn.DisableCharging(); err != nil { logrus.Errorf("failed to disable charging: %v", err) } maintainedChargingInProgress = true } else if pluggedIn && conf.UpperLimit() < 100 && charge <= conf.LowerLimit() { // 低于下限,开始充电 if err := smcConn.EnableCharging(); err != nil { logrus.Errorf("failed to enable charging: %v", err) } maintainedChargingInProgress = true } else { maintainedChargingInProgress = false }}
复制代码

SMC 通信模块

// pkg/smc/apple_smc.gotype AppleSMC struct {    conn gosmc.Connection    capabilities map[string]bool}
func (c *AppleSMC) EnableCharging() error { logrus.Tracef("EnableCharging called") // 预 Tahoe 固件版本 if c.capabilities[ChargingKey1] && c.capabilities[ChargingKey2] { err := c.Write(ChargingKey1, []byte{0x0}) if err != nil { return err } err = c.Write(ChargingKey2, []byte{0x0}) return err } // Tahoe 固件版本 return c.Write(ChargingKey3, []byte{0x00, 0x00, 0x00, 0x00})}
func (c *AppleSMC) DisableCharging() error { logrus.Tracef("DisableCharging called") // 预 Tahoe 固件版本 if c.capabilities[ChargingKey1] && c.capabilities[ChargingKey2] { err := c.Write(ChargingKey1, []byte{0x2}) if err != nil { return err } err = c.Write(ChargingKey2, []byte{0x2}) return err } // Tahoe 固件版本 return c.Write(ChargingKey3, []byte{0x01, 0x00, 0x00, 0x00})}
复制代码

客户端 API 通信

// pkg/client/client.gotype Client struct {    socketPath string    httpClient *http.Client}
func (c *Client) SetLimit(l int) (string, error) { return c.Put("/limit", strconv.Itoa(l))}
func (c *Client) GetCharging() (bool, error) { ret, err := c.Get("/charging") if err != nil { return false, pkgerrors.Wrapf(err, "failed to get charging status") } return parseBoolResponse(ret)}
func (c *Client) Send(method string, path string, data string) (string, error) { logrus.WithFields(logrus.Fields{ "method": method, "path": path, "data": data, "unix": c.socketPath, }).Debug("sending request") var resp *http.Response var err error url := "http://unix" + path // 通过 Unix socket 与守护进程通信 switch method { case "GET": resp, err = c.httpClient.Get(url) case "PUT": req, err2 := http.NewRequest("PUT", url, strings.NewReader(data)) if err2 != nil { return "", fmt.Errorf("failed to create request: %w", err2) } resp, err = c.httpClient.Do(req) default: return "", fmt.Errorf("unknown method: %s", method) } if err != nil { return "", fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() b, err := io.ReadAll(resp.Body) return string(b), err}
复制代码

系统睡眠监听

// pkg/daemon/sleep_darwin.go//export canSystemSleepCallbackfunc canSystemSleepCallback() {    logrus.Debugln("received kIOMessageCanSystemSleep notification")        if !conf.PreventIdleSleep() {        logrus.Debugln("PreventIdleSleep is disabled, allow idle sleep")        C.AllowPowerChange()        return    }        // 系统刚唤醒时拒绝空闲睡眠    if timeAfterWokenUp := time.Since(lastWakeTime);        timeAfterWokenUp < time.Duration(preSleepLoopDelaySeconds)*time.Second {        logrus.Debugf("system has just waked up, deny idle sleep")        C.CancelPowerChange()        return    }        // 立即运行循环更新充电状态    maintainLoopInner(false)        if maintainedChargingInProgress {        logrus.Debugln("maintained charging in progress, deny idle sleep")        C.CancelPowerChange()    } else {        C.AllowPowerChange()    }}
复制代码


batt 通过深度集成 macOS 系统服务,提供了完整的电池健康管理解决方案,让您的 Apple Silicon MacBook 电池寿命得到有效延长。更多精彩内容 请关注我的个人公众号 公众号(办公 AI 智能小助手)对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)


公众号二维码


办公AI智能小助手


公众号二维码


网络安全技术点滴分享


用户头像

qife122

关注

还未添加个人签名 2021-05-19 加入

还未添加个人简介

评论

发布
暂无评论
掌控Apple Silicon MacBook电池健康的神器_macos_qife122_InfoQ写作社区