From c77ae41b47754ebac4fd2d1256ef42635cf3e5f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Thu, 27 Jul 2023 15:29:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=93=9D=E7=89=99=E6=95=B0=E6=8D=AE=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E5=B0=81=E8=A3=85=E3=80=81=E6=95=B0=E6=8D=AE=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/command/io_protocol/io_addUser.dart | 66 +++++ .../lib/command/io_protocol/io_openDoor.dart | 59 +++++ .../lib/command/io_protocol/io_reply.dart | 23 ++ .../lib/command/io_protocol/io_sender.dart | 49 ++++ .../lib/command/io_protocol/io_type.dart | 222 +++++++++++++++++ star_lock/lib/command/io_tool/io_manager.dart | 39 +++ star_lock/lib/command/io_tool/io_model.dart | 46 ++++ star_lock/lib/command/io_tool/io_tool.dart | 229 ++++++++++++++++++ .../command/io_tool/manager_event_bus.dart | 24 ++ star_lock/lib/command/reciver_data.dart | 6 + star_lock/lib/command/sender_data.dart | 107 ++++++++ star_lock/lib/command/sender_manage.dart | 44 ++++ star_lock/lib/login/login/entity/Data.dart | 44 ++++ .../lib/login/login/entity/LoginEntity.dart | 32 +++ .../lib/main/lockMian/lockMain_page.dart | 18 +- star_lock/lib/network/api.dart | 12 + star_lock/lib/network/api_provider.dart | 23 ++ star_lock/lib/network/api_provider_base.dart | 45 ++++ star_lock/lib/network/api_repository.dart | 28 +++ .../lib/network/request_interceptor.dart | 15 ++ .../lib/network/request_interceptor_log.dart | 13 + .../lib/network/response_interceptor.dart | 20 ++ .../lib/network/response_interceptor_log.dart | 11 + .../lib/tools/manager/client_manager.dart | 57 +++++ .../tools/reactiveBlueTool/ble_scanner.dart | 2 + star_lock/lib/tools/store_service.dart | 40 +-- star_lock/pubspec.yaml | 4 + 27 files changed, 1246 insertions(+), 32 deletions(-) create mode 100644 star_lock/lib/command/io_protocol/io_addUser.dart create mode 100644 star_lock/lib/command/io_protocol/io_openDoor.dart create mode 100644 star_lock/lib/command/io_protocol/io_reply.dart create mode 100644 star_lock/lib/command/io_protocol/io_sender.dart create mode 100644 star_lock/lib/command/io_protocol/io_type.dart create mode 100644 star_lock/lib/command/io_tool/io_manager.dart create mode 100644 star_lock/lib/command/io_tool/io_model.dart create mode 100644 star_lock/lib/command/io_tool/io_tool.dart create mode 100644 star_lock/lib/command/io_tool/manager_event_bus.dart create mode 100644 star_lock/lib/command/reciver_data.dart create mode 100644 star_lock/lib/command/sender_data.dart create mode 100644 star_lock/lib/command/sender_manage.dart create mode 100644 star_lock/lib/login/login/entity/Data.dart create mode 100644 star_lock/lib/login/login/entity/LoginEntity.dart create mode 100644 star_lock/lib/network/api.dart create mode 100644 star_lock/lib/network/api_provider.dart create mode 100644 star_lock/lib/network/api_provider_base.dart create mode 100644 star_lock/lib/network/api_repository.dart create mode 100644 star_lock/lib/network/request_interceptor.dart create mode 100644 star_lock/lib/network/request_interceptor_log.dart create mode 100644 star_lock/lib/network/response_interceptor.dart create mode 100644 star_lock/lib/network/response_interceptor_log.dart create mode 100644 star_lock/lib/tools/manager/client_manager.dart diff --git a/star_lock/lib/command/io_protocol/io_addUser.dart b/star_lock/lib/command/io_protocol/io_addUser.dart new file mode 100644 index 00000000..b815c8b2 --- /dev/null +++ b/star_lock/lib/command/io_protocol/io_addUser.dart @@ -0,0 +1,66 @@ + +import '../io_tool/io_tool.dart'; +import 'io_reply.dart'; +import 'io_sender.dart'; +import 'io_type.dart'; + +//TODO:添加用户 +class AddUserCommand extends SenderProtocol { + + int? cmdID; + String? lockID; + String? authUserID; + String? keyID; + String? userID; + int? openMode; + int? keyType; + int? startDate; + int? expireDate; + int? role; + String? password; + int? token; + int? authCodeLen; + String? authCode; + AddUserCommand({ + this.cmdID, + this.lockID, + this.authUserID, + this.keyID, + this.userID, + this.openMode, + this.keyType, + this.startDate, + this.expireDate, + this.role, + this.password, + this.token, + this.authCodeLen, + this.authCode, + }) : super(CommandType.addUser); + + @override + List messageDetail() { + List data = []; + // data.add(0x21); + // int d = direction!.toInt(); + // data.addAll(intToByte2ListHigh(d)); + // data.add(0x22); + // int s = speed!.toInt(); + // data.add(s); + return data; + } +} + +class RemoteControlReply extends Reply { + RemoteControlReply.parseData(CommandType commandType, List dataDetail, int endIndex) + : super.parseData(commandType, dataDetail, endIndex) { + int index = 0; + while(index < endIndex){ + commandKey = byteUInt8(dataDetail, index); + index += offset_1!; + switch(commandKey){ + + } + } + } +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_openDoor.dart b/star_lock/lib/command/io_protocol/io_openDoor.dart new file mode 100644 index 00000000..b44b5782 --- /dev/null +++ b/star_lock/lib/command/io_protocol/io_openDoor.dart @@ -0,0 +1,59 @@ + + +import 'dart:convert'; + +import '../io_tool/io_tool.dart'; +import 'io_reply.dart'; +import 'io_sender.dart'; +import 'io_type.dart'; + +//TODO:开门 +class OpenDoorCommand extends SenderProtocol { + + int? cmdID; + String? keyID; + String? userID; + int? openMode; + int? openTime; + int? token; + int? authCodeLen; + String? authCode; + OpenDoorCommand({ + this.cmdID, + this.keyID, + this.userID, + this.openMode, + this.openTime, + this.token, + this.authCodeLen, + this.authCode, + }) : super(CommandType.openDoor); + + @override + List messageDetail() { + List data = []; + data.addAll(intToInt8List(cmdID!)); + data.addAll(utf8.encode(keyID!)); + data.addAll(utf8.encode(userID!)); + data.addAll(intToInt8List(openMode!)); + data.addAll(intToInt8List(openTime!)); + data.addAll(intToInt8List(token!)); + data.addAll(intToInt8List(authCodeLen!)); + data.addAll(utf8.encode(authCode!)); + return data; + } +} + +class RemoteControlReply extends Reply { + RemoteControlReply.parseData(CommandType commandType, List dataDetail, int endIndex) + : super.parseData(commandType, dataDetail, endIndex) { + int index = 0; + while(index < endIndex){ + commandKey = byteUInt8(dataDetail, index); + index += offset_1!; + switch(commandKey){ + + } + } + } +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_reply.dart b/star_lock/lib/command/io_protocol/io_reply.dart new file mode 100644 index 00000000..b4e449e3 --- /dev/null +++ b/star_lock/lib/command/io_protocol/io_reply.dart @@ -0,0 +1,23 @@ +import 'io_type.dart'; + +abstract class Reply{ + //value字节长度 + int? offset_19 = 19; //基准源长度 + int? offset_8 = 8; //草坪名称 + int? offset_6 = 6; //基准源识别码6个字节 + int? offset_4 = 4; + int? offset_2 = 2; + int? offset_1 = 1; + CommandType? commandType; + int? result = 1; //1是正常 0 是异常 + + //command key flag + int commandKey = 0; + + Reply.parseData(this.commandType,List dataDetail,int endIndex); + Reply({this.result}); + + + bool get isSuccessfully => result == 1; + +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_sender.dart b/star_lock/lib/command/io_protocol/io_sender.dart new file mode 100644 index 00000000..97f0d552 --- /dev/null +++ b/star_lock/lib/command/io_protocol/io_sender.dart @@ -0,0 +1,49 @@ +import '../io_tool/io_manager.dart'; +import '../io_tool/io_tool.dart'; +import 'io_type.dart'; + +abstract class IOData { + List messageDetail(); +} + +abstract class SenderProtocol extends IOData { + + CommandType? commandType; //指令类型 + final int header = 0XEF01EE02; //帧头 固定取值 0XEF01EE02,长度 4 字节 + final int ask = 0X01 ; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节 + int? _commandIndex; //帧序号 + final int identifier = 0x22 ; // 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) + + List? commandData = []; //数据域 + final int? tail = 0xFF; //帧尾 + + SenderProtocol(this.commandType) { + _commandIndex = IoManager().commandIndex; + } + + //TODO:拼装数据 + List packageData() { + commandData = messageDetail(); + List commandList = []; + commandList.add(header); //帧头 + commandList.add(_commandIndex!); //帧序号 + commandList.addAll(intToInt8List(dataSourceLength())); + int type = commandType!.typeValue; + commandList.addAll(intToInt8List(type)); //指令类型 + commandList.addAll(commandData!); //数据域 + commandList.add(checkSum(commandList)); //校验和 + commandList.add(tail!); //帧尾 + + //帧头 + // commandList.add(0xEF); + // commandList.add(0x01); + // commandList.add(0xEE); + // commandList.add(0x02); + + return commandList; + } + + //TODO:校验和 + int dataSourceLength() => commandData!.length; + +} \ No newline at end of file diff --git a/star_lock/lib/command/io_protocol/io_type.dart b/star_lock/lib/command/io_protocol/io_type.dart new file mode 100644 index 00000000..2a516eb7 --- /dev/null +++ b/star_lock/lib/command/io_protocol/io_type.dart @@ -0,0 +1,222 @@ +//TODO:发送指令类型 +enum CommandType { + addUser, //增加用户 = 0x3001 + deletUser , //删除用户 = 0x3002 + modifyingUser , //修改用户 = 0x3003 + factoryDataReset , //恢复出厂设置 = 0x3004 + openDoor , //开门 = 0x3005 + readLockStatusInfo, //读取锁状态信息 = 0x300A + transferPermissions, //转移权限 = 0x300B + reportDoorOpenRecord, //开门记录上报 = 0x3020 + generalExtendedCommond , // 通用扩展指令 = 0x3030 + getLockPublicKey , // 获取锁公钥 = 0x3090 + getLockPrivateKey, // 获取锁私钥 = 0x3091 + calibrationTime, // 校时 = 0x30f0 + synchronizingLocationInformation, // 同步位置信息 = 0x30f1 + opsUnlocks, // 运维开锁 0x30f2 + writeHotelInfo, // 写酒店信息 = 0x3016 + readHotelInfo, //读酒店信息 0x3017 +} + +extension ExtensionCommandType on CommandType { + + static CommandType getCommandType(int value){ + CommandType type = CommandType.readLockStatusInfo; + switch(value){ + case 0x3001: + { + type = CommandType.addUser; + } + break; + case 0x3002: + { + type = CommandType.deletUser; + } + break; + case 0x3003: + { + type = CommandType.modifyingUser; + } + break; + case 0x3004: + { + type = CommandType.factoryDataReset; + } + break; + case 0x3005: + { + type = CommandType.openDoor; + } + break; + case 0x300A: + { + type = CommandType.readLockStatusInfo; + } + break; + case 0x300B: + { + type = CommandType.transferPermissions; + } + break; + case 0x3020: + { + type = CommandType.reportDoorOpenRecord; + } + break; + case 0x3030: + { + type = CommandType.generalExtendedCommond; + } + break; + case 0x3090: + { + type = CommandType.getLockPublicKey; + } + break; + case 0x3091: + { + type = CommandType.getLockPrivateKey; + } + break; + case 0x30f0: + { + type = CommandType.calibrationTime; + } + break; + case 0x30f1: + { + type = CommandType.synchronizingLocationInformation; + } + break; + case 0x30f2: + { + type = CommandType.opsUnlocks; + } + break; + case 0x3016: + { + type = CommandType.writeHotelInfo; + } + break; + case 0x3017: + { + type = CommandType.readHotelInfo; + } + break; + } + return type; + } + + int get typeValue { + int type = 0x300A; + switch(this){ + case CommandType.addUser: + type = 0x3001; + break; + case CommandType.deletUser: + type = 0x3002; + break; + case CommandType.modifyingUser: + type = 0x3003; + break; + case CommandType.factoryDataReset: + type = 0x3004; + break; + case CommandType.openDoor: + type = 0x3005; + break; + case CommandType.readLockStatusInfo: + type = 0x300A; + break; + case CommandType.transferPermissions: + type = 0x300B; + break; + case CommandType.reportDoorOpenRecord: + type = 0x3020; + break; + case CommandType.generalExtendedCommond: + type = 0x3030; + break; + case CommandType.getLockPublicKey: + type = 0x3090; + break; + case CommandType.getLockPrivateKey: + type = 0x3091; + break; + case CommandType.calibrationTime: + type = 0x30f0; + break; + case CommandType.synchronizingLocationInformation: + type = 0x30f1; + break; + case CommandType.opsUnlocks: + type = 0x30f2; + break; + case CommandType.writeHotelInfo: + type = 0x3016; + break; + case CommandType.readHotelInfo: + type = 0x3017; + break; + } + // AppLog.log('数组组装指令类型:$name commandIndex:${IoManager + // ().commandIndex}'); + return type; + } + + String get typeName { + String t = ''; + switch(typeValue){ + case 0x3001: + t = '增加用户'; + break; + case 0x3002: + t = '删除用户'; + break; + case 0x3003: + t = '修改用户'; + break; + case 0x3004: + t = '恢复出厂设置'; + break; + case 0x3005: + t = '开门'; + break; + case 0x300A: + t = '读取锁状态信息'; + break; + case 0x300B: + t = '转移权限'; + break; + case 0x3020: + t = '开门记录上报'; + break; + case 0x3030: + t = '通用扩展指令'; + break; + case 0x3090: + t = '获取锁公钥'; + break; + case 0x3091: + t = '获取锁私钥'; + break; + case 0x30f0: + t = '校时'; + break; + case 0x30f1: + t = '同步位置信息'; + break; + case 0x30f2: + t = '运维开锁'; + break; + case 0x3016: + t = '写酒店信息'; + break; + case 0x3017: + t = '读酒店信息'; + break; + + } + return t; + } +} \ No newline at end of file diff --git a/star_lock/lib/command/io_tool/io_manager.dart b/star_lock/lib/command/io_tool/io_manager.dart new file mode 100644 index 00000000..46928819 --- /dev/null +++ b/star_lock/lib/command/io_tool/io_manager.dart @@ -0,0 +1,39 @@ + +enum DataTransmissionMode { + ble, +} + +class IoManager { + + static IoManager? _ioManager; + IoManager._init(); + static IoManager share(){ + _ioManager ??= IoManager._init(); + return _ioManager!; + } + factory IoManager() => share(); + IoManager get manager => share(); + + //数据传输方式 + DataTransmissionMode _dataTransmissionMode = DataTransmissionMode.ble; + bool get isBleChannel =>_dataTransmissionMode == DataTransmissionMode.ble; + + ///蓝牙传输协议 + void bleTransmission() => _dataTransmissionMode = DataTransmissionMode.ble; + + int _commandIndex = 0; //割草机协议帧序号 + configCommandIdx(int idx) => _commandIndex = idx; + Future increaseCommandIndex() async { + _commandIndex < 255 ? _commandIndex++ : _commandIndex = 0; + } + + void resetCommandIndex(){ + _commandIndex = 0; + } + + int get commandIndex => _commandIndex; + + void resetAllFlags() { + resetCommandIndex(); + } +} \ No newline at end of file diff --git a/star_lock/lib/command/io_tool/io_model.dart b/star_lock/lib/command/io_tool/io_model.dart new file mode 100644 index 00000000..391a2bc0 --- /dev/null +++ b/star_lock/lib/command/io_tool/io_model.dart @@ -0,0 +1,46 @@ + +///发送数据类 +enum DataChannel{ + ble +} + +extension Extension on DataChannel { + bool get isBLE => this == DataChannel.ble; +} + +class EventSendModel { + List? data = []; + String? topic = ''; + DataChannel? sendChannel; + EventSendModel({required this.data,this.topic,this.sendChannel}); +} + +///接收数据类 +class EventReceiveModel { + dynamic data; + String? tag = ''; + DataChannel? sendChannel; + + EventReceiveModel({ + required this.data, + this.sendChannel, + this.tag}); +} + + +///解析数据域 +class EventParseModel { + int? type; + int? commandIndex; + dynamic data; + EventParseModel({required this.type, required this.data, this.commandIndex}); +} + + +///debug info model +class StateModel { + final String title; + final String subTitle; + final bool result; + StateModel({this.title= '',this.subTitle = '',this.result = false}); +} \ No newline at end of file diff --git a/star_lock/lib/command/io_tool/io_tool.dart b/star_lock/lib/command/io_tool/io_tool.dart new file mode 100644 index 00000000..871c8899 --- /dev/null +++ b/star_lock/lib/command/io_tool/io_tool.dart @@ -0,0 +1,229 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/services.dart'; + +//TODO:int->两个字节 List 低字节在前,高字节在后(大端存储)=>嵌入式小端接收(协议用到) + +int byteInt8(List dataDetail, int index)=>_toInt8(dataDetail[index]); +int _toInt8(int value){ + var buffer = Int8List(4).buffer; + var bData = ByteData.view(buffer); + bData.setInt8(0, value); + return bData.getInt8(0); +} + +int byteInt16(List dataDetail, int index)=>_byteInt16(dataDetail, index); +int _byteInt16(List dataDetail, int index){ + if(checkListIndex(dataDetail, index, 2)){ + return 0; + } + + int value = (dataDetail[index +1] & 0xff) << 8 | (dataDetail[index] & 0xff); + return _toInt16(value); +} +int _toInt16(int value){ + var buffer = Int16List(1).buffer; + var bData = ByteData.view(buffer); + bData.setInt16(0, value); + int outputValue = bData.getInt16(0); + return outputValue; +} + +int byteInt32(List dataDetail, int index)=>_byteInt32(dataDetail, index); +int _byteInt32(List dataDetail, int index){ + if(checkListIndex(dataDetail, index, 4)){ + return 0; + } + int value = ((0xFF & + dataDetail[(index + 3)]) << 24 | (0xFF & + dataDetail[index + 2]) << 16 | (0xFF & dataDetail[index + 1]) << 8 | 0xFF & + dataDetail[index]); + return _toInt32(value); +} +int _toInt32(int value){ + var buffer = Int32List(2).buffer; + var bData = ByteData.view(buffer); + bData.setInt32(0, value); + int outputValue = bData.getInt32(0); + return outputValue; +} + +List intToInt8List(int value) =>[value]; + +List intToByte2ListHigh(int value) => [value,value >> 8]; + +//TODO:int->4个字节List 低字节在前,高字节在后(大端存储) 1byte = 8bit +List intToByte4ListHigh(int value) => [value, value >> 8, value >> 16, value >> 24]; + +int byteUInt8(List dataDetail, int index)=>_toUInt8(dataDetail[index]); +int _toUInt8(int value){ + var buffer = Int8List(1).buffer; + var bData = ByteData.view(buffer); + bData.setInt8(0, value); + return bData.getUint8(0); +} + +int byteUInt16(List dataDetail, int index)=>_byteUInt16(dataDetail, index); +_byteUInt16(List dataDetail, int index){ + if(checkListIndex(dataDetail, index, 2)){ + return 0; + } + int value = (dataDetail[index + 1]) << 8 | dataDetail[index]; + return _toUInt16(value); +} +int _toUInt16(int value){ + var buffer = Uint16List(2).buffer; + var bData = ByteData.view(buffer); + bData.setInt16(0, value); + return bData.getUint16(0); +} + + +int byteUInt32(List dataDetail, int index)=>_byteUInt32(dataDetail, index); + +int _byteUInt32(List dataDetail, int index){ + if(checkListIndex(dataDetail, index, 4)){ + return 0; + } + int value = ((0xFF & + dataDetail[(index + 3)]) << 24 | (0xFF & + dataDetail[index + 2]) << 16 | (0xFF & dataDetail[index + 1]) << 8 | 0xFF & + dataDetail[index]); + return _toUInt32(value); +} + +int _toUInt32(int value){ + var buffer = Int32List(2).buffer; + var bData = ByteData.view(buffer); + bData.setInt32(0, value); + int outputValue = bData.getUint32(0); + return outputValue; +} + +bool checkListIndex(List dataDetail, int index, int offsetLength){ + if(dataDetail == null){ + print('❌解析 dataDetail == null'); + return true; + } + var len = dataDetail.length; + bool result = index + offsetLength > len; + if(result){ + } + return result; +} + +int checkSum(List data) { + int sum = 0; + for(int v in data){ + sum ^= v; + } + return sum; +} + +Future> loadAssetsFile(String assetsPath) async{ + var byteData = await rootBundle.load(assetsPath); + return byteData.buffer.asUint8List().toList(); +} + + +//TODO:获取数据包分包后包的数量 +int getPackageCount(List data,{required int averageLen}){ + int len = data.length; + return len%averageLen > 0 ? (len~/averageLen + 1) : len~/averageLen; +} + +List getSubData({ + required int index, + required int average, + required List data +}){ + if(data == null || data.length == 0){ + return []; + } + int totalLength = data.length; + if(average >= totalLength){ + return data; + } + + if(index*average > totalLength){ + if((index - 1)*average > totalLength){ + return []; + }else{ + int tempCount = average*(index - 1); + return data.sublist(tempCount,totalLength); + } + }else{ + return data.sublist(average*(index - 1),average*index); + } +} + +List reverseList(List srcData){ + print('srcData:$srcData'); //[1,3] + int srcLen = srcData.length; + int halfLen = srcLen ~/2; + List dstData = []; + dstData.addAll(srcData); + for(int i =0; i < halfLen; i++){ + int begin = i; + int end = srcLen-i-1; + List beginData = srcData.sublist(begin,begin+1); + List endData = srcData.sublist(end,end + 1); + dstData.replaceRange(begin, begin+1, endData); + dstData.replaceRange(end, end+1, beginData); + } + print('dstData:$dstData'); + return dstData; +} + +//TODO:int->两个字节 List 高字节在前,低字节在后(小端存储) 本工程只有配置 WiFi用到的!!!! +List intToByte2ListLow(int value) =>[value >> 8,value]; + + +int dealWeekDays({ + required int mon, + required int tue, + required int wed, + required int thu, + required int fri, + required int sat, + required int sun, +}){ + return mon + tue * 2 + wed * 4 + thu * 8 + fri * 16 + sat * 32 + sun * 64; +} + +String radixString(List codeUnits){ + String result = ''; + codeUnits.forEach((value){ + result += value.toRadixString(16).padLeft(2,'0'); + }); + return result; +} + +String asciiString(List codeUnits){ + String result = ''; + codeUnits.forEach((value){ + result += String.fromCharCode(value); + }); + return result; +} + +String utf8String(List codeUnits){ + return utf8.decode(codeUnits); +} + +bool compareTwoList({List? list1,List? list2}) { + if(list1!.length != list2!.length)return false; + int ctn = list1.length; + for(int i = 0; i < ctn;i++){ + int v1 = list1[i]; + int v2 = list2[i]; + if(v1 != v2){ + print('不包含 $i'); + return false; + } + } + return true; +} + +List encodeStringToInt(String input)=>utf8.encode(input); \ No newline at end of file diff --git a/star_lock/lib/command/io_tool/manager_event_bus.dart b/star_lock/lib/command/io_tool/manager_event_bus.dart new file mode 100644 index 00000000..d094cff5 --- /dev/null +++ b/star_lock/lib/command/io_tool/manager_event_bus.dart @@ -0,0 +1,24 @@ + + +import 'package:event_bus/event_bus.dart'; + +class EventBusManager { + EventBus? eventBus; + + static EventBusManager? _manager; + EventBusManager._init(){ + eventBus = EventBus(sync: false); + } + + static EventBusManager shareManager(){ + _manager ??= EventBusManager._init(); + return _manager!; + } + + factory EventBusManager() => shareManager(); + EventBusManager get manager => shareManager(); + //发送事件 + eventBusFir(dynamic event) { + eventBus?.fire(event); + } +} diff --git a/star_lock/lib/command/reciver_data.dart b/star_lock/lib/command/reciver_data.dart new file mode 100644 index 00000000..1a8a2960 --- /dev/null +++ b/star_lock/lib/command/reciver_data.dart @@ -0,0 +1,6 @@ + + +class CommandReciverManager { + + +} \ No newline at end of file diff --git a/star_lock/lib/command/sender_data.dart b/star_lock/lib/command/sender_data.dart new file mode 100644 index 00000000..8d9eee15 --- /dev/null +++ b/star_lock/lib/command/sender_data.dart @@ -0,0 +1,107 @@ + +import '../app_settings/app_settings.dart'; +import 'io_protocol/io_sender.dart'; +import 'io_protocol/io_type.dart'; +import 'io_tool/io_model.dart'; +import 'io_tool/manager_event_bus.dart'; + +typedef CommandSendCallBack = void Function(ErrorType errorType); +class CommandSenderManager { + + static final CommandSenderManager _manager = CommandSenderManager + ._init(); + factory CommandSenderManager()=>_manager; + static CommandSenderManager getInstance()=>_manager; + CommandSenderManager._init(){ + init(); + } + + init(){ + + } + + CommandType lastCommandType = CommandType.readLockStatusInfo; + bool canSendControlCommand = false; + + //TODO:发送常规数据 + void managerSendData ({ + required SenderProtocol command, + CommandSendCallBack? callBack}) { + if (callBack != null && command.commandType != CommandType.readLockStatusInfo) { + // if (!BluetoothManager().connected) { + print('❌ 蓝牙断开了'); + if (callBack != null) { + print('managerSendData ❌ callBack'); + // EasyLoading.dismiss(); + callBack(ErrorType.notConnected); + } + return; + } + + List value = command.packageData(); + _sendNormalData(value); + // startCommandCutDown(command.commandType, value, callBack); + } + + void _sendNormalData(List data) async { + if (data != null && data.isNotEmpty) { + EventBusManager().eventBusFir(EventSendModel(data: data, sendChannel: DataChannel.ble)); + } + } + +// Timer? _commandTimer; +// List? bufferList = []; +// int? outTimeCount = 1; +// CommandType? sendCommandType; //发送指令类型 +// +// void startCommandCutDown(CommandType? commandType, List? data, Function? callBack) async { +// +// bool needCutDownTime = commandType.cutDown; +// int maxResendCount = commandType.resendCnt; +// int outMax = commandType.duration; +// +// if(needCutDownTime){ +// lastCommandType = commandType; +// cancelCommandCutDown(); +// if(needCutDownTime){ +// bufferList = data; +// _commandTimer = Timer.periodic( Duration( +// milliseconds: outMax, +// ), (t){ +// if(outTimeCount < maxResendCount){ +// outTimeCount++; +// if(bufferList.length > 0){ +// AppLog.log('''' +// ------->\n超时 第 $outTimeCount 次 重发 $commandType 指令 ''',error: true); +// // if(commandType != CommandType.upgrade){ +// // print('重发重置帧序号'); +// // bufferList.replaceRange(1, 2, [IoManager().commandIndex]); +// // } +// _sendNormalData(bufferList); +// } +// }else{ +// bufferList = []; +// cancelCommandCutDown(); +// print('managerSendData ❌ callBack'); +// if(callBack != null){ +// callBack(ErrorType.timeOut); +// } +// } +// }); +// } +// } +// } +// +// void cancelCommandCutDown({CommandType commandType}){ +// AppLog.log('发送指令类取消定时'); +// if(commandType != null && commandType != lastCommandType)return; +// if(_commandTimer != null){ +// _commandTimer.cancel(); +// _commandTimer = null; +// } +// outTimeCount = 1; +// bufferList.clear(); +// bufferList = []; +// } + +} \ No newline at end of file diff --git a/star_lock/lib/command/sender_manage.dart b/star_lock/lib/command/sender_manage.dart new file mode 100644 index 00000000..7bd419b7 --- /dev/null +++ b/star_lock/lib/command/sender_manage.dart @@ -0,0 +1,44 @@ + +import 'package:star_lock/command/sender_data.dart'; + +import 'io_protocol/io_addUser.dart'; +import 'io_protocol/io_openDoor.dart'; + +class IoSenderManage { + + //todo:添加用户 + static void senderAddUser({CommandSendCallBack? callBack}) { + CommandSenderManager().managerSendData( + command: AddUserCommand( + cmdID: 0, + lockID: "", + authUserID: "", + keyID: "", + userID: "", + openMode: 0, + keyType: 0, + startDate: 0, + expireDate: 0, + role: 0, + password: "", + token: 0, + authCodeLen: 0, + authCode: "", + ), callBack:callBack); + } + + //todo:开锁 + static void senderOpenDoor({CommandSendCallBack? callBack}) { + CommandSenderManager().managerSendData( + command: OpenDoorCommand( + cmdID: 0, + keyID: "", + userID: "", + openMode: 0, + openTime: 0, + token: 0, + authCodeLen: 0, + authCode: "", + ), callBack:callBack); + } +} \ No newline at end of file diff --git a/star_lock/lib/login/login/entity/Data.dart b/star_lock/lib/login/login/entity/Data.dart new file mode 100644 index 00000000..a424c161 --- /dev/null +++ b/star_lock/lib/login/login/entity/Data.dart @@ -0,0 +1,44 @@ +class Data { + Data({ + this.id, + this.tel, + this.email, + this.deviceId, + this.type, + this.token, + this.snName, + this.createTime,}); + + Data.fromJson(dynamic json) { + id = json['id']; + tel = json['tel']; + email = json['email']; + deviceId = json['deviceId']; + type = json['type']; + token = json['token']; + snName = json['snName']; + createTime = json['createTime']; + } + int? id; + String? tel; + String? email; + String? deviceId; + int? type; + String? token; + String? snName; + int? createTime; + + Map toJson() { + final map = {}; + map['id'] = id; + map['tel'] = tel; + map['email'] = email; + map['deviceId'] = deviceId; + map['type'] = type; + map['token'] = token; + map['snName'] = snName; + map['createTime'] = createTime; + return map; + } + +} \ No newline at end of file diff --git a/star_lock/lib/login/login/entity/LoginEntity.dart b/star_lock/lib/login/login/entity/LoginEntity.dart new file mode 100644 index 00000000..a441a31f --- /dev/null +++ b/star_lock/lib/login/login/entity/LoginEntity.dart @@ -0,0 +1,32 @@ +import 'Data.dart'; + +class LoginEntity { + LoginEntity({ + this.msg, + this.msgCode, + this.data, + this.code,}); + + LoginEntity.fromJson(dynamic json) { + msg = json['msg']; + msgCode = json['msgCode']; + data = json['data'] != null ? Data.fromJson(json['data']) : null; + code = json['code']; + } + String? msg; + int? msgCode; + Data? data; + int? code; + + Map toJson() { + final map = {}; + map['msg'] = msg; + map['msgCode'] = msgCode; + if (data != null) { + map['data'] = data!.toJson(); + } + map['code'] = code; + return map; + } + +} \ No newline at end of file diff --git a/star_lock/lib/main/lockMian/lockMain_page.dart b/star_lock/lib/main/lockMian/lockMain_page.dart index d385a814..4bc703a8 100644 --- a/star_lock/lib/main/lockMian/lockMain_page.dart +++ b/star_lock/lib/main/lockMian/lockMain_page.dart @@ -29,21 +29,13 @@ class _StarLockMainState extends State with BaseWidget{ final flutterReactiveBle = FlutterReactiveBle(); List deviceList = []; - @override - void setState(VoidCallback fn) { - // TODO: implement setState - super.setState(fn); - - // BleScanner.to.startScan([ - // - // ]); - - GetxBle.call.scanner.startScan([]); - } - - @override Widget build(BuildContext context) { + + // final logic = Get.put(GetxBle()); + // // Get.lazyPut(()=>GetxBle()); + // logic.scanner.startScan([]); + return Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: TitleAppBar(barTitle: TranslationLoader.lanKeys!.starLock!.tr, haveBack:false, haveOtherLeftWidget: true, leftWidget: Builder( diff --git a/star_lock/lib/network/api.dart b/star_lock/lib/network/api.dart new file mode 100644 index 00000000..f88e9b23 --- /dev/null +++ b/star_lock/lib/network/api.dart @@ -0,0 +1,12 @@ + +abstract class Api { + + final String baseUrl = ""; + + final String getVerificationCodeUrl = '/api/v1/vcode/email'; + + final String registerUrl = '/api/v1/vcode/email'; + + final String loginUrl = '/api/v1/vcode/email'; + +} diff --git a/star_lock/lib/network/api_provider.dart b/star_lock/lib/network/api_provider.dart new file mode 100644 index 00000000..445237b7 --- /dev/null +++ b/star_lock/lib/network/api_provider.dart @@ -0,0 +1,23 @@ + +import 'package:get/get.dart'; +import 'api_provider_base.dart'; + +class ApiProvider extends BaseProvider { + + Future requestForVCode(String email) => post(getVerificationCodeUrl.toUrl, null,query: { + 'email':email, + }); + + Future register(String email, String vCode,String password) => post(registerUrl.toUrl, null,query: { + 'email':email, + 'vCode':vCode, + "password":password + }); + + Future login(String email,String password) => post(loginUrl.toUrl, null,query: {'email':email,'password':password}); + +} + +extension ExtensionString on String { + String get toUrl => '/$this'; +} \ No newline at end of file diff --git a/star_lock/lib/network/api_provider_base.dart b/star_lock/lib/network/api_provider_base.dart new file mode 100644 index 00000000..2c33b465 --- /dev/null +++ b/star_lock/lib/network/api_provider_base.dart @@ -0,0 +1,45 @@ + +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; +import 'api.dart'; +import 'request_interceptor.dart'; +import 'request_interceptor_log.dart'; +import 'response_interceptor.dart'; +import 'response_interceptor_log.dart'; + +class BaseProvider extends GetConnect with Api { + @override + void onInit() { + httpClient.baseUrl = baseUrl; + httpClient.addRequestModifier(requestInterceptor); + httpClient.addResponseModifier(responseInterceptor); + httpClient.addRequestModifier(requestLogInterceptor); + httpClient.addResponseModifier(responseLogInterceptor); + httpClient.timeout = 15.seconds; + super.onInit(); + } + + @override + Future> post(String? url, body, {String? contentType, Map? headers, Map? query, Decoder? decoder, Progress? uploadProgress}) async { + var res = await super.post(url, body, contentType: contentType, headers:headers, query: query, decoder:decoder, uploadProgress: uploadProgress); + if(res.body == null){ + if(EasyLoading.isShow)EasyLoading.dismiss(animation: true); + var rs = { + "msg": "Network Error!", + "msgCode": -1, + "data": null, + "code": 200 + }; + return Response( + request: res.request, + statusCode: -1, + bodyString: res.bodyString, + bodyBytes: res.bodyBytes, + body: rs as T, + statusText: res.statusText, + ); + } + return res; + } + +} \ No newline at end of file diff --git a/star_lock/lib/network/api_repository.dart b/star_lock/lib/network/api_repository.dart new file mode 100644 index 00000000..1ff0cae3 --- /dev/null +++ b/star_lock/lib/network/api_repository.dart @@ -0,0 +1,28 @@ + + +import 'package:get/get.dart'; +import 'api_provider.dart'; + +class ApiRepository { + final ApiProvider apiProvider; + + static ApiRepository get to => Get.find(); + ApiRepository(this.apiProvider); + + // Future requestForVCode(String email) async { + // final res = await apiProvider.requestForVCode(email); + // return VerficationCodeEntity.fromJson(res.body); + // } + // + // Future register(String email, String vCode,String password) async { + // final res = await apiProvider.register(email,vCode,SecrecyUtils.md5EncodeUpperCase(input: password)); + // return LoginEntity.fromJson(res.body); + // } + // + // Future login({String? email,String? password}) async { + // final res = await apiProvider.login(email,SecrecyUtils.md5EncodeUpperCase(input: password)); + // return LoginEntity.fromJson(res.body); + // } + +} + diff --git a/star_lock/lib/network/request_interceptor.dart b/star_lock/lib/network/request_interceptor.dart new file mode 100644 index 00000000..a5d2de01 --- /dev/null +++ b/star_lock/lib/network/request_interceptor.dart @@ -0,0 +1,15 @@ + + +import 'dart:async'; +import 'package:get/get.dart'; +import 'package:get/get_connect/http/src/request/request.dart'; + +import '../tools/platform_info_services.dart'; +import '../tools/store_service.dart'; + +FutureOr requestInterceptor(Request request) async { + request.headers['User-Agent'] = 'Mower/CANDELA_18E/${PlatformInfoService.to.info.version}/${PlatformInfoService.to.info.buildNumber}/${GetPlatform.isAndroid ? 'Android' : 'iOS'}'; + request.headers['Accept-Language'] = 'zh_CN'; + request.headers['token'] = StoreService.to.userToken!; + return request; +} \ No newline at end of file diff --git a/star_lock/lib/network/request_interceptor_log.dart b/star_lock/lib/network/request_interceptor_log.dart new file mode 100644 index 00000000..6c458de1 --- /dev/null +++ b/star_lock/lib/network/request_interceptor_log.dart @@ -0,0 +1,13 @@ + + +import 'dart:async'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; +import 'package:get/get_connect/http/src/request/request.dart'; + +FutureOr requestLogInterceptor(Request request) async { + Get.log('GET HTTP REQUEST \n${request.url} \n${request.headers} ${request.toString()} '); + Get.log(request.headers.toString()); + EasyLoading.show(); + return request; +} \ No newline at end of file diff --git a/star_lock/lib/network/response_interceptor.dart b/star_lock/lib/network/response_interceptor.dart new file mode 100644 index 00000000..38f6dbbe --- /dev/null +++ b/star_lock/lib/network/response_interceptor.dart @@ -0,0 +1,20 @@ +import 'package:get/get.dart'; +import 'dart:async'; +import 'package:get/get_connect/http/src/request/request.dart'; + +import '../tools/manager/client_manager.dart'; + + +FutureOr responseInterceptor(Request request,Response response) async { + var statusCode = response.statusCode; + if(statusCode == 403){ + await ClientManager().logOff(); + // Get.offAllNamed(RouteConfig.homePage); + return response; + } + if(response.isOk){ + // Get.log('接口成功返回${response.body}'); + } + return response; +} + diff --git a/star_lock/lib/network/response_interceptor_log.dart b/star_lock/lib/network/response_interceptor_log.dart new file mode 100644 index 00000000..bca76248 --- /dev/null +++ b/star_lock/lib/network/response_interceptor_log.dart @@ -0,0 +1,11 @@ + +import 'dart:async'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; +import 'package:get/get_connect/http/src/request/request.dart'; + +FutureOr responseLogInterceptor(Request request,Response response) { + Get.log('HTTP RESPONSE =>\n stataCode:${response.statusCode} ${response.body} ${response.headers}'); + EasyLoading.dismiss(animation: true); + return response; +} \ No newline at end of file diff --git a/star_lock/lib/tools/manager/client_manager.dart b/star_lock/lib/tools/manager/client_manager.dart new file mode 100644 index 00000000..1264e6f0 --- /dev/null +++ b/star_lock/lib/tools/manager/client_manager.dart @@ -0,0 +1,57 @@ +// import 'package:hookii_robot/get_dom/services/store_service.dart'; +// import '../../get_dom/network/api_models/login/LoginEntity.dart'; +// import '../mower_manager/model_equipment.dart'; +import '../../login/login/entity/Data.dart' as ud; +import '../../login/login/entity/LoginEntity.dart'; +import '../store_service.dart'; + + +class ClientManager { + ClientManager._init(){ + + } + static ClientManager? _manager; + + static ClientManager shareManager(){ + _manager ??= ClientManager._init(); + return _manager!; + } + + factory ClientManager() => shareManager(); + + List devices = []; + + String vCode = '',cardText = '',password = ''; + bool isEmail = true; + + bool hasCheckedAppVersion = false; + + // void updateDevice(ud.Data data) { + // int idx = devices.indexWhere((element) => element.serialNumber == data.serialNumber); + // if(idx == -1) { + // devices.add(ud.Data.fromJson(data.toJson())); + // }else { + // devices[idx] = ud.Data.fromJson(data.toJson()); + // } + // } + + // bool checkAlias(String name) { + // int idx = devices.indexWhere((element) => element.alias == name); + // return idx != -1; + // } + + void resetDevices() => devices = []; + + Future logOff() async { + await StoreService.to.removeUserInfo(); + resetDevices(); + } + + Future loginSuccess({LoginEntity? loginEntity,bool byToken = false}) async { + if(byToken){ + return; + } + await StoreService.to.saveLogInInfo(loginEntity!); + } + +} \ No newline at end of file diff --git a/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart b/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart index 5364097c..ec8b9a5e 100644 --- a/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart +++ b/star_lock/lib/tools/reactiveBlueTool/ble_scanner.dart @@ -40,6 +40,8 @@ class BleScanner extends GetxController { _devices.clear(); _subscription?.cancel(); _subscription = _ble.scanForDevices(withServices: serviceIds).listen((device) { + print("11111111111111111:${device}"); + final knownDeviceIndex = _devices.indexWhere((d) => d.id == device.id); if (knownDeviceIndex >= 0) { diff --git a/star_lock/lib/tools/store_service.dart b/star_lock/lib/tools/store_service.dart index 38a1dae7..d5490d15 100644 --- a/star_lock/lib/tools/store_service.dart +++ b/star_lock/lib/tools/store_service.dart @@ -1,13 +1,15 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; +import '../login/login/entity/LoginEntity.dart'; + final box = GetStorage(); class StoreService extends GetxService { static StoreService get to => Get.find(); Future> init() async { await GetStorage.init(); - // await resetUserInfo(); + await resetUserInfo(); return this; } @@ -23,22 +25,22 @@ class StoreService extends GetxService { final String _userAccount = 'USER_ACCOUNT'; - // LoginEntity _loginEntity; - // LoginEntity get loginEntity => _loginEntity; - // Future resetUserInfo() async{ - // if(hasData(_loginUserInfoKey)){ - // _loginEntity = LoginEntity.fromJson(box.read(_loginUserInfoKey)); - // } - // } - // Future removeUserInfo() => remove(_loginUserInfoKey); - // - // Future saveLogInInfo(LoginEntity entity) { - // _loginEntity = LoginEntity.fromJson(entity.toJson()); - // save(_loginUserInfoKey, entity.toJson()); - // if(_loginEntity != null && _loginEntity.data != null && _loginEntity.data.email != null && _loginEntity.data.email.isNotEmpty) { - // save(_userAccount, _loginEntity.data.email); - // } - // } + LoginEntity? _loginEntity; + // LoginEntity get loginEntity => _loginEntity!; + Future resetUserInfo() async{ + if(hasData(_loginUserInfoKey)){ + _loginEntity = LoginEntity.fromJson(box.read(_loginUserInfoKey)); + } + } + Future removeUserInfo() => remove(_loginUserInfoKey); + + Future saveLogInInfo(LoginEntity entity) async { + _loginEntity = LoginEntity.fromJson(entity.toJson()); + save(_loginUserInfoKey, entity.toJson()); + if(_loginEntity != null && _loginEntity!.data != null && _loginEntity!.data!.email != null && _loginEntity!.data!.email!.isNotEmpty) { + save(_userAccount, _loginEntity?.data?.email); + } + } // String getDeviceId() => hasData(_deviceUUID!) ? read(_deviceUUID!): ""; Future saveDeviceId(String uuid) => save(_deviceUUID, uuid); @@ -46,8 +48,8 @@ class StoreService extends GetxService { // String getLanguageCode() => hasData(_languageCode) ? read(_languageCode): ""; Future saveLanguageCode(String code) => save(_languageCode, code); - // bool get hadToken => loginEntity != null && loginEntity.data.token != null && loginEntity.data.token.isNotEmpty; - // String get userToken => hadToken ? loginEntity.data.token : ""; + bool get hadToken => _loginEntity !=null && _loginEntity!.data!.token!.isNotEmpty; + String? get userToken => hadToken ? _loginEntity!.data!.token : ""; // String getLastUserAccount() => hasData(_userAccount) ? read(_userAccount): ""; void removeLastUserAccount() => remove(_userAccount); diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 7f557d6d..d1e98a3e 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -70,6 +70,10 @@ dependencies: flutter_reactive_ble: ^5.1.1 # flutter_blue_plus: ^1.10.5 + event_bus: ^2.0.0 + + flutter_easyloading: ^3.0.5 + dev_dependencies: flutter_test: sdk: flutter