feat: E1002 顶部加设备电量/温湿度列+server 四路上游并行拉取与响应预算
- 新增 SenseCraft 设备遥测客户端(api-key 走 .env),读电量/充电/温度/湿度,DEVICE_TTL 与设备 300s 上报周期同步 - 大时钟 F84 右侧一列三行左缘对齐:电池(充电绿/≤20% 红)、温度计+蓝色水滴、星期日期(与时钟基线对齐) - server 过期上游由串行改并行,整体最多等 FETCH_BUDGET 秒(默认 5);超预算的一路本次用旧值、后台拉完回填缓存,同一路不重复实拉 - 此前串行且上游 socket 超时 30s,任一路卡住即整图拖到平台抓取超时;「多路 TTL 同时到期」猜想经日志核查不成立,排查顺序写入 CLAUDE.md Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,9 @@ reTerminal E1002 渲染层 —— 复用 renderer.DashboardRenderer 的组件(
|
||||
并生成一张固定 800x480 的 HTML 页面供 SenseCraft HMI 的 HTML 控件云端截图拉取。
|
||||
|
||||
版式(k=1,点阵字体且**只用整数倍字号 12/24/36/48/84**,不放大;四段,三道横规):
|
||||
A 顶部(0~90) :**大时钟 F84**(墨迹 16~79,占满上下边距内的整段高度)+ 星期/日期 F12 紧随其右、与时钟数字**基线对齐**(左)
|
||||
A 顶部(0~90) :**大时钟 F84**(墨迹 16~79)+ 其右一列三行、左缘对齐:① 电池图标+电量 ② 温度计+温度 | 水滴+湿度 ③ 星期/日期
|
||||
(F12,行距 22,日期与时钟数字**基线对齐**;设备数据来自 SenseCraft 遥测 `data.device`;2026-09-14 定稿,
|
||||
此前「状态栏横排在时钟上方+时钟缩 F60」版被否)
|
||||
|天气(右,贴 790)——天气组件与三色版同尺寸。
|
||||
B 用量(96~206) :左半 **Claude Usage**(两行:5h + 合并行 7d——一个大边框内上下两条实心 = 总 7d / fable 7d,右侧数字取较大者,`_usage_row_split`)|竖规 x=400|右半 **Codex Usage**(5h / 7d,ChatGPT 订阅的 Codex 额度池;未推送时 mock 标「示例数据」)。
|
||||
行组件沿用三色版的紧凑单行 `_usage_row`(行距 31);**三处文字统一 12px**(基类 F13/F16/FPACE 都映射到 12px):
|
||||
@@ -98,6 +100,43 @@ class E1002Renderer(DashboardRenderer):
|
||||
return BLACK
|
||||
|
||||
# ---------- 组件 ----------
|
||||
def _status_battery(self, x, cy, dev):
|
||||
"""状态项·电池(F12,墨迹中心 cy):外框 16×9 + 正极 2×4,内部按电量实心填充——充电中 GREEN、≤20% RED、其余 BLACK;
|
||||
右侧电量数字,缺失 "--"。返回末端 x。"""
|
||||
F, GAP_I = self.F12, 5
|
||||
lvl, chg = (dev or {}).get("battery"), (dev or {}).get("charging")
|
||||
self.d.rectangle([x, cy - 4, x + 15, cy + 4], outline=BLACK, width=1)
|
||||
self.d.rectangle([x + 16, cy - 2, x + 17, cy + 2], fill=BLACK)
|
||||
if lvl is not None:
|
||||
fill = GREEN if chg else RED if lvl <= 20 else BLACK
|
||||
fw = round(12 * max(0, min(100, lvl)) / 100)
|
||||
if fw > 0:
|
||||
self.d.rectangle([x + 2, cy - 2, x + 2 + fw, cy + 2], fill=fill)
|
||||
x += 18 + GAP_I
|
||||
txt = f"{lvl}%" if lvl is not None else "--"
|
||||
self._mid(x, cy, txt, F)
|
||||
return x + self._tw(txt, F)
|
||||
|
||||
def _status_env(self, x, cy, dev):
|
||||
"""状态项·环境(F12,墨迹中心 cy):温度计(细管 3×8 + 底部球 7×7,管内水银线)+温度 | 蓝色水滴(上尖下圆)+湿度,
|
||||
项间距 16、图标↔数字 5;缺失 "--"。返回末端 x。"""
|
||||
F, GAP_I, GAP = self.F12, 5, 16
|
||||
dev = dev or {}
|
||||
self.d.rectangle([x + 2, cy - 6, x + 4, cy + 1], outline=BLACK, width=1)
|
||||
self.d.ellipse([x, cy + 1, x + 6, cy + 7], fill=BLACK)
|
||||
self.d.line([x + 3, cy - 2, x + 3, cy + 1], fill=BLACK)
|
||||
x += 7 + GAP_I
|
||||
t = dev.get("temp")
|
||||
txt = f"{t:.1f}℃" if t is not None else "--"
|
||||
self._mid(x, cy, txt, F); x += self._tw(txt, F) + GAP
|
||||
self.d.polygon([(x + 4, cy - 6), (x, cy + 2), (x + 8, cy + 2)], fill=BLUE)
|
||||
self.d.ellipse([x, cy - 1, x + 8, cy + 6], fill=BLUE)
|
||||
x += 9 + GAP_I
|
||||
h = dev.get("humidity")
|
||||
txt = f"{h:.0f}%" if h is not None else "--"
|
||||
self._mid(x, cy, txt, F)
|
||||
return x + self._tw(txt, F)
|
||||
|
||||
def _color_strip(self, y0, y1, x0=None, x1=None):
|
||||
"""六色测试色条:六块等宽实心色块,白块加 1px 黑框以便可见。真机校准用。"""
|
||||
x0 = 10 if x0 is None else x0
|
||||
@@ -255,16 +294,24 @@ class E1002Renderer(DashboardRenderer):
|
||||
dt, wt, mao = data["date"], data["weather"], data["mao"]
|
||||
usage, gpt = data["usage"], data.get("usage_gpt") or {}
|
||||
|
||||
# ---- A. 顶部:大时钟 F84 占满整段(左)+ 星期/日期紧随其右、与时钟数字基线对齐 / 天气(右)----
|
||||
# ---- A. 顶部:大时钟 F84 占满整段(左);其右一列三行、左缘与日期对齐:① 电池 ② 温度+湿度 ③ 星期/日期(与时钟基线对齐)/ 天气(右)----
|
||||
DIV_Y = 90
|
||||
TIME_BOLD, INK_TOP = 3, 16 # 伪粗体 3px;墨迹顶沿 16 与旧版 F48 相同,保住上边距
|
||||
_, tt, _, tb = self.F84.getbbox(dt["time"]) # F84 数字墨迹 28~91 → 高 63,摆到 16~79,距横规 11px
|
||||
TIME_BOLD, INK_TOP = 3, 16 # 伪粗体 3px;墨迹顶沿 16,底沿 79(F84 数字墨迹高 63)
|
||||
_, tt, _, tb = self.F84.getbbox(dt["time"])
|
||||
time_y = INK_TOP - tt
|
||||
base_y = time_y + tb # 时钟数字基线(墨迹底沿)
|
||||
self.text(10, time_y, dt["time"], self.F84, bold=TIME_BOLD)
|
||||
col_x = 10 + self._tw(dt["time"], self.F84) + TIME_BOLD + 14 # 右侧信息列左缘
|
||||
date_txt = f'{dt["week"]} {dt["greg"]}'
|
||||
_, _, _, db = self.F12.getbbox(dt["greg"]) # 用日期数字的底沿对齐基线(汉字底沿比数字低 1px,忽略)
|
||||
self.text(10 + self._tw(dt["time"], self.F84) + TIME_BOLD + 14, base_y - db, date_txt, self.F12)
|
||||
date_y = base_y - db
|
||||
self.text(col_x, date_y, date_txt, self.F12)
|
||||
# 状态两行叠在日期上方:行距 22(F12 墨迹中心 ≈ 文字 y+8.5),三行中心约 30.5 / 52.5 / 74.5,落在时钟墨迹 16~79 之内
|
||||
PITCH = 22
|
||||
cy_date = date_y + 8.5
|
||||
dev = data.get("device")
|
||||
self._status_battery(col_x, cy_date - 2 * PITCH, dev)
|
||||
self._status_env(col_x, cy_date - PITCH, dev)
|
||||
loc, temp, cr = wt["loc"], wt["temp"], f'{wt["cond"]} {wt["range"]}'
|
||||
self.rtext(R, 8, loc, self.F12)
|
||||
self.rtext(R, 30, temp, self.F24, bold=1)
|
||||
|
||||
Reference in New Issue
Block a user