我是如何在博客上“实时直播”我的手机状态的?
"我在干什么?我还在睡吗?我的手机还有电吗?"
以前,只有 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),并赋予了它们 “使用情况访问权限” 和 “无限制后台运行” 权限。
自动化逻辑
我设置了两个核心触发器:
当应用切换时 (Active):
获取当前 App 名称、电量、WiFi SSID。
发送
POST请求给服务器。
当屏幕关闭时 (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 逻辑,支持页面上同时存在多个侧边栏卡片而不冲突。
最终效果是一个悬浮在侧边栏的“仪表盘”,实时跳动的数据让人感到一种莫名的连接感。
💥 遇到的坑与填坑
CORS 报错:起初博客侧边栏一直报
Failed to fetch,后来发现是浏览器拦截了跨域请求。在 FastAPI 加了 Middleware 后解决。HTTPS 证书:给 API 域名配置 SSL 证书时,一定要申请独立的证书,不能混用主域名的(除非是通配符)。
安卓杀后台:一定要把自动化 App 的省电策略设为“无限制”,并锁定在后台,否则锁屏后发不出“休息中”的信号,导致博客一直显示我在线。
🔚 总结
现在,我的博客不再是一个静态的文字展示柜,它有了生命。它知道我何时醒来,何时入睡,何时在赛博空间里冲浪。
这就是 数字孪生 的魅力。