kerosix/foobot-local

GitHub: kerosix/foobot-local

在 Foobot 云服务关闭后,通过逆向 MQTT 协议和 DNS 重定向让空气质量监测器完全本地化运行的开源救砖方案。

Stars: 0 | Forks: 0

# foobot-local **在云端服务关闭后,让 Foobot 空气质量监测器重获新生,完全本地化运行——无需账号,无需 App,无需 API token。** [Foobot](https://foobot.io)(由 Airboxlab 生产)的 App 和实时服务依赖于云后端。随着该后端变得不再可靠,这台设备就成了一块“砖头”:它依然在检测环境,但没有任何东西来收集或显示数据。 本项目能让一台原装的 Foobot 将数据汇报给**你自己的机器**而不是云端,并在**本地**解码其读数。一旦设置完成,该设备就不再需要来自 Airboxlab 的任何服务——它只需要你的本地主机保持运行即可。 这里的一切都是**纯 Python 标准库**(零依赖),外加一小段 DNS 配置。已在 Raspberry Pi 上测试通过,但任何常开的 Linux 主机都可以胜任。 ## 工作原理 Foobot 的 Wi-Fi 模块(一块 Hi-Flying **HF-LPB100**)通过**明文 MQTT,TCP 1883 端口,无 TLS** 连接到主机名 `broker-gw-nc.foobot.io`。以下两个事实使得本地接管成为可能: 1. 该模块暴露了一个**远程配置通道**(基于 **UDP 48899** 的 Hi-Flying AT 命令)——因此你可以在笔记本上重定向它,无需连线,无需靠近设备,且随时可以还原。 2. **`WSDNS`** 设置(模块的 DNS 服务器)**在重启后依然保持有效**。将其指向你的主机,并在该主机上运行一个 DNS 服务,把 broker 的主机名解析为你的主机 IP,设备就会连接到**你的** broker。 ``` UDP 48899 (AT commands) MQTT 1883 (plain) your host <─────────────────────── Foobot ───────────────────────> your host set WSDNS = your host (module) broker-gw-nc.foobot.io resolves -> your host (via your DNS) your host: [dnsmasq: broker-gw-nc.foobot.io -> me] + [foobot_service.py: MQTT broker + decoder] │ raw sensor/push ────┘──> decode + allpollu ──> dashboard / Home Assistant ``` 为什么改用 `WSDNS` 而不是直接更改 broker 地址?因为模块在每次重启时都会将其 broker 目标地址(`SOCKB`)重写回云端主机名——这条路由**不会**保留。但 `WSDNS` 会保留。详情见 [`docs/PROTOCOL.md`](docs/PROTOCOL.md)。 ## 包含内容 | 文件 | 作用 | |---|---| | `provision.py` | 在没有 App 的情况下将 Foobot 重新连接到你的 Wi-Fi(从官方 APK 逆向还原)。仅在设备掉线时需要。 | | `scan.sh` / `join.sh` | 辅助工具,用于在配置前查找并连接到 Foobot 的配置模式接入点。 | | `foobot_at.py` | 通过 UDP 48899 远程重新配置模块。读取配置,执行 `--to-local`、`--to-cloud`、`--selftest`(安全的模拟写入)。 | | `foobot_service.py` | 本地服务:一个宽松的 MQTT broker,负责接收设备读数,进行解码,计算污染指数,驱动 LED,并(可选)推送到 Home Assistant。 | | `pollution.py` | 逆向得出的校准公式(原始值 → 实际单位)以及控制圆环颜色的 `allpollu` 污染指数公式。可使用 `python3 pollution.py` 进行自测。 | | `sandbox_test.py` | 使用模拟设备进行端到端测试,无需硬件和网络。 | | `webapp/app.py` | 可选的单页 Web UI,将上述所有功能整合在一起:Wi-Fi 设置、LED 控制以及本地/云端网络切换,并带有实时日志。 | | `config/dnsmasq-foobot.conf` | 唯一的一条 DNS 重写规则:将 `broker-gw-nc.foobot.io` 指向你的主机。 | | `systemd/foobot-local.service` | 将该服务作为 systemd 单元运行。 | | `docs/WIFI.md` | 如何在没有 App 的情况下(通过配置协议)将 Foobot 重新连接到 Wi-Fi。 | | `docs/PROTOCOL.md` | 完整的协议说明:MQTT 主题、校准、LED 行为、AT 通道。 | | `docs/RECOVERY.md` | 将设备重新连接回云端(一条命令),或者在你的主机宕机时进行恢复。 | ## 设置说明 你需要:一台与 Foobot 处于同一局域网且常开的 Linux 主机、Python 3 以及 `dnsmasq`(或者任何允许你添加一条解析记录的 DNS 服务)。 **0 —(仅在 Foobot 未连接到你的 Wi-Fi 时)** 先将其重新连网。由于官方设置 App 已经失效,请使用逆向得出的配置协议——参见 [`docs/WIFI.md`](docs/WIFI.md):`scan.sh` → `join.sh` → `provision.py`。如果设备已经处于你的局域网中,请跳过此步骤。 **1 — 找到你的参数。** Foobot 的局域网 IP(从你的路由器获取),以及你主机的局域网 IP。读取设备当前的配置(安全,只读): ``` FOOBOT_IP=192.168.1.42 python3 foobot_at.py ``` 这会打印出 `WSDNS`、`SOCKB`、`WANN`、SSID 和固件信息。请注意,设备连接后(第 4 步),其 UUID 会显示为 MQTT 的 clientID。 **2 — 将 DNS 指向你的主机。** 编辑 `config/dnsmasq-foobot.conf`,在两处将 `192.168.1.50` 替换为你主机的局域网 IP,然后执行: ``` sudo cp config/dnsmasq-foobot.conf /etc/dnsmasq.d/foobot.conf sudo systemctl restart dnsmasq # 验证它仅重写 broker 并转发其余部分: dig +short broker-gw-nc.foobot.io @127.0.0.1 # -> your host IP dig +short api.foobot.io @127.0.0.1 # -> real cloud IP (still forwarded) ``` **3 — 启动本地服务**(监听 TCP 1883 端口): ``` FOOBOT_UUID= FOOBOT_IP=192.168.1.42 python3 foobot_service.py ``` 如果没有设置 `HA_TOKEN`,它将以 **dry-run**(试运行)模式运行,并仅记录解码后的读数——这是在配置仪表板之前确认整个 pipeline 是否畅通的好方法。请参阅下方的 [Home Assistant](#home-assistant-optional) 以接入真实的传感器。 **4 — 将 Foobot 指向你的主机**(写入 `WSDNS`,重启模块): ``` # 可选但推荐:首先验证写入+重启+还原机制 FOOBOT_IP=192.168.1.42 python3 foobot_at.py --selftest # 使用 local(LOCAL_IP 为自动检测;如需要可使用 LOCAL_IP=... 覆盖) FOOBOT_IP=192.168.1.42 python3 foobot_at.py --to-local ``` 在大约 30 秒内,服务日志会显示 `CONNECT clientID=`,并且每隔大约 5 分钟输出解码后的测量数据。大功告成——这台 Foobot 现在归你管了。 **5 —(可选)将其作为服务运行。** 编辑 `systemd/foobot-local.service` (配置用户、路径、UUID、IP),然后执行: ``` sudo cp systemd/foobot-local.service /etc/systemd/system/ sudo systemctl enable --now foobot-local ``` ## Home Assistant(可选) 该服务可以通过其 REST API 将六个传感器(`sensor.foobot_co2`、`_voc`、`_pm25`、`_temperature`、`_humidity`、`_pollution`)直接推送到 Home Assistant 中——无需集成 MQTT。只需创建一个长期有效的 token 并执行: ``` FOOBOT_UUID= FOOBOT_IP= \ HA_URL=http://127.0.0.1:8123 HA_TOKEN= \ python3 foobot_service.py ``` `foobot_pollution` 传感器带有 `band`、`ring_color` 和 `source` 属性。 ## LED 控制(可选) 一旦设备连接到你的 broker,你就可以通过在服务旁边的 `inject` 文件中追加 `topic|payload` 行来控制圆环: ``` echo 'device//attribute/brightness|{"brightness":0}' >> inject # off ``` 重新**开启**圆环需要重启模块(`foobot_at.py`,`AT+Z`)——如果圆环已关闭,仅调整亮度是无法让其重新亮起的。`foobot_service.py` 中内置的夜间计划任务(`LED_OFF_H`/`LED_ON_H`,或者支持热重载的 `led_config.json`)正是利用了这一点。详细说明见 [`docs/PROTOCOL.md`](docs/PROTOCOL.md)。 ## Web 界面(可选,最后一步) 如果你不想使用命令行,`webapp/app.py` 提供了一个单页面(默认地址为 `http://:8099`),它将上述所有功能与实时日志整合在一起: - **状态** — Foobot 是否已出现在局域网中(通过其 MAC 地址识别)。 - **Wi-Fi 设置** — 扫描设备的配置模式 AP,并推送你的家庭 Wi-Fi(执行 `provision.py` 流程,无需 CLI)。 - **LED 圆环** — 开启(需重启)/ 关闭 / 亮度调节,以及夜间计划任务编辑器。 - **网络模式** — 一键在本地主机和云端之间切换设备(很实用:在关闭你的主机之前,可以先将其切换回云端)。 完全基于标准库。在执行 Wi-Fi 步骤时,它会通过 shell 调用 `nmcli`/`rfkill`,因此请使用提供的 systemd 单元运行它,并为这两个命令配置免密码 sudo: ``` # 首先在 unit 中配置设备 MAC/IP/UUID sudo cp webapp/foobot-web.service /etc/systemd/system/ sudo systemctl enable --now foobot-web ``` 配置通过环境变量进行(`FOOBOT_MAC`、`FOOBOT_IP`、`FOOBOT_UUID`、`HOME_SSID`、`LOCAL_IP`、`FOOBOT_DIR`);详情请参阅 `webapp/app.py` 顶部的说明。Wi-Fi 密码绝不会存储或记录在日志中。它会复用 `foobot_at.py` 和服务的 `inject` / `led_config.json` 文件,因此请将其与仓库的其他部分放在一起。 ## 还原 只需一条命令,可以从局域网内的任何一台机器执行——参见 [`docs/RECOVERY.md`](docs/RECOVERY.md): ``` FOOBOT_IP= python3 foobot_at.py --to-cloud ``` 因为重定向逻辑保存在设备内部(而不是你的服务器上),所以即使你的主机已经报废,还原操作依然有效。AT 通道绝对不会触碰 Wi-Fi,因此模块在整个过程中都能保持连接。 ## 注意事项与说明 - **校准是因设备而异的。** `pollution.py` 中的常量是从某一台设备中逆向得出的,在与云端数据对比时误差在约 2.5 个点以内。如果你的设备读数有偏差,请根据你自己的原始值/参考值对重新拟合 `PM_DIVISOR` 和 `allpollu` 系数。 - **确切的圆环颜色**是由设备根据其通过 `attribute/thresholds` 接收到的阈值在本地计算得出的(此处未进行抓包拦截);本项目虽然为你的仪表板计算了污染指数,但无法百分百复现设备上的颜色。 - **你的主机将成为 Foobot 的依赖项。** 一旦 `WSDNS` 指向了它,设备就需要该主机保持运行才能连接到 broker。请为其分配一个固定的 IP;主机故障的处理请参阅 `RECOVERY.md`。 - **请勿向** `ota`/`mcuota`/`reboot`/`failsafe` 主题发布消息——参见 `docs/PROTOCOL.md`。 ## 免责声明 本项目基于对自有硬件的观察进行逆向工程,目的在于实现互操作性和设备维修。与 Airboxlab/Foobot 没有任何关联或认可。`Foobot` 是其所有者的商标。使用风险自负;你需要对自己的网络和设备负责。 ## 许可证 MIT — 详见 [LICENSE](LICENSE)。
标签:DNS劫持, Python, 命令控制, 数据采集, 无后门, 智能家居, 本地化部署, 物联网, 逆向工具