其他深度

Odoo IoT 为什么不只是“连上打印机”:Longpolling、WebSocket 与设备驱动分发链路讲透

很多人以为 Odoo IoT 就是把打印机或扫码枪接进系统,但源码里的 longpolling、websocket_client 和 interface 说明它其实是一条双向设备控制链。看懂这条链,才能真正理解 Odoo 为什么能把前端动作落到现场硬件上。

其他
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

Odoo IoT 的本质,不是“把外设接到 Odoo 上”,而是建立一条浏览器、Odoo 服务器、IoT Box、设备驱动之间的双向控制链。

/home/ubuntu/odoo-temp/addons/iot_base/static/src/network_utils/longpolling.jsaddons/iot_drivers/websocket_client.pyaddons/iot_drivers/interface.py 来看,官方把两种通信方向拆得很清楚:

  • 浏览器 / 前端 → IoT Box:主要通过 longpolling / HTTP action
  • Odoo 服务器 → IoT Box:主要通过 WebSocket 下发远程消息
  • IoT Box → 本地设备:通过 interface 检测设备,再分配给具体 driver

所以它真正解决的问题不是“设备在线没有”,而是:

一个前台动作如何跨过网络与盒子,最终变成某个具体硬件驱动上的执行动作,并把结果再带回来。


第一层:为什么前端侧用的是 Longpolling,而不是只发一次 HTTP

IoTLongpolling 这个类名称已经很说明问题。

它有两条固定路由:

  • actionRoute = '/iot_drivers/action'
  • pollRoute = '/iot_drivers/event'

同时维护:

  • _session_id
  • _listeners
  • last_event
  • abortController
  • 重试延迟和退避逻辑

这表示浏览器和 IoT Box 的关系不是“按一次按钮发一次请求”这么简单。

前端除了发 action,还要持续维持一个监听关系,接收设备事件返回。

这很重要,因为硬件交互不是纯同步世界:

  • 扫码枪什么时候扫到码,不由前端控制
  • 打印机执行结果可能要稍后返回
  • 秤、屏幕、脚踏板这类设备会不断产生事件流

如果只靠单次 RPC,浏览器根本没法建立稳定的设备事件通道。

所以 longpolling 在这里承担的其实是:

把 Web 界面的请求-响应世界,拓展成“可等待设备事件”的半实时通道。


第二层:监听器为什么要按 iot_ip 和 device_identifier 分层

addListener(iot_ip, devices, listener_id, callback, fallback) 会把监听关系挂到:

  • 某个 IoT Box IP
  • 其下若干 device_identifier

每个设备还有自己的 callback。

这套结构特别关键,因为一个 IoT Box 往往不只接一个设备:

  • 打印机
  • 扫码枪
  • 客显
  • 电子秤
  • 键盘类输入设备

如果监听不按设备标识拆开,返回事件一多,前端根本不知道该把哪条结果交给哪个组件。

而源码里每个 listener 既保存 session,又保存 device map,本质上是在做一个轻量设备事件路由表。

这也是为什么 _onSuccess() 里会根据 result.device_identifier 去调用对应 callback——

Odoo IoT 不是只在“连通性”层面集成设备,而是在“事件语义”层面集成设备。


第三层:为什么要同时保留 Longpolling 和 WebSocket 两条链

很多人会问:既然已经有 longpolling,为什么 IoT Box 侧还要跑一个 WebsocketClient

答案是它们服务的方向不同。

Longpolling 更偏前端与盒子的局部交互

比如:

  • 浏览器组件监听扫码事件
  • 前端向某设备发 action
  • 页面维持和本地盒子的短链路

WebSocket 更偏服务器与盒子的远程控制

websocket_client.py 里,IoT Box 连接到 Odoo 服务端的 websocket 通道,并订阅自身 channel。 收到消息后会处理:

  • iot_action
  • server_clear
  • server_update
  • restart_odoo
  • webrtc_offer
  • remote_debug
  • test_connection
  • bundle_changed

这说明 WebSocket 的角色更像“远程控制总线”。

也就是说,前端 longpolling 解决的是“当前页面如何和盒子对话”; 而服务端 websocket 解决的是“数据库如何远程管理和调度这台盒子”。

这两条链互补,而不是重复。


第四层:设备动作为什么最终都要落到 driver 上

在 WebSocket 的 on_message() 里,处理 iot_action 时会:

  • 遍历 device_identifiers
  • 判断 device_identifier 是否在 main.iot_devices
  • 找到后执行 main.iot_devices[device_identifier].action(payload)

这一步特别重要。

它说明 IoT Box 并不是直接“认识打印机、认识扫码枪”,而是先把设备抽象成 driver 对象,再把动作交给 driver 执行。

这就带来三个好处:

1. 设备接入与设备动作解耦

只要 driver 实现统一 action 协议,前端和服务端就不必关心底层硬件细节。

2. 多设备类型可以共存

不同驱动只要都注册进 iot_devices,消息分发路径就统一了。

3. 未连接设备可以被明确回报

如果找不到对应 device_identifier,源码会回传 status = disconnected,而不是默默失败。

这类失败显式化,对现场运维特别关键。


第五层:Interface 为什么是 IoT 体系里最容易被忽略的一层

interface.py 展示了 IoT Box 如何把“物理世界”接进软件世界。

每个 Interface:

  • 带一个 connection_type
  • 周期性 get_devices()
  • 跟踪 _detected_devices
  • 根据支持的 driver 自动 add_device()
  • 消失时 remove_device()

add_device() 并不是见到设备就接入,而是:

  1. 根据 connection type 过滤可用 driver
  2. 找到第一个 supported(device) 为真的 driver
  3. 用它实例化真正的设备对象
  4. 放入 iot_devices
  5. 启动设备线程

这说明 Interface 做的不是业务动作,而是设备发现与驱动匹配

很多人会把 IoT 理解成“写几个控制接口”,但如果没有 Interface 这一层:

  • 新设备插上来不会被发现
  • 同一连接类型下无法自动挑选驱动
  • 断连事件不能及时清理

所以从架构上看,Interface 更像硬件即插即用的入口。


第六层:为什么系统要认真处理失败、超时和重连

无论 longpolling 还是 websocket,源码里都花了不少篇幅处理异常:

Longpolling 侧

  • 失败会 _doWarnFail() 弹通知
  • timeout 时会指数退避式重启 polling
  • AbortController 用于及时取消监听

WebSocket 侧

  • 记录 last_message_id
  • 断开后持久化消息位置
  • run_forever(reconnect=10) 持续重连
  • 启动初期对旧 server_clear 做防抖处理

这说明官方非常清楚:

IoT 集成最真实的敌人不是功能缺失,而是网络不稳定、设备断连和时序错位。

所以能不能稳定重连、能不能避免重复消息、能不能清楚提示失败,和“能不能打印”一样重要。


第七层:为什么 IoT 不是“浏览器直连设备”

longpolling.js 里其实已经透露了一个现实:浏览器只是在和 IoT Box 的 HTTP 接口对话。 真正复杂的设备世界被挡在盒子后面。

这样做的好处很明显:

  • 浏览器不需要直接访问 USB / 串口 / 本地驱动
  • 设备兼容性问题集中到 IoT Box 处理
  • Odoo 服务端也能通过 websocket 和盒子做远程协同

于是整个体系被拆成了三层边界:

  1. 浏览器:界面与业务动作发起者
  2. IoT Box:本地设备代理与驱动宿主
  3. Odoo Server:远程控制、配置与状态协调中心

这才是 Odoo IoT 能在复杂现场环境里落地的根本原因。


最容易误解的三个点

误区一:IoT 就是把设备 IP 填进系统

错。核心不在登记地址,而在事件监听、动作分发、驱动执行和失败反馈。

误区二:Longpolling 和 WebSocket 二选一

也不对。它们分工不同,分别解决前端监听与服务端远控。

误区三:驱动只是实现细节,不重要

恰恰相反。没有 driver / interface 分层,所有设备集成都会退化成不可维护的硬编码。


最后一句话

Odoo IoT 真正厉害的地方,不是“能连打印机”,而是它把页面动作、网络消息、盒子代理和设备驱动串成了一条完整控制链。

所以理解它最好的方式不是“硬件接入插件”,而是:

它是一套让 Odoo 业务动作落地到真实设备世界的中间层。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。