开发者调试页:在没有真实配 WiFi 的 CM4 的情况下直连当前区域的 CulinaTech 自建 Mosquitto broker,连接写死的设备 ID CM4_A322,并订阅该设备的两个 MQTT topic:/CM4/CM4_A322/data 与 /CM4/CM4_A322/sett;页面可手动发 4 个测试命令(SET_RD / SET_F / SET_C / VER),实时查看 MQTT log 流。
lib/features/thermometer/presentation/pages/mqtt_test_page.dart(319 行)regionServiceProvider(MqttService 为页面内直接实例化,无全局 Provider)MqttService.connect / disconnect / sendCommand / logStream / connectionStateStream补充:设置页里的这个入口不是始终显示。代码先读取 devModeEnabledProvider(回退到 DevLogService.instance.enabled),只有 devModeEnabled 为 true 时才渲染 Developer 区及 '/mqtt-test' 入口;普通用户默认可能看不到此入口。
/mqtt-test(MqttTestPage.routeName)lib/app.dart 静态 routes map「终端调试器」风格:黑色背景,AppBar 标题左边一个连接状态色圆点(绿/橙/红)+ "MQTT Debug" 文字(Courier 字体绿色)。下方一个连接信息 banner,内部有两行文字:第一行显示 broker 地址(host:port,引自 region service),第二行显示设备 ID 与状态。再下方是一组 5 个胶囊按钮(Connect/Disconnect / SET_RD / SET_F / SET_C / VER),使用 Wrap 排列,窄屏时可换行;未连接时除 Connect 外都置灰。下方区域在 _logs 为空时先显示居中的 Tap Connect to start... 占位文案;有日志后才渲染占满剩余空间的 ListView.builder。:每条带颜色编码(红=错误、绿=包含 "Connected" 或 "Success" 的日志、青=接收、橙=发布、浅绿=订阅、浅白(Colors.white70)=其他)。AppBar 右上有 🗑 清空 log 按钮。
补充:页面退出时除了 Navigator.pop(context) 之外,还会在 dispose() 中取消 _logSub、_stateSub 两个订阅,并调用 _mqtt.dispose() 主动销毁这个调试页独占的 MqttService,从而关闭它自己的 broker session。
Navigator.pop(context)IconButton.onPressed: _clearLog_logs 列表 + 清空 MqttService.logHistory_logs 和 MqttService.logHistory,但 _clearLog() 本身没有额外的 banner 重置逻辑,也没有主动重置 scroll。当 _connState 处于 connecting 或 reconnecting 时,这个位置的按钮不会显示文字,而是显示一个 14x14 的 CircularProgressIndicator;同时按钮 onPressed 为 null。
_ActionButton.onPressed,isConnecting 时禁用onPressed → _connect()
→ final region = ref.read(regionServiceProvider)
→ _mqtt.connect(_testDeviceId='CM4_A322', serverConfig: region.config)
→ 触发 mqtt 客户端 TLS 握手 → 订阅 device topic → emit 状态流
onPressed → _disconnect() → _mqtt.disconnect()
MqttService()(不走 CloudConnectionRegistry):本页 dev tool 调试盒 CM4_A322 单独取一个 MqttService 实例 + 独立 clientId,不影响正常 App 流(每个绑定 CM4 各自一份 MqttService 与 broker session);先前共享单例时同 clientId 三个并发 connect 会被 broker 按 MQTT 3.1.4 互踢出独占(field log 单 session 2181 次 autoReconnect 暴风)现已根除_ActionButton,分别 onPressed: () => _publishTest('SET_RD' / 'SET_F' / 'SET_C' / 'VER')onPressed → _publishTest(command)
→ _mqtt.sendCommand(_testDeviceId, command)
→ MQTT publish → broker → 设备
→ 设备回应;若 `MqttService` 将事件写入 `logStream`,本页会在 log 中显示相关日志。本页代码未直接监听 `telemetryStream`。
initState 拉一次 _mqtt.logHistory 当快照填入 _logs;订阅 _mqtt.logStream + _mqtt.connectionStateStream 持续更新本地 state,每来新 entry 调 _scrollToBottom 自动滚到底部。
不直接 ref.watch —— 因为 MqttService 的 stream 不是 Riverpod Provider 形态,本页用原生 StreamSubscription。regionServiceProvider 通过 ref.read 取实例(MqttService 为页面内直接实例化)。
无显著差异。broker 地址和端口来自 regionServiceProvider 的 region.config;本页代码并未把端口写死为 8883。
_testDeviceId 硬编码 'CM4_A322':仅当真有这个设备 ID 时测试才有意义;其他情况 publish 命令会发到无人订阅的 topic,看不到回应。改设备测试时必须改源码。MqttService()(不走 per-device CloudConnectionRegistry),从而获得独立 MqttService + 独立 clientId,不再串扰正常流。_logColor 启发式:根据 message 里的关键词判定颜色("Connected" / "Received" / "Published")。文案变化会让颜色失效。