掌控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 电池寿命得到有效延长。

相关推荐
静Yu1 小时前
基于CANN框架的算子开发:释放AI计算潜能的核心引擎
人工智能
嵌入式-老费1 小时前
自己动手写深度学习框架(最终的ncnn部署和测试)
人工智能·深度学习
阿十六2 小时前
OUC AI Lab 第七章:ViT & Swin Transformer
人工智能·深度学习·transformer
Mintopia2 小时前
🌳 Claude `code/worktree` 命令最佳实践指南
人工智能·claude·trae
阿里云大数据AI技术2 小时前
阿里云 Elasticsearch 的 AI 革新:高性能、低成本、智能化的搜索新纪元
人工智能·elasticsearch·阿里云
paperxie_xiexuo2 小时前
如何用自然语言生成科研图表?深度体验PaperXie AI科研绘图模块在流程图、机制图与结构图场景下的实际应用效果
大数据·人工智能·流程图·大学生
Mintopia2 小时前
🌌 AIGC模型的冷启动问题:Web应用的初期技术支撑策略
人工智能·trae
win4r2 小时前
🚀谷歌凌晨炸场!Nano Banana Pro 首发深度评测:20轮地狱级测试,它不仅会画画,还读懂了物理世界
aigc·openai·google io
2501_941805312 小时前
边缘计算:引领智能化未来的新技术
人工智能