1优化改动设备栏中全部标签栏的设备列表中数据的整合,又数据合并解耦成使用已有组件各自维护,使其样式和逻辑一致。
2接入了无人机机场的实时信息和无人机的实时信息,并创建了对应的组件,并测试。 3.实现了机器人的详情页的视频显示的逻辑为当机器人在线,就在下方同步出来机器人的各个方位视频,并且支持切换。 4.实现了全部设备中对类型的区分和实现了点击进入对应的详情页。 5.修复了部分bug,优化了代码结构,提高了代码的可读性和可维护性。 6更改了机器人列表项中的信息展示为机器序列号和别名和id(优先展示别名) 7.更改了无人机场的信息展示上位 无人机及序列号下位机场序列号。 8优化了无人机机场信息只能是的为明文展示。便于观看理解。
This commit is contained in:
@@ -192,11 +192,14 @@ Future<void> init() async {
|
||||
sl.registerLazySingleton<ILoggerService>(() => SentryLoggerImpl());
|
||||
|
||||
/// 1.4 --- MQTT Data Sources ---
|
||||
sl.registerLazySingleton<DroneOsdDataSource>(
|
||||
() => DroneOsdDataSourceImpl(sl<MqttClient>(instanceName: 'droneOsdClient')),
|
||||
sl.registerFactory<DroneOsdDataSource>(
|
||||
() =>
|
||||
DroneOsdDataSourceImpl(sl<MqttClient>(instanceName: 'droneOsdClient')),
|
||||
);
|
||||
sl.registerLazySingleton<TaskMessageDataSource>(
|
||||
() => TaskMessageDataSourceImpl(sl<MqttClient>(instanceName: 'taskMessageClient')),
|
||||
sl.registerFactory<TaskMessageDataSource>(
|
||||
() => TaskMessageDataSourceImpl(
|
||||
sl<MqttClient>(instanceName: 'taskMessageClient'),
|
||||
),
|
||||
);
|
||||
|
||||
/// 1.5 --- MQTT Repositories ---
|
||||
@@ -492,9 +495,7 @@ Future<void> init() async {
|
||||
);
|
||||
|
||||
/// 创建设备任务(通过接口执行作业)
|
||||
sl.registerLazySingleton(
|
||||
() => CreateDeviceTaskUseCase(sl<PathRepository>()),
|
||||
);
|
||||
sl.registerLazySingleton(() => CreateDeviceTaskUseCase(sl<PathRepository>()));
|
||||
|
||||
/// 6. 认证 (Auth)
|
||||
// --- 关键修改点 1: AuthCubit 必须在 GoRouter 之前注册,并传入参数 ---
|
||||
@@ -546,12 +547,5 @@ Future<void> init() async {
|
||||
sl.registerLazySingleton(() => CancelTaskUseCase(sl()));
|
||||
sl.registerLazySingleton(() => PauseTaskUseCase(sl()));
|
||||
sl.registerLazySingleton(() => RecoveryTaskUseCase(sl()));
|
||||
sl.registerFactory(
|
||||
() => DeviceTaskCubit(
|
||||
sl(),
|
||||
sl(),
|
||||
sl(),
|
||||
sl(),
|
||||
),
|
||||
);
|
||||
sl.registerFactory(() => DeviceTaskCubit(sl(), sl(), sl(), sl()));
|
||||
}
|
||||
|
||||
@@ -40,6 +40,17 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
required String deviceSn,
|
||||
required String gatewaySn,
|
||||
}) async {
|
||||
if (_deviceSn == deviceSn &&
|
||||
_gatewaySn == gatewaySn &&
|
||||
_subscription != null) {
|
||||
debugPrint('[DroneOsdDataSource] already listening');
|
||||
return;
|
||||
}
|
||||
|
||||
if (_deviceSn != null || _gatewaySn != null) {
|
||||
await stopListening();
|
||||
}
|
||||
|
||||
_deviceSn = deviceSn;
|
||||
_gatewaySn = gatewaySn;
|
||||
|
||||
@@ -50,8 +61,12 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
debugPrint(' 无人机: $droneTopic');
|
||||
debugPrint(' 机场: $stationTopic');
|
||||
|
||||
await mqttClient.subscribe(droneTopic);
|
||||
await mqttClient.subscribe(stationTopic);
|
||||
if (deviceSn.isNotEmpty) {
|
||||
await mqttClient.subscribe(droneTopic);
|
||||
}
|
||||
if (gatewaySn.isNotEmpty) {
|
||||
await mqttClient.subscribe(stationTopic);
|
||||
}
|
||||
|
||||
_subscription = mqttClient.messageStream?.listen((message) {
|
||||
_handleMessage(message);
|
||||
@@ -63,11 +78,13 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
await _subscription?.cancel();
|
||||
_subscription = null;
|
||||
|
||||
if (_deviceSn != null) {
|
||||
await mqttClient.unsubscribe('thing/product/$_deviceSn/osd');
|
||||
if (_deviceSn != null && _deviceSn!.isNotEmpty) {
|
||||
final deviceSn = _deviceSn!;
|
||||
await mqttClient.unsubscribe('thing/product/$deviceSn/osd');
|
||||
}
|
||||
if (_gatewaySn != null) {
|
||||
await mqttClient.unsubscribe('thing/product/$_gatewaySn/osd');
|
||||
if (_gatewaySn != null && _gatewaySn!.isNotEmpty) {
|
||||
final gatewaySn = _gatewaySn!;
|
||||
await mqttClient.unsubscribe('thing/product/$gatewaySn/osd');
|
||||
}
|
||||
|
||||
_deviceSn = null;
|
||||
@@ -79,12 +96,22 @@ class DroneOsdDataSourceImpl implements DroneOsdDataSource {
|
||||
final jsonData = jsonDecode(message.payload) as Map<String, dynamic>;
|
||||
final osdData = DroneOsdEntity.fromJson(jsonData);
|
||||
|
||||
if (message.topic.contains(_deviceSn ?? '')) {
|
||||
debugPrint('🛸 [DroneOsdDataSource] 无人机 OSD 更新');
|
||||
_droneOsdController.add(osdData);
|
||||
} else if (message.topic.contains(_gatewaySn ?? '')) {
|
||||
// 🔥 重要修复:先判断 gatewaySn,再判断 deviceSn
|
||||
// 因为 topic 可能同时包含两者,但我们需要优先匹配机场
|
||||
if (_gatewaySn != null &&
|
||||
_gatewaySn!.isNotEmpty &&
|
||||
message.topic.contains(_gatewaySn!)) {
|
||||
debugPrint('🏢 [DroneOsdDataSource] 机场 OSD 更新');
|
||||
debugPrint('🏢 [DroneOsdDataSource] Topic: ${message.topic}');
|
||||
_stationOsdController.add(osdData);
|
||||
} else if (_deviceSn != null &&
|
||||
_deviceSn!.isNotEmpty &&
|
||||
message.topic.contains(_deviceSn!)) {
|
||||
debugPrint('🛸 [DroneOsdDataSource] 无人机 OSD 更新');
|
||||
debugPrint('🛸 [DroneOsdDataSource] Topic: ${message.topic}');
|
||||
_droneOsdController.add(osdData);
|
||||
} else {
|
||||
debugPrint('⚠️ [DroneOsdDataSource] 未知设备类型,Topic: ${message.topic}');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ [DroneOsdDataSource] 解析 OSD 数据失败: $e');
|
||||
|
||||
@@ -21,7 +21,8 @@ class TaskMessageDataSourceImpl implements TaskMessageDataSource {
|
||||
final MqttClient mqttClient;
|
||||
final _taskStatusController = StreamController<TaskStatusEntity>.broadcast();
|
||||
final _taskArriveController = StreamController<TaskArriveEntity>.broadcast();
|
||||
final _realTimeMessageController = StreamController<RealTimeMessageEntity>.broadcast();
|
||||
final _realTimeMessageController =
|
||||
StreamController<RealTimeMessageEntity>.broadcast();
|
||||
|
||||
StreamSubscription<MqttMessage>? _subscription;
|
||||
String? _deviceId;
|
||||
@@ -40,6 +41,18 @@ class TaskMessageDataSourceImpl implements TaskMessageDataSource {
|
||||
|
||||
@override
|
||||
Future<void> startListening({required String deviceId}) async {
|
||||
if (_deviceId == deviceId && _subscription != null) {
|
||||
debugPrint('[TaskMessageDataSource] already listening: $deviceId');
|
||||
return;
|
||||
}
|
||||
|
||||
if (_deviceId != null && _deviceId != deviceId) {
|
||||
await stopListening();
|
||||
} else {
|
||||
await _subscription?.cancel();
|
||||
_subscription = null;
|
||||
}
|
||||
|
||||
_deviceId = deviceId;
|
||||
|
||||
final taskStatusTopic = 'task/$deviceId/status';
|
||||
@@ -66,9 +79,10 @@ class TaskMessageDataSourceImpl implements TaskMessageDataSource {
|
||||
_subscription = null;
|
||||
|
||||
if (_deviceId != null) {
|
||||
await mqttClient.unsubscribe('task/$_deviceId/status');
|
||||
await mqttClient.unsubscribe('task/$_deviceId/arrive');
|
||||
await mqttClient.unsubscribe('device/$_deviceId/realTimeMessage');
|
||||
final deviceId = _deviceId!;
|
||||
await mqttClient.unsubscribe('task/$deviceId/status');
|
||||
await mqttClient.unsubscribe('task/$deviceId/arrive');
|
||||
await mqttClient.unsubscribe('device/$deviceId/realTimeMessage');
|
||||
}
|
||||
|
||||
_deviceId = null;
|
||||
@@ -88,7 +102,9 @@ class TaskMessageDataSourceImpl implements TaskMessageDataSource {
|
||||
_taskArriveController.add(arriveInfo);
|
||||
} else if (message.topic.contains('/realTimeMessage')) {
|
||||
final realTimeMsg = RealTimeMessageEntity.fromJson(jsonData);
|
||||
debugPrint('💬 [TaskMessageDataSource] 实时消息 - 类型: ${realTimeMsg.type}, 数据点数: ${realTimeMsg.data.length}');
|
||||
debugPrint(
|
||||
'💬 [TaskMessageDataSource] 实时消息 - 类型: ${realTimeMsg.type}, 数据点数: ${realTimeMsg.data.length}',
|
||||
);
|
||||
_realTimeMessageController.add(realTimeMsg);
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mqtt_client/mqtt_client.dart' as mqtt;
|
||||
import 'package:mqtt_client/mqtt_server_client.dart' as mqtt_server;
|
||||
@@ -10,8 +11,14 @@ import '../../domain/models/mqtt_message.dart';
|
||||
class MqttClientImpl implements MqttClient {
|
||||
mqtt_server.MqttServerClient? _client;
|
||||
final _messageController = StreamController<MqttMessage>.broadcast();
|
||||
final Map<String, int> _subscriptionRefs = <String, int>{};
|
||||
|
||||
MqttConfig? _currentConfig;
|
||||
StreamSubscription? _updatesSubscription;
|
||||
Timer? _reconnectTimer;
|
||||
bool _isConnected = false;
|
||||
bool _isConnecting = false;
|
||||
bool _manualDisconnect = false;
|
||||
|
||||
@override
|
||||
Stream<MqttMessage>? get messageStream => _messageController.stream;
|
||||
@@ -21,148 +28,239 @@ class MqttClientImpl implements MqttClient {
|
||||
|
||||
@override
|
||||
Future<void> connect(MqttConfig config) async {
|
||||
if (_isConnecting) {
|
||||
debugPrint('[MqttClient] connect ignored, already connecting');
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isConnected) {
|
||||
debugPrint('⚠️ [MqttClient] 已连接,先断开');
|
||||
debugPrint('[MqttClient] already connected, disconnect first');
|
||||
await disconnect();
|
||||
}
|
||||
|
||||
_manualDisconnect = false;
|
||||
_currentConfig = config;
|
||||
_reconnectTimer?.cancel();
|
||||
_reconnectTimer = null;
|
||||
_isConnecting = true;
|
||||
|
||||
try {
|
||||
_currentConfig = config;
|
||||
final clientId = '${config.clientId}_${DateTime.now().millisecondsSinceEpoch}';
|
||||
|
||||
switch (config.protocol) {
|
||||
case MqttProtocol.websocket:
|
||||
_client = mqtt_server.MqttServerClient.withPort(
|
||||
config.host,
|
||||
clientId,
|
||||
config.port,
|
||||
);
|
||||
_client!.useWebSocket = true;
|
||||
break;
|
||||
case MqttProtocol.wss:
|
||||
_client = mqtt_server.MqttServerClient.withPort(
|
||||
config.host,
|
||||
clientId,
|
||||
config.port,
|
||||
);
|
||||
_client!.useWebSocket = true;
|
||||
_client!.secure = true;
|
||||
break;
|
||||
case MqttProtocol.tcp:
|
||||
default:
|
||||
_client = mqtt_server.MqttServerClient.withPort(
|
||||
config.host,
|
||||
clientId,
|
||||
config.port,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
_client!.logging(on: false);
|
||||
_client!.keepAlivePeriod = config.keepAlivePeriod;
|
||||
_client!.autoReconnect = true;
|
||||
_client!.resubscribeOnAutoReconnect = true;
|
||||
_client!.onDisconnected = _onDisconnected;
|
||||
_client!.onConnected = _onConnected;
|
||||
_client!.onSubscribed = _onSubscribed;
|
||||
|
||||
final connMessage = mqtt.MqttConnectMessage()
|
||||
.withClientIdentifier(clientId)
|
||||
.startClean()
|
||||
.withWillQos(mqtt.MqttQos.atLeastOnce);
|
||||
|
||||
_client!.connectionMessage = connMessage;
|
||||
|
||||
debugPrint('🔌 [MqttClient] 开始连接到 ${config.host}:${config.port}');
|
||||
await _updatesSubscription?.cancel();
|
||||
_updatesSubscription = null;
|
||||
_client = _createClient(config);
|
||||
_configureClient(_client!, config);
|
||||
|
||||
debugPrint('[MqttClient] connecting to ${config.connectionAddress}');
|
||||
await _client!.connect(config.username, config.password);
|
||||
|
||||
if (_client!.connectionStatus?.state == mqtt.MqttConnectionState.connected) {
|
||||
if (_client!.connectionStatus?.state ==
|
||||
mqtt.MqttConnectionState.connected) {
|
||||
_isConnected = true;
|
||||
debugPrint('✅ [MqttClient] 连接成功');
|
||||
debugPrint('[MqttClient] connected');
|
||||
_listenToMessages();
|
||||
_resubscribeAll();
|
||||
} else {
|
||||
throw Exception('连接失败: ${_client!.connectionStatus?.returnCode}');
|
||||
throw Exception(
|
||||
'MQTT connect failed: ${_client!.connectionStatus?.returnCode}',
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ [MqttClient] 连接异常: $e');
|
||||
debugPrint('[MqttClient] connect error: $e');
|
||||
_isConnected = false;
|
||||
_isConnecting = false;
|
||||
_scheduleReconnect();
|
||||
rethrow;
|
||||
} finally {
|
||||
_isConnecting = false;
|
||||
}
|
||||
}
|
||||
|
||||
mqtt_server.MqttServerClient _createClient(MqttConfig config) {
|
||||
final clientId =
|
||||
'${config.clientId}_${DateTime.now().millisecondsSinceEpoch}';
|
||||
|
||||
switch (config.protocol) {
|
||||
case MqttProtocol.websocket:
|
||||
case MqttProtocol.wss:
|
||||
final client = mqtt_server.MqttServerClient.withPort(
|
||||
config.connectionAddress,
|
||||
clientId,
|
||||
config.port,
|
||||
);
|
||||
client.useWebSocket = true;
|
||||
client.websocketProtocols = ['mqtt'];
|
||||
return client;
|
||||
case MqttProtocol.tcp:
|
||||
return mqtt_server.MqttServerClient.withPort(
|
||||
config.host,
|
||||
clientId,
|
||||
config.port,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _configureClient(
|
||||
mqtt_server.MqttServerClient client,
|
||||
MqttConfig config,
|
||||
) {
|
||||
client.logging(on: false);
|
||||
client.keepAlivePeriod = config.keepAlivePeriod;
|
||||
client.autoReconnect = false;
|
||||
client.resubscribeOnAutoReconnect = false;
|
||||
client.onDisconnected = _onDisconnected;
|
||||
client.onConnected = _onConnected;
|
||||
client.onSubscribed = _onSubscribed;
|
||||
|
||||
var connMessage = mqtt.MqttConnectMessage()
|
||||
.withClientIdentifier(client.clientIdentifier)
|
||||
.withWillQos(mqtt.MqttQos.atLeastOnce);
|
||||
|
||||
if (config.cleanSession) {
|
||||
connMessage = connMessage.startClean();
|
||||
}
|
||||
|
||||
client.connectionMessage = connMessage;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> disconnect() async {
|
||||
debugPrint('🔌 [MqttClient] 断开连接');
|
||||
debugPrint('[MqttClient] disconnect');
|
||||
_manualDisconnect = true;
|
||||
_reconnectTimer?.cancel();
|
||||
_reconnectTimer = null;
|
||||
await _updatesSubscription?.cancel();
|
||||
_updatesSubscription = null;
|
||||
_client?.disconnect();
|
||||
_client = null;
|
||||
_isConnected = false;
|
||||
_isConnecting = false;
|
||||
_currentConfig = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> subscribe(String topic) async {
|
||||
final previousRefs = _subscriptionRefs[topic] ?? 0;
|
||||
_subscriptionRefs[topic] = previousRefs + 1;
|
||||
|
||||
if (!_isConnected || _client == null) {
|
||||
throw Exception('MQTT 未连接');
|
||||
debugPrint('[MqttClient] queued subscription while disconnected: $topic');
|
||||
_scheduleReconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('📡 [MqttClient] 订阅主题: $topic');
|
||||
if (previousRefs > 0) {
|
||||
debugPrint('[MqttClient] subscription already active: $topic');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('[MqttClient] subscribe: $topic');
|
||||
_client!.subscribe(topic, mqtt.MqttQos.atLeastOnce);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> unsubscribe(String topic) async {
|
||||
if (!_isConnected || _client == null) {
|
||||
throw Exception('MQTT 未连接');
|
||||
final currentRefs = _subscriptionRefs[topic] ?? 0;
|
||||
if (currentRefs <= 1) {
|
||||
_subscriptionRefs.remove(topic);
|
||||
} else {
|
||||
_subscriptionRefs[topic] = currentRefs - 1;
|
||||
debugPrint('[MqttClient] subscription still in use: $topic');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('🔕 [MqttClient] 取消订阅: $topic');
|
||||
if (!_isConnected || _client == null) {
|
||||
debugPrint('[MqttClient] removed queued subscription: $topic');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('[MqttClient] unsubscribe: $topic');
|
||||
_client!.unsubscribe(topic);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> publish(String topic, String message) async {
|
||||
if (!_isConnected || _client == null) {
|
||||
throw Exception('MQTT 未连接');
|
||||
throw Exception('MQTT is not connected');
|
||||
}
|
||||
|
||||
debugPrint('📤 [MqttClient] 发布消息到 $topic');
|
||||
debugPrint('[MqttClient] publish: $topic');
|
||||
final builder = mqtt.MqttClientPayloadBuilder();
|
||||
builder.addString(message);
|
||||
_client!.publishMessage(topic, mqtt.MqttQos.atLeastOnce, builder.payload!);
|
||||
}
|
||||
|
||||
void _listenToMessages() {
|
||||
_client!.updates!.listen((List<mqtt.MqttReceivedMessage<mqtt.MqttMessage>> messages) {
|
||||
for (final msg in messages) {
|
||||
final topic = msg.topic;
|
||||
final payload = mqtt.MqttPublishPayload.bytesToStringAsString((msg.payload as mqtt.MqttPublishMessage).payload.message);
|
||||
_updatesSubscription = _client!.updates!.listen(
|
||||
(List<mqtt.MqttReceivedMessage<mqtt.MqttMessage>> messages) {
|
||||
for (final msg in messages) {
|
||||
final topic = msg.topic;
|
||||
final payload = mqtt.MqttPublishPayload.bytesToStringAsString(
|
||||
(msg.payload as mqtt.MqttPublishMessage).payload.message,
|
||||
);
|
||||
|
||||
debugPrint('📥 [MqttClient] 收到消息 [$topic]: $payload');
|
||||
debugPrint('[MqttClient] received [$topic]: $payload');
|
||||
_messageController.add(MqttMessage(topic: topic, payload: payload));
|
||||
}
|
||||
},
|
||||
onError: (Object error) {
|
||||
debugPrint('[MqttClient] updates stream error: $error');
|
||||
_isConnected = false;
|
||||
_scheduleReconnect();
|
||||
},
|
||||
cancelOnError: false,
|
||||
);
|
||||
}
|
||||
|
||||
_messageController.add(MqttMessage(
|
||||
topic: topic,
|
||||
payload: payload,
|
||||
));
|
||||
}
|
||||
});
|
||||
void _resubscribeAll() {
|
||||
if (_subscriptionRefs.isEmpty || _client == null) return;
|
||||
|
||||
for (final topic in _subscriptionRefs.keys) {
|
||||
debugPrint('[MqttClient] resubscribe: $topic');
|
||||
_client!.subscribe(topic, mqtt.MqttQos.atLeastOnce);
|
||||
}
|
||||
}
|
||||
|
||||
void _onConnected() {
|
||||
debugPrint('✅ [MqttClient] 已连接');
|
||||
debugPrint('[MqttClient] connected callback');
|
||||
_isConnected = true;
|
||||
}
|
||||
|
||||
void _onDisconnected() {
|
||||
debugPrint('❌ [MqttClient] 已断开');
|
||||
debugPrint('[MqttClient] disconnected callback');
|
||||
_isConnected = false;
|
||||
if (!_manualDisconnect) {
|
||||
_scheduleReconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void _onSubscribed(String topic) {
|
||||
debugPrint('✅ [MqttClient] 订阅成功: $topic');
|
||||
debugPrint('[MqttClient] subscribed: $topic');
|
||||
}
|
||||
|
||||
void _scheduleReconnect() {
|
||||
final config = _currentConfig;
|
||||
if (_manualDisconnect || config == null || _isConnected || _isConnecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_reconnectTimer?.isActive ?? false) return;
|
||||
|
||||
final delay = Duration(milliseconds: config.reconnectDelayMs);
|
||||
debugPrint('[MqttClient] reconnect scheduled in ${delay.inMilliseconds}ms');
|
||||
_reconnectTimer = Timer(delay, () async {
|
||||
if (_manualDisconnect || _isConnected || _isConnecting) return;
|
||||
|
||||
try {
|
||||
debugPrint('[MqttClient] reconnecting...');
|
||||
await connect(config);
|
||||
} catch (e) {
|
||||
debugPrint('[MqttClient] reconnect failed: $e');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_messageController.close();
|
||||
disconnect();
|
||||
_messageController.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
enum MqttProtocol { tcp, websocket, wss }
|
||||
/// MQTT 传输协议类型
|
||||
enum MqttProtocol {
|
||||
/// 纯 TCP 连接(原生 MQTT)
|
||||
tcp,
|
||||
|
||||
/// WebSocket 连接(MQTT over WebSocket)
|
||||
websocket,
|
||||
|
||||
/// 加密的 WebSocket 连接(MQTT over WSS)
|
||||
wss,
|
||||
}
|
||||
|
||||
class MqttConfig extends Equatable {
|
||||
final String host;
|
||||
@@ -12,6 +22,9 @@ class MqttConfig extends Equatable {
|
||||
final bool cleanSession;
|
||||
final int keepAlivePeriod;
|
||||
final int reconnectDelayMs;
|
||||
|
||||
/// WebSocket 路径(仅 WebSocket 模式使用)
|
||||
final String? wsPath;
|
||||
|
||||
const MqttConfig({
|
||||
required this.host,
|
||||
@@ -23,8 +36,23 @@ class MqttConfig extends Equatable {
|
||||
this.cleanSession = true,
|
||||
this.keepAlivePeriod = 60,
|
||||
this.reconnectDelayMs = 3000,
|
||||
this.wsPath,
|
||||
});
|
||||
|
||||
/// 获取完整的连接地址
|
||||
String get connectionAddress {
|
||||
switch (protocol) {
|
||||
case MqttProtocol.websocket:
|
||||
return 'ws://$host:$port${wsPath ?? '/mqtt'}';
|
||||
case MqttProtocol.wss:
|
||||
return 'wss://$host:$port${wsPath ?? '/mqtt'}';
|
||||
case MqttProtocol.tcp:
|
||||
default:
|
||||
return host;
|
||||
}
|
||||
}
|
||||
|
||||
/// 无人机/机场 OSD 数据(WebSocket MQTT)
|
||||
factory MqttConfig.droneOsd() {
|
||||
return const MqttConfig(
|
||||
host: '1.95.137.212',
|
||||
@@ -33,11 +61,13 @@ class MqttConfig extends Equatable {
|
||||
password: 'jsmbzn520',
|
||||
protocol: MqttProtocol.websocket,
|
||||
clientId: 'drone_osd_client',
|
||||
wsPath: '/mqtt',
|
||||
cleanSession: true,
|
||||
reconnectDelayMs: 3000,
|
||||
);
|
||||
}
|
||||
|
||||
/// 任务状态消息(TCP MQTT)
|
||||
factory MqttConfig.taskMessage() {
|
||||
return const MqttConfig(
|
||||
host: '1.95.137.212',
|
||||
@@ -61,6 +91,7 @@ class MqttConfig extends Equatable {
|
||||
bool? cleanSession,
|
||||
int? keepAlivePeriod,
|
||||
int? reconnectDelayMs,
|
||||
String? wsPath,
|
||||
}) {
|
||||
return MqttConfig(
|
||||
host: host ?? this.host,
|
||||
@@ -72,6 +103,7 @@ class MqttConfig extends Equatable {
|
||||
cleanSession: cleanSession ?? this.cleanSession,
|
||||
keepAlivePeriod: keepAlivePeriod ?? this.keepAlivePeriod,
|
||||
reconnectDelayMs: reconnectDelayMs ?? this.reconnectDelayMs,
|
||||
wsPath: wsPath ?? this.wsPath,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,5 +118,6 @@ class MqttConfig extends Equatable {
|
||||
cleanSession,
|
||||
keepAlivePeriod,
|
||||
reconnectDelayMs,
|
||||
wsPath,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -20,20 +20,31 @@ class MqttManager {
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('🔧 [MqttManager] 开始初始化 MQTT 连接...');
|
||||
|
||||
final droneOsdClient = sl<MqttClient>(instanceName: 'droneOsdClient');
|
||||
final taskMessageClient = sl<MqttClient>(instanceName: 'taskMessageClient');
|
||||
|
||||
// 独立连接两个 MQTT 客户端,互不影响
|
||||
await _connectClient(droneOsdClient, MqttConfig.droneOsd(), 'droneOsdClient');
|
||||
await _connectClient(taskMessageClient, MqttConfig.taskMessage(), 'taskMessageClient');
|
||||
|
||||
_isInitialized = true;
|
||||
debugPrint('✅ [MqttManager] MQTT 初始化完成');
|
||||
}
|
||||
|
||||
Future<void> _connectClient(
|
||||
MqttClient client,
|
||||
MqttConfig config,
|
||||
String clientName,
|
||||
) async {
|
||||
try {
|
||||
debugPrint('🔧 [MqttManager] 开始初始化 MQTT 连接...');
|
||||
|
||||
final droneOsdClient = sl<MqttClient>(instanceName: 'droneOsdClient');
|
||||
final taskMessageClient = sl<MqttClient>(instanceName: 'taskMessageClient');
|
||||
|
||||
await droneOsdClient.connect(MqttConfig.droneOsd());
|
||||
await taskMessageClient.connect(MqttConfig.taskMessage());
|
||||
|
||||
_isInitialized = true;
|
||||
debugPrint('✅ [MqttManager] MQTT 初始化完成');
|
||||
debugPrint('🔌 [MqttManager] 连接 $clientName...');
|
||||
await client.connect(config);
|
||||
debugPrint('✅ [MqttManager] $clientName 连接成功');
|
||||
} catch (e) {
|
||||
debugPrint('❌ [MqttManager] MQTT 初始化失败: $e');
|
||||
rethrow;
|
||||
debugPrint('❌ [MqttManager] $clientName 连接失败: $e');
|
||||
// 不抛出异常,允许其他客户端继续连接
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user