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

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

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

功能特性

  • 智能充电限制:设置上下充电阈值(10%-100%),像 ThinkPad 一样保护电池健康
  • MagSafe LED 控制:根据充电状态自动控制 MagSafe LED 指示灯颜色
  • 睡眠保护机制:防止系统睡眠时电池过充,支持空闲睡眠和系统睡眠防护
  • 电源适配器控制:可手动启用或禁用电源适配器供电
  • 实时状态监控:提供详细的电池状态和电源信息监控
  • 图形化界面:提供直观的 GUI 界面,方便用户操作

安装指南

系统要求

  • macOS 11.0 或更高版本
  • Apple Silicon MacBook
  • 需要 root 权限进行系统级安装

快速安装

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

手动安装

  1. GitHub Releases 下载最新版本
  2. 解压到系统目录:
bash 复制代码
sudo tar -xzf batt-*.tar.gz -C /usr/local/bin
  1. 安装守护进程:
bash 复制代码
sudo batt install --allow-non-root-access

Homebrew 安装

bash 复制代码
brew install batt
sudo brew services start batt

使用说明

基础命令

设置充电上限为 80%:

bash 复制代码
batt limit 80

禁用电池充电限制:

bash 复制代码
batt disable

查看当前状态:

bash 复制代码
batt status

高级功能

启用 MagSafe LED 控制:

bash 复制代码
batt magsafe-led enable

防止空闲睡眠:

bash 复制代码
batt prevent-idle-sleep enable

禁用充电前睡眠保护:

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

电源适配器控制

启用电源适配器:

bash 复制代码
batt adapter enable

禁用电源适配器:

bash 复制代码
batt adapter disable

核心代码

充电限制核心逻辑

go 复制代码
// pkg/daemon/loop.go
func 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 通信模块

go 复制代码
// pkg/smc/apple_smc.go
type 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 通信

go 复制代码
// pkg/client/client.go
type 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
}

系统睡眠监听

go 复制代码
// pkg/daemon/sleep_darwin.go
//export canSystemSleepCallback
func 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 电池寿命得到有效延长。

相关推荐
明月醉窗台1 分钟前
Opencv 之 几个常见的对比度调整方法
人工智能·opencv·计算机视觉
AI生成未来3 分钟前
NeurIPS 2025 | 硬刚可灵1.5!阿里通义&清华等开源Wan-Move:指哪动哪的“神笔马良”
aigc·视频编辑·视频生成
MUTA️5 分钟前
边缘计算资源分配和任务调度优化
人工智能·边缘计算
璞华Purvar7 分钟前
璞华易知ChatBI精彩亮相百度智能云Agent大会,以自然语言驱动企业智能决策
大数据·人工智能
Jerryhut7 分钟前
sklearn函数总结十 —— 决策树
人工智能·决策树·sklearn
星川皆无恙7 分钟前
基于ARIMA 算法模型和NLP:社交媒体舆情分析在涉众型经济犯罪情报挖掘中的应用研究
人工智能·爬虫·python·算法·机器学习·自然语言处理·数据分析
何小少8 分钟前
论文写作全流程自动化:5个阶段的高效工具链构建
人工智能·论文写作·学术写作·ai工具·科研工具
摘星观月9 分钟前
【深度学习6】多层感知机2
人工智能·深度学习
啊巴矲10 分钟前
小白从零开始勇闯人工智能:机器学习初级篇(KNN算法)
人工智能
FL162386312913 分钟前
[C#][winform]基于yolov11的水下目标检测系统C#源码+onnx模型+评估指标曲线+精美GUI界面
人工智能·yolo·目标检测