fix:完善对讲流程、增加蓝牙透传消息指令

This commit is contained in:
liyi 2025-01-08 09:14:29 +08:00
parent c16c9be4c6
commit 92fcf4a4fa
29 changed files with 581 additions and 192 deletions

View File

@ -12,7 +12,7 @@ import 'package:star_lock/mine/about/debug/debug_tool.dart';
import 'package:star_lock/network/api_provider.dart';
import 'package:star_lock/network/api_repository.dart';
import 'package:star_lock/network/start_chart_api.dart';
import 'package:star_lock/talk/startChart/appLifecycle_observer.dart';
import 'package:star_lock/talk/startChart/status/appLifecycle_observer.dart';
import 'package:star_lock/tools/bugly/bugly_tool.dart';
import 'package:star_lock/tools/device_info_service.dart';
import 'package:star_lock/tools/platform_info_services.dart';

View File

@ -21,7 +21,7 @@ class CatEyeSetLogic extends BaseGetXController {
}
}
//
//
Future<void> updateLightScreenTimeConfig() async {
final VersionUndateEntity entity = await ApiRepository.to.updateLightScreenTimeConfig(
lockId: state.lockSetInfoData.value.lockId!,
@ -112,4 +112,6 @@ class CatEyeSetLogic extends BaseGetXController {
}
return entity;
}
}

View File

@ -1,9 +1,14 @@
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:star_lock/blue/blue_manage.dart';
import 'package:star_lock/blue/io_tool/io_tool.dart';
import 'package:star_lock/blue/sender_manage.dart';
import 'package:star_lock/common/XSConstantMacro/XSConstantMacro.dart';
import 'package:star_lock/main/lockDetail/lockSet/catEyeSet/catEyeWorkMode/catEyeWorkMode_state.dart';
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart';
import 'package:star_lock/network/api_repository.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/storage.dart';
import 'package:star_lock/versionUndate/versionUndate_entity.dart';
class CatEyeWorkModeLogic extends BaseGetXController {
@ -11,7 +16,8 @@ class CatEyeWorkModeLogic extends BaseGetXController {
//
Future<void> updateCatEyeModeConfig() async {
final VersionUndateEntity entity = await ApiRepository.to.updateCatEyeModeConfig(
final VersionUndateEntity entity =
await ApiRepository.to.updateCatEyeModeConfig(
lockId: state.lockSetInfoData.value.lockId!,
catEyeConfig: [
<String, Object>{
@ -53,9 +59,47 @@ class CatEyeWorkModeLogic extends BaseGetXController {
}
}
///
void _handlerBleData() {
BlueManage().blueSendData(BlueManage().connectDeviceName,
(BluetoothConnectionState connectionState) async {
if (connectionState == BluetoothConnectionState.connected) {
final List<String>? privateKey =
await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList =
changeStringListToIntList(privateKey!);
final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> getTokenList = changeStringListToIntList(token!);
final List<String>? publicKey =
await Storage.getStringList(saveBluePublicKey);
final List<int> getPublicKeyList =
changeStringListToIntList(publicKey!);
List<int> featureData = [];
IoSenderManage.setSupportFunctionsWithParametersCommand(
keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(),
userID: await Storage.getUid(),
featureBit: 33,
featureParaLength: 1,
featureData: featureData,
token: getTokenList,
needAuthor: 1,
publicKey: getPublicKeyList,
privateKey: getPrivateKeyList);
} else if (connectionState == BluetoothConnectionState.disconnected) {
dismissEasyLoading();
cancelBlueConnetctToastTimer();
}
});
}
//
Future<void> getLockSettingInfoData() async {
final LockSetInfoEntity entity = await ApiRepository.to.getLockSettingInfoData(
final LockSetInfoEntity entity =
await ApiRepository.to.getLockSettingInfoData(
lockId: state.lockSetInfoData.value.lockId.toString(),
);
if (entity.errorCode!.codeIsSuccessful) {

View File

@ -105,10 +105,11 @@ class ConfiguringWifiLogic extends BaseGetXController {
serversList.add(type2);
}
final StarChartRegisterNodeEntity? registerNodeEntity =
await Storage.getStarChartRegisterNodeInfo();
//
final loginData = await Storage.getLoginData();
// app用户的peerId
String appPeerId = registerNodeEntity?.peer?.id ?? '';
String appPeerId = loginData?.starchart?.starchartId ?? '';
final List<String> uidList = <String>[Storage.getUid().toString()];
IoSenderManage.senderConfiguringWifiCommand(
@ -201,10 +202,11 @@ class ConfiguringWifiLogic extends BaseGetXController {
final String? uidStr = await Storage.getUid();
final List<String> uidList = <String>[uidStr.toString()];
final StarChartRegisterNodeEntity? registerNodeEntity =
await Storage.getStarChartRegisterNodeInfo();
//
final loginData = await Storage.getLoginData();
// app用户的peerId
String appPeerId = registerNodeEntity?.peer?.id ?? '';
String appPeerId = loginData?.starchart?.starchartId ?? '';
IoSenderManage.senderConfiguringWifiCommand(
keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(),
userID: await Storage.getUid(),

File diff suppressed because one or more lines are too long

View File

@ -6,6 +6,7 @@ import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart';
import 'package:star_lock/talk/startChart/constant/protocol_flag_constant.dart';
import 'package:star_lock/talk/startChart/constant/udp_constant.dart';
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
import 'package:star_lock/talk/startChart/proto/ble_message.pb.dart';
import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
@ -386,7 +387,7 @@ class MessageCommand {
final payload = rbcuInfo.writeToBuffer();
ScpMessage message = ScpMessage(
ProtocolFlag: ProtocolFlagConstant.scp01,
MessageType: MessageTypeConstant.Resp,
MessageType: MessageTypeConstant.Req,
MessageId: MessageId,
SpTotal: 1,
SpIndex: 1,
@ -401,6 +402,40 @@ class MessageCommand {
return _hexToBytes(serializedBytesString);
}
//
static List<int> bleMessage({
required String FromPeerId,
required String ToPeerId,
required String bluetoothDeviceName,
required List<int> bleStructData,
int? MessageId,
int? timeout = 30,
int? IdleTimeout = 0,
}) {
final bleReq = BleReq(
bluetoothDeviceName: bluetoothDeviceName,
structData: bleStructData,
timeout: timeout,
idleTimeout: 0,
);
final payload = bleReq.writeToBuffer();
ScpMessage message = ScpMessage(
ProtocolFlag: ProtocolFlagConstant.scp01,
MessageType: MessageTypeConstant.Req,
MessageId: MessageId,
SpTotal: 1,
SpIndex: 1,
FromPeerId: FromPeerId,
ToPeerId: ToPeerId,
Payload: payload,
PayloadCRC: calculationCrc(Uint8List.fromList(payload)),
PayloadLength: payload.length,
PayloadType: PayloadTypeConstant.blePassthrough,
);
String serializedBytesString = message.serialize();
return _hexToBytes(serializedBytesString);
}
// 16
static List<int> _hexToBytes(String hex) {
final bytes = <int>[];

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/talk/startChart/exception/start_chart_message_exception.dart';
import 'package:star_lock/talk/startChart/handle/impl/udp_heart_beat_handler.dart';
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
import 'package:star_lock/talk/startChart/handle/scp_message_handler_factory.dart';

View File

@ -1,8 +1,11 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:star_lock/appRouters.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/talk/startChart/constant/message_type_constant.dart';
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
import 'package:star_lock/talk/startChart/handle/scp_message_base_handle.dart';
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
@ -16,13 +19,16 @@ class UdpBlePassThroughHandler extends ScpMessageBaseHandle
implements ScpMessageHandler {
@override
void handleReq(ScpMessage scpMessage) {
final BleResp bleResp = scpMessage.Payload;
//TODO
}
@override
void handleResp(ScpMessage scpMessage) {
// TODO:
final BleResp bleResp = scpMessage.Payload;
//
// if (bleResp.status == BleResp_StatusE.SUCCESS) {
AppLog.log('收到蓝牙消息回复:${bleResp.structData}');
// }
}
@override
@ -41,8 +47,17 @@ class UdpBlePassThroughHandler extends ScpMessageBaseHandle
int? spTotal,
int? spIndex,
int? messageId}) {
final BleResp bleResp = BleResp();
bleResp.mergeFromBuffer(byte);
return bleResp;
if (messageType == MessageTypeConstant.Resp) {
final BleResp bleResp = BleResp();
bleResp.mergeFromBuffer(byte);
return bleResp;
} else if (messageType == MessageTypeConstant.Req) {
final BleReq talkExpect = BleReq();
talkExpect.mergeFromBuffer(byte);
return talkExpect;
} else {
String payload = utf8.decode(byte);
return payload;
}
}
}

View File

@ -46,16 +46,20 @@ class UdpRbcuInfoHandler extends ScpMessageBaseHandle
@override
void handleReq(ScpMessage scpMessage) {
final RbcuInfo rbcuInfo = scpMessage.Payload();
final RbcuInfo rbcuInfo = scpMessage.Payload;
if (rbcuInfo.isResp) {
//
_handleResultRbcuInfo(rbcuInfo);
} else {
//
startChartManage.replyRbcuInfoMessage(ToPeerId: scpMessage.FromPeerId!);
}
replySuccessMessage(scpMessage);
}
@override
void handleResp(ScpMessage scpMessage) {
final GenericResp genericResp = scpMessage.Payload();
final GenericResp genericResp = scpMessage.Payload;
if (checkGenericRespSuccess(genericResp)) {
//
startChartManage.stopSendingRbcuInfoMessages();
@ -65,5 +69,6 @@ class UdpRbcuInfoHandler extends ScpMessageBaseHandle
/// rbcuInfo消息
void _handleResultRbcuInfo(RbcuInfo rbcuInfo) {
P2pManage().communicationObjectRbcuInfo = rbcuInfo;
startChartManage.stopSendingRbcuInfoMessages();
}
}

View File

@ -12,25 +12,21 @@ import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
import 'package:star_lock/talk/startChart/views/talkView/talk_view_logic.dart';
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
import '../../start_chart_manage.dart';
class UdpTalkExpectHandler extends ScpMessageBaseHandle
implements ScpMessageHandler {
final TalkViewState talkViewState = TalkViewState();
final TalkViewState talkViewState = Get.put(TalkViewLogic()).state;
@override
void handleReq(ScpMessage scpMessage) {
//
final TalkExpectReq talkExpect = scpMessage.Payload;
print('收到预期音视频数据请求:$talkExpect');
//
replySuccessMessage(scpMessage);
//
// startChartManage.startTalkDataTimer();
}
@override
@ -38,10 +34,13 @@ class UdpTalkExpectHandler extends ScpMessageBaseHandle
//
final TalkExpectResp talkExpectResp = scpMessage.Payload;
if (talkExpectResp != null) {
print('收到预期音视频数据回复');
// print('收到预期音视频数据回复,scpMessage:$scpMessage');
//
startChartManage.stopTalkExpectMessageTimer();
talkViewState.rotateAngle.value = talkExpectResp.rotate ?? 0;
//
// x秒内没有收到通话保持则执行的操作;
talkePingOverTimeTimerManager.start();
}
}

View File

@ -15,17 +15,17 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle
implements ScpMessageHandler {
@override
void handleReq(ScpMessage scpMessage) {
if (talkStatus.status != TalkStatus.answeredSuccessfully) {
//
return;
}
// if (talkStatus.status != TalkStatus.answeredSuccessfully) {
// //
// return;
// }
print('收到通话中挂断请求');
//
replySuccessMessage(scpMessage);
talkStatus.setHangingUpDuring();
stopRingtone();
StartChartManage().stopTalkExpectMessageTimer();
StartChartManage().stopTalkPingMessageTimer();
}
@override

View File

@ -15,15 +15,13 @@ class UdpTalkPingHandler extends ScpMessageBaseHandle
void handleReq(ScpMessage scpMessage) {
// ,
replySuccessMessage(scpMessage);
talkePingOverTimeTimerManager.renew();
}
@override
void handleResp(ScpMessage scpMessage) {
//
// print('收到通话保持回复');
final GenericResp genericResp = scpMessage.Payload;
if (checkGenericRespSuccess(genericResp)) {
//
talkePingOverTimeTimerManager.renew();
}
}

View File

@ -20,6 +20,8 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
implements ScpMessageHandler {
@override
void handleReq(ScpMessage scpMessage) async {
//
replySuccessMessage(scpMessage);
//
final loginData = await Storage.getLoginData();
if (loginData == null ||
@ -28,11 +30,8 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
//
return;
}
//
replySuccessMessage(scpMessage);
//
final TalkReq talkReq = scpMessage.Payload;
startChartManage.FromPeerId = scpMessage.ToPeerId!;
startChartManage.ToPeerId = scpMessage.FromPeerId!;
//
@ -64,8 +63,6 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
_showTalkRequestNotification(talkObjectName: talkObjectName);
//
talkStatus.setWaitingAnswer();
//
_handleStartTalkPing();
//
talkeRequestOverTimeTimerManager.start();
//
@ -123,12 +120,4 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle
//
startChartManage.sendOnlyImageVideoTalkExpectData();
}
// x秒内是否收到通话保持
void _handleStartTalkPing() {
//
startChartManage.startTalkPingMessageTimer();
// x秒内没有收到通话保持则执行的操作
talkePingOverTimeTimerManager.start();
}
}

View File

@ -5,7 +5,8 @@ import 'package:get/get.dart';
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
class TalkDataOverTimeTimerManager {
//

View File

@ -5,7 +5,7 @@ import 'package:get/get.dart';
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
class TalkePingOverTimeTimerManager {
//
@ -41,6 +41,8 @@ class TalkePingOverTimeTimerManager {
//
void start() {
//
_timer?.cancel();
_timer = Timer(timeout, onTimeout);
}

View File

@ -5,7 +5,7 @@ import 'package:get/get.dart';
import 'package:star_lock/talk/startChart/constant/talk_constant.dart';
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
class TalkeRequestOverTimeTimerManager {
//
@ -31,6 +31,7 @@ class TalkeRequestOverTimeTimerManager {
EasyLoading.showToast('通话未接通,以挂断', duration: 2000.milliseconds);
//
StartChartManage().sendTalkRejectMessage();
talkStatus.setInitializationCompleted();
Get.back();
}
}

View File

@ -22,7 +22,8 @@ import 'package:star_lock/talk/startChart/handle/other/talke_request_over_time_t
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
class ScpMessageBaseHandle {
/// 使 TimerManager

View File

@ -1,5 +1,6 @@
import 'package:star_lock/talk/startChart/constant/payload_type_constant.dart';
import 'package:star_lock/talk/startChart/handle/impl/udp_ble_passthrough_handler.dart';
import 'package:star_lock/talk/startChart/handle/impl/udp_rbcuInfo_handler.dart';
import 'package:star_lock/talk/startChart/handle/impl/udp_talk_request_handler.dart';
import 'package:star_lock/talk/startChart/handle/impl/udp_echo_test_handler.dart';
import 'package:star_lock/talk/startChart/handle/impl/udp_gateway_reset_handler.dart';
@ -55,7 +56,7 @@ class ScpMessageHandlerFactory {
case PayloadTypeConstant.talkHangup:
return UdpTalkHangUpHandler();
case PayloadTypeConstant.RbcuInfo:
return UdpTalkHangUpHandler();
return UdpRbcuInfoHandler();
default:
return UnKnowPayloadTypeHandler();
}

View File

@ -1,14 +1,25 @@
import 'dart:async';
import 'dart:io';
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
class P2pManage {
//
static const String testMessage = 'Hello'; //
static const int localPort = 0; // 0
static const Duration connectionTimeout = Duration(seconds: 5); //
static const List<String> localNetworkPrefixes = [
'192.168.',
'10.',
'172.'
]; // IP
RbcuInfo? communicationObjectRbcuInfo;
void init(){
void init() {
//
}
// address IP
List<Map<String, String>> parseRemoteAddresses() {
final addresses = communicationObjectRbcuInfo?.address ?? [];
@ -18,4 +29,80 @@ class P2pManage {
}).toList();
}
// IP
bool _isLocalNetworkIp(String ip) {
for (final prefix in localNetworkPrefixes) {
if (ip.startsWith(prefix)) {
// 172.16.x.x 172.31.x.x
if (prefix == '172.') {
final secondOctet = int.tryParse(ip.split('.')[1]) ?? 0;
if (secondOctet >= 16 && secondOctet <= 31) {
return true;
}
} else {
return true;
}
}
}
return false;
}
// UDP
Future<void> createUdpConnection() async {
final addresses = parseRemoteAddresses();
// 使 IP
addresses.sort((a, b) {
final isALocal = _isLocalNetworkIp(a['ip']!);
final isBLocal = _isLocalNetworkIp(b['ip']!);
if (isALocal && !isBLocal) return -1; // a IP
if (!isALocal && isBLocal) return 1; // b IP
return 0; //
});
//
for (final addr in addresses) {
final ip = addr['ip']!;
final port = int.parse(addr['port']!);
try {
final socket = await RawDatagramSocket.bind(
InternetAddress.anyIPv4, localPort); //
//
final testData = testMessage.codeUnits;
socket.send(testData, InternetAddress(ip), port);
//
final completer = Completer<void>();
//
socket.listen((event) {
if (event == RawSocketEvent.read) {
final datagram = socket.receive();
if (datagram != null) {
final response = String.fromCharCodes(datagram.data);
print('收到来自 $ip:$port 的响应: $response');
completer.complete(); // Future
}
}
});
//
try {
await completer.future.timeout(connectionTimeout);
print('成功连接到 $ip:$port');
return; // 退
} on TimeoutException {
print('连接到 $ip:$port 超时');
} finally {
socket.close(); // socket
}
} catch (e) {
print('连接到 $ip:$port 失败: $e');
}
}
print('无法连接到任何地址');
}
}

View File

@ -17,18 +17,27 @@ import 'ble_message.pbenum.dart';
export 'ble_message.pbenum.dart';
///
class BleReq extends $pb.GeneratedMessage {
factory BleReq({
$core.int? timeout,
$core.String? bluetoothDeviceName,
$core.List<$core.int>? structData,
$core.int? idleTimeout,
}) {
final $result = create();
if (timeout != null) {
$result.timeout = timeout;
}
if (bluetoothDeviceName != null) {
$result.bluetoothDeviceName = bluetoothDeviceName;
}
if (structData != null) {
$result.structData = structData;
}
if (idleTimeout != null) {
$result.idleTimeout = idleTimeout;
}
return $result;
}
BleReq._() : super();
@ -36,8 +45,10 @@ class BleReq extends $pb.GeneratedMessage {
factory BleReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BleReq', package: const $pb.PackageName(_omitMessageNames ? '' : 'main'), createEmptyInstance: create)
..a<$core.int>(1, _omitFieldNames ? '' : 'Timeout', $pb.PbFieldType.OU3, protoName: 'Timeout')
..aOS(2, _omitFieldNames ? '' : 'bluetoothDeviceName', protoName: 'bluetoothDeviceName')
..a<$core.List<$core.int>>(3, _omitFieldNames ? '' : 'StructData', $pb.PbFieldType.OY, protoName: 'StructData')
..a<$core.int>(6, _omitFieldNames ? '' : 'IdleTimeout', $pb.PbFieldType.OU3, protoName: 'IdleTimeout')
..hasRequiredFields = false
;
@ -62,25 +73,45 @@ class BleReq extends $pb.GeneratedMessage {
static BleReq getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BleReq>(create);
static BleReq? _defaultInstance;
/// ++
@$pb.TagNumber(1)
$core.int get timeout => $_getIZ(0);
@$pb.TagNumber(1)
set timeout($core.int v) { $_setUnsignedInt32(0, v); }
@$pb.TagNumber(1)
$core.bool hasTimeout() => $_has(0);
@$pb.TagNumber(1)
void clearTimeout() => clearField(1);
/// mac地址
@$pb.TagNumber(2)
$core.String get bluetoothDeviceName => $_getSZ(0);
$core.String get bluetoothDeviceName => $_getSZ(1);
@$pb.TagNumber(2)
set bluetoothDeviceName($core.String v) { $_setString(0, v); }
set bluetoothDeviceName($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasBluetoothDeviceName() => $_has(0);
$core.bool hasBluetoothDeviceName() => $_has(1);
@$pb.TagNumber(2)
void clearBluetoothDeviceName() => clearField(2);
///
@$pb.TagNumber(3)
$core.List<$core.int> get structData => $_getN(1);
$core.List<$core.int> get structData => $_getN(2);
@$pb.TagNumber(3)
set structData($core.List<$core.int> v) { $_setBytes(1, v); }
set structData($core.List<$core.int> v) { $_setBytes(2, v); }
@$pb.TagNumber(3)
$core.bool hasStructData() => $_has(1);
$core.bool hasStructData() => $_has(2);
@$pb.TagNumber(3)
void clearStructData() => clearField(3);
/// 0
@$pb.TagNumber(6)
$core.int get idleTimeout => $_getIZ(3);
@$pb.TagNumber(6)
set idleTimeout($core.int v) { $_setUnsignedInt32(3, v); }
@$pb.TagNumber(6)
$core.bool hasIdleTimeout() => $_has(3);
@$pb.TagNumber(6)
void clearIdleTimeout() => clearField(6);
}
class BleResp extends $pb.GeneratedMessage {
@ -103,7 +134,7 @@ class BleResp extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BleResp', package: const $pb.PackageName(_omitMessageNames ? '' : 'main'), createEmptyInstance: create)
..e<BleResp_StatusE>(1, _omitFieldNames ? '' : 'Status', $pb.PbFieldType.OE, protoName: 'Status', defaultOrMaker: BleResp_StatusE.SUCCESS, valueOf: BleResp_StatusE.valueOf, enumValues: BleResp_StatusE.values)
..a<$core.List<$core.int>>(4, _omitFieldNames ? '' : 'StructData', $pb.PbFieldType.OY, protoName: 'StructData')
..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'StructData', $pb.PbFieldType.OY, protoName: 'StructData')
..hasRequiredFields = false
;
@ -138,15 +169,15 @@ class BleResp extends $pb.GeneratedMessage {
@$pb.TagNumber(1)
void clearStatus() => clearField(1);
///
@$pb.TagNumber(4)
///
@$pb.TagNumber(2)
$core.List<$core.int> get structData => $_getN(1);
@$pb.TagNumber(4)
@$pb.TagNumber(2)
set structData($core.List<$core.int> v) { $_setBytes(1, v); }
@$pb.TagNumber(4)
@$pb.TagNumber(2)
$core.bool hasStructData() => $_has(1);
@$pb.TagNumber(4)
void clearStructData() => clearField(4);
@$pb.TagNumber(2)
void clearStructData() => clearField(2);
}

View File

@ -18,16 +18,16 @@ class BleResp_StatusE extends $pb.ProtobufEnum {
static const BleResp_StatusE SUCCESS = BleResp_StatusE._(0, _omitEnumNames ? '' : 'SUCCESS');
static const BleResp_StatusE FAIL = BleResp_StatusE._(1, _omitEnumNames ? '' : 'FAIL');
static const BleResp_StatusE NOT_FOUND = BleResp_StatusE._(2, _omitEnumNames ? '' : 'NOT_FOUND');
static const BleResp_StatusE CANNOT_CONNECT = BleResp_StatusE._(3, _omitEnumNames ? '' : 'CANNOT_CONNECT');
static const BleResp_StatusE CANNOT_SEND = BleResp_StatusE._(4, _omitEnumNames ? '' : 'CANNOT_SEND');
static const BleResp_StatusE CONNECT_FAIL = BleResp_StatusE._(3, _omitEnumNames ? '' : 'CONNECT_FAIL');
static const BleResp_StatusE SEND_FAIL = BleResp_StatusE._(4, _omitEnumNames ? '' : 'SEND_FAIL');
static const BleResp_StatusE TIMEOUT = BleResp_StatusE._(5, _omitEnumNames ? '' : 'TIMEOUT');
static const $core.List<BleResp_StatusE> values = <BleResp_StatusE> [
SUCCESS,
FAIL,
NOT_FOUND,
CANNOT_CONNECT,
CANNOT_SEND,
CONNECT_FAIL,
SEND_FAIL,
TIMEOUT,
];

View File

@ -19,20 +19,23 @@ const BleReq$json = {
'2': [
{'1': 'bluetoothDeviceName', '3': 2, '4': 1, '5': 9, '10': 'bluetoothDeviceName'},
{'1': 'StructData', '3': 3, '4': 1, '5': 12, '10': 'StructData'},
{'1': 'Timeout', '3': 1, '4': 1, '5': 13, '10': 'Timeout'},
{'1': 'IdleTimeout', '3': 6, '4': 1, '5': 13, '10': 'IdleTimeout'},
],
};
/// Descriptor for `BleReq`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List bleReqDescriptor = $convert.base64Decode(
'CgZCbGVSZXESMAoTYmx1ZXRvb3RoRGV2aWNlTmFtZRgCIAEoCVITYmx1ZXRvb3RoRGV2aWNlTm'
'FtZRIeCgpTdHJ1Y3REYXRhGAMgASgMUgpTdHJ1Y3REYXRh');
'FtZRIeCgpTdHJ1Y3REYXRhGAMgASgMUgpTdHJ1Y3REYXRhEhgKB1RpbWVvdXQYASABKA1SB1Rp'
'bWVvdXQSIAoLSWRsZVRpbWVvdXQYBiABKA1SC0lkbGVUaW1lb3V0');
@$core.Deprecated('Use bleRespDescriptor instead')
const BleResp$json = {
'1': 'BleResp',
'2': [
{'1': 'Status', '3': 1, '4': 1, '5': 14, '6': '.main.BleResp.StatusE', '10': 'Status'},
{'1': 'StructData', '3': 4, '4': 1, '5': 12, '10': 'StructData'},
{'1': 'StructData', '3': 2, '4': 1, '5': 12, '10': 'StructData'},
],
'4': [BleResp_StatusE$json],
};
@ -44,8 +47,8 @@ const BleResp_StatusE$json = {
{'1': 'SUCCESS', '2': 0},
{'1': 'FAIL', '2': 1},
{'1': 'NOT_FOUND', '2': 2},
{'1': 'CANNOT_CONNECT', '2': 3},
{'1': 'CANNOT_SEND', '2': 4},
{'1': 'CONNECT_FAIL', '2': 3},
{'1': 'SEND_FAIL', '2': 4},
{'1': 'TIMEOUT', '2': 5},
],
};
@ -53,7 +56,7 @@ const BleResp_StatusE$json = {
/// Descriptor for `BleResp`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List bleRespDescriptor = $convert.base64Decode(
'CgdCbGVSZXNwEi0KBlN0YXR1cxgBIAEoDjIVLm1haW4uQmxlUmVzcC5TdGF0dXNFUgZTdGF0dX'
'MSHgoKU3RydWN0RGF0YRgEIAEoDFIKU3RydWN0RGF0YSJhCgdTdGF0dXNFEgsKB1NVQ0NFU1MQ'
'ABIICgRGQUlMEAESDQoJTk9UX0ZPVU5EEAISEgoOQ0FOTk9UX0NPTk5FQ1QQAxIPCgtDQU5OT1'
'RfU0VORBAEEgsKB1RJTUVPVVQQBQ==');
'MSHgoKU3RydWN0RGF0YRgCIAEoDFIKU3RydWN0RGF0YSJdCgdTdGF0dXNFEgsKB1NVQ0NFU1MQ'
'ABIICgRGQUlMEAESDQoJTk9UX0ZPVU5EEAISEAoMQ09OTkVDVF9GQUlMEAMSDQoJU0VORF9GQU'
'lMEAQSCwoHVElNRU9VVBAF');

View File

@ -3,26 +3,29 @@ package main;
option go_package = "./spb";
//
message BleReq {
// mac地址
string bluetoothDeviceName = 2;
//
bytes StructData = 3;
// ++
uint32 Timeout = 1;
// 0
uint32 IdleTimeout = 6;
}
message BleResp {
//
enum StatusE {
SUCCESS = 0;
FAIL = 1;
NOT_FOUND = 2;
CANNOT_CONNECT = 3;
CANNOT_SEND = 4;
TIMEOUT = 5;
SUCCESS = 0; //
FAIL = 1; //
NOT_FOUND = 2; //
CONNECT_FAIL = 3; //
SEND_FAIL = 4; //
TIMEOUT = 5; //
}
//
StatusE Status = 1;
//
bytes StructData = 4;
//
bytes StructData = 2;
}

View File

@ -29,7 +29,7 @@ import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
import 'package:star_lock/talk/startChart/proto/talk_expect.pbserver.dart';
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/deviceInfo_utils.dart';
import 'package:star_lock/tools/storage.dart';
@ -221,7 +221,8 @@ class StartChartManage {
}
// RbcuInfo
void _sendRbcuInfoMessage() async {
void _sendRbcuInfoMessage(
{required String ToPeerId, bool isResp = false}) async {
final uuid = _uuid.v1();
final int timestamp = DateTime.now().millisecondsSinceEpoch;
final Int64 int64Timestamp = Int64(timestamp); // 使
@ -252,7 +253,7 @@ class StartChartManage {
name: uuid,
address: address,
time: int64Timestamp,
isResp: false,
isResp: isResp,
);
final message = MessageCommand.genericRbcuInfoMessage(
ToPeerId: ToPeerId,
@ -264,12 +265,12 @@ class StartChartManage {
}
//
void startSendingRbcuInfoMessages() {
void startSendingRbcuInfoMessages({required String ToPeerId}) {
// 1 _sendRbcuInfoMessage
rbcuInfoTimer ??=
Timer.periodic(Duration(seconds: _defaultIntervalTime), (timer) {
// RbcuInfo
_sendRbcuInfoMessage();
_sendRbcuInfoMessage(ToPeerId: ToPeerId);
});
}
@ -279,6 +280,11 @@ class StartChartManage {
rbcuInfoTimer = null;
}
// RbcuInfo
void replyRbcuInfoMessage({required String ToPeerId}) {
_sendRbcuInfoMessage(ToPeerId: ToPeerId, isResp: true);
}
// 线
Future<void> _sendOnlineMessage() async {
if (isOnlineStartChartServer) {
@ -329,7 +335,7 @@ class StartChartManage {
MessageCommand.getNextMessageId(ToPeerId, increment: false);
//
final message = MessageCommand.talkDataMessage(
ToPeerId: ToPeerId,
ToPeerId: 'D78Fo4CjNzUXz8DxuUhLtcRpnGFXhSzhzs191XzhJttS',
FromPeerId: FromPeerId,
payload: packet,
SpTotal: totalPackets,
@ -891,8 +897,36 @@ class StartChartManage {
talkExpect: talkExpectReq);
}
///
void sendRemoteUnLockMessage({
required String bluetoothDeviceName,
required List<int> openLockCommand,
}) {
sendBleMessage(
bluetoothDeviceName: bluetoothDeviceName,
bleStructData: openLockCommand,
);
}
///
void sendBleMessage({
required String bluetoothDeviceName,
required List<int> bleStructData,
}) {
// 线
final message = MessageCommand.bleMessage(
FromPeerId: FromPeerId,
ToPeerId: ToPeerId,
MessageId: MessageCommand.getNextMessageId(ToPeerId, increment: true),
bluetoothDeviceName: bluetoothDeviceName,
bleStructData: bleStructData,
);
_sendMessage(message: message);
}
///
void destruction() async {
sendTalkHangupMessage();
isOnlineStartChartServer = false;
stopHeartbeat();
stopTalkExpectMessageTimer();

View File

@ -25,7 +25,7 @@ class AppLifecycleObserver extends WidgetsBindingObserver {
void onAppPaused() {
//
print('App has entered the background.');
StartChartManage().destruction();
// StartChartManage().destruction();
}
void onAppResumed() {

View File

@ -16,6 +16,13 @@ import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/blue/blue_manage.dart';
import 'package:star_lock/blue/io_protocol/io_openLock.dart';
import 'package:star_lock/blue/io_tool/io_tool.dart';
import 'package:star_lock/main/lockDetail/lockDetail/lockDetail_logic.dart';
import 'package:star_lock/main/lockDetail/lockDetail/lockDetail_state.dart';
import 'package:star_lock/main/lockDetail/lockDetail/lockNetToken_entity.dart';
import 'package:star_lock/network/api_repository.dart';
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
@ -24,12 +31,16 @@ import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
import 'package:star_lock/talk/startChart/start_chart_manage.dart';
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
import 'package:star_lock/talk/udp/udp_manage.dart';
import 'package:star_lock/talk/udp/udp_senderManage.dart';
import 'package:star_lock/tools/bugly/bugly_tool.dart';
import 'package:star_lock/tools/storage.dart';
import '../../../../tools/baseGetXController.dart';
class TalkViewLogic extends BaseGetXController {
final TalkViewState state = TalkViewState();
final LockDetailState lockDetailState = Get.find<LockDetailLogic>().state;
Timer? _syncTimer; //
int _startTime = 0; //
final int bufferSize = 20; //
@ -258,7 +269,61 @@ class TalkViewLogic extends BaseGetXController {
}
///
udpOpenDoorAction(List<int> list) async {}
udpOpenDoorAction() async {
final List<String>? privateKey =
await Storage.getStringList(saveBluePrivateKey);
final List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
final List<String>? signKey = await Storage.getStringList(saveBlueSignKey);
final List<int> signKeyDataList = changeStringListToIntList(signKey!);
final List<String>? token = await Storage.getStringList(saveBlueToken);
final List<int> getTokenList = changeStringListToIntList(token!);
await _getLockNetToken();
final OpenLockCommand openLockCommand = OpenLockCommand(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
openMode: lockDetailState.openDoorModel,
openTime: _getUTCNetTime(),
onlineToken: lockDetailState.lockNetToken,
token: getTokenList,
needAuthor: 1,
signKey: signKeyDataList,
privateKey: getPrivateKeyList,
);
final messageDetail = openLockCommand.messageDetail();
//
StartChartManage().sendRemoteUnLockMessage(
bluetoothDeviceName: BlueManage().connectDeviceName,
openLockCommand: messageDetail,
);
showToast('已发送开门通知');
}
int _getUTCNetTime() {
if (lockDetailState.isHaveNetwork) {
return DateTime.now().millisecondsSinceEpoch ~/ 1000 +
lockDetailState.differentialTime;
} else {
return 0;
}
}
// token
Future<void> _getLockNetToken() async {
final LockNetTokenEntity entity = await ApiRepository.to.getLockNetToken(
lockId: lockDetailState.keyInfos.value.lockId.toString());
if (entity.errorCode!.codeIsSuccessful) {
lockDetailState.lockNetToken = entity.data!.token!.toString();
AppLog.log('从服务器获取联网token:${lockDetailState.lockNetToken}');
} else {
BuglyTool.uploadException(
message: '点击了需要联网开锁', detail: '点击了需要联网开锁 获取连网token失败', upload: true);
showToast('网络访问失败,请检查网络是否正常'.tr, something: () {});
}
}
///
Future<bool> getPermissionStatus() async {
@ -285,6 +350,55 @@ class TalkViewLogic extends BaseGetXController {
}
}
Future<void> requestPermissions() async {
//
var storageStatus = await Permission.storage.request();
//
var microphoneStatus = await Permission.microphone.request();
if (storageStatus.isGranted && microphoneStatus.isGranted) {
print("Permissions granted");
} else {
print("Permissions denied");
//
if (await Permission.storage.isPermanentlyDenied) {
openAppSettings(); //
}
}
}
Future<void> startRecording() async {
requestPermissions();
if (state.isRecordingScreen.value) {
showToast('录屏已开始,请勿重复点击');
}
bool start = await FlutterScreenRecording.startRecordScreen(
"Screen Recording", //
titleNotification: "Recording in progress", //
messageNotification: "Tap to stop recording", //
);
if (start) {
state.isRecordingScreen.value = true;
}
}
Future<void> stopRecording() async {
String path = await FlutterScreenRecording.stopRecordScreen;
print("Recording saved to: $path");
//
bool? success = await GallerySaver.saveVideo(path);
if (success == true) {
print("Video saved to gallery");
} else {
print("Failed to save video to gallery");
}
showToast('录屏结束,已保存到系统相册');
state.isRecordingScreen.value = false;
}
@override
void onReady() {
super.onReady();
@ -310,12 +424,16 @@ class TalkViewLogic extends BaseGetXController {
//
_initAudioRecorder();
requestPermissions();
}
@override
void onClose() {
_stopPlayG711Data();
state.listData.value = Uint8List(0);
state.audioBuffer.clear();
state.videoBuffer.clear();
_syncTimer?.cancel();
_syncTimer = null;
}
@ -387,32 +505,6 @@ class TalkViewLogic extends BaseGetXController {
}
}
///
Future<void> startRecording() async {
getPermissionStatus();
bool started =
await FlutterScreenRecording.startRecordScreenAndAudio("Recording");
if (started) {
state.isRecordingScreen.value = true;
}
}
///
Future<void> stopRecording() async {
String path = await FlutterScreenRecording.stopRecordScreen;
if (path != null) {
state.isRecordingScreen.value = false;
//
// await GallerySaver.saveVideo(path).then((bool? success) {});
//
await ImageGallerySaver.saveFile(path);
showToast('录屏已保存到相册'.tr);
} else {
state.isRecordingScreen.value = false;
print("Recording failed");
}
}
///
void _initAudioRecorder() {
state.voiceProcessor = VoiceProcessor.instance;

View File

@ -1,6 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
@ -15,6 +17,7 @@ import 'package:star_lock/talk/startChart/constant/talk_status.dart';
import 'package:star_lock/talk/startChart/views/talkView/talk_view_logic.dart';
import 'package:star_lock/talk/startChart/views/talkView/talk_view_state.dart';
import 'package:star_lock/talk/udp/udp_manage.dart';
import '../../../../app_settings/app_colors.dart';
import '../../../../tools/showTFView.dart';
@ -35,6 +38,7 @@ class _TalkViewPageState extends State<TalkViewPage>
void initState() {
super.initState();
state.listData.value = Uint8List(0);
//
// state.autoBackTimer = Timer(const Duration(seconds: 30), Get.back);
@ -65,43 +69,61 @@ class _TalkViewPageState extends State<TalkViewPage>
alignment: Alignment.center,
children: <Widget>[
Obx(
() => state.listData.value.isEmpty
? Image.asset(
'images/main/monitorBg.png',
width: ScreenUtil().screenWidth,
height: ScreenUtil().screenHeight,
fit: BoxFit.cover,
)
: Container(
decoration: state.isRecordingScreen.value
? BoxDecoration(
border: Border.all(color: Colors.red, width: 1))
: BoxDecoration(),
child: PopScope(
() {
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final logicalWidth = MediaQuery.of(context).size.width;
final logicalHeight = MediaQuery.of(context).size.height;
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
//
final physicalWidth = logicalWidth * devicePixelRatio;
final physicalHeight = logicalHeight * devicePixelRatio;
//
final rotatedImageWidth = 480; //
final rotatedImageHeight = 864; //
//
final scaleWidth = physicalWidth / rotatedImageWidth;
final scaleHeight = physicalHeight / rotatedImageHeight;
final scale = max(scaleWidth, scaleHeight); //
return state.listData.value.isEmpty
? Image.asset(
'images/main/monitorBg.png',
width: screenWidth,
height: screenHeight,
fit: BoxFit.cover,
)
: PopScope(
canPop: false,
child: RepaintBoundary(
key: state.globalKey,
child: RotatedBox(
quarterTurns: 1, // 90 1
child: Image.memory(
state.listData.value,
gaplessPlayback: true,
width: 1.sw,
height: 1.sh,
fit: BoxFit.cover,
filterQuality: FilterQuality.high,
errorBuilder: (
BuildContext context,
Object error,
StackTrace? stackTrace,
) {
return Container(color: Colors.transparent);
},
child: Transform.rotate(
angle:
state.rotateAngle.value * (pi / 180), // 90
child: Transform.scale(
scale: scale, //
child: Image.memory(
state.listData.value,
gaplessPlayback: true,
fit: BoxFit.cover,
filterQuality: FilterQuality.high,
errorBuilder: (
BuildContext context,
Object error,
StackTrace? stackTrace,
) {
return Container(color: Colors.transparent);
},
),
),
),
),
),
),
);
},
),
Obx(() => state.listData.value.isEmpty
? Positioned(
@ -200,13 +222,12 @@ class _TalkViewPageState extends State<TalkViewPage>
GestureDetector(
onTap: () async {
logic.showToast('功能暂未开放'.tr);
// if (state.talkStatus.value == TalkStatus.answeredSuccessfully) {
// if (
// state.talkStatus.value == TalkStatus.answeredSuccessfully) {
// if (state.isRecordingScreen.value) {
// await logic.stopRecording();
// print('停止录屏');
// } else {
// await logic.startRecording();
// print('开始录屏');
// }
// }
},
@ -276,7 +297,14 @@ class _TalkViewPageState extends State<TalkViewPage>
'images/main/icon_lockDetail_monitoringUnlock.png',
'开锁',
AppColors.mainColor,
onClick: () {},
onClick: () {
if (UDPManage().remoteUnlock == 1) {
logic.udpOpenDoorAction();
// showDeletPasswordAlertDialog(context);
} else {
logic.showToast('请在锁设置中开启远程开锁'.tr);
}
},
)
]);
}
@ -342,7 +370,7 @@ class _TalkViewPageState extends State<TalkViewPage>
context: context,
builder: (BuildContext context) {
return ShowTFView(
title: '请输入位数字开锁密码'.tr,
title: '请输入6位数字开锁密码'.tr,
tipTitle: '',
controller: state.passwordTF,
inputFormatters: <TextInputFormatter>[
@ -350,22 +378,23 @@ class _TalkViewPageState extends State<TalkViewPage>
FilteringTextInputFormatter.allow(RegExp('[0-9]')),
],
sureClick: () async {
// //
//
// if (state.passwordTF.text.isEmpty) {
// logic.showToast('请输入开锁密码'.tr);
// return;
// }
//
// // List<int> numbers = state.passwordTF.text.split('').map((char) => int.parse(char)).toList();
// //
// // lockID
// List<int> numbers = <int>[];
// List<int> lockIDData = utf8.encode(state.passwordTF.text);
// List<int> numbers = state.passwordTF.text.split('').map((char) => int.parse(char)).toList();
//
// lockID
// final List<int> numbers = <int>[];
// final List<int> lockIDData = utf8.encode(state.passwordTF.text);
// numbers.addAll(lockIDData);
// // topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length);
// for (int i = 0; i < 6 - lockIDData.length; i++) {
// numbers.add(0);
// }
logic.udpOpenDoorAction();
},
cancelClick: () {
Get.back();
@ -409,6 +438,8 @@ class _TalkViewPageState extends State<TalkViewPage>
state.animationController.dispose();
state.realTimePicTimer.cancel();
state.autoBackTimer.cancel();
state.videoBuffer.clear();
state.listData.value = Uint8List(0);
CallTalk().finishAVData();
super.dispose();
}

View File

@ -10,7 +10,7 @@ import 'package:network_info_plus/network_info_plus.dart';
import 'package:star_lock/talk/startChart/constant/talk_status.dart';
import 'package:star_lock/talk/startChart/handle/other/talk_data_repository.dart';
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
import 'package:star_lock/talk/startChart/start_chart_talk_status.dart';
import 'package:star_lock/talk/startChart/status/start_chart_talk_status.dart';
import '../../../../tools/storage.dart';