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, 命令控制, 数据采集, 无后门, 智能家居, 本地化部署, 物联网, 逆向工具