其他深度

Odoo IoT 为什么不只是“设备连上就行”:标识、动作路由与远程连接令牌链路讲透

很多人以为 Odoo IoT 的核心只是发现设备并发出动作,但从 iot_base 的 longpolling.js、device_controller.js 与 iot_drivers 的 websocket_client.py、helpers.py 看,真正撑起系统的是 identifier、device_identifier、路由端点和远程令牌管理。看懂这条链,IoT 才不会停留在“偶尔能连上”。

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

先说结论

Odoo IoT 真正难的,不是“能不能发现一个设备”,而是:

  • 系统如何知道自己在和哪一个 IoT Box 说话
  • 这台 Box 上具体要操作哪一个设备
  • 指令该走 longpolling、websocket 还是远程连接
  • 远程能力开启后,凭什么保证不是谁都能接进来

/home/ubuntu/odoo-temp/addons/iot_base/static/src/network_utils/longpolling.jsdevice_controller.js/home/ubuntu/odoo-temp/addons/iot_drivers/websocket_client.pytools/helpers.py 来看,Odoo 实际上把 IoT 通信拆成了两层标识:

  • box 级别的 identifier
  • 设备级别的 device_identifier

所以它真正解决的问题不是:

浏览器里点一下按钮,设备动起来。

而是:

一个动作如何跨过浏览器、Odoo、IoT Box 与具体驱动,准确落到目标设备。

第一层:为什么 identifierdevice_identifier 必须分开

在前端 DeviceController 里,实例拿到的典型信息有:

  • iot_ip
  • identifier
  • iot_id

这里的 identifier 其实是设备标识,而 Box 本身还有另一层来自 helpers.get_identifier() 的机器标识。

这两层不能混。

因为一台 IoT Box 往往挂着多个外设:

  • 打印机
  • 扫码枪
  • 显示器
  • 工业按钮或传感器

如果只有 box 级 id,你只能知道“发给这台盒子”,却无法知道“盒子上哪个设备该执行动作”。

所以 Odoo 的标识体系天然是分层的:

  • Box identifier:回答“是哪一台盒子”
  • device_identifier:回答“盒子上的哪一个设备”

第二层:为什么前端动作路由默认走 /iot_drivers/action

longpolling.js 里把动作端点单独定义成:

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

前端调用 action() 时,会明确把:

  • device_identifier
  • data

发到 IoT Box。

这说明 Odoo 没把 IoT 交互设计成“前端直接懂设备协议”,而是统一收口到 Box 的驱动层。

也就是说,浏览器只负责表达:

  • 我要哪个设备
  • 我想做什么动作

至于底层怎么把动作翻译成打印、称重、开抽屉或读信号,是驱动的事。

这种分层特别重要,因为它让业务前端不用感知各种硬件差异,扩展新驱动时也不必重写整套业务界面。

第三层:为什么监听机制是“按设备订阅”,不是“按盒子一锅端”

addListener() 时,longpolling 服务会把监听挂到:

  • 某个 iot_ip
  • 该 ip 下的多个 device_identifier
  • 每个 device 对应自己的 callback

收到轮询结果后,又会按 result.device_identifier 找对应监听器。

这说明 Odoo 监听事件时,粒度并不是“这台盒子有消息”,而是“这台盒子上的哪个设备有消息”。

这对现实硬件场景非常重要。因为一台 Box 上可能同时接着:

  • 一台打印机正在工作
  • 一台秤在持续回传数值
  • 一个按钮在上报触发事件

如果不按设备分发,前端就得自己从混杂事件流里做二次拆包,复杂度会非常高。

第四层:为什么 websocket 也要再次校验盒子身份

websocket_client.py 里,收到消息后第一件事之一,就是检查:

  • 当前 Box 的 helpers.get_identifier()
  • 是否在 payload 的 iot_identifiers 列表里

也就是说,即使消息已经通过 websocket 通道进来了,Box 仍然不会无条件处理,而是先确认:这条消息是不是发给我的。

这是一道很关键的护栏。

因为远程通道一旦建立,真正危险的不是“连不上”,而是“连上了以后消息边界不清”。

Odoo 在这里的思路很明确:

  • 通道是共享机制
  • 处理动作必须按 identifier 精准命中

这样才能避免多盒子环境里发生串话。

第五层:为什么远程连接要单独用 token 开关

helpers.toggle_remote_connection(token="") 的语义很清楚:

  • 有 token,就配置 ngrok authtoken 并重启相关服务
  • 没 token,就停掉远程连接服务

同时还有 genproxytoken.py 负责生成 proxy access token,并把哈希值写入配置。

这说明 Odoo 并没有把“远程可访问”当成默认常驻能力,而是把它设计成:

  • 明确开启
  • 明确持有令牌
  • 明确可关闭

这很合理,因为 IoT Box 往往接的是现实世界设备。打印机、门店外设、工厂终端一旦暴露错误,风险远高于普通网页功能。

所以远程能力必须可审计、可开关、可换 token,而不是配好一次后长期裸奔。

第六层:为什么 devtools 还要能禁掉 longpolling 或指定动作

helpers.py 里还有一层经常被忽略的保护:

  • 可以关闭 longpolling
  • 可以禁用某些 action,甚至全禁

这说明官方在 IoT 设计上并不盲目迷信“只要能发命令就好”,而是承认硬件联调阶段需要更细粒度的保险丝。

这类机制对实施尤其有帮助,因为现场问题常常不是纯软件 bug,而是:

  • 某类动作在当前环境下不该触发
  • 某个驱动正在排障
  • 某个通道需要临时熔断

能在驱动层和工具层设置护栏,比让业务端自己绕开更可靠。

最容易误解的三个点

误区一:IoT 只要知道盒子 IP 就够了

不够。还必须知道具体 device_identifier

误区二:前端直接调用设备就行

不是。前端只表达动作意图,真正执行要收口到驱动路由。

误区三:远程连接打开后就是一直可用的基础能力

也不是。它依赖 token、服务切换和身份校验,应该被谨慎控制。

实战上怎么用最稳

如果你在做 IoT 实施,我建议:

  1. 把 Box 标识和设备标识分开管理,排障时不要混说“identifier”
  2. 任何业务动作先确认最终命中了哪个 device_identifier
  3. 多设备场景重点验证事件回传是否按设备正确分发
  4. 远程连接只在需要时开启,并定期轮换 token
  5. 联调期间善用禁用动作/禁用 longpolling 的护栏,而不是让测试人员硬碰真设备

最后总结

Odoo IoT 真正成熟的地方,不是它能接几种外设,而是它把 盒子身份、设备身份、动作路由、事件分发与远程令牌控制 串成了一条可控通信链。

这让 IoT 不只是“设备能连上”,而是“设备能被准确、安全、可维护地驱动”。

DISCUSSION

评论区

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