这是一个基于 ESP32-C3-MINI-1U 和 1.28 英寸 GC9A01 圆形 TFT 屏幕的桌面 API 余额/用量监控项目。
当前推荐方案是:电脑本地代理 + ESP32 读取代理返回的小 JSON。
因为你只有开电脑 vibecoding 时才需要这个摆件,所以不需要额外买服务器。
src/main.cpp:ESP32 固件,只负责联网、请求代理接口、解析 JSON、绘制圆屏 UI。server/local-proxy/anpin_proxy.py:电脑本地代理,请求anpin.ai,隐藏 Bearer Token,并返回精简 JSON。server/cloudflare-worker/worker.js:可选 Cloudflare Worker 代理。如果以后想电脑不开机也能用,可以再部署它。platformio.ini:PlatformIO 配置,包含 ESP32-C3、TFT_eSPI、ArduinoJson 依赖和 GC9A01 引脚参数。
anpin.ai
-> 你电脑上的本地代理
-> ESP32-C3 圆屏小摆件
ESP32 期望代理返回这样的 JSON:
{
"station_name": "Anpin",
"balance": 37.3729,
"total_available": 100,
"total_usage": 62.6271,
"last_model": "claude-3.7",
"last_usage": 0.184
}其中:
station_name:中转站名称,显示在屏幕顶部。balance:剩余额度,显示在屏幕中央。total_available:总额度,用来计算外圈进度。total_usage:累计已用额度。last_model:最近一次使用的模型,目前可以先返回占位值。last_usage:最近一次使用量,目前可以先返回0。
现在即使 ESP32 还没到,也可以完整测试“登录 anpin -> 获取余额 -> 浏览器预览圆屏 UI”。
在项目根目录运行:
cd server/local-proxy
python3 anpin_proxy.py看到下面的输出就说明代理启动成功:
Local proxy listening on http://0.0.0.0:8787/balance
Setup page: http://127.0.0.1:8787/setup
Use your computer LAN IP in ESP32 proxy URL, not 127.0.0.1.
浏览器打开:
http://127.0.0.1:8787/setup
填写:
Anpin 登录邮箱Anpin 登录密码设备 Token
不用填写 Anpin Bearer Token。代理会自动调用 anpin 登录接口获取 Token。
建议先把 设备 Token 填成:
CHANGE_ME_DEVICE_TOKEN
后面 ESP32 和预览页也填同一个值。
新开一个终端窗口,运行:
curl -H "X-Device-Token: CHANGE_ME_DEVICE_TOKEN" \
http://127.0.0.1:8787/balance成功时会返回类似:
{
"station_name": "Anpin",
"balance": 37.3729,
"total_available": 100,
"total_usage": 62.6271,
"last_model": "model pending",
"last_usage": 0,
"updated_at": "2026-06-27T20:30:00+0800"
}如果这一步失败,先不要管 ESP32,先看终端返回的错误。常见情况:
unauthorized_device:X-Device-Token和设置页里的设备 Token 不一致。ANPIN_EMAIL / ANPIN_PASSWORD is not set:设置页没有保存邮箱或密码。Login succeeded but token field was not found:登录成功了,但返回 JSON 里的 Token 字段路径和当前代码猜的不一样,需要把错误返回贴出来再适配。upstream_http_error:anpin 上游返回错误,可能是密码错误、账号异常、登录接口字段不匹配或 Token 失效。
保持本地代理运行,再回到项目根目录,新开一个终端:
python3 -m http.server 8080浏览器打开:
http://127.0.0.1:8080/preview/
在预览页里确认:
代理地址是http://127.0.0.1:8787/balance设备 Token和设置页一致
点击“请求本地代理”。如果成功,圆屏模拟器会显示真实余额。
第一次烧录前,可以先在 src/main.cpp 里填默认值:
const char *DEFAULT_WIFI_SSID = "YOUR_WIFI_SSID";
const char *DEFAULT_WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char *DEFAULT_API_URL = "http://YOUR_COMPUTER_LAN_IP:8787/balance";
const char *DEFAULT_API_DEVICE_TOKEN = "CHANGE_ME_DEVICE_TOKEN";说明:
YOUR_COMPUTER_LAN_IP是你电脑在局域网里的 IP,例如192.168.1.23。- 不要填
127.0.0.1。对 ESP32 来说,127.0.0.1指的是 ESP32 自己,不是你的电脑。 DEFAULT_API_DEVICE_TOKEN要和本地代理的DEVICE_TOKEN保持一致。- 只是临时测试的话,两边都可以留空,但长期使用建议设置一个。
后期如果电脑局域网 IP 或 Wi-Fi 变了,不需要重新烧录。进入 ESP32 设置页即可修改。
ESP32 现在内置了设置网页。可以修改:
- Wi-Fi 名称
- Wi-Fi 密码
- 代理接口 URL
- 设备 Token
查看串口或路由器里的 ESP32 IP,然后浏览器打开:
http://ESP32的局域网IP/
例如:
http://192.168.31.52/
ESP32 会自动开启设置热点。用手机或电脑连接:
Wi-Fi: ESP32-Balance-Setup
密码: 12345678
然后浏览器打开:
http://192.168.4.1
如果你想强制进入热点配置模式,可以按住开发板 BOOT 键再上电或重启。
保存时填写新的代理地址,例如:
http://192.168.1.23:8787/balance
点击保存后,ESP32 会自动重启。
保存后的配置会写在 ESP32 的 Flash/NVS 里,断电也不会丢。下次电脑 IP 再变,重复这个设置流程即可。
默认刷新频率是 60 秒:
const unsigned long API_POLL_INTERVAL_MS = 60UL * 1000UL;如果想更快,可以改成 30 秒:
const unsigned long API_POLL_INTERVAL_MS = 30UL * 1000UL;不建议设置得太短,因为每次刷新都会让电脑代理请求一次上游中转站。
在项目根目录启动本地代理:
cd server/local-proxy
python3 anpin_proxy.py看到类似输出就说明代理启动了:
Local proxy listening on http://0.0.0.0:8787/balance
Setup page: http://127.0.0.1:8787/setup
Use your computer LAN IP in ESP32 API_URL, not 127.0.0.1.
打开设置页面:
http://127.0.0.1:8787/setup
在页面里填写:
Anpin 登录邮箱Anpin 登录密码设备 Token:和 ESP32 里的设备 Token 保持一致。
不用填写 Anpin Bearer Token。代理会在请求余额时调用:
https://anpin.ai/api/v1/auth/login
自动登录并保存新的 Bearer Token。
点击保存后,配置会写入:
server/local-proxy/config.local.json
这个文件已经加入 .gitignore,不会被误提交。
如果自动登录失败,再展开设置页里的“高级备用:手动填写 Bearer Token”,从浏览器抓包里手动复制:
authorization: Bearer xxxxx然后把 Bearer 后面的 xxxxx 填到设置页的 Anpin Bearer Token。
在同一台电脑上测试:
curl -H "X-Device-Token: CHANGE_ME_DEVICE_TOKEN" \
http://127.0.0.1:8787/balance如果返回类似下面的 JSON,就说明代理正常:
{
"balance": 37.3729,
"total_available": 100,
"total_usage": 62.6271,
"updated_at": "2026-06-27T20:30:00+0800"
}Mac 使用 Wi-Fi 时通常运行:
ipconfig getifaddr en0如果你使用的是有线网络,可以试:
ipconfig getifaddr en1假设输出是:
192.168.1.23
那么 ESP32 里的默认代理地址,或设置模式里的代理地址,应该填:
const char *DEFAULT_API_URL = "http://192.168.1.23:8787/balance";注意:电脑和 ESP32 必须在同一个 Wi-Fi/局域网内。
如果电脑上 curl 正常,但 ESP32 显示 API Error,可能是 macOS 防火墙拦截了 Python 的入站连接。
项目里有一个浏览器预览页:
preview/index.html
直接双击打开,或者在项目根目录运行一个静态服务器:
python3 -m http.server 8080然后浏览器访问:
http://127.0.0.1:8080/preview/
预览页支持两种模式:
- 使用模拟数据:直接改“剩余额度”和“总额度”。
- 请求本地代理:先启动
server/local-proxy/anpin_proxy.py,再点击“请求本地代理”。 - 切换中转站:点击
‹/›,或者在圆屏上左右滑动。现在是预览用的多站点结构,后续接多个真实中转站时可以沿用。
如果本地代理设置了 DEVICE_TOKEN,预览页里的“设备 Token”也要填写同一个值。
默认 GC9A01 引脚在 platformio.ini 里配置:
TFT_MOSI=7
TFT_SCLK=6
TFT_CS=10
TFT_DC=2
TFT_RST=3
TFT_BL=4如果你的屏幕接线不同,需要修改这些值。
如果使用 Arduino IDE,而不是 PlatformIO,需要把 src/main.cpp 复制成 .ino,并按源码头部注释修改 TFT_eSPI 的 User_Setup.h。
使用 PlatformIO:
pio run
pio run -t upload
pio device monitor如果本机没有 pio 命令,需要先安装 PlatformIO。
如果屏幕底部显示 API Error,先在电脑上测试代理:
curl -H "X-Device-Token: CHANGE_ME_DEVICE_TOKEN" \
http://127.0.0.1:8787/balance如果代理返回上游错误、未授权、或者 token 相关错误,通常说明 ANPIN_BEARER_TOKEN 过期了。
处理方法:
- 打开设置页确认邮箱和密码正确。
- 点击保存。
- 再请求一次
/balance,代理会尝试重新登录并刷新 Token。
如果自动登录仍然失败,再使用手动 Bearer Token:
- 在浏览器重新登录
anpin.ai。 - 打开开发者工具,进入
Network。 - 找到
/api/v1/auth/me?timezone=Asia%2FShanghai请求。 - 复制请求头里的
authorization: Bearer xxxxx。 - 打开
http://127.0.0.1:8787/setup更新 Token。
注意:自动登录目前按常见 JSON 格式发送:
{
"email": "你的邮箱",
"password": "你的密码"
}这个格式和当前抓到的 anpin.ai/api/v1/auth/login 请求一致。
代理会从常见字段里提取 token,例如 data.token、data.access_token、token。如果 anpin 实际登录响应字段不同,代理会返回错误信息,我们再按真实响应补一下字段路径。
如果以后想让电脑不开机也能使用,可以部署 server/cloudflare-worker/worker.js。
安装 Wrangler:
npm install -g wrangler
wrangler login创建配置:
cd server/cloudflare-worker
cp wrangler.toml.example wrangler.toml设置密钥:
wrangler secret put ANPIN_BEARER_TOKEN
wrangler secret put DEVICE_TOKEN部署:
wrangler deploy测试:
curl -H "X-Device-Token: CHANGE_ME_DEVICE_TOKEN" \
https://YOUR_WORKER_NAME.YOUR_SUBDOMAIN.workers.dev/balance如果返回 balance、total_available、total_usage,就可以把这个 Worker 地址填进 src/main.cpp 的 API_URL。