绑定设备+覆盖模式+控制显示bug+在线更新
This commit is contained in:
@@ -7,10 +7,12 @@ import 'package:maibu_satabot_v2/features/devices/domain/entities/running_status
|
||||
import 'package:maibu_satabot_v2/features/devices/domain/entities/gps_entity.dart';
|
||||
import 'package:maibu_satabot_v2/core/network/protocol_decoder.dart';
|
||||
import 'package:maibu_satabot_v2/core/network/mqtt/domain/repositories/task_message_repository.dart';
|
||||
import 'package:maibu_satabot_v2/core/network/mqtt/domain/repositories/mower_realtime_repository.dart';
|
||||
import 'package:maibu_satabot_v2/core/network/mqtt/domain/entities/task_arrive_entity.dart';
|
||||
import 'package:maibu_satabot_v2/core/network/mqtt/domain/entities/task_status_entity.dart';
|
||||
|
||||
import '../../../../core/logging/i_logger_service.dart';
|
||||
import '../../../../core/logging/log_time.dart';
|
||||
import '../../../../core/network/net_message_dispatcher.dart';
|
||||
import '../../../../core/network/tcp/tcp_client.dart';
|
||||
import 'device_status_event.dart';
|
||||
@@ -20,6 +22,10 @@ import 'devices_cubit.dart';
|
||||
// 定义全局的TaskMessageRepository获取方式
|
||||
TaskMessageRepository get _taskMessageRepo => GetIt.I<TaskMessageRepository>();
|
||||
|
||||
// 🔥 MQTT机器状态数据源(替代TCP 0x02)
|
||||
MowerRealtimeRepository get _mowerRealtimeRepo =>
|
||||
GetIt.I<MowerRealtimeRepository>();
|
||||
|
||||
class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
||||
final NetMessageDispatcher _dispatcher;
|
||||
final TcpClient tcpClient; // 🔥 新增:直接访问 TcpClient
|
||||
@@ -30,6 +36,10 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
||||
StreamSubscription? _mqttArriveSubscription;
|
||||
StreamSubscription? _mqttStatusSubscription;
|
||||
|
||||
// 🔥 MQTT机器状态订阅(车辆实时+定位,替代TCP 0x02)
|
||||
StreamSubscription? _mqttVehicleSubscription;
|
||||
StreamSubscription? _mqttLocationSubscription;
|
||||
|
||||
// 🔥 节流相关:500ms节流控制0x02数据推送频率
|
||||
Timer? _throttleTimer;
|
||||
static const _throttleDuration = Duration(milliseconds: 500);
|
||||
@@ -42,11 +52,17 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
||||
// 🔥 当前监听的设备ID
|
||||
String? _currentDeviceId;
|
||||
|
||||
// 🔥 MQTT机器状态收帧计数(用于链路日志)
|
||||
int _mqttVehicleFrameCount = 0;
|
||||
int _mqttLocationFrameCount = 0;
|
||||
|
||||
DeviceStatusBloc(this._dispatcher, {TcpClient? client})
|
||||
: tcpClient = client ?? GetIt.I<TcpClient>(),
|
||||
super(DeviceStatusInitial()) {
|
||||
// 🔥 核心改动:直接在构造函数中建立TCP监听,类似RemoteControlCubit
|
||||
_initDirectTcpListener();
|
||||
// 🔥 已停用:机器状态数据源已改为MQTT(见 startMqttRealtimeListening,
|
||||
// 由用户切换设备时触发)。TCP监听逻辑保留,回滚时取消下行注释即可。
|
||||
// _initDirectTcpListener();
|
||||
|
||||
// 🔥 初始化MQTT到达点监听
|
||||
_initMqttArriveListener();
|
||||
@@ -191,6 +207,86 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
||||
_logger.log('✅ [DeviceStatusBloc] 直接TCP监听器已建立完成');
|
||||
}
|
||||
|
||||
/// 🔥 MQTT机器状态监听(替代TCP 0x02数据源)
|
||||
///
|
||||
/// [deviceSn] 与TCP时代 switchDevice / connectBySwitch 的设备号获取方式一致
|
||||
/// (即 DeviceEntity.deviceName),由用户点击设备列表切换设备时调用。
|
||||
///
|
||||
/// 第一阶段:订阅并打印原始报文;确认格式后在第二阶段解析为
|
||||
/// RunningStatusEntity + GPSEntity,复用现有500ms节流逻辑。
|
||||
void startMqttRealtimeListening(String deviceSn) {
|
||||
if (deviceSn.isEmpty) {
|
||||
debugPrint('${LogTime.now()} ⚠️ [DeviceStatusBloc] MQTT订阅跳过:设备SN为空');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('${LogTime.now()} 🚀 [DeviceStatusBloc] 启动MQTT机器状态监听: $deviceSn');
|
||||
|
||||
// 按SN订阅(数据源内部自动退旧订新、同SN去重)
|
||||
_mowerRealtimeRepo.startListening(deviceSn: deviceSn).then((result) {
|
||||
result.fold(
|
||||
(failure) => debugPrint(
|
||||
'${LogTime.now()} ❌ [DeviceStatusBloc] MQTT机器状态订阅失败: ${failure.message}',
|
||||
),
|
||||
(_) => debugPrint(
|
||||
'${LogTime.now()} ✅ [DeviceStatusBloc] MQTT机器状态订阅完成: $deviceSn',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
// 切换设备时重置收帧计数,便于观察新设备的首帧与频率
|
||||
_mqttVehicleFrameCount = 0;
|
||||
_mqttLocationFrameCount = 0;
|
||||
|
||||
// 流监听只建立一次,第一阶段仅打印解析结果验证链路
|
||||
_mqttVehicleSubscription ??= _mowerRealtimeRepo.vehicleStream.listen((
|
||||
message,
|
||||
) {
|
||||
_mqttVehicleFrameCount++;
|
||||
debugPrint(
|
||||
'${LogTime.now()} 📊 [MQTT-机器状态] 车辆实时第$_mqttVehicleFrameCount帧 type=${message.type} 数据点=${message.data.length}',
|
||||
);
|
||||
// TODO 第二阶段:将数据点映射到 RunningStatusEntity 字段,复用500ms节流emit
|
||||
});
|
||||
|
||||
_mqttLocationSubscription ??= _mowerRealtimeRepo.locationStream.listen((
|
||||
location,
|
||||
) {
|
||||
_mqttLocationFrameCount++;
|
||||
debugPrint(
|
||||
'${LogTime.now()} 📍 [MQTT-location] 定位第$_mqttLocationFrameCount帧 lat=${location.latitude}, lng=${location.longitude}, heading=${location.heading}',
|
||||
);
|
||||
|
||||
// 🔥 核心:用 MQTT location 数据更新缓存并节流 emit
|
||||
if (location.isValid) {
|
||||
// 更新 _cachedGps
|
||||
_cachedGps = GPSEntity(location.latitude!, location.longitude!);
|
||||
|
||||
// 更新 _cachedStatus 中的航向角和坐标(复用已有缓存或新建空壳)
|
||||
final base = _cachedStatus ?? RunningStatusEntity();
|
||||
_cachedStatus = base.copyWith(
|
||||
latitude: location.latitude!,
|
||||
longitude: location.longitude!,
|
||||
yaw: location.heading ?? base.yaw,
|
||||
);
|
||||
|
||||
// 500ms节流:与 TCP 0x02 时代逻辑一致
|
||||
if (_throttleTimer == null || !_throttleTimer!.isActive) {
|
||||
_throttleTimer = Timer(_throttleDuration, () {
|
||||
_emitCachedStatus();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
debugPrint(
|
||||
'${LogTime.now()} ⚠️ [MQTT-location] 坐标无效,跳过 - lat=${location.latitude}, lng=${location.longitude}',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
debugPrint('${LogTime.now()} ✅ [DeviceStatusBloc] MQTT机器状态监听已启动: $deviceSn');
|
||||
_logger.log('✅ [DeviceStatusBloc] MQTT机器状态监听已启动: $deviceSn');
|
||||
}
|
||||
|
||||
// 🔥 初始化MQTT到达点监听
|
||||
void _initMqttArriveListener() {
|
||||
debugPrint('🔗 [DeviceStatusBloc] 初始化MQTT到达点监听器');
|
||||
@@ -304,7 +400,7 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
||||
// 🔥 节流发射:500ms到期后发射缓存的最新数据
|
||||
void _emitCachedStatus() {
|
||||
if (_cachedStatus != null && _cachedGps != null && !isClosed) {
|
||||
debugPrint('📤 [0x02] 节流发射 | 电压=${_cachedStatus!.voltage}V 电量=${_cachedStatus!.battery}% 经纬度=(${_cachedGps!.latitude}, ${_cachedGps!.longitude}) | ${DateTime.now().toString().substring(11, 19)}');
|
||||
debugPrint('📤 [节流发射] 电压=${_cachedStatus!.voltage}V 电量=${_cachedStatus!.battery}% 经纬度=(${_cachedGps!.latitude}, ${_cachedGps!.longitude}) yaw=${_cachedStatus!.yaw} | ${DateTime.now().toString().substring(11, 19)}');
|
||||
emit(DeviceStatusUpdated(_cachedStatus!, _cachedGps!));
|
||||
}
|
||||
}
|
||||
@@ -423,6 +519,12 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
|
||||
_mqttStatusSubscription?.cancel();
|
||||
_mqttStatusSubscription = null;
|
||||
|
||||
// 🔥 清理MQTT机器状态订阅
|
||||
_mqttVehicleSubscription?.cancel();
|
||||
_mqttVehicleSubscription = null;
|
||||
_mqttLocationSubscription?.cancel();
|
||||
_mqttLocationSubscription = null;
|
||||
|
||||
// 🔥 清理节流timer和缓存
|
||||
_throttleTimer?.cancel();
|
||||
_throttleTimer = null;
|
||||
|
||||
Reference in New Issue
Block a user