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

相关推荐
数字游民95274 小时前
网站备案全流程回放(腾讯云)
人工智能·git·github·腾讯云·网站备案·waytoopc
飞哥数智坊4 小时前
3位实战分享、6个案例展示,TRAE Friends@济南第二场圆满完成
人工智能·ai编程·trae
xiaobaishuoAI4 小时前
全链路性能优化实战指南:从瓶颈定位到极致优化
大数据·人工智能·科技·百度·geo
人工小情绪4 小时前
深度学习模型部署形式
人工智能·深度学习
AI_56784 小时前
零基础学Linux:21天从“命令小白”到独立部署服务器
linux·服务器·人工智能·github
乾元4 小时前
如何把 CCIE / HCIE 的实验案例改造成 AI 驱动的工程项目——从“实验室能力”到“可交付系统”的完整迁移路径
大数据·运维·网络·人工智能·深度学习·安全·机器学习
GZKPeng4 小时前
pytorch +cuda成功安装后, torch.cuda.is_available 是False
人工智能·pytorch·python
QBoson4 小时前
量子机器学习用于药物发现:系统综述
人工智能·机器学习·量子计算
DatGuy4 小时前
Week 32: 深度学习补遗:Agent的认知架构、记忆系统与高阶规划
人工智能·深度学习
A尘埃4 小时前
OpenCV常用方法介绍
人工智能·opencv·计算机视觉