embedded-host-platform

07 PC 自己兼任网关

问题

要加一个 Android 客户端,让手机也能看实时数据、报警、历史,能问问题、能控制风扇。 设备通过串口接在 PC 上。

选项

方案 取舍
手机直连设备(USB OTG 或蓝牙) 手机要重新实现一遍串口、拼帧、协议、报警、统计。两份实现迟早不一致;而且串口是独占的,手机和电脑不能同时连
独立的网关服务进程 标准做法,可伸缩;但 PC 上位机已经实现了设备管理、数据处理、报警、控制的全部职责,另起一个进程只是把它们再搬一遍
PC 上位机进程内加一层网络接口 一台 PC 加几台手机的规模不需要网关与客户端分离的伸缩性;局域网内也不需要公网服务器

决定

网关是 PC 上位机的又一个呈现端,与桌面界面平级,同样只经 api.ApiInterface 访问系统:

                 ┌─► ui       (转成 Qt 信号,给桌面界面)
api.ApiInterface ┤
                 └─► gateway  (转成 HTTP 响应与 WebSocket 消息,给手机和浏览器)

每个端点都是某个已有 ApiInterface 方法的直译,网关里不写业务逻辑。

几处细节

同步回调到异步推送的桥。 数据回调是同步的,跑在采集线程上;WebSocket 发送是异步的。 EventHub 用 call_soon_threadsafe 把消息投递到事件循环,再扇出给每个客户端:

问答分两段。 REST 立即返回模板答案(毫秒级),模型改写好之后(数秒)经 WebSocket 补送替换。 如果让请求挂着等模型,没接模型的部署也会变慢,手机端一旦超时就什么都拿不到。分成两段之后, 只调 REST 的客户端总能拿到正确答案,接了 WebSocket 的多收一条更自然的版本。

串口只有一个。 桌面界面和网关要同时看数据,只能在一个进程里同时承载两者(run_all.py), 数据只解码一次,再扇出给两边——不能起两个程序去抢同一个 COM 口。

向后兼容靠”只增不改”。 后来为浏览器控制台加的接口与消息类型,REST 只增字段、WebSocket 只增类型。 Android 的消息解析器对不认识的类型返回”未知”并忽略,旧版 App 不受影响。

结果

代价与没做的