thieggs/battery-widget
GitHub: thieggs/battery-widget
一款 KDE Plasma 6 桌面电池监控小组件,通过可插拔数据源汇聚系统原生无法识别的各类设备的电量信息。
Stars: 0 | Forks: 0
# 电池 Widget
**一个 KDE Plasma 6 小组件,适用于你拥有的每一块电池。**
手机、无线外设、无头 Android 盒子、那些不向任何东西汇报电量的
蓝牙音箱——全部作为圆环显示在你的桌面上。

*一台通过 KDE Connect 连接的手机,一台通过 adb 连接的无头 Android 服务器,一把无线
键盘,一个游戏手柄,以及一个在 Linux 上不向任何程序报告电量的
蓝牙音箱——全部集中在一处。*
## 为什么会有这个项目
Linux 已经能显示它所识别的设备的电量。问题在于
其他所有设备:
- **充当服务器的手机**。`upower` 根本不知道它的
存在。
- **与你的手机配对而非与电脑配对的蓝牙外设**。
- **不向任何对象报告电量的音箱**——不是 upower,不是
蓝牙电量配置文件,甚至不是它自己的 USB 通道。厂商应用
知道。其他都没人知道。
Battery Widget 就是为填补这一空白而生的。数据源是可插拔的,其中之一是
“任何能写入 JSON 文件的程序”,因此对于具有专有
协议的设备,只需一个小脚本就能将其变成桌面上的一个圆环。
**如果你只需要标准设备,
[BatteryWatch](https://github.com/itayavra/batterywatch) 是一个极好的选择,可能更适合
你**——它在一个整洁的系统托盘图标中涵盖了 upower、KDE Connect、OpenRazer 和
OpenLinkHub。Battery Widget 适用于那些拒绝合作的硬件。
## 数据源
| 数据源 | 覆盖范围 | 设置 |
|---|---|---|
| **upower** | 鼠标、键盘、耳机、游戏手柄——任何内核暴露的设备 | 无,自动发现 |
| **KDE Connect** | 已配对的手机、平板电脑、笔记本电脑 | 无,如果你已经在使用 |
| **OpenRazer** | Razer 外设 | 无,前提是已安装 daemon |
| **OpenLinkHub** | Corsair 外设 | 无,前提是它正在运行 |
| **adb** | 通过无线调试连接的 Android 设备,**以及与其配对的蓝牙外设** | 在设置中添加设备 |
| **external** | 任何设备——你只需将数值写入 JSON 文件 | 编写一个脚本 |
每一个数据源都可以安全地保持启用。当其 daemon 未安装时,
查询会瞬间失败,该数据源只会保持为空——即使它们全都不
存在,整个集合的运行时间也能远远控制在一秒以内。
### 关于 adb 数据源
这是一个 **pull 模型**。手机上不运行任何东西;小组件在需要时
主动询问。有两个值得理解的要点:
- **离开家不会产生任何开销。** mDNS 找不到设备,收集器会在大约
一秒后放弃,永远不会去联系手机。
- **必须开启无线调试。** 一些银行应用会在此状态下拒绝运行,
因此这可能不适合你的日常手机。但它非常适合那些放在
架子上作为服务器的设备。
每次重启无线调试时,Android 都会分配一个**新端口**,因此
硬编码的地址会不断失效。使用 `auto`,它每次都会通过
mDNS 重新被发现。
## 安装
无需 root 权限,完全可逆。
```
git clone https://github.com/thieggs/battery-widget
cd battery-widget
./install.sh
```
然后:**右键点击桌面 → 添加小组件… → “Battery Widget”**。
如果它没有出现在列表中,请重新加载 shell——Plasma 会缓存小组件的 QML:
```
systemctl --user restart plasma-plasmashell.service
```
要移除所有内容:
```
./uninstall.sh # keeps the cache
./uninstall.sh --purge # deletes it too
```
### 依赖项
只有 **python3** 是真正必需的。其他每个工具都会启用一个数据源,
如果缺少该工具,只会导致该数据源为空:
| 工具 | 启用 |
|---|---|
| `upower` | 本地外设 |
| `kdeconnect-cli`, `gdbus` | KDE Connect 设备,以及即时刷新 |
| `adb`, `avahi-browse` | Android 设备 |
| `gatttool`, `bluetoothctl` | JBL 示例数据源 |
`install.sh` 会告诉你缺少哪些工具,并继续执行。
## 配置
右键点击小组件 → **配置 Battery Widget**。
**常规** —— 刷新间隔,隐藏离线设备,显示/隐藏标题和
设备名称。
**外观** —— 圆环直径和厚度,图标大小(0 表示隐藏),
警告和严重阈值,以及所有三种颜色。
**数据源** —— 切换每个数据源,并管理 **adb 设备网格**:
| 字段 | 含义 |
|---|---|
| **目标** | 使用 `auto` 通过 mDNS 发现,使用 `auto:HINT` 在多个设备中选择(例如 `auto:SM-M356B`),或者直接填入 `192.168.1.10:5555` |
| **名称** | 圆环的标签 |
| **蓝牙** | 同时读取与该设备配对的蓝牙外设 |
| **跳过自身** | 忽略设备自身的电池——当 KDE Connect 已经显示该手机,而你只想要它的外设时非常有用 |
你可以随意添加任意数量的设备。
## 工作原理
三个部分,刻意保持独立:
```
battery-hub-watch ──touches──▶ ~/.cache/battery-hub/dirty
(D-Bus listener) │
stat, every 2 s
▼
┌───────────────┐
│ widget │
└───────┬───────┘
│ runs, with your settings as flags
▼
┌───────────────┐ ┌──────────────┐
│ battery-hub │◀─────│ external.json│
│ (collector) │ └──────────────┘
└───────┬───────┘ ▲
│ │
upower · KDE Connect · adb your script
```
**收集器** (`battery-hub`) 是一个普通的程序:它查询数据源
并输出 JSON。你可以在终端中运行它,将其通过管道传递给 `jq`,或者在与 Plasma 毫无关系的
状态栏中使用它。
**小组件** 从不与设备直接通信。它根据其
设置构建命令行,运行收集器,并绘制结果。支持新硬件
只需修改收集器,完全不需要碰 QML。
**监听器** (`battery-hub-watch`) 监听 D-Bus —— UPower、BlueZ 和 KDE
Connect —— 并在有设备连接时触碰一个标记文件。小组件每两
秒钟检查一次该文件的统计信息,这几乎不消耗任何资源,并且只有在
时间戳发生变化时才运行真正的收集器。实测从插入设备到
圆环出现的延迟:**大约一秒钟**。
它故意*不*自己运行收集器,因为只有小组件才
知道你的设置。它只负责敲响警钟。
如果监听器没有运行,所有功能仍会根据轮询定时器正常运行。这是
功能降级,而不是中断。
## 编写你自己的数据源
将一个 JSON 数组写入 `~/.cache/battery-hub/external.json`:
```
[
{
"id": "my-thing",
"name": "My Thing",
"kind": "headset",
"pct": 80,
"charging": false,
"ts": 1750000000
}
]
```
- `id` —— 保持稳定,这样你就可以在不影响其他条目的情况下更新自己的条目
- `kind` —— 选择图标:`phone`, `tablet`, `laptop`, `mouse`, `keyboard`,
`headset`, `gamepad`, `watch`, `generic`
- `ts` —— Unix 时间戳,可选。如果早于 TTL(默认为 15 分钟),
该设备将显示为 **离线**,而不是显示一个过时的错误数值。
有两点值得从 `contrib/jbl-battery` 中借鉴:
- **合并,不要覆盖。** 读取文件,只删除你自己的 `id`,然后写
回——否则你会删除别人的数据源。
- **原子写入** (`os.replace`),否则收集器最终会读取到一个
写了一半的文件。
## 案例研究:一个对谁都保密的音箱
插上 USB 后,音箱枚举出了一个 HID 接口,带有一个
**厂商定义的通道,进出各 63 字节**。看起来很有希望——却是一个
彻底的死胡同。在狂按每个按钮的同时监听它,结果只产生了媒体键
报告。它从不主动报告电量,而且用于询问电量的厂商命令
在任何地方都没有文档记录。
**传输方式错了。** JBL 通过 **BLE GATT** 进行通信,该协议已由
[ConnectPlus](https://github.com/pembem22/connect-plus/discussions/56) 记录,这是对官方应用的
一次开源重新实现:
```
packet AA | type | length | payload
payload 00 | token | value...
write AA 11 00 "tell me about yourself"
read AA 12 .. 00 44 token 0x44 = BATTERY_STATUS
```
写入该内容,读取通知,搞定。完整的详细指南——包括
应该使用哪些 handle 以及如何在其他型号上找到它们——位于
[`docs/JBL-PROTOCOL.md`](docs/JBL-PROTOCOL.md)。
这个经验具有普适性:**在对协议进行逆向工程之前,先检查一下
你是否选对了传输方式。**
## 故障排除
**小组件永远显示“正在读取设备…”。**
手动运行收集器:`~/.local/bin/battery-hub`。它会输出 JSON 或者
一个错误。
**我修改了 QML,但没有任何反应。**
Plasma 缓存了小组件的 QML。重新加载 shell:
`systemctl --user restart plasma-plasmashell.service`。
**设置无法保存,点击“确定”没有任何反应。**
原因同上。一个小程序会在**加载时读取一次**其配置 schema —— 如果
schema 到达时小组件已经在运行,它就不会读取。请重新加载
shell。(症状:你在
`~/.config/plasma-org.kde.plasma.desktop-appletsrc` 中的小程序组里有一个 `[ConfigDialog]`
部分,但没有 `[General]`。)
**adb 设备从未出现。**
检查 `adb devices`,并确保无线调试已开启且 PC 已配对。如果
你固定了 `host:port`,请记住 Android 每次重启时都会更改端口——
将目标切换为 `auto`。
**蓝牙设备不显示电量。**
有些设备根本不报告。尝试启用 BlueZ 实验性功能,这
适用于许多音频设备:在
`/etc/bluetooth/main.conf` 中设置 `Experimental = true` 并重启 `bluetooth.service`。
## 许可证
MIT —— 详见 [LICENSE](LICENSE)。
# 🇧🇷 Português
**Um widget do KDE Plasma 6 para todas as suas baterias.**
Celulares, periféricos sem fio, Android headless e caixas de som que não contam
sua bateria pra ninguém — tudo em anéis na sua área de trabalho.

## 为什么存在
O Linux já mostra a bateria dos aparelhos que ele entende. O problema é o
resto: um **celular servindo de servidor** na rede, os **periféricos Bluetooth
pareados no celular** (e não no PC), e a **caixa de som que não reporta bateria
pra ninguém** — nem upower, nem perfil Bluetooth, nem o próprio canal USB dela.
O Battery Widget foi feito pra essa lacuna. As fontes são plugáveis, e uma delas é
"qualquer programa que saiba escrever um JSON" — então um aparelho de protocolo
proprietário está a um script de virar um anel na sua tela.
**Se você só precisa de aparelhos comuns, o
[BatteryWatch](https://github.com/itayavra/batterywatch) é excelente e
provavelmente serve melhor.** Este aqui é pra quando o hardware não colabora.
## 安装
```
git clone https://github.com/thieggs/battery-widget
cd battery-widget
./install.sh
```
Depois: **botão direito na área de trabalho → Adicionar widgets… → "Battery Widget"**.
Se não aparecer na lista, recarregue o shell (o Plasma guarda o QML em cache):
```
systemctl --user restart plasma-plasmashell.service
```
Pra remover: `./uninstall.sh` (ou `--purge` pra apagar o cache junto).
Só o **python3** é realmente obrigatório. Cada outra ferramenta habilita uma
fonte, e a falta dela só deixa aquela fonte vazia.
## adb 来源
É um **modelo pull**: nada roda no celular, o widget é que pergunta quando quer
saber. Duas consequências:
- **Estar fora de casa não custa nada.** O mDNS não acha, o coletor desiste em
~1s, e o celular nunca é contatado.
- **Precisa da depuração sem fio ligada.** Alguns apps de banco se recusam a
funcionar assim — então pode não servir pro seu celular do dia a dia, mas
serve muito bem pra um aparelho que vive numa prateleira sendo servidor.
O Android **sorteia uma porta nova toda vez** que a depuração sem fio reinicia.
Por isso use `auto` no campo de alvo: ele redescobre por mDNS sozinho.
## 配置
Botão direito no widget → **Configurar**. Você controla intervalo, aparência
(tamanho e espessura do anel, ícones, limiares e cores) e as fontes — incluindo
uma **grade onde dá pra adicionar quantos aparelhos adb quiser**, cada um com
alvo, nome, e as opções de ler os periféricos Bluetooth dele e de ignorar a
bateria dele mesmo.
## 工作原理
Três peças separadas de propósito: o **coletor** (`battery-hub`) consulta as
fontes e imprime JSON — dá pra rodar no terminal, jogar no `jq`, usar em outra
barra de status. O **widget** nunca fala com aparelho nenhum: monta a de
comando a partir das configurações, roda o coletor e desenha o resultado. E o
**vigia** (`battery-hub-watch`) escuta o D-Bus e avisa quando algo conecta —
latência medida de **cerca de 1 segundo** entre plugar e o anel aparecer.
Suportar hardware novo significa mexer no coletor, nunca no QML.
## 许可证
MIT.
标签:KDE Plasma, 桌面组件, 电量监控, 系统工具, 蓝牙设备