- server.py:三条恒定 URL 并行——/e1002.png 内存现渲染 PNG(主力)、 /e1002.html 现代网页、/e1002-web.png 网页经无头 Chrome 截图后固化六色; 天气/橘喵/BTC 按 WEATHER_TTL/MAO_TTL/BTC_TTL 走内存缓存,过期才实拉、 失败沿用旧值;用量不读本机文件,改由 POST /push/usage(_gpt) 推送暂存 - push_client.py:本机把 Claude 用量快照推送到服务(X-Push-Token 鉴权) - btc_api.py:OKX/Coinbase/Huobi 免费接口逐源兜底,时K 近 72 小时,涨绿跌红 - data.py 拆出 weather_fetch/mao_fetch/btc_fetch 与 usage_from_raw, 统一按 TZ_NAME 时区;宽版只用点阵字体整数倍字号 12/24/36/48 - probe_server.py:验证平台对同一 URL 是否周期重抓(结论:Image 控件 不重抓,HTML 控件重抓) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
122 lines
8.5 KiB
Markdown
122 lines
8.5 KiB
Markdown
# 墨水屏仪表盘推送(eink-push)
|
||
|
||
将日期天气、Claude Code 用量、橘喵今日经营合成为一张 **400×300 三色(黑/白/红,BWR)**图片,
|
||
推送到 Zectrix 极趣云墨水屏设备。
|
||
|
||
纯 Python + Pillow + Fusion Pixel 点阵字体,**无浏览器依赖**,适合后台/定时运行。
|
||
|
||
> **`feature/colorful` 分支**:新设备支持红色,渲染升级为黑/白/红三色,版式为上中下三段
|
||
> (时钟天气 / Claude Usage / 今日实时)。红作**语义强调**——用量吃紧预警、涨、定位、天气太阳/闪电——
|
||
> 全图只三种纯色、无灰阶不抖动。近30天趋势图当前隐藏(代码保留可挂回)。
|
||
|
||
## 效果
|
||
|
||
- 顶部:大号时钟 + 日期 | 天气(矢量手绘图标 + 温度 + 天气/温区,定位南京·江宁)
|
||
- 中部:**Claude Usage**——5h / 7d 用量进度条 + 大号百分比 + 时间维度对比 pace(用量%−时间%,超前↑ / 节余↓);用量 ≥ 阈值时该条转红预警
|
||
- 底部:橘喵今日实时经营(单量 / 流水 / 毛利,含环比、同比涨跌,涨=红)
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
eink-push/
|
||
├── main.py # 入口:取数据 → 渲染 → 推送(--target e1002 时改为产出 HTML 页)
|
||
├── renderer_e1002.py# reTerminal E1002:800x480 六色版式 + 固定尺寸 index.html 生成
|
||
├── server.py # E1002 动态服务:恒定 URL,每次请求现取数据、内存现渲染(PNG / HTML 两方案)+ 用量推送接口
|
||
├── html_renderer.py # 方案二:800x480 现代网页版(无 JS,内联 SVG K 线)
|
||
├── html_shot.py # 方案三:网页 → 无头 Chrome 截图 → 最近色固化六色 PNG
|
||
├── push_client.py # 本机推送端:用量快照 → server.py
|
||
├── btc_api.py # BTC K 线(OKX/Coinbase/Huobi 免费接口,逐源兜底)
|
||
├── probe_server.py # 验证工具:平台对同一 URL 是否周期重抓
|
||
├── config.py # 配置:设备、天气、用量、字体、尺寸、推送参数、缓存路径
|
||
├── data.py # 数据层:拉真实数据并映射,失败回退占位 "--"(不回退 mock);天气/趋势缓存
|
||
├── jm_api.py # jm-devops 后端统计接口客户端(设备密钥 client_secret 授权 + token 缓存)
|
||
├── weather_api.py # 和风天气(QWeather)客户端(实时天气 + 今日温区)
|
||
├── usage_local.py # Claude Code 用量:只读 statusline 生产的本地快照(不发网络请求)
|
||
├── renderer.py # 渲染层:DashboardRenderer 生成 400×300 三色(黑/白/红)图片
|
||
├── pusher.py # 推送层:按 .env 设备 MAC 直接推送图片(标准库 urllib)
|
||
├── run.sh # cron 包装脚本(本机专用,git 忽略)
|
||
├── fonts/ # Fusion Pixel 点阵字体(OFL 协议)
|
||
├── output/ # 生成的图片与 cron.log(git 忽略)
|
||
├── requirements.txt
|
||
└── README.md
|
||
```
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
pip install -r requirements.txt # 仅 Pillow>=10.0;网络请求用标准库 urllib
|
||
```
|
||
|
||
## 使用
|
||
|
||
```bash
|
||
python3 main.py # 渲染并推送(设备取 .env 的 ZECTRIX_DEVICE_ID)
|
||
python3 main.py --render-only # 只渲染到 output/dashboard.png,不推送(本地调试渲染用)
|
||
python3 main.py --target e1002 # reTerminal E1002(800x480 六色):产出 output/e1002/index.html + dashboard.png,
|
||
# 部署到公网 HTTPS 后填入 SenseCraft HMI 的 HTML 控件(云端每周期重新抓取)
|
||
python3 server.py # reTerminal E1002 动态服务(部署公网 HTTPS):/e1002.png 每次请求内存渲染 PNG,/e1002.html 现代网页,
|
||
# /e1002-web.png 网页经服务端无头 Chrome 截图后固化六色(需装 Chrome);
|
||
# 天气/橘喵/BTC 实时拉取,Claude/ChatGPT 用量由本机推送
|
||
python3 main.py --target push # 本机:推送 ~/.claude/usage-snapshot.json 到 server.py(.env: PUSH_URL + PUSH_TOKEN)
|
||
```
|
||
|
||
环境变量可覆盖配置(详见 `config.py`):
|
||
|
||
```bash
|
||
# Zectrix 设备
|
||
ZECTRIX_API_KEY=zt_xxx ZECTRIX_DEVICE_ID=AA:BB:CC:DD:EE:FF python3 main.py
|
||
# jm-devops 后端 / 和风天气
|
||
JM_BASE_API=... JM_CLIENT_ID=...
|
||
QWEATHER_HOST=... QWEATHER_KEY=... WEATHER_LOCATION=经度,纬度 WEATHER_TTL=900
|
||
# Claude Code 用量(只读 statusline 生产的本地快照,不发请求)
|
||
USAGE_LOCAL_PATH=~/.claude/usage-snapshot.json USAGE_WARN=80
|
||
```
|
||
|
||
## 定时刷新(cron)
|
||
|
||
设计为**每分钟**触发:业务数据每次都刷新,天气靠缓存、用量读本地文件,避免高频打接口(见下「设计说明」)。
|
||
`run.sh` 是 cron 入口——cron 不继承登录环境,故脚本内 python 写死绝对路径、`cd` 到项目目录后追加日志到 `output/cron.log`。
|
||
|
||
```cron
|
||
* * * * * /path/to/eink-push/run.sh
|
||
```
|
||
|
||
手动测试:`sh run.sh`。
|
||
|
||
## 数据来源
|
||
|
||
- **橘喵今日经营**:接入 jm-devops 后端统计接口(`jm_api.py`,设备密钥 client_secret 授权):
|
||
- `GET /system/statistics/realtime` —— 今日单量/流水/毛利 + 环比/同比
|
||
- `GET /system/statistics/recent-days?days=30` —— 近30天每日数据(趋势图当前隐藏,仍会拉取并缓存)
|
||
- **天气**:接入真实和风天气(QWeather,`weather_api.py`),定位固定南京·江宁。
|
||
实时天气取 `now.text`/`now.temp`/`now.icon`,今日温区取 `/3d` 的 `daily[0]`。需配置 `QWEATHER_HOST` + `QWEATHER_KEY`。
|
||
- **Claude Code 用量**:**只读本地**(`usage_local.py`,不发请求),**生产者/消费者**模式——
|
||
生产者是**打过补丁的 claude-statusline**:它把每次 Claude Code 经 stdin 喂来的**权威实时**额度
|
||
落盘为快照 `~/.claude/usage-snapshot.json`(`five_hour`/`seven_day` 的 `utilization` + `resets_at`);
|
||
本项目作消费者读取。活跃使用时快照持续刷新、准确;空闲时停在最后一次。**需先安装补丁版 statusline**
|
||
(见其仓库 `bin/statusline.sh` 的 usage snapshot 段 + `node bin/install.js`)。
|
||
- **日期 / 时间 / 上次更新**:真实系统时间。
|
||
- **比特币 K 线**(仅 800×480 宽版底部面板,默认时 K 近 72 小时,`BTC_BAR`/`BTC_LIMIT` 可配):免费公开接口,无需密钥,逐源兜底 OKX → Coinbase → Huobi(`btc_api.py`),5 分钟文件缓存 `.btc_cache.json`,失败沿用旧缓存。涨(收≥开)绿、跌红。
|
||
|
||
> `data.py` 负责把响应映射成渲染结构;**任何接口失败都回退占位 `"--"`,不回退 mock**。
|
||
|
||
## 缓存机制
|
||
|
||
为「每分钟触发、但天气/趋势无需高频刷新」而设的两套**文件缓存**(cron 每次独立进程,必须落盘):
|
||
|
||
- **天气缓存** `.weather_cache.json`:TTL = `WEATHER_TTL`(默认 15 分钟),未过期不发请求。
|
||
- **趋势缓存** `.trend_cache.json`:按日期为 key,当天命中即不再调 `recent-days`,每天只拉一次。
|
||
|
||
两者拉取失败均**沿用旧缓存**避免天气区整片 `"--"`,仍无缓存才回退占位。想强制重拉删掉对应缓存文件即可(均已 git 忽略)。
|
||
Claude 用量**不自建缓存**——直接读 statusline 生产的本地快照 `~/.claude/usage-snapshot.json`,文件缺失/损坏即显示 `"--"`。
|
||
|
||
## 设计说明
|
||
|
||
- 设备为**三色(黑/白/红)无真灰阶**,灰阶只能抖动成网点(难看),故底色只用黑白 + 红作稀缺强调,靠构图、字号、留白建立层级。
|
||
- **红只承载语义**(方向·警示·强调),占墨保持很小(实测红≈全图 0.6%、占墨迹 <10%);整图仅三种纯色 `(0,0,0)/(255,255,255)/(255,0,0)`,无灰、不抖动。
|
||
- 字体用 **Fusion Pixel 12px 点阵字体**,首选整数倍(12/24/48)最锐利;用量区另用 13/16px(非整数倍、笔画略不均)取字号层级,关抗锯齿仍保持纯色不糊;重点数据用「伪粗体」(偏移叠绘)加粗。
|
||
- **Claude Usage**:每条单行 = 左标签(5h/7d) + 粗进度条 + 百分比 + pace(上/下三角);用量 ≥ `USAGE_WARN`(默认 80) 时该条进度条与百分比转红预警。行内所有元素按墨迹竖直中心对齐到同一中线。
|
||
- 天气图标为**全矢量手绘**(无图片资源):按和风 icon 代码归并为 8 类(晴/晴夜/多云/阴/雷/雨/雪/雾),用基本图元描边画出;太阳与闪电着红。
|
||
- 近30天趋势折线图当前**隐藏**(`renderer._trend_chart` 及依赖保留、未调用,随时可挂回)。
|
||
- 推送用 `dither=false`(硬阈值),三色纯色图最锐利。
|
||
``` |