远程开锁优化

配网错误提示优化
配网界面去掉2.4
This commit is contained in:
sky_min 2025-12-10 11:07:39 +08:00
parent cd9e5da6a0
commit 5e0eea5486
8 changed files with 144 additions and 208 deletions

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
@ -35,11 +36,23 @@ import '../../../blue/blue_manage.dart';
import '../../../blue/io_protocol/io_openLock.dart';
import '../../../blue/io_protocol/io_referEventRecordTime.dart';
import '../../../blue/io_reply.dart';
import '../../../blue/io_sender.dart';
import '../../../blue/io_tool/io_tool.dart';
import '../../../blue/io_tool/manager_event_bus.dart';
import '../../../blue/sender_manage.dart';
import '../../../network/api_repository.dart';
import '../../../network/start_chart_api.dart';
import '../../../talk/other/audio_player_manager.dart';
import '../../../talk/starChart/constant/message_type_constant.dart';
import '../../../talk/starChart/constant/payload_type_constant.dart';
import '../../../talk/starChart/constant/protocol_flag_constant.dart';
import '../../../talk/starChart/entity/scp_message.dart';
import '../../../talk/starChart/exception/start_chart_message_exception.dart';
import '../../../talk/starChart/handle/impl/udp_ble_passthrough_handler.dart';
import '../../../talk/starChart/handle/impl/udp_remote_un_lock_handler.dart';
import '../../../talk/starChart/handle/scp_message_handle.dart';
import '../../../talk/starChart/handle/scp_message_handler_factory.dart';
import '../../../talk/udp/udp_reciverData.dart';
import '../../../tools/baseGetXController.dart';
import '../../../tools/commonDataManage.dart';
import '../../../tools/dateTool.dart';
@ -207,8 +220,9 @@ class LockDetailLogic extends BaseGetXController {
signKey: signKeyDataList,
privateKey: getPrivateKeyList,
);
//
if (StartChartManage().talkStatus.status == TalkStatus.answeredSuccessfully) {
//
if (StartChartManage().talkStatus.status == TalkStatus.answeredSuccessfully ||
StartChartManage().lockPeerId.isNotEmpty) {
sendStarChartOpenLockMessage(reply);
}
@ -689,57 +703,74 @@ class LockDetailLogic extends BaseGetXController {
//
Future<void> remoteOpenLock() async {
final catEyeConfig = state.keyInfos.value.lockSetting?.catEyeConfig ?? [];
//
if (state.keyInfos.value.lockFeature?.isSupportCatEye == 1 && catEyeConfig[0].catEyeMode == 0) {
showToast('猫眼设置为省电模式时无法进行远程开锁,请在猫眼设置中切换为其他模式'.tr);
return;
}
final LockListInfoItemEntity currentKeyInfo = CommonDataManage().currentKeyInfo;
var lockId = currentKeyInfo.lockId ?? 0;
var remoteUnlock = currentKeyInfo.lockSetting?.remoteUnlock ?? 0;
final lockPeerId = StartChartManage().lockPeerId;
final LockListInfoGroupEntity? lockListInfoGroupEntity = await Storage.getLockMainListData();
var lockPeerId = StartChartManage().lockPeerId;
//
final connectedDevices = await FlutterBluePlus.connectedDevices;
final isDeviceConnected = connectedDevices.any((device) =>
device.remoteId.str == BlueManage().connectDeviceName);
if (!isDeviceConnected) {
AppLog.log('蓝牙已断开,尝试重新连接');
// token
await _reconnectAndRefreshToken();
}
if (lockListInfoGroupEntity != null) {
lockListInfoGroupEntity!.groupList?.forEach((element) {
final lockList = element.lockList;
if (lockList != null && lockList.length != 0) {
for (var lockInfo in lockList) {
final peerId = lockInfo.network?.peerId;
if (peerId != null && peerId != '') {
if (peerId == lockPeerId) {
lockId = lockInfo.lockId ?? 0;
remoteUnlock = lockInfo.lockSetting?.remoteUnlock ?? 0;
}
}
}
}
});
if (lockPeerId.isEmpty) {
final network = currentKeyInfo.network;
if (network != null && network.peerId != null && network.peerId!.isNotEmpty) {
lockPeerId = network.peerId!;
StartChartManage().lockPeerId = lockPeerId;
}
}
if (remoteUnlock == 1) {
//
await _sendUnlockViaBluetooth();
// api
final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60);
if (entity.errorCode!.codeIsSuccessful) {
showToast('已开锁'.tr);
StartChartManage().lockListPeerId = [];
try {
if (lockPeerId.isEmpty) {
AppLog.log('远程服务未连接,无法进行远程开锁');
return;
}
final response = await StartChartApi.to.analyzeInformationOtherEnd(peerId: lockPeerId);
if (response.statusCode == 200) {
AppLog.log('成功分析对端信息');
} else {
AppLog.log('分析对端信息失败,状态码: ${response.statusCode}');
return;
}
// WiFi锁
final network = currentKeyInfo.network;
if (network != null && (network.peerId != null && network.peerId!.isNotEmpty)){
//
await _sendUnlockViaBluetooth();
} else {
// API
final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60);
if (entity.errorCode!.codeIsSuccessful) {
showToast('已开锁'.tr);
StartChartManage().lockListPeerId = [];
}
}
} catch (e) {
AppLog.log('远程开锁失败: $e');
showToast('远程开锁失败'.tr);
}
} else {
AppLog.log('该锁的远程开锁功能未启用');
showToast('该锁的远程开锁功能未启用'.tr);
}
}
//
//
Future<void> _sendUnlockViaBluetooth() async {
try {
//
final String targetDeviceName = state.keyInfos.value.bluetooth!.bluetoothDeviceName!;
final String currentConnectedDevice = BlueManage().connectDeviceName;
if (targetDeviceName != currentConnectedDevice) {
AppLog.log('目标设备与当前连接设备不匹配,目标: $targetDeviceName, 当前: $currentConnectedDevice');
}
//
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
final List<int> privateKeyList = changeStringListToIntList(privateKey!);
@ -750,10 +781,23 @@ class LockDetailLogic extends BaseGetXController {
final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> tokenList = changeStringListToIntList(token!);
//
final String bluetoothDeviceName = BlueManage().connectDeviceName;
if (bluetoothDeviceName.isEmpty) {
throw Exception('未找到连接的蓝牙设备');
}
// ID
final String? userID = await Storage.getUid();
if (userID == null || userID.isEmpty) {
throw Exception('未找到用户ID');
}
AppLog.log('用户ID: $userID');
//
final OpenLockCommand openLockCommand = OpenLockCommand(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
lockID: bluetoothDeviceName,
userID: userID,
openMode: state.openDoorModel,
openTime: getUTCNetTime(),
onlineToken: state.lockNetToken,
@ -762,151 +806,20 @@ class LockDetailLogic extends BaseGetXController {
signKey: signKeyList,
privateKey: privateKeyList,
);
AppLog.log('构建开锁命令成功');
//
final List<int> messageDetail = openLockCommand.packageData();
//
//
StartChartManage().sendRemoteUnLockMessage(
bluetoothDeviceName: BlueManage().connectDeviceName,
bluetoothDeviceName: bluetoothDeviceName,
openLockCommand: messageDetail,
);
AppLog.log('通过蓝牙透传发送远程开锁命令');
// token不一致的情况
_listenForOpenLockReply(tokenList);
AppLog.log('蓝牙透传开锁命令已发送到设备: $bluetoothDeviceName');
} catch (e) {
AppLog.log('蓝牙透传开锁异常: $e');
showToast('蓝牙透传开锁失败'.tr);
}
}
// token验证
void _listenForOpenLockReply(List<int> originalToken) {
StreamSubscription<Reply>? subscription;
//
subscription = EventBusManager().eventBus!.on<Reply>().listen((Reply reply) async {
if (reply is OpenDoorReply) {
final int status = reply.data[6];
// token不一致的情况(0x06)
if (status == 0x06) {
AppLog.log('token不一致使用新token重新开锁');
// token
final List<int> newToken = reply.data.sublist(2, 6);
// token到存储
final List<String> saveStrList = changeIntListToStringList(newToken);
Storage.setStringList(saveBlueToken, saveStrList);
// 使token重新发送开锁命令
await _reSendUnlockWithNewToken(newToken);
}
//
subscription?.cancel();
}
});
//
Timer(const Duration(seconds: 10), () {
subscription?.cancel();
});
}
// 使token重新发送开锁命令
Future<void> _reSendUnlockWithNewToken(List<int> newToken) async {
try {
//
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
final List<int> privateKeyList = changeStringListToIntList(privateKey!);
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyList = changeStringListToIntList(signKey!);
//
final OpenLockCommand openLockCommand = OpenLockCommand(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
openMode: state.openDoorModel,
openTime: getUTCNetTime(),
onlineToken: state.lockNetToken,
token: newToken,
needAuthor: 1,
signKey: signKeyList,
privateKey: privateKeyList,
);
//
final List<int> messageDetail = openLockCommand.packageData();
//
StartChartManage().sendRemoteUnLockMessage(
bluetoothDeviceName: BlueManage().connectDeviceName,
openLockCommand: messageDetail,
);
AppLog.log('使用新token重新发送开锁命令');
} catch (e) {
AppLog.log('使用新token重新开锁异常: $e');
showToast('重新开锁失败'.tr);
}
}
// token
Future<void> _reconnectAndRefreshToken() async {
try {
//
await BlueManage().blueSendData(
state.keyInfos.value.bluetooth!.bluetoothDeviceName!,
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
AppLog.log('蓝牙重新连接成功');
// token
await _refreshLockToken();
} else if (deviceConnectionState == BluetoothConnectionState.disconnected) {
AppLog.log('蓝牙重新连接失败');
showToast('蓝牙连接失败,请重试'.tr);
}
},
);
} catch (e) {
AppLog.log('蓝牙重连异常: $e');
showToast('蓝牙连接异常,请重试'.tr);
}
}
// token
Future<void> _refreshLockToken() async {
try {
final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> tokenList = changeStringListToIntList(token!);
final List<String>? privateKey = await Storage.getStringList(saveBluePrivateKey);
final List<int> privateKeyList = changeStringListToIntList(privateKey!);
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyList = changeStringListToIntList(signKey!);
// token的命令
IoSenderManage.senderOpenLock(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
openMode: state.openDoorModel,
openTime: getUTCNetTime(),
onlineToken: state.lockNetToken,
token: tokenList,
needAuthor: 1,
signKey: signKeyList,
privateKey: privateKeyList,
);
// token更新完成
await Future.delayed(Duration(milliseconds: 500));
} catch (e) {
AppLog.log('刷新token异常: $e');
rethrow;
}
}

View File

@ -695,9 +695,9 @@ class _LockDetailPageState extends State<LockDetailPage> with TickerProviderStat
child: GestureDetector(
onTap: () {
ShowCupertinoAlertView().isToRemoteUnLockAlert(remoteUnlockAction: () {
if (state.keyInfos.value.hasGateway != 1) {
logic.showToast('附近没有可用网关'.tr);
}
// if (state.keyInfos.value.hasGateway != 1) {
// logic.showToast('附近没有可用网关'.tr);
// }
logic.remoteOpenLock();
});
},

View File

@ -191,7 +191,7 @@ class ConfiguringWifiLogic extends BaseGetXController {
state.lockSetInfoData.value?.lockBasicInfo?.networkInfo?.wifiName =
wifiName;
state.lockSetInfoData.value?.lockBasicInfo?.networkInfo?.rssi =
rssi as int?;
rssi;
/// ,peerId
StartChartManage().lockPeerId = peerId;

View File

@ -79,14 +79,6 @@ class _ConfiguringWifiPageState extends State<ConfiguringWifiPage>
SizedBox(
height: 20.h,
),
Text(
'请确保网络是2.4GHz Wi-Fi'.tr,
style: TextStyle(
color: AppColors.blackColor,
fontSize: 20.sp,
fontWeight: FontWeight.w500,
),
),
],
));
}

View File

@ -1074,6 +1074,7 @@ class StartChartManage {
void _handleUdpResultData(ScpMessage scpMessage) {
final int payloadType = scpMessage.PayloadType ?? 0;
final int messageType = scpMessage.MessageType ?? 0;
AppLog.log('payloadType:$payloadType,messageType:$messageType');
//
if (payloadType == PayloadTypeConstant.remoteUnlock) {
AppLog.log('收到蓝牙设备回应消息,${scpMessage.PayloadType}');

View File

@ -58,6 +58,12 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
List<int>? _cachedPps;
bool _waitingForCompleteIFrame = false;
///
static const int STATUS_DEBOUNCE_TIME = 500;
///
int _lastStatusChangeTime = 0;
int _frameProcessCount = 0;
int _lastFrameProcessTime = 0;
double _actualFps = 0.0;
@ -833,6 +839,14 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
///
void _startListenTalkStatus() {
state.startChartTalkStatus.statusStream.listen((talkStatus) {
//
final int currentTime = DateTime.now().millisecondsSinceEpoch;
if (currentTime - _lastStatusChangeTime < STATUS_DEBOUNCE_TIME) {
AppLog.log('状态变更过于频繁,忽略此次变更: $talkStatus');
return;
}
//
_lastStatusChangeTime = currentTime;
state.talkStatus.value = talkStatus;
switch (talkStatus) {
case TalkStatus.rejected:
@ -865,13 +879,9 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData);
FlutterPcmSound.feed(fromList);
if (!state.isPlaying.value) {
AppLog.log('play');
FlutterPcmSound.play();
state.isPlaying.value = true;
}
} else if (state.isOpenVoice.isFalse) {
FlutterPcmSound.pause();
state.isPlaying.value = false;
}
}

View File

@ -39,29 +39,32 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
final TalkViewNativeDecodeState state = Get.find<TalkViewNativeDecodeLogic>().state;
final startChartManage = StartChartManage();
late AnimationController _animationController; //
@override
void initState() {
super.initState();
state.animationController = AnimationController(
vsync: this, // 使TickerProvider是当前Widget
_animationController = AnimationController( // 使
vsync: this,
duration: const Duration(seconds: 1),
);
state.animationController.repeat();
//
state.animationController = _animationController; //
_animationController.repeat();
SchedulerBinding.instance.addPostFrameCallback((_) {
//
state.animationController.duration = const Duration(milliseconds: 500);
_animationController.duration = const Duration(milliseconds: 500);
});
//StatusListener
state.animationController.addStatusListener((AnimationStatus status) {
_animationController.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
state.animationController.reset();
state.animationController.forward();
_animationController.reset();
_animationController.forward();
} else if (status == AnimationStatus.dismissed) {
state.animationController.reset();
state.animationController.forward();
_animationController.reset();
_animationController.forward();
}
});
}
@ -360,9 +363,12 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
state.isLongPressing.value = false;
},
onClick: () async {
//
if (state.talkStatus.value == TalkStatus.passiveCallWaitingAnswer) {
//
logic.initiateAnswerCommand();
//
if (!state.isMonitoringMode()) {
logic.initiateAnswerCommand();
}
}
},
),
@ -393,6 +399,10 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
}
String getAnswerBtnImg() {
//
if (state.isMonitoringMode.value) {
return 'images/main/icon_lockDetail_monitoringUnTalkback.png';
}
switch (state.talkStatus.value) {
case TalkStatus.passiveCallWaitingAnswer:
return 'images/main/icon_lockDetail_monitoringAnswerCalls.png';
@ -405,6 +415,10 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
}
String getAnswerBtnName() {
//
if (state.isMonitoringMode.value) {
return '长按说话'.tr;
}
switch (state.talkStatus.value) {
case TalkStatus.passiveCallWaitingAnswer:
return '接听'.tr;
@ -506,8 +520,11 @@ class _TalkViewNativeDecodePageState extends State<TalkViewNativeDecodePage> wit
@override
void dispose() {
state.animationController.dispose();
CallTalk().finishAVData();
// animation controller
_animationController.dispose();
super.dispose();
}
}

View File

@ -129,4 +129,7 @@ class TalkViewNativeDecodeState {
//
RxBool isFullScreen = false.obs;
//
final RxBool isMonitoringMode = false.obs;
}