"我在干什么?我还在睡吗?我的手机还有电吗?"

以前,只有 Steam 好友列表能告诉你我在玩什么游戏。但作为一个极致的数字原住民,我觉得这还不够。我想在我的博客上,实时展示我的全维度数字状态

这就是我的**“数字孪生 (Digital Twin)”** 计划。

现在,只要你看一眼我的博客侧边栏,你就能知道:

  • 📱 我当前正在使用的 App(是 B站摸鱼,还是微信对线?)

  • 🔋 我的手机剩余电量(有没有在充电?)

  • 📶 我连接的 WiFi 名称

  • 💤 我是否已经锁屏睡觉了

下面是我实现这套系统的完整技术复盘。

🏗️ 架构设计:极简主义

为了实现这个功能,我不想引入笨重的数据库或复杂的 Home Assistant。我的需求很简单:手机上报 -> 服务器暂存 -> 网页展示

技术栈选择:

  • 服务端 (大脑):Python + FastAPI (运行在 2核2G 的云服务器上)

  • 移动端 (信使):Android 自动化工具 (Tasker / MacroDroid / AutoCmd)

  • 前端 (颜值):原生 HTML + CSS + JS (手搓赛博朋克风组件)

  • 运维:1Panel 面板 + Nginx 反向代理

🛠️ 第一步:搭建“大脑” (服务端)

服务端的核心逻辑非常简单:它只需要一个“邮箱”,手机往里面扔状态,网页从里面取状态。

我使用了 FastAPI,因为它足够快,且代码极其简洁。

1. 核心代码逻辑

我没有使用数据库,而是直接使用内存变量。为什么?因为“实时状态”不需要持久化,服务器重启了也没关系,反正手机几秒钟后就会上报新的数据。

# main.py 核心逻辑片段
from fastapi import FastAPI, Header
from pydantic import BaseModel

app = FastAPI()

# 内存数据库:存当前的状态
current_data = {
    "app": "等待连接...",
    "battery": 0,
    "locked": True,
    "wifi": "未知",
    "start_ts": 0 # 用于计算持续时间
}

@app.post("/update")
async def update_status(data: PhoneData, token: str = Header(None)):
    # 鉴权:防止坏人乱发数据
    if token != "你的token": return {"msg": "滚粗"}
    
    # 更新内存数据
    current_data.update(data.dict())
    return {"status": "ok"}

@app.get("/status")
async def get_status():
    return current_data

2. 部署与跨域

为了让博客的前端能访问 API,我遇到了经典的 CORS (跨域) 问题。解决办法是在 FastAPI 里加上 CORSMiddleware,允许我的博客域名访问。

最后,利用 1Panel 的反向代理功能,我给接口配置了一个帅气的二级域名:https://api.yourdomain.com

📱 第二步:训练“信使” (手机端)

这是最折腾的一步。安卓系统出于隐私保护,默认是不允许 App 读取“当前前台应用”的。

我使用了自动化软件(如 AutoCmd+ / Tasker),并赋予了它们 “使用情况访问权限”“无限制后台运行” 权限。

自动化逻辑

我设置了两个核心触发器:

  1. 当应用切换时 (Active)

    • 获取当前 App 名称、电量、WiFi SSID。

    • 发送 POST 请求给服务器。

  2. 当屏幕关闭时 (Locked)

    • 发送 POST 请求,将状态标记为 locked: true,App 名称标记为“休息中”。

# 模拟发送的 Shell 命令 (curl)
curl -X POST "[https://api.yourdomain.com/update](https://api.yourdomain.com/update)" \
     -H "token:你的token" \
     -d '{"app": "Bilibili", "battery": 85, "wifi": "5G_WiFi", "locked": false}'

🎨 第三步:赛博朋克风 UI (前端)

数据有了,最后一步是画出来。 为了配合博客的深色模式,我设计了一套 “模块化、半透明、高对比度” 的 UI 组件。

设计亮点:

  • 动态呼吸灯:在线时绿色呼吸,离线时灰色静止。

  • 智能判断:如果没连 WiFi,自动显示 "5G / DATA"。

  • 计时器:JS 本地每秒刷新,显示我“沉迷”在这个 App 里多久了。

  • 多开兼容:重构了 JS 逻辑,支持页面上同时存在多个侧边栏卡片而不冲突。

最终效果是一个悬浮在侧边栏的“仪表盘”,实时跳动的数据让人感到一种莫名的连接感

💥 遇到的坑与填坑

  1. CORS 报错:起初博客侧边栏一直报 Failed to fetch,后来发现是浏览器拦截了跨域请求。在 FastAPI 加了 Middleware 后解决。

  2. HTTPS 证书:给 API 域名配置 SSL 证书时,一定要申请独立的证书,不能混用主域名的(除非是通配符)。

  3. 安卓杀后台:一定要把自动化 App 的省电策略设为“无限制”,并锁定在后台,否则锁屏后发不出“休息中”的信号,导致博客一直显示我在线。

🔚 总结

现在,我的博客不再是一个静态的文字展示柜,它有了生命。它知道我何时醒来,何时入睡,何时在赛博空间里冲浪。

这就是 数字孪生 的魅力。