芳莲芳莲

文档 / 平台设计

顶层设计与技术架构

系统全景、TDengine 数据库、服务器与部署拓扑、命名规范、鉴权体系与 API 一览。

系统全景

 ┌─────────────┐   HTTPS 事件/心跳    ┌──────────────────────────────┐
 │  ESP32 Hub  │ ───────────────────▶ │            服务器             │
 │ 磁吸/压力/按钮│ ◀──── BLE 配网 ──── │  Nginx                       │
 └─────────────┘                      │   ├─ /fanglian        → 后端 API │
        ▲                             │   └─ /fanglian-admin  → Web 管理台│
        │ 蓝牙下发 Wi-Fi               │                              │
        │                             │  后端 API(PM2 fanglian-backend)│
 ┌─────────────┐   REST / JWT         │   ├─ TDengine(时序事件库)      │
 │  微信小程序  │ ───────────────────▶ │   └─ metadata.json(业务元数据) │
 └─────────────┘                      └─────────────┬────────────────┘
        ▲ 微信服务通知(订阅消息)                     │
        └────────────────────────────────────────────┘

一次典型事件链路:传感器触发 → Hub 立即 HTTPS 上报 → 后端写入 TDengine 并按订阅偏好推送微信服务通知 → 小程序时间线与 Web 管理台实时可查。Hub 每 60 秒一次心跳,用于判断在线/离线。

四端清单

技术栈 代码目录 关键说明
ESP32 Hub Arduino / PlatformIO firmware/esp32 三种开发板环境,详见固件与烧录
云端后端 Next.js App Router API backend 设备认证、事件入库、微信登录、订阅与亲友卡
数据库 TDengine 3.x database/01_init.sql 时序事件存储,REST 接口 6041
微信小程序 Taro + React miniprogram 用户端全部体验入口
Web 管理台 Next.js 16 + Tailwind 4 web basePath=/fanglian-admin,页面说明见使用手册

数据库:TDengine

时序事件全部存入 TDengine,初始化脚本为 database/01_init.sqltaos -f 执行):

CREATE DATABASE IF NOT EXISTS elder_guard KEEP 365 DURATION 1;
USE elder_guard;

CREATE STABLE IF NOT EXISTS sensor_events (
  ts TIMESTAMP, `event_type` VARCHAR(64), `value` DOUBLE
) TAGS (hub_id VARCHAR(64), sensor_id VARCHAR(64), sensor_type VARCHAR(64));

设计要点:

  • elder_guard 库保留 365 天数据,按天切分存储文件,贴合 IoT 时序负载。
  • 所有事件共用一张超级表 sensor_events,子表以 ${hub_id}_${sensor_id} 命名、首次写入时自动创建,无需预建。
  • event_typevalue 是 TDengine 保留字,SQL 中必须用反引号包裹。
  • 后端通过 REST 接口(默认 http://localhost:6041)读写,事件查询一律 ORDER BY ts DESC,最新在前。

业务元数据持久化

设备、用户、绑定、激活码、亲友卡等业务元数据不放在 TDengine,而是持久化在服务器目录 /var/www/fanglian/data/

文件 内容
fanglian_metadata.json 用户、家庭组、绑定关系、设备白名单(含配对码)、激活码、亲友卡
last-seen 数据 各 Hub 最近上报时间,用于在线状态判断

后端运行时有内存缓存:直接改文件必须 pm2 restart fanglian-backend 才生效;通过 API 操作会自动刷新缓存并落盘。该目录务必避免被部署流程清空。

服务器与部署拓扑

生产环境单机部署,Nginx 统一入口 https://yeezytb.com

路径 指向 进程
/fanglian 后端 API PM2 fanglian-backend
/fanglian-admin Web 管理台 PM2 fanglian-web

部署纪律(都是踩过的坑):

  • Web 端必须在服务器上构建:本地构建会把 NEXT_PUBLIC_API_BASE_URL 固化成 localhost,线上请求全部失败。
  • rsync 同步必须排除环境文件:Web 端排除 .env.local,后端排除 .env.env.local,否则 --delete 会删掉生产配置。
  • 服务器上构建用 nohup npm run build & 后台执行,再 pm2 restart,避免 SSH 长连接被断。
  • 完整步骤见 dev-logs/web-deploy-guide.mdscripts/deploy-web.sh

命名与标识规范

对象 格式 示例
家庭组 ID fl_hh_<6位随机> fl_hh_x7k9p2
Hub ID fl_<类型缩写>_<6位随机> fl_reed_a3m8n1fl_fsr_b2k4p7
传感器 ID 固定语义名 reed_01fsr_01button_01
激活码 fl_sub_… 月卡 30 天 / 年卡 365 天
亲友卡邀请 fl_gc_… 微信分享卡片携带 token

自定义名(用户称呼、家庭组名、设备名)不超过 6 个字符;Web 端优先显示自定义名,系统 ID 以灰色小字随行展示。

鉴权体系

调用方 凭据 说明
设备 → 后端 请求头 X-Hub-ID + X-Hub-Token token 在设备自激活时签发,存入 NVS
小程序 → 后端 Authorization: Bearer <JWT> wx.login 换 openid 后签发,默认 7 天
Web 管理接口 admin JWT + X-Admin-Secret 双重校验;ADMIN_SECRET 未配置时管理接口返回 503

后端 .envSUBSCRIPTION_REQUIRED=false 可关闭全部订阅校验(开源自部署模式):事件照常写入,查询接口恒返回会员有效,小程序不显示续费引导。

API 一览

baseURL:https://yeezytb.com/fanglian

设备侧

方法 路径 说明
POST /api/v1/devices/activate 设备自激活,签发 hub_token 与配对码
POST /api/v1/events 写入传感器事件 / 心跳

用户侧(小程序)

方法 路径 说明
POST /api/v1/auth/wechat 微信登录,返回 JWT
GET /api/v1/me 我的设备、家庭组与会员状态
POST /api/v1/me/activate 激活码开通/续费会员
POST /api/v1/me/name · /api/v1/households/name · /api/v1/devices/name 自定义命名
POST /api/v1/devices/bind 配对码绑定(支持 preview);DELETE 解绑
GET /api/v1/today · /api/v1/timeline 今日守护状态 / 事件时间线
GET/POST /api/v1/subscriptions 按 Hub 查询与设置订阅通知
POST/GET/DELETE /api/v1/me/cards 亲友卡创建、列表、撤回
GET/POST /api/v1/me/cards/invite · /api/v1/me/cards/accept 亲友卡预览与接受

管理侧(Web)

方法 路径 说明
POST /api/v1/auth/admin 管理员登录
GET /api/v1/admin/devices 全量 Hub 状态
GET /api/v1/admin/whitelist 设备白名单(含配对码)
GET /api/v1/admin/users 注册用户与绑定关系
POST/GET /api/v1/admin/subscription-codes 生成 / 列出激活码
POST /api/v1/admin/subscription-codes/extend · /revoke 会员延期 / 撤销