632 lines
21 KiB
Dart
Raw Normal View History

import 'dart:async';
2024-05-07 16:45:59 +08:00
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
2024-05-07 16:45:59 +08:00
import 'package:crypto/crypto.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
2024-05-07 16:45:59 +08:00
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
2024-05-07 16:45:59 +08:00
import 'package:permission_handler/permission_handler.dart';
import 'package:star_lock/blue/io_protocol/io_getPrivateKey.dart';
import 'package:star_lock/blue/io_protocol/io_getPublicKey.dart';
2024-05-07 16:45:59 +08:00
import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart';
import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart';
import 'package:star_lock/mine/addLock/nearbyLock/nearbyLock_page.dart';
import 'package:star_lock/permission/permission_dialog.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import '../../../appRouters.dart';
2024-04-26 15:38:59 +08:00
import '../../../app_settings/app_settings.dart';
2023-08-08 09:42:35 +08:00
import '../../../blue/blue_manage.dart';
import '../../../blue/io_protocol/io_getStarLockStatusInfo.dart';
import '../../../blue/io_reply.dart';
import '../../../blue/io_tool/io_tool.dart';
2023-08-08 09:42:35 +08:00
import '../../../blue/io_tool/manager_event_bus.dart';
import '../../../blue/sender_manage.dart';
import '../../../tools/storage.dart';
import 'nearbyLock_state.dart';
class NearbyLockLogic extends BaseGetXController {
final NearbyLockState state = NearbyLockState();
2024-05-07 16:45:59 +08:00
int otaCount = 0;
int otaIndex = 0;
Uint8List? otaBin;
int startSecond = 0;
Map? headJson;
String? deviceName;
StreamSubscription<Reply>? _replySubscription;
// 点击连接设备
2024-04-18 16:01:08 +08:00
void connect(String deviceName) {
showTitleEasyLoading("获取锁信息 1/3");
// if(state.sureBtnState.value == 1){
// return;
// }
// state.sureBtnState.value = 1;
// showEasyLoading();
2024-05-07 16:45:59 +08:00
showBlueConnetctToastTimer(action: () {
dismissEasyLoading();
// state.sureBtnState.value = 0;
});
2024-05-07 16:45:59 +08:00
BlueManage().bludSendData(deviceName,
(BluetoothConnectionState state) async {
AppLog.log("点击要添加的设备了");
if (state == BluetoothConnectionState.connected) {
AppLog.log("开始获取公钥");
2024-01-02 18:03:50 +08:00
IoSenderManage.getPublicKey(lockId: deviceName);
2024-04-18 16:01:08 +08:00
} else if (state == BluetoothConnectionState.disconnected) {
2024-01-02 18:03:50 +08:00
dismissEasyLoading();
}
}, isAddEquipment: true);
2023-08-08 09:42:35 +08:00
}
void _initReplySubscription() {
2024-05-07 16:45:59 +08:00
_replySubscription =
EventBusManager().eventBus!.on<Reply>().listen((reply) {
if (reply is GetPublicKeyReply) {
2024-05-07 16:45:59 +08:00
_replyGetPublicKey(reply);
}
if (reply is GetPrivateKeyReply) {
_replyGetPrivateKeyKey(reply);
}
// 获取锁状态信息
if (reply is GetStarLockStatuInfoReply) {
_replyGetStarLockStatusInfo(reply);
}
2024-05-07 16:45:59 +08:00
if (reply is OTAUpgradeReply) {
if (reply.status == 0x00) {
//验证通过,开始发送数据包
dismissEasyLoading();
startOTAData();
processOtaUpgrade();
} else if (reply.status == 0x06) {
blueOTAUpgrade(headJson!, reply.token);
}
} else if (reply is ProcessOtaUpgradeReply && reply.status == 0x00) {
otaIndex++;
processOtaUpgrade();
} else if (reply is ConfirmationOTAUpgradeReply && reply.status == 0x00) {
showToast('固件升级完成'.tr);
closeOTADAta();
}
});
}
Future<void> _replyGetPublicKey(Reply reply) async {
// dismissEasyLoading();
// 获取公钥
switch (reply.status) {
case 0x00:
//成功
AppLog.log("获取公钥成功");
// 储存公钥
var publicKey = reply.data.sublist(3);
var saveStrList = changeIntListToStringList(publicKey);
Storage.setStringList(saveBluePublicKey, saveStrList);
// 获取私钥
AppLog.log("开始获取私钥");
showTitleEasyLoading("获取锁信息 2/3");
IoSenderManage.getPrivateKey(
lockId: BlueManage().connectDeviceName,
keyID: "1",
authUserID: await Storage.getUid(),
nowTime: DateTime.now().millisecondsSinceEpoch ~/ 1000,
publicKeyData: publicKey,
needAuthor: 1);
break;
default:
// state.sureBtnState.value = 0;
AppLog.log("获取公钥失败");
break;
}
}
Future<void> _replyGetPrivateKeyKey(Reply reply) async {
switch (reply.status) {
case 0x00:
AppLog.log("获取私钥成功");
//成功
reply.data.removeAt(0);
// 私钥
List<int> privateKey = reply.data.sublist(0, 16);
var savePrivateKeyList = changeIntListToStringList(privateKey);
Storage.setStringList(saveBluePrivateKey, savePrivateKeyList);
// signKey
List<int> signKey = reply.data.sublist(16, 32);
var saveSignKeyList = changeIntListToStringList(signKey);
Storage.setStringList(saveBlueSignKey, saveSignKeyList);
// 时间戳
List<int> timestamp = reply.data.sublist(32, 36);
state.timestampValue = ((0xff & timestamp[(0)]) << 24 |
(0xff & timestamp[1]) << 16 |
(0xff & timestamp[2]) << 8 |
(0xFF & timestamp[3]));
showTitleEasyLoading("获取锁信息 3/3");
_getStarLockStatus();
break;
default:
// state.sureBtnState.value = 0;
break;
}
}
// 获取星锁状态
Future<void> _replyGetStarLockStatusInfo(Reply reply) async {
int status = reply.data[2];
switch (status) {
case 0x00:
//成功
AppLog.log("获取锁状态成功");
// 厂商名称
var vendor = reply.data.sublist(3, 23);
var vendorStr = utf8String(vendor);
state.lockInfo["vendor"] = vendorStr;
// state.lockInfo["vendor"] = "XL";
2024-05-03 11:47:10 +08:00
AppLog.log("厂商名称 vendorStr:$vendorStr");
// 锁设备类型
var product = reply.data[23];
state.lockInfo["product"] = product;
AppLog.log("锁设备类型 product:$product");
// 产品名称
var model = reply.data.sublist(24, 44);
var modelStr = utf8String(model);
state.lockInfo["model"] = modelStr;
// state.lockInfo["model"] = "JL-BLE-01";
AppLog.log("产品名称 mmodelStr:$modelStr");
// 软件版本
var fwVersion = reply.data.sublist(44, 64);
var fwVersionStr = utf8String(fwVersion);
state.lockInfo["fwVersion"] = fwVersionStr;
AppLog.log("软件版本 fwVersionStr:$fwVersionStr");
// 硬件版本
var hwVersion = reply.data.sublist(64, 84);
var hwVersionStr = utf8String(hwVersion);
state.lockInfo["hwVersion"] = hwVersionStr;
AppLog.log("硬件版本 hwVersionStr:$hwVersionStr");
// 厂商序列号
var serialNum0 = reply.data.sublist(84, 100);
var serialNum0Str = utf8String(serialNum0);
state.lockInfo["serialNum0"] = serialNum0Str;
// state.lockInfo["serialNum0"] = "${DateTime.now().millisecondsSinceEpoch ~/ 10}";
AppLog.log("厂商序列号 serialNum0Str:${serialNum0Str.length}");
// 成品商序列号
var serialNum1 = reply.data.sublist(100, 116);
var serialNum1Str = utf8String(serialNum1);
state.lockInfo["serialNum1"] = serialNum1Str;
AppLog.log("成品商序列号 serialNum1Str:$serialNum1Str");
// 蓝牙名称
var btDeviceName = reply.data.sublist(116, 132);
var btDeviceNameStr = utf8String(btDeviceName);
state.lockInfo["btDeviceName"] = btDeviceNameStr;
AppLog.log("蓝牙名称 btDeviceNameStr:$btDeviceNameStr");
// 电池剩余电量
var battRemCap = reply.data[132];
state.lockInfo["electricQuantity"] = battRemCap;
AppLog.log("电池剩余电量 battRemCap:$battRemCap");
2024-04-30 16:16:06 +08:00
// 备用电池剩余电量
2024-05-03 11:47:10 +08:00
// var battRemCapStandby = reply.data[133];
// state.lockInfo["electricQuantityStandby"] = battRemCapStandby;
// AppLog.log("电池剩余电量 battRemCap:$battRemCap");
2024-04-30 16:16:06 +08:00
// 重置次数
2024-05-03 11:47:10 +08:00
var restoreCounter = reply.data.sublist(133, 135);
2024-05-07 16:45:59 +08:00
state.lockInfo["restoreCount"] =
restoreCounter[0] * 256 + restoreCounter[1];
AppLog.log(
"重置次数 restoreCounter:${restoreCounter[0] * 256 + restoreCounter[1]}");
// 重置时间
2024-05-03 11:47:10 +08:00
var restoreDate = reply.data.sublist(135, 139);
int restoreDateValue = ((0xff & restoreDate[(0)]) << 24 |
(0xff & restoreDate[1]) << 16 |
(0xff & restoreDate[2]) << 8 |
(0xFF & restoreDate[3]));
// String restoreDateStr = DateTool().dateToYMDHNSString(restoreDateValue.toString());
state.lockInfo["restoreDate"] = restoreDateValue * 1000;
AppLog.log("重置时间 restoreDateValue:$restoreDateValue");
// 主控芯片型号
2024-05-03 11:47:10 +08:00
var icPartNo = reply.data.sublist(139, 149);
var icPartNoStr = utf8String(icPartNo);
state.lockInfo["icPartNo"] = icPartNoStr;
AppLog.log("主控芯片型号 icPartNoStr:$icPartNoStr");
// 有效时间
2024-05-03 11:47:10 +08:00
var indate = reply.data.sublist(149, 153);
int indateValue = ((0xff & indate[(0)]) << 24 |
(0xff & indate[1]) << 16 |
(0xff & indate[2]) << 8 |
(0xFF & indate[3]));
// String indateStr = DateTool().dateToYMDHNSString("$indateValue");
state.lockInfo["indate"] = indateValue * 1000;
AppLog.log("有效时间 indateValue:$indateValue");
// mac地址
2024-05-03 11:47:10 +08:00
var macAddress = reply.data.sublist(153, 173);
var macAddressStr = utf8String(macAddress);
state.lockInfo["mac"] = macAddressStr;
AppLog.log("mac地址 macAddressStr:$macAddressStr");
2024-05-03 11:47:10 +08:00
var index = 173;
// 锁特征值字符串长度
2024-05-03 11:47:10 +08:00
var featureValueLength = reply.data[index];
AppLog.log("锁特征值字符串长度 featureValueLength:$featureValueLength");
// 锁特征值说明(本机能支持的功能)
// 获取到锁给的字符数组
var featureNetxLength = index + featureValueLength + 1;
2024-04-18 16:01:08 +08:00
if (reply.data.length < featureNetxLength) {
showToast("锁数据异常,请重试");
return;
}
2024-04-18 16:01:08 +08:00
var featureValue =
reply.data.sublist(index + 1, index + featureValueLength + 1);
String featureValueStr = asciiString(featureValue);
state.featureValue = featureValueStr;
// List allFeatureValueTwoList = charListChangeIntList(featureValue);
2024-04-26 15:38:59 +08:00
// AppLog.log("featureValueLength:$featureValueLength featureValue:$featureValue \n featureValueStr:$featureValueStr");
index = index + featureValueLength + 1;
AppLog.log("锁特征值字符串 featureValueStr:$featureValueStr");
// 使能特征值字符串长度
var featureEnValLength = reply.data[index];
AppLog.log("使能特征值字符串长度 featureEnValLength:$featureEnValLength");
// 使能锁特征值说明(本机启用的功能)
var featureEnNextLength = index + featureEnValLength + 1;
2024-04-18 16:01:08 +08:00
if (reply.data.length < featureEnNextLength) {
showToast("锁数据异常,请重试");
return;
}
2024-04-18 16:01:08 +08:00
var featureEnVal =
reply.data.sublist(index + 1, index + featureEnValLength + 1);
String featureEnValStr = asciiString(featureEnVal);
state.featureSettingValue = featureEnValStr;
// List allFeatureEnValTwoList = charListChangeIntList(featureEnVal);
2024-04-26 15:38:59 +08:00
// AppLog.log("featureEnValLength:$featureEnValLength featureEnVal:$featureEnVal \n featureEnValStr:$featureEnValStr");
index = index + featureEnValLength + 1;
AppLog.log("使能锁特征值说明 featureEnValStr:$featureEnValStr");
// 支持的带参数特征值的总条目数
// var featureParaTotal = reply.data[index];
var featureParaTotalList = reply.data.sublist(index);
state.featureSettingParams = featureParaTotalList;
AppLog.log("featureParaTotalList:$featureParaTotalList");
Get.toNamed(Routers.lockAddressGaoDePage, arguments: {
"pwdTimestamp": state.timestampValue * 1000,
"lockInfo": state.lockInfo,
"featureValue": state.featureValue,
"featureSettingValue": state.featureSettingValue,
"featureSettingParams": state.featureSettingParams,
});
break;
case 0x06:
//无权限
var privateKey = await Storage.getStringList(saveBluePrivateKey);
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
// IoSenderManage.senderGetLockStatu(
// lockID:BlueManage().connectDeviceName,
// userID:await Storage.getUid(),
// privateKey:getPrivateKeyList,
// );
IoSenderManage.senderGetStarLockStatuInfo(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
isBeforeAddUser: true,
privateKey: getPrivateKeyList,
);
break;
default:
//失败
// state.sureBtnState.value = 0;
break;
}
}
// 获取锁状态
Future<void> _getStarLockStatus() async {
// 进来之后首先连接
// BlueManage().bludSendData(BlueManage().connectDeviceName, (BluetoothConnectionState state) async {
// if (state == BluetoothConnectionState.connected) {
// dismissEasyLoading();
2024-05-07 16:45:59 +08:00
AppLog.log("开始获取锁状态");
var privateKey = await Storage.getStringList(saveBluePrivateKey);
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
// IoSenderManage.senderGetLockStatu(
// lockID:BlueManage().connectDeviceName,
// userID:await Storage.getUid(),
// privateKey:getPrivateKeyList,
// );
IoSenderManage.senderGetStarLockStatuInfo(
lockID: BlueManage().connectDeviceName,
userID: await Storage.getUid(),
isBeforeAddUser: true,
privateKey: getPrivateKeyList,
);
// } else if (state == BluetoothConnectionState.disconnected) {
// dismissEasyLoading();
// }
// }, isAddEquipment: true);
}
2024-04-18 16:01:08 +08:00
void startScanBlueList() {
BlueManage().startScan(2000, (List<ScanResult> list) {
2023-12-27 10:47:58 +08:00
state.devices.clear();
for (int i = 0; i < list.length; i++) {
ScanResult device = list[i];
2024-04-18 16:01:08 +08:00
if (((device.advertisementData.serviceUuids.isNotEmpty
? device.advertisementData.serviceUuids[0]
: "")
.toString()[31] !=
"1")) {
2023-12-27 10:47:58 +08:00
state.devices.add(list[i]);
}
}
});
}
2024-04-18 16:01:08 +08:00
void stopScanBlueList() {
BlueManage().disconnect();
BlueManage().stopScan();
}
2024-05-07 16:45:59 +08:00
// 点击连接设备,升级 ota 固件
void oTAUpgrade(String deviceName) {
showTitleEasyLoading("连接设备中...");
this.deviceName = deviceName;
BlueManage().bludSendData(deviceName,
(BluetoothConnectionState state) async {
AppLog.log("连接设备");
if (state == BluetoothConnectionState.connected) {
AppLog.log("连接成功");
dismissEasyLoading();
otaUpdate();
} else if (state == BluetoothConnectionState.disconnected) {
AppLog.log("连接失败");
dismissEasyLoading();
}
}, isAddEquipment: true);
}
//手动升级
Future<void> otaUpdate() async {
var status = await PermissionDialog.request(
Permission.storage, '需要访问读写权限才能使用手动升级固件'.tr);
if (status != true) {
return;
}
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result == null || result.files.single.path is! String) {
return;
}
File file = File(result.files.single.path!);
Uint8List data = await file.readAsBytes();
headJson = await getHeadFile(data);
if (headJson is! Map) {
return;
}
otaBin = await checkFile(data, headJson!);
if (otaBin == null) {
return;
}
String md5Str = md5.convert(otaBin!).toString();
headJson!['fwMd5'] = md5Str;
blueOTAUpgrade(headJson!, [0, 0, 0, 0]);
}
//蓝牙操作 ota 升级
void blueOTAUpgrade(Map data, List<int> token) {
if (deviceName == null) {
AppLog.log('blueOTAUpgrade:设备名字为 null');
return;
}
BlueManage().bludSendData(deviceName!,
(BluetoothConnectionState deviceConnectionState) async {
if (deviceConnectionState == BluetoothConnectionState.connected) {
String uid = await Storage.getUid() ?? '';
BlueManage().writeCharacteristicWithResponse(OTAUpgradeCommand(
lockID: deviceName,
userID: uid,
keyID: deviceName,
platform: int.tryParse(data['platform']) ?? 0,
product: int.tryParse(data['product']) ?? 0,
hwVersion: data['hwVersion'],
fwVersion: data['fwVersion'],
fwSize: data['fwSize'],
fwMD5: data['fwMd5'],
needAuthor: 1,
token: token,
encrypt: false,
).packageData());
showTitleEasyLoading("连接设备中...");
} else if (deviceConnectionState ==
BluetoothConnectionState.disconnected) {}
},isAddEquipment: true);
}
//循环传输升级固件包
Future<void> processOtaUpgrade() async {
if (!state.otaUpdateIng.value) {
return;
}
int length = otaBin?.length ?? 0;
if (otaCount == 0) {
//首次
int difference = length % 240;
otaCount = length ~/ 240 + (difference > 0 ? 1 : 0);
startSecond = DateTime.now().millisecondsSinceEpoch ~/ 1000;
}
if (otaCount <= otaIndex) {
int now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
String msg =
'传输完成 时间:${now - startSecond}秒 otaCount:$otaCount otaIndex:$otaIndex ';
closeOTADAta();
AppLog.log(msg);
// showToast(msg);
return;
}
int star = otaIndex * 240;
int end = (otaIndex + 1) * 240;
if (end > length) {
end = length;
}
int size = end - star;
List<int> data = otaBin!.sublist(star, end);
state.otaProgress.value = otaIndex / otaCount;
await BlueManage().writeCharacteristicWithResponse(
ProcessOtaUpgradeCommand(index: otaIndex, size: size, data: data)
.packageData());
}
//开始 ota升级
void startOTAData() {
state.otaUpdateIng.value = true;
state.oTAProgressDialog = true;
Get.dialog(
OTAProgressDialog(
logic: this,
),
barrierDismissible: false)
.then((value) => state.oTAProgressDialog = false);
}
//清楚 ata 安装文件
void closeOTADAta() {
if (state.oTAProgressDialog) {
Get.back();
}
state.otaUpdateIng.value = false;
state.otaProgress.value = 0;
otaIndex = 0;
otaCount = 0;
startSecond = 0;
otaBin = null;
}
// 拦截返回事件
void getBack() {
if (state.otaUpdateIng.value) {
closeOTADAta();
} else {
Get.back();
}
}
// 检查文件头
Future<Map?> getHeadFile(Uint8List data) async {
if (data.length <= 16) {
showToast('错误固件,请选择正确的文件'.tr);
return null;
}
// 检查文件头
String header;
try {
header = utf8.decode(data.sublist(0, 12));
} catch (e) {
showToast('非SYD固件请选择正确的文件'.tr);
return null;
}
if (header != 'SYD-BIN-DATA') {
showToast('非SYD固件请选择正确的文件'.tr);
return null;
}
// 解析元数据长度
Uint8List metaLenList;
int metaLen;
try {
metaLenList = data.sublist(12, 16);
metaLen = ByteData.sublistView(metaLenList).getUint32(0);
} catch (e) {
showToast('文件校验失败 0x01'.tr);
return null;
}
if (metaLen < 2 || metaLen > 10240) {
showToast('文件校验失败 0x01'.tr);
return null;
}
// 读取和解析元数据
Uint8List metaStrList;
String metaStr;
try {
metaStrList = data.sublist(16, 16 + metaLen);
metaStr = utf8.decode(metaStrList);
} catch (e) {
showToast('解析元数据失败,请选择正确的文件'.tr);
return null;
}
AppLog.log(metaStr);
var meta = jsonDecode(metaStr);
if (meta is! Map) {
showToast('解析元数据失败,请选择正确的文件'.tr);
return null;
}
return meta..['metaLen'] = metaLen;
}
//检测升级文件并读取 bin
Future<Uint8List?> checkFile(Uint8List data, Map meta) async {
num binOffset = 16 + (meta['metaLen'] ?? 0);
// 获取固件数据部分
Uint8List bin = data.sublist(binOffset.toInt(), data.length);
//md5 校验有问题,暂时不解析
String md5Str = md5.convert(bin).toString().toUpperCase();
AppLog.log('---> $md5Str ${meta['fwMd5']}');
if (md5Str != meta['fwMd5']) {
showToast('文件校验失败 0x02'.tr);
return null;
}
if (bin.length != meta['fwSize']) {
showToast('文件校验失败 0x03'.tr);
return null;
}
return bin;
}
@override
void onReady() {
super.onReady();
_initReplySubscription();
state.ifCurrentScreen.value = true;
startScanBlueList();
}
@override
void onInit() {
super.onInit();
}
2023-08-08 09:42:35 +08:00
@override
void onClose() {
super.onClose();
2024-05-07 16:45:59 +08:00
_replySubscription?.cancel();
2023-08-08 09:42:35 +08:00
}
}