当前位置: 首页 > news >正文

掌控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 权限进行系统级安装

快速安装

# 使用自动安装脚本
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 batt
sudo 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.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 通信模块

// pkg/smc/apple_smc.go
type AppleSMC struct {conn gosmc.Connectioncapabilities 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.go
type Client struct {socketPath stringhttpClient *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.Responsevar err errorurl := "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 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 电池寿命得到有效延长。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)

公众号二维码

公众号二维码

http://www.gsyq.cn/news/56813.html

相关文章:

  • 立方数
  • Rust环境搭建
  • 20251117~20251123NOIP模拟赛
  • Java的第一个程序
  • 20232310 2025-2026-1 《网络与系统攻防技术》实验七实验报告
  • 完整教程:基于Python楼王争霸劳动竞赛数据处理分析
  • 【springboot线上零食舱系统】(免费领源码+演示录像)|可做计算机毕设Java、Python、PHP、小程序APP、C#、爬虫大数据、单片机、文案 - 详解
  • 2025.11.21博客
  • NVM 与 单节点下PM2进程守护 安装配置以及使用教程完整指南(含 Node.js 环境搭建)
  • 北大六院的诊断
  • django项目前端模版文件,在pycahrm无法使用ctrl+alt+l格式化代码的解决办法
  • QT:Qt5.14向文档输出表格--编译异常信息
  • 《程序员修炼之道》阅读笔记5
  • 2025.11.21 - A
  • 2025年新版ADB工具箱下载+驱动+ADB指令集+fastboot刷机ROOT程序
  • 与括号序列相关的 DP 笔记
  • 题解:SP5830 ALTPERM - Alternating Permutations
  • Dify异步接口调用优化实践:解决长时任务处理与网络超时疑问
  • 【251121】CF2171 Div.3 vp 总结
  • OI 笑传 #32
  • PyOpenGL实现Bresenham算法
  • nju实验七 状态机及键盘输入
  • 2025-11-21 XQQ NOIP Round 1 hetao1733837的record
  • Mozilla CI日志中暴露微软x-apikey的安全事件分析
  • Gephi中MySQL数据的节点和边如何设置
  • Gephi对MySQL数据的导入导出有何支持
  • P6727 [COCI 2015/2016 #5] OOP
  • 智能制造(MOM)-详细设计 - 智慧园区
  • STM32中断、NVIC、EXTI
  • 深入解析:自动化文件管理:分类、重命名和备份