先说结论
Odoo IoT Box 的网络设计重点,不是“尽量一直在线”,而是一旦掉线,设备还能重新被人接管。
这也是为什么 addons/iot_drivers/tools/wifi.py 里最关键的逻辑,不是驱动发现,而是:
- 怎么识别当前网络状态
- 怎么尝试恢复旧连接
- 失败后什么时候切回热点模式
- 怎么把重新接入这件事尽量降低门槛
换句话说,IoT Box 最核心的生存能力不是“联网”,而是“掉网后还能重新入网”。
第一层:为什么 get_available_ssids() 会在必要时重载 NetworkManager
get_available_ssids() 并不是简单跑一次 nmcli 就结束。
它先调用 _scan_network(),如果发现结果异常到只剩“当前已连接网络”这一种,就会尝试 _reload_network_manager() 再扫一次。
这说明官方很清楚:现场网络问题不一定真是 Wi‑Fi 没了,有时候只是 NetworkManager 自己状态不可靠。
所以 Odoo 的思路不是一上来就让用户重启盒子,而是先把网络管理服务本身当成可恢复对象。
第二层:为什么 reconnect() 先等 10 秒,不急着抢连 Wi‑Fi
reconnect() 开头有一段容易被忽略的逻辑:在不是 force_update 的情况下,它会先等最多 10 秒,看设备是否已经拿到 IP。
这背后的判断很成熟:
- 设备刚启动时,网络栈可能还没稳定
- 有线网也可能已经可用
- 如果此时立刻重连 Wi‑Fi,反而可能把现有正常网络打断
所以 Odoo 先问的是:我是不是已经有可用网络了?
如果已经有 IP,而且当前还处在 AP 模式,系统甚至会顺手把 AP 关掉,避免设备同时暴露不必要的热点入口。
第三层:为什么没有 SSID 时直接回 AP,而不是报失败
reconnect() 如果拿不到目标 ssid,并不会抛一个“无法连接”的错误就完事,而是直接 toggle_access_point(START)。
这个选择非常关键。
因为对现场部署来说,最糟糕的状态不是“暂时没网”,而是“没人能重新配网”。
只要热点还能起来,部署人员就还能:
- 连接到 IoT Box 自身
- 打开本地管理页
- 重新输入 Wi‑Fi 配置
- 继续做后续配对
所以 AP 模式本质上是 IoT Box 的自救入口。
第四层:为什么 _connect() 要先关 AP,再尝试持久化配置
_connect() 会先检查两个前提:
- 目标 SSID 是否真的在可见网络列表里
- 能否成功停掉 AP 模式
只有这样才会继续执行 nmcli device wifi connect。
连接成功后,它还会调用 _validate_configuration(),把网络配置同步到 /root_bypass_ramdisks。
这个细节非常 Odoo IoT:
- 临时连上网还不够
- 关键是重启之后还能自动回来
官方注释也说得很明确:IoT Box 的根文件系统里有些内容重启会丢,所以必须把网络配置额外落到保留区域。
这就是“现场恢复”和“重启后持续可用”之间的区别。
第五层:为什么失败时是否回 AP,要看原来有没有退路
reconnect() 里还有个很精细的变量:should_start_access_point_on_failure。
它不是一刀切地说“失败就开热点”,而是根据当前状态判断:
- 如果原本就在 AP 模式,失败后当然应该继续回 AP
- 如果当前没有任何 IP,也该回 AP
- 但如果还有别的网络通路,未必需要强行开热点
这种判断避免了两种坏结果:
- 完全失联
- 不必要地暴露热点接口
这是典型的运维思维,而不是单纯的开发思维。
第六层:为什么二维码生成属于网络恢复链的一部分
get_qr_data_for_wifi() 和 generate_network_qr_codes() 看起来像 UI 小功能,其实它们属于恢复链的重要一环。
逻辑很直接:
- 如果当前在 AP 模式,就生成 IoT Box 热点的二维码
- 如果已经配置了 Wi‑Fi,就生成目标 Wi‑Fi 的二维码
- 同时再生成一个本地管理页 URL 的二维码
这等于把“找盒子、连盒子、打开盒子”三件事用最少输入动作串起来。
在仓库、门店、展会这种现场环境里,这比让运维手打 SSID、密码和 IP 地址稳定得多。
第七层:为什么 disconnect() 也会顺手开 AP
disconnect() 并不是简单地断掉当前网络。
它在断开后会检查 get_ip(),如果设备已经没有网络入口,就会切回 AP。
这说明在 IoT Box 的世界里,“主动断网”也必须保留回退路径。
否则你今天点了断开,明天可能连设备在哪个网段都找不到。
实战部署最容易踩的坑
1. 只验证连接成功,不验证配置持久化
如果 _validate_configuration() 没做好,设备可能这次连上、下次重启就失联。
2. 把 AP 模式当成异常状态
实际上它是恢复链的重要保底,不是简单的失败标志。
3. 忽略已有有线网络
reconnect() 明确会先观察是否已有 IP,说明 Wi‑Fi 恢复不应该破坏已有可用网络。
4. 现场只给文字说明,不给二维码入口
现场环境里,二维码往往比文档步骤更可靠。
结论
Odoo IoT Box 的网络逻辑真正聪明的地方,不是连接 Wi‑Fi 这件事本身,而是它把“恢复接入能力”摆在了第一优先级。
所以理解这块源码时,最值得盯住的不是某个驱动,而是这条容错链:
get_available_ssids():尽量拿到可信网络视图reconnect():优先复用现有连通性_connect():建立连接并落地持久配置toggle_access_point():兜底恢复可接入入口generate_network_qr_codes():降低重新入网门槛
这也是为什么真正稳定的 IoT 部署,靠的从来不只是“第一次配成功”,而是“出问题后还回得来”。
DISCUSSION
评论区