Files
eink-push/config.py
YANG JIANKUAN 7378d6bb88 feat: AI 用量改账户级本机采集(Claude 钥匙串/Codex RPC)+宽版 7d 合并行
- Claude:复用 Claude Code 钥匙串登录态直调 /api/oauth/usage,零依赖 statusline 与 Claude Code 进程;只读不刷新 token
- Codex:经 codex app-server JSON-RPC 读 ChatGPT 订阅的 Codex 额度池(普通聊天额度无账户级途径,右块改名 Codex Usage)
- 两路采集共用 TTL 缓存+失败退避(CLAUDE_USAGE_TTL/CODEX_USAGE_TTL,语义同 WEATHER_TTL),推送端两路独立上报
- E1002:Claude 7d 与 fable 7d 合并为一行(单边框内上下对半实心,数字取较大者)、标签去 all 前缀、空值按 00% 00 占位等宽
- E1002/网页版:今日实时环比同比改涨绿跌红,与 K 线一致

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 14:08:21 +08:00

143 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""全局配置。敏感项从同目录 .env 读取,真实环境变量(如 cron 注入)优先。"""
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
def _load_dotenv(path):
"""极简零依赖 .env 加载器:把 KEY=VALUE 写入 os.environ。
已存在的真实环境变量优先(不覆盖),故 cron/命令行注入仍可压过 .env。
支持 # 注释、空行、行内 KEY=VALUE值两侧成对的单/双引号会被去掉。"""
try:
with open(path, "r", encoding="utf-8") as fp:
for raw in fp:
line = raw.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, _, val = line.partition("=")
key, val = key.strip(), val.strip()
if len(val) >= 2 and val[0] == val[-1] and val[0] in "\"'":
val = val[1:-1]
if key:
os.environ.setdefault(key, val)
except FileNotFoundError:
pass
_load_dotenv(os.path.join(BASE_DIR, ".env"))
# ---- 局域网墨水屏设备喵喵固件开源https://gitee.com/gxp666111/miaomiao----
# 不再走 Zectrix 公网 API + 设备 MAC改为直连局域网设备 mDNS host 的 HTTP 接口。
EPD_HOST = os.environ.get("EPD_HOST", "epd400a44.local")
# ---- 时区 ----
# 服务端可能部署在境外 VPS所有「现在时刻」与时间戳格式化统一按此时区data.TZ本机与服务端结果一致。
TZ_NAME = os.environ.get("TZ_NAME", "Asia/Shanghai")
# ---- 画布(喵喵固件 400x300 三色屏)----
WIDTH, HEIGHT = 400, 300
# ---- reTerminal E1002800x480E Ink Spectra 6 六色;经 SenseCraft HMI 的 HTML 控件云端抓取)----
# 产物:固定 800x480 的 index.html + 同目录 dashboard.png需部署到公网 HTTPS 地址供平台每周期重新拉取。
E1002_WIDTH, E1002_HEIGHT = 800, 480
E1002_COLOR_STRIP = os.environ.get("E1002_COLOR_STRIP", "0") == "1" # 底部六色测试色条(真机校准用,默认关)
# ---- 图片服务server.py恒定 URL每次请求内存中现渲染 800x480 PNG供 SenseCraft HTML 控件周期抓取)----
# 服务端三路上游的内存缓存有效期(秒):收到请求先查缓存是否过期,过期才实拉并更新时间戳,否则直接用缓存渲染;
# 拉取失败沿用旧值且不更新时间戳(下次请求再试)。设 0 = 每次请求都实拉。天气/BTC 复用上面的 WEATHER_TTL/BTC_TTL。
MAO_TTL = int(os.environ.get("MAO_TTL", "60")) # 橘喵今日实时,默认 60 秒
# 真机验证结论Image 控件只在填写 URL 时抓一次快照、此后不再更新HTML 控件填同一图片 URL 则每周期重抓。
SERVER_HOST = os.environ.get("SERVER_HOST", "0.0.0.0")
SERVER_PORT = int(os.environ.get("SERVER_PORT", "8790"))
IMAGE_PATH = os.environ.get("IMAGE_PATH", "/e1002.png") # 方案一:恒定图片路径(每次请求内存渲染 PNG可改成难猜的路径防扫描
HTML_PATH = os.environ.get("HTML_PATH", "/e1002.html") # 方案二:恒定网页路径(每次请求生成 800x480 现代网页,平台截图)
# 方案三:服务端用无头 Chrome 把方案二的网页截成 800x480再按「最近色、不抖动」固化为六色 PNG需服务器装 Chrome/Chromium
HTML_PNG_PATH = os.environ.get("HTML_PNG_PATH", "/e1002-web.png")
CHROME_BIN = os.environ.get("CHROME_BIN", "") # 为空则按常见路径自动探测macOS Google Chrome / google-chrome / chromium
CHROME_EXTRA_ARGS = os.environ.get("CHROME_EXTRA_ARGS", "") # 例如 Linux 以 root 运行需 "--no-sandbox"
# 每通道二值化阈值0~255低于阈值归 0、否则归 255取 160而非 128偏向保留墨迹细笔画的浅灰边不至于被丢成白
HTML_PNG_THRESHOLD = int(os.environ.get("HTML_PNG_THRESHOLD", "160"))
PUSH_TOKEN = os.environ.get("PUSH_TOKEN", "") # 推送鉴权令牌X-Push-Token 头);为空则拒绝一切推送
PUSH_STATE_PATH = os.environ.get("PUSH_STATE_PATH", "") # 推送数据落盘路径(重启后恢复);为空=仅内存
# 本机推送端main.py --target push服务地址含协议与端口不含路径令牌同 PUSH_TOKEN
PUSH_URL = os.environ.get("PUSH_URL", "")
# ---- 资源路径 ----
FONT_PATH = os.path.join(BASE_DIR, "fonts", "fusion-pixel-12px-proportional-zh_hans.otf")
OUTPUT_DIR = os.path.join(BASE_DIR, "output")
OUTPUT_PATH = os.path.join(OUTPUT_DIR, "dashboard.png")
E1002_OUTPUT_DIR = os.path.join(OUTPUT_DIR, "e1002")
E1002_PNG_PATH = os.path.join(E1002_OUTPUT_DIR, "dashboard.png")
E1002_HTML_PATH = os.path.join(E1002_OUTPUT_DIR, "index.html")
# ---- 橘喵 jm-devops 后端(今日经营 / 近30天趋势 数据源)----
# 鉴权方式设备密钥授权grant_type=client_secret免验证码
# 用 CLIENT_ID + CLIENT_SECRET 调 /auth/login 换 token再带 Bearer 调统计接口(详见 jm_api.py
# CLIENT_SECRET 等价于长期凭证,务必走 HTTPS、优先用环境变量覆盖、可在后端 sys_client 轮换。
BASE_API = os.environ.get("JM_BASE_API", "https://admin.jumiaotandian.com/prod-api")
CLIENT_ID = os.environ.get("JM_CLIENT_ID", "")
CLIENT_SECRET = os.environ.get("JM_CLIENT_SECRET", "")
GRANT_TYPE = os.environ.get("JM_GRANT_TYPE", "client_secret")
TENANT_ID = os.environ.get("JM_TENANT_ID", "000000")
# ---- 和风天气QWeather数据源 ----
# 专属 API Host 与 Key 在 https://console.qweather.com/setting 查看,须用环境变量配置;
# 未配置时天气区显示占位 "--",不影响其余渲染与推送。
QWEATHER_HOST = os.environ.get("QWEATHER_HOST", "") # 用户专属 API Host
QWEATHER_KEY = os.environ.get("QWEATHER_KEY", "")
# 定位固定为南京·江宁区。和风经纬度格式为「经度,纬度」
WEATHER_LOCATION = os.environ.get("WEATHER_LOCATION", "118.840,31.953")
WEATHER_LOC_NAME = "南京·江宁"
# 天气缓存:业务数据每分钟刷新,但天气 15 分钟才重新拉一次cron 每次独立进程,缓存须落盘)。
WEATHER_TTL = int(os.environ.get("WEATHER_TTL", "900")) # 秒,默认 900=15 分钟(本机文件缓存与 server.py 内存缓存共用)
WEATHER_CACHE_PATH = os.path.join(BASE_DIR, ".weather_cache.json")
# 近30天趋势缓存recent-days 每天只更新一次,按日期为 key 缓存,当天命中即不再请求。
TREND_CACHE_PATH = os.path.join(BASE_DIR, ".trend_cache.json")
# ---- 比特币 K 线(仅 800x480 宽版底部面板)----
# 免费公开接口无需密钥逐源兜底OKX → Coinbase → Huobi见 btc_api.py。当前为时 K、近 48 小时2 天);
# 每 5 分钟刷新(与 launchd 节律一致,最新一根随实时价推进)。拉取失败沿用旧缓存。缓存文件已在 .gitignore。
BTC_BAR = os.environ.get("BTC_BAR", "1H") # 周期:"1H" 时K / "1D" 日K
BTC_LIMIT = int(os.environ.get("BTC_LIMIT", "48")) # 展示最近 N 根(时 K 默认 48 = 近 2 天2026-09-14 由 72 改 48
BTC_TTL = int(os.environ.get("BTC_TTL", "300")) # 秒,默认 5 分钟(本机文件缓存与 server.py 内存缓存共用)
BTC_CACHE_PATH = os.path.join(BASE_DIR, ".btc_cache.json")
# ---- AI 用量数据源Claude Usage / Codex Usage 两个模块)----
# 形态 A两路都在**本机**采集(需本机的登录态),由 main.py --target push 上报给 server.py服务端不持任何凭证、不读本机文件。
# Claudeclaude_usage.py复用 Claude Code 自身的 OAuth 登录态macOS 钥匙串「Claude Code-credentials」只读、绝不刷新
# 直接调 https://api.anthropic.com/api/oauth/usage——与 Claude Code `/usage` 同源、**账户级**CLI/桌面/网页消耗都算),
# 不依赖 Claude Code 进程在跑、不依赖 statusline 插件。
CLAUDE_USAGE_TTL = int(os.environ.get("CLAUDE_USAGE_TTL", "300")) # 秒,快照有效期(同 WEATHER_TTL 语义0=每次实拉);社区一致建议 ≥300突发调用 429 会封约 24 小时)
CLAUDE_USAGE_BACKOFF = int(os.environ.get("CLAUDE_USAGE_BACKOFF", "1800")) # 秒;拉取失败后的退避期,期内沿用旧快照
CLAUDE_USAGE_SCOPE_MODEL = os.environ.get("CLAUDE_USAGE_SCOPE_MODEL", "Fable") # limits[] 里模型限定周额度按 display_name 识别
CLAUDE_USAGE_SCOPE_FALLBACK_KEY = os.environ.get("CLAUDE_USAGE_SCOPE_FALLBACK_KEY", "seven_day_opus") # 旧版顶层键兜底
CLAUDE_USAGE_UA = os.environ.get("CLAUDE_USAGE_UA", "claude-code/2.1.34")
CLAUDE_USAGE_CACHE_PATH = os.path.join(BASE_DIR, ".claude_usage_cache.json") # 只存快照与时间戳,不存凭证
# Codexcodex_usage.py经官方 `codex app-server` JSON-RPC 读 ChatGPT 订阅的 Codex 额度池CLI/IDE/Web/桌面 App 内 Codex 共用);
# token 刷新由 Codex CLI 代管。需 Codex 以 ChatGPT 账号登录(`codex login`CODEX_USAGE_HOME 留空用默认 ~/.codex
# 也可指向独立 CODEX_HOME 与日常配置隔离。
def _which_codex():
"""launchd 不继承登录 shell 的 PATH无 /opt/homebrew/bin故按 PATH → Homebrew/常见位置解析出绝对路径。"""
import shutil
env = os.environ.get("CODEX_BIN", "")
if env:
return os.path.expanduser(env)
for cand in (shutil.which("codex"), "/opt/homebrew/bin/codex", "/usr/local/bin/codex", os.path.expanduser("~/.npm-global/bin/codex")):
if cand and os.path.exists(cand):
return cand
return "codex"
CODEX_BIN = _which_codex()
# 留空 = 用 Codex 默认目录 ~/.codex2026-09-14 用户直接在默认目录用 ChatGPT 账号登录,故默认跟随之);
# 若日常 Codex 需保持 API Key/中转登录而另开一份 ChatGPT 登录,可设为独立目录(如 ~/.codex-usage并在其下 `CODEX_HOME=… codex login`。
CODEX_USAGE_HOME = os.environ.get("CODEX_USAGE_HOME", "")
CODEX_USAGE_TTL = int(os.environ.get("CODEX_USAGE_TTL", "300")) # 秒快照有效期0=每次实拉)
CODEX_USAGE_BACKOFF = int(os.environ.get("CODEX_USAGE_BACKOFF", "900"))
CODEX_USAGE_CACHE_PATH = os.path.join(BASE_DIR, ".codex_usage_cache.json")
USAGE_WARN = int(os.environ.get("USAGE_WARN", "80")) # 用量 ≥ 此百分比 → 进度条与百分比转红预警(两个版面统一)
# 以下两项仅六色宽版E1002使用三色小屏只有 黑/红 两档。用量与 pace 各自三档、独立取色,颜色顺序固定为 绿 → 黑 → 红
# 黄不用2026-09-14 曾按要求加过 60%80% 黄档,随即被否——黄小字压白底发虚、且四档在三行里过于花):
USAGE_OK = int(os.environ.get("USAGE_OK", "30")) # 用量 ≤ OK 绿「健康」OK~WARN 黑「正常」|≥ WARN 红「危险」;进度条、边框与百分比数字同色
PACE_TOL = int(os.environ.get("PACE_TOL", "10")) # pace=用量%−时间%:≤ TOL 绿「节余」±TOL 内黑「持平」|≥ +TOL 红「偏快」