Files
tuiche/lib/common/util/Ble.dart
2025-04-16 14:27:10 +08:00

1101 lines
34 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:ef/ef.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/pages/common/selectDialog.dart';
String findInput = "";
double rssichange = -90;
Function? findCall;
int mcuMax = 500;
String myuuid = "00000001-0000-1000-8000-00805F9B34FB";
int closeTime = 20000;
Map devices = Map();
StreamSubscription<BluetoothAdapterState>? subscription_adapterState;
Map<String, ConnectedDeviceProp> connectList =
Map<String, ConnectedDeviceProp>();
bool isBleStart = false;
StreamSubscription<List<ScanResult>>? onScanResultsListen;
StreamSubscription<OnConnectionStateChangedEvent>?
streamSubscription_onConnectionStateChangedEvent;
Timer? showToastTimer;
List permissionInfo = [
["位置权限说明", "获得位置信息,连接附近的蓝牙设备与推荐附近门店"],
["蓝牙权限说明", "搜索链接附近的蓝牙设备"],
["附近设备权限说明", "搜索链接附近的蓝牙设备"]
];
bool isQuanShiDevice(name) {
return "$name".contains("S4-ZM-M94-4") || "$name".contains("S4-ZM-N94-4") || "$name".contains("MHT-SWES-D");
}
bool isMHTSWES(name) {
return "$name".contains("MHT-SWES-H") || "$name".contains("MHT-SWES-M") || "$name".contains("MHT-SWES-S");
}
bleParse() {
findCall = null;
print("bleParse 执行了");
showToastTimer?.cancel();
if (FlutterBluePlus.isScanningNow) {
FlutterBluePlus.stopScan();
}
}
start(Function fun, {Function? bleOnCall}) async {
if (isBleStart) {
var isOk = await requestBluetoothPermission();
if (isOk == true) {
findCall = fun;
bleOnCall?.call();
bleOnCall = null;
}
print("ble start again");
return;
}
print("ble start");
FlutterBluePlus.setLogLevel(LogLevel.info, color: false);
streamSubscription_onConnectionStateChangedEvent?.cancel();
streamSubscription_onConnectionStateChangedEvent =
FlutterBluePlus.events.onConnectionStateChanged.listen((event) {
print('${event.device} ${event.connectionState}');
});
if (await FlutterBluePlus.isSupported == false) {
print("Bluetooth not supported by this device");
return;
}
// handle bluetooth on & off
// note: for iOS the initial state is typically BluetoothAdapterState.unknown
// note: if you have permissions issues you will get stuck at BluetoothAdapterState.unauthorized
subscription_adapterState?.cancel();
int callIndex = 0;
subscription_adapterState =
FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) async {
print(state);
print("蓝牙状态 $state");
if (state == BluetoothAdapterState.on) {
showToastTimer?.cancel();
// usually start scanning, connecting, etc
findCall = fun;
var isOk = await requestBluetoothPermission();
if (isOk == true) {
bleOnCall?.call();
bleOnCall = null;
}
} else {
// show an error to the user, etc
if (Platform.isIOS &&
callIndex == 0 &&
state == BluetoothAdapterState.unknown) {
callIndex++;
return;
}
if (Platform.isAndroid) {
showToast("请打开蓝牙开关");
}
if (Platform.isIOS) {
showToast("请打开蓝牙开关且开启蓝牙权限");
await showCustomConfirmAndCancelDialog(
Get.context!, "请在“设置-蓝牙”中打开蓝牙开关或者在“设置-APP”中找到对应APP开启蓝牙权限",
confirmName: "去设置")
.then((msg) async {
if (msg == "confirm") {
openAppSettings();
}
});
}
isBleStart = false;
showToastTimer?.cancel();
showToastTimer = Timer.periodic(const Duration(seconds: 5), (t) {
if (t.tick > 3) {
t.cancel();
}
if (Platform.isAndroid) {
showToast("请打开蓝牙开关");
}
if (Platform.isIOS) {
showToast("请打开蓝牙开关且开启蓝牙权限");
}
});
}
callIndex++;
});
// turn on bluetooth ourself if we can
// for iOS, the user controls bluetooth enable/disable
if (Platform.isAndroid &&
FlutterBluePlus.adapterStateNow != BluetoothAdapterState.on) {
showPermissionInfoDialog(Get.context!, permissionInfo);
FlutterBluePlus.turnOn().then((e) {
Get.back();
}).catchError((e) {
Get.back();
});
}
var timer = null;
onScanResultsListen?.cancel();
onScanResultsListen = FlutterBluePlus.onScanResults.listen(
(List<ScanResult> results) {
// print(results.length);
for (ScanResult result in results) {
// if (result.device.id.toString().contains("A3:76")) {
// print("$result");
// }
Map d = {
"updateTime": DateTime.now().millisecondsSinceEpoch,
"name": result.device.advName,
"id": result.device.remoteId.str,
"rssi": result.rssi,
"device": result.device,
"connectable": result.advertisementData.connectable
};
Map<int, List<int>> m_d = result.advertisementData.manufacturerData;
m_d.keys.toList().forEach((v) {
if (v == 65517 && m_d[65517]?.length != 0) {
List<int> a = [0, 0, ...?m_d[65517]];
advertisDataFormatter(a, d);
} else if (v == 11125 && m_d[11125]?.length == 8) {
List<int> a = [...?m_d[11125]];
d['adData'] = {'deviceId': ab2str(a.sublist(2, 8)).toUpperCase()};
} else if (m_d[v]?.length == 8 && isQuanShiDevice(d["name"])) {
List<int> a = [...?m_d[v]];
d['adData'] = {'deviceId': ab2str(a.sublist(2, 8)).toUpperCase()};
} else if (m_d[v]?.length == 4 && isMHTSWES(d["name"])) {
ByteData bd = ByteData(2);
bd.setUint16(0, v, Endian.little);
List<int> a = [bd.getUint8(0), bd.getUint8(1), ...?m_d[v]];
d['adData'] = {'deviceId': ab2str(a).toUpperCase()};
} else if (m_d[v]?.length == 6 && isMHTSWES(d["name"])) {
List<int> a = [...?m_d[v]];
d['adData'] = {'deviceId': ab2str(a).toUpperCase()};
}
});
devices[d['id']] = d;
// print('Device found: ${result.device.name}, ${result.device.id}');
if (timer == null) {
timer = 1;
timer = Future.delayed(const Duration(microseconds: 300), () {
timer = null;
find();
});
}
}
},
onError: (e) => print(e),
);
}
// Future<Position?> locationCheck({bool isGetLocation = true}) async {
// // 先查看定位服务是否开启
// bool b = await Geolocator.isLocationServiceEnabled();
// if (b == false) {
// if (Platform.isAndroid) {
// showToast("请开启系统位置开关", closeTime: 5);
// await showCustomConfirmAndCancelDialog(Get.context!, "请开启系统位置开关",
// confirmName: "去设置")
// .then((msg) async {
// if (msg == "confirm") {
// // await Geolocator.openLocationSettings();
// await openGeolocatorLocationSettingsAndWait();
// b = await Geolocator.isLocationServiceEnabled();
// }
// });
// }
// if (Platform.isIOS) {
// showToast("请开启系统定位服务与定位权限", closeTime: 5);
// await showCustomConfirmAndCancelDialog(Get.context!,
// "请在“设置-隐私与安全性-定位服务”中开启定位服务开关或者在“设置-APP”中找到对应APP开启定位服务权限",
// confirmName: "去设置")
// .then((msg) async {
// if (msg == "confirm") {
// // await Geolocator.openAppSettings();
// await openGeolocatorAppSettingsAndWait();
// b = await Geolocator.isLocationServiceEnabled();
// }
// });
// }
// }
// var permission = await Geolocator.checkPermission();
// if (permission == LocationPermission.denied ||
// permission == LocationPermission.deniedForever) {
// showPermissionInfoDialog(Get.context!, [permissionInfo[0]]);
// permission = await Geolocator.requestPermission().catchError((e) {
// Get.back();
// });
// Get.back();
// if (permission == LocationPermission.deniedForever) {
// if (Platform.isAndroid) {
// await showCustomConfirmAndCancelDialog(Get.context!, "请开启位置权限(打开精确位置)",
// confirmName: "去设置")
// .then((msg) async {
// if (msg == "confirm") {
// // await Geolocator.openAppSettings();
// await openGeolocatorAppSettingsAndWait();
// }
// });
// }
// if (Platform.isIOS) {
// await showCustomConfirmAndCancelDialog(Get.context!,
// "请在“设置-隐私与安全性-定位服务”中开启定位服务开关或者在“设置-APP”中找到对应APP开启定位服务权限",
// confirmName: "去设置")
// .then((msg) async {
// if (msg == "confirm") {
// // await Geolocator.openAppSettings();
// await openGeolocatorAppSettingsAndWait();
// }
// });
// }
// }
// }
// Position? position;
// if (isGetLocation) {
// if (b &&
// permission != LocationPermission.denied &&
// permission != LocationPermission.deniedForever) {
// try {
// position = await Geolocator.getCurrentPosition(
// locationSettings:
// const LocationSettings(timeLimit: Duration(seconds: 5)));
// print("$position");
// } catch (e) {
// print("error $e");
// }
// }
// }
// return position;
// }
/// 使用 Completer 来等待用户返回应用,自定义的 LifecycleEventHandler 类将监视应用程序的生命周期状态,
/// 并在应用程序恢复时完成,有效地等待用户从设置屏幕返回
/// ------开始-----
Future<void> openGeolocatorAppSettingsAndWait() async {
final geolocatorAppSettingsLifecycleState =
GeolocatorAppSettingsLifecycleEventHandler();
WidgetsBinding.instance.addObserver(geolocatorAppSettingsLifecycleState);
// await Geolocator.openAppSettings();
await geolocatorAppSettingsLifecycleState.waitForResume();
WidgetsBinding.instance.removeObserver(geolocatorAppSettingsLifecycleState);
print('AppSettings have been opened and user has returned');
}
class GeolocatorAppSettingsLifecycleEventHandler
extends WidgetsBindingObserver {
final Completer<void> _completer = Completer<void>();
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed && !_completer.isCompleted) {
_completer.complete();
}
}
Future<void> waitForResume() => _completer.future;
}
/// 使用 Completer 来等待用户返回应用,自定义的 LifecycleEventHandler 类将监视应用程序的生命周期状态,
/// 并在应用程序恢复时完成,有效地等待用户从设置屏幕返回
/// ------结束-----
/// 使用 Completer 来等待用户返回应用,自定义的 LifecycleEventHandler 类将监视应用程序的生命周期状态,
/// 并在应用程序恢复时完成,有效地等待用户从设置屏幕返回
/// ------开始-----
Future<void> openGeolocatorLocationSettingsAndWait() async {
final geolocatorLocationSettingsLifecycleState =
GeolocatorLocationSettingsLifecycleEventHandler();
WidgetsBinding.instance.addObserver(geolocatorLocationSettingsLifecycleState);
// await Geolocator.openLocationSettings();
await geolocatorLocationSettingsLifecycleState.waitForResume();
WidgetsBinding.instance
.removeObserver(geolocatorLocationSettingsLifecycleState);
print('LocationSettings have been opened and user has returned');
}
class GeolocatorLocationSettingsLifecycleEventHandler
extends WidgetsBindingObserver {
final Completer<void> _completer = Completer<void>();
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed && !_completer.isCompleted) {
_completer.complete();
}
}
Future<void> waitForResume() => _completer.future;
}
/// 使用 Completer 来等待用户返回应用,自定义的 LifecycleEventHandler 类将监视应用程序的生命周期状态,
/// 并在应用程序恢复时完成,有效地等待用户从设置屏幕返回
/// ------结束-----
Future requestBluetoothPermission() async {
if (Platform.isIOS) {
PermissionStatus isBleGranted = await Permission.bluetooth.request();
print('checkBlePermissions-ios, isBleGranted=$isBleGranted');
if (isBleGranted.isGranted) {
startBluetoothScanning();
return true;
} else {
showToast("蓝牙开关或蓝牙权限未开启,请开启蓝牙开关与蓝牙权限", closeTime: 7);
await showCustomConfirmAndCancelDialog(
Get.context!, "请“设置-蓝牙”中打开蓝牙开关或者在“设置-APP”中找到对应APP开启蓝牙权限",
confirmName: "去设置")
.then((msg) async {
if (msg == "confirm") {
openAppSettings();
}
});
return false;
}
} else if (Platform.isAndroid) {
// 检查蓝牙扫描权限
String error = "";
bool isShowDialog = false;
if (!await Permission.bluetoothScan.isGranted) {
if (!isShowDialog) {
isShowDialog = true;
showPermissionInfoDialog(Get.context!, permissionInfo);
}
PermissionStatus status = await Permission.bluetoothScan.request();
if (!status.isGranted) {
error += "蓝牙扫描权限未开启,请开启附近设备权限";
}
print("蓝牙扫描 $status");
}
// 检查蓝牙连接权限
if (!await Permission.bluetoothConnect.isGranted) {
if (!isShowDialog) {
isShowDialog = true;
showPermissionInfoDialog(Get.context!, permissionInfo);
}
PermissionStatus status = await Permission.bluetoothConnect.request();
if (!status.isGranted) {
if (error.isNotEmpty) {
error += "\n";
}
error += "蓝牙连接权限未开启,请开启蓝牙权限";
}
print("蓝牙连接 $status");
}
// 检查位置权限
if (!await Permission.location.isGranted) {
if (!isShowDialog) {
isShowDialog = true;
showPermissionInfoDialog(Get.context!, permissionInfo);
}
//检查
PermissionStatus status = await Permission.location.request();
print("位置权限 $status");
if (!status.isGranted) {
await showCustomConfirmAndCancelDialog(Get.context!, "请开启位置权限(打开精确位置)",
confirmName: "去设置")
.then((msg) async {
if (msg == "confirm") {
await openGeolocatorAppSettingsAndWait();
// await Future.delayed(const Duration(seconds: 2));
print('Proceeding with other operations');
status = await Permission.location.request();
}
});
}
if (!status.isGranted) {
if (error.isNotEmpty) {
error += "\n";
}
error += "位置权限未开启,请开启位置权限";
}
}
if (isShowDialog) {
Get.back();
}
if (await Permission.bluetoothScan.isGranted &&
await Permission.bluetoothConnect.isGranted &&
await Permission.location.isGranted) {
// bool b = await Geolocator.isLocationServiceEnabled();
bool b =false;
if (b == false) {
await showCustomConfirmAndCancelDialog(Get.context!, "请开启系统位置开关",
confirmName: "去设置")
.then((msg) async {
if (msg == "confirm") {
// bool isOpen = await Geolocator.openLocationSettings();
await openGeolocatorLocationSettingsAndWait();
// await Future.delayed(const Duration(seconds: 2));
print('Proceeding with other operations');
// b = await Geolocator.isLocationServiceEnabled();
}
});
}
if (b) {
isBleStart = true;
startBluetoothScanning();
return true;
} else {
showToast("系统位置开关未开启,请开启系统位置开关", closeTime: 7);
return false;
}
} else {
Timer(Duration.zero, () async {
showToast(error, closeTime: 7);
});
return false;
}
} else {
showToast("当前系统不支持蓝牙,无法使用此功能", closeTime: 7);
return false;
}
}
void find() {
int len = devices.length;
String reg = findInput.toLowerCase().replaceAll(RegExp("[:]"), "");
List list = devices.values.toList();
for (int i = 0; i < len; i++) {
Map d = list[i];
bool flag = d['rssi'] >= rssichange;
if (flag) {
bool a = d['name'].toString().toLowerCase().contains(reg);
a = a ||
d['id']
.toString()
.toLowerCase()
.replaceAll(RegExp("[:]"), "")
.contains(reg);
// if(d.adData && d.adData.deviceId) {
// a = a || d.adData.deviceId.toLowerCase().replace(/[:]/g, "").indexOf(reg) > -1
// }
// if(d.adData && d.adData.version && reg) {
// a = a || (d.adData.version + "").indexOf(reg) > -1
// }
flag = flag && a;
}
if (flag) {
flag = flag &&
DateTime.now().millisecondsSinceEpoch - d['updateTime'] < closeTime;
}
if (!flag) {
d['isClose'] = true;
} else {
d['isClose'] = false;
}
}
var result = list.where((item) => item['isClose'] == false).toList();
if (result == null) {
findCall?.call([]);
} else {
// print(result);
result.sort((a, b) {
// print("${a['rssi']},${b['rssi']}");
return b['rssi'] - a['rssi'];
});
if (result.length > 0) {
findCall?.call(result.where((d) => d?['adData'] != null).toList());
} else {
findCall?.call(result);
}
}
}
String ab2str(List<int> buffer) {
return buffer.map((x) => x.toRadixString(16).padLeft(2, '0')).join('');
}
void advertisDataFormatter(var a, item) {
Map<String, dynamic> obj = {};
try {
if (a[2] == 1) {
obj['sn'] = a[3];
obj['deviceId'] = ab2str(a.sublist(4, 10)).toUpperCase();
obj['b'] = a[10];
obj['h'] = a[11];
obj['t'] = a[12];
item['adData'] = obj;
} else if (a[2] == 2) {
obj['sn'] = a[3];
obj['deviceId'] = ab2str(a.sublist(4, 10)).toUpperCase();
obj['b'] = a[10];
obj['h'] = a[11];
obj['t'] = a[12];
obj['net'] = (a[13] & 1) == 1 ? '在线' : '离线';
obj['flag'] = (a[13] & 2) == 2 ? '异常' : '正常';
ByteData byteData = ByteData.sublistView(
Uint8List.fromList(a.sublist(14, 18).reversed.toList()));
obj['version'] = byteData.getUint32(0);
item['adData'] = obj;
} else if (a[2] == 3) {
List<String> otherstr = [];
obj['sn'] = a[3];
obj['deviceId'] = ab2str(a.sublist(4, 10)).toUpperCase();
obj['b'] = a[10];
obj['h'] = a[11];
obj['t'] = a[12];
obj['net'] = (a[13] & 1) == 1 ? '在线' : '离线';
obj['flag'] = (a[13] & 2) == 2 ? '异常' : '正常';
if ((a[13] & 4) == 4) {
otherstr.add('呼吸暂停');
}
if ((a[13] & 8) == 8 && (a[13] & 1) == 1) {
obj['isbed'] = '在床';
} else {
obj['isbed'] = '离床';
}
if ((a[13] & 16) == 16) {
otherstr.add('授权过期');
}
if ((a[13] & 64) == 64) {
otherstr.add('设备休眠');
}
obj['other'] = otherstr.join('');
ByteData byteData = ByteData.sublistView(
Uint8List.fromList(a.sublist(14, 18).reversed.toList()));
obj['version'] = byteData.getUint32(0);
ByteData qsnData =
ByteData.sublistView(Uint8List.fromList(a.sublist(17, 19)));
obj['qsn'] = qsnData.getUint16(0) * 256 + obj['sn'];
item['adData'] = obj;
} else if (a.length > 17) {
obj['sn'] = a[3];
obj['deviceId'] = ab2str(a.sublist(4, 10)).toUpperCase();
obj['b'] = a[10];
obj['h'] = a[11];
obj['t'] = a[12];
obj['net'] = (a[13] & 1) == 1 ? '在线' : '离线';
obj['flag'] = (a[13] & 2) == 2 ? '异常' : '正常';
ByteData byteData = ByteData.sublistView(
Uint8List.fromList(a.sublist(14, 18).reversed.toList()));
obj['version'] = byteData.getUint32(0);
item['adData'] = obj;
}
} catch (e) {
print(e);
}
}
void startBluetoothScanning() async {
// 开始扫描附近的蓝牙设备
if (FlutterBluePlus.isScanningNow) {
await FlutterBluePlus.stopScan();
}
FlutterBluePlus.startScan(timeout: const Duration(seconds: 15));
}
getOneConnectedDeviceProp(id) {
return connectList[id];
}
void setOther(device, connectedDeviceProp, fun) async {
try {
List<BluetoothService> services = await device.discoverServices();
print(services);
bool isNotify = false;
bool isWrite = false;
for (var service in services) {
if (connectedDeviceProp.connectedDevicePropType ==
ConnectedDevicePropType.JunHe) {
if (service.uuid.str128.toUpperCase() != myuuid) {
continue;
}
}
// print("serviece $service");
for (BluetoothCharacteristic element in service.characteristics) {
if (isNotify == false && element.properties.notify) {
await element.setNotifyValue(true);
print("setNotifyValue 完成");
connectedDeviceProp.createLisetenReceive(element);
isNotify = true;
if (connectedDeviceProp.connectedDevicePropType ==
ConnectedDevicePropType.JunHe) {
continue;
}
if (connectedDeviceProp.connectedDevicePropType ==
ConnectedDevicePropType.MHT) {
continue;
}
}
if (isWrite == false && element.properties.write) {
connectedDeviceProp?.writeCharacteristic = element;
isWrite = true;
print("$element");
}
}
}
if (!isWrite || !isNotify) {
if (connectedDeviceProp != null) {
disconnect(connectedDeviceProp!);
}
print("service 订阅失败 isWrite $isWrite isNotify $isNotify");
fun['fail']?.call("service 订阅失败 isWrite $isWrite isNotify $isNotify");
return;
}
print("service 注册完成");
connectList[connectedDeviceProp.id] = connectedDeviceProp;
connectedDeviceProp.createListenState();
if (connectedDeviceProp.connectedDevicePropType ==
ConnectedDevicePropType.JunHe) {
connectedDeviceProp.heartbeat();
}
print("回调成功");
fun['success']?.call(connectedDeviceProp);
} catch (e) {
print("连接失败 执行失败回调 错误: $e");
if (connectedDeviceProp != null) {
disconnect(connectedDeviceProp!);
}
print("连接失败 执行失败回调");
fun['fail']?.call(e);
}
}
// 连接设备
void connectToDevice(fun) async {
BluetoothDevice device = fun['device'];
ConnectedDeviceProp? connectedDeviceProp =
getOneConnectedDeviceProp(device.remoteId.str);
if (connectedDeviceProp != null) {
disconnect(connectedDeviceProp);
Future.delayed(const Duration(seconds: 1), () {
connectToDevice(fun);
});
return;
}
try {
print("connecting");
await device.connect(timeout: const Duration(seconds: 8));
print("device.connect success");
ConnectedDevicePropType connectedDevicePropType =
ConnectedDevicePropType.JunHe;
if (isQuanShiDevice(device.advName)) {
connectedDevicePropType = ConnectedDevicePropType.QuanShi;
} else if (isMHTSWES(device.advName)) {
connectedDevicePropType = ConnectedDevicePropType.MHT;
}
connectedDeviceProp = ConnectedDeviceProp(
connectDevice: device,
fun: fun,
connectedDevicePropType: connectedDevicePropType);
if (Platform.isAndroid) {
await device.requestMtu(mcuMax);
}
Timer(const Duration(milliseconds: 1000), () {
setOther(device, connectedDeviceProp, fun);
});
} catch (e) {
print("连接失败 执行失败回调 错误: $e");
if (connectedDeviceProp != null) {
disconnect(connectedDeviceProp!);
}
print("连接失败 执行失败回调");
fun['fail']?.call(e);
}
}
void disconnect(ConnectedDeviceProp connectedDeviceProp) {
connectedDeviceProp.closeHeartBeat();
connectList.remove(connectedDeviceProp.id);
connectedDeviceProp.closeConnectedDeviceProp();
}
void closeAll() {
findCall = null;
connectList.values.toList().forEach((element) {
disconnect(element);
});
}
enum ConnectedDevicePropType { JunHe, QuanShi, MHT }
class ConnectedDeviceProp {
ConnectedDevicePropType connectedDevicePropType;
Timer? heartbeatTimer = null;
int _seq = 0;
var connectDevice;
var writeCharacteristic;
var listenState;
StreamSubscription<List<int>>? lisetenReceive;
Map fun;
List receiveMethods = [];
List logList = [];
Function? logChange;
ConnectedDeviceProp(
{required this.connectDevice,
required Map this.fun,
this.connectedDevicePropType = ConnectedDevicePropType.JunHe});
List receiveLogArr = [];
int deviceType = 2;
int encodeType = 2;
List sendArr = [];
double sendExecAverage = 100;
bool isClose = false;
String get id {
return connectDevice.remoteId.str;
}
int sum_ab(dv) {
ByteData sum = ByteData(1);
for (int i = 0; i < dv.buffer.lengthInBytes; i++) {
sum.setUint8(0, dv.getUint8(i) + sum.getUint8(0));
}
return sum.getUint8(0);
}
void heartbeat() {
closeHeartBeat();
heartbeatTimer = Timer.periodic(const Duration(seconds: 8), (timer) {
ByteData dv = ByteData(4);
dv.setUint8(0, 4);
dv.setUint8(2, seq);
dv.setUint8(3, 5);
dv.setUint8(1, sum_ab(dv));
writeBle(dv);
});
}
closeHeartBeat() {
if (heartbeatTimer != null) {
heartbeatTimer!.cancel();
heartbeatTimer = null;
}
}
ByteData str2ab_oneByte(String str, {int startLength = 0}) {
Uint8List utf8str = utf8.encode(str);
int len = utf8str.length + startLength;
ByteData buf2 = ByteData.sublistView(utf8str);
ByteData buf = ByteData(len);
for (int i = startLength; i < len; i++) {
buf.setUint8(i, buf2.getUint8(i - startLength));
}
return buf;
}
void write3OfString(sendDate, {Function? success, Function? fail}) {
ByteData dv = str2ab_oneByte(sendDate, startLength: 4);
int len = dv.buffer.lengthInBytes;
dv.setUint8(0, len);
dv.setUint8(2, seq);
dv.setUint8(3, 8 * 16 + 3);
dv.setUint8(1, sum_ab(dv));
writeBle(dv, success: success, fail: fail);
}
void writeBle(ByteData d, {Function? success, Function? fail}) {
Uint8List d_ = Uint8List.view(d.buffer);
if (sendArr.length == 0) {
write(d_, success, fail);
}
sendArr.insert(0, {"d": d_, "success": success, "fail": fail});
}
void write(Uint8List d, Function? success, Function? fail, {int exec = 100}) {
if (writeCharacteristic != null) {
// try {
// if (d[3] == 8 * 16 + 3) {
// print(
// "blewrite s = $sendExecAverage d = ${utf8.decode(d.sublist(4))}");
// } else {
// print("ble last write d = ${d[3]}");
// }
// } catch (e) {
// print("write logprint error $e");
// }
writeCharacteristic.write(d, withoutResponse: true).then((e) {
// print("write success $e");
if (connectedDevicePropType != ConnectedDevicePropType.JunHe) {
print("发送 $d");
}
if (exec > 95) {
sendExecAverage = sendExecAverage + 0.5;
}
if (sendExecAverage > 99) {
sendExecAverage = 99;
}
if (sendArr.length > 0) {
sendArr.removeLast();
Map last = sendArr.last;
write(last["d"], last["success"], last["fail"]);
}
success?.call();
}).catchError((e) {
// print("exec = $exec , $e");
if (exec < 0) {
print("$e");
fail?.call();
}
if (exec > -1 && isClose == false) {
int time = ((100.0 - sendExecAverage) * 5.0).toInt();
if (exec < 80) {
time = (100 - exec) * 5;
sendExecAverage = exec * 1.0;
} else {
sendExecAverage = sendExecAverage - (100 - exec) * 0.1;
}
Timer(Duration(milliseconds: time), () {
write(d, success, fail, exec: exec - 1);
});
}
});
}
}
void read6() {
ByteData dv = ByteData(4);
dv.setUint8(0, 4);
dv.setUint8(2, seq);
dv.setUint8(3, 6);
dv.setUint8(1, sum_ab(dv));
writeBle(dv);
}
addLog(String log) {
if (logList.length > 500) {
logList.removeRange(0, 50);
}
DateTime date = DateTime.now();
String h = date.hour > 10 ? "${date.hour}" : "0${date.hour}";
String m = date.minute > 10 ? "${date.minute}" : "0${date.minute}";
String s = date.second > 10 ? "${date.second}" : "0${date.second}";
logList.add({"time": "$h:$m:$s", "value": log});
print("ble $id log: $log");
if (logChange != null) {
logChange?.call(logList, log);
}
}
createListenState() {
listenState = connectDevice.connectionState.listen((state) {
print('ble Device state $id $state');
if (state == BluetoothConnectionState.disconnected) {
print('ble Device state $id disconnected');
isClose = true;
disconnect(this);
fun['stateChange']?.call(state, this);
}
});
}
createLisetenReceive(BluetoothCharacteristic element) {
lisetenReceive = element.onValueReceived.listen((List<int> value) {
if (connectedDevicePropType == ConnectedDevicePropType.JunHe) {
if (value.isEmpty) {
return;
}
bool isOk = sumCheck(value);
if (isOk) {
receiveMethods.forEach((m) {
m?.call();
});
yewuSwitch(value[3], value.sublist(4));
}
} else {
print("onValueReceived $value");
receiveLogArr.forEach((m) {
m(value);
});
}
});
}
closeConnectedDeviceProp() {
isClose = true;
if (listenState != null) {
listenState?.cancel();
}
if (lisetenReceive != null) {
lisetenReceive?.cancel();
}
connectDevice?.disconnect();
}
int get seq {
int r = _seq % 256;
_seq++;
return r;
}
bool sumCheck(List<int> ab) {
ByteData dv = ByteData.sublistView(Uint8List.fromList(ab));
if (dv.getUint8(0) != ab.length) {
print("和校验失败:长度不对");
return false;
} //和校验失败
if (sumList(ab) != dv.getUint8(1)) {
print("和校验失败: 校验失败");
return false;
}
return true;
}
int sumList(List<int> ab) {
ByteData dv = ByteData.sublistView(Uint8List.fromList(ab));
ByteData sum = ByteData.sublistView(Uint8List(1));
sum.setUint8(0, dv.getUint8(0));
for (int i = 2; i < ab.length; i++) {
sum.setUint8(0, dv.getUint8(i) + sum.getUint8(0));
}
return sum.getUint8(0);
}
List<int> endLogValue = [];
Timer? endLogTimer;
void yewuSwitch(int yewu, List<int> abData) {
switch (yewu) {
case 7:
String error = ab2StrByType(abData);
print(error);
break;
case 131:
List<int>? logData;
if (abData.last != 10) {
int index = abData.lastIndexOf(10);
if (index == -1) {
index = abData.length;
endLogValue = [...endLogValue, ...abData.sublist(0, index)];
} else {
logData = [...endLogValue, ...abData.sublist(0, index)];
endLogValue = abData.sublist(index);
}
// if (index == -1) {
// index = abData.length;
// }
// if(endLogValue.isNotEmpty) {
// logData = [...endLogValue, ...abData.sublist(0, index)];
// endLogValue = [];
// } else {
// logData = [...abData.sublist(0, index)];
// }
// if(index != abData.length) {
// endLogValue = abData.sublist(index);
// }
} else {
int index = abData.length;
if (endLogValue.isNotEmpty) {
logData = [...endLogValue, ...abData];
} else {
logData = abData;
}
endLogValue = [];
}
if (endLogTimer != null) {
endLogTimer!.cancel();
endLogTimer = null;
}
if (endLogValue != null && endLogValue!.isNotEmpty) {
endLogTimer = Timer(Duration(milliseconds: 400), () {
String log = ab2StrByType(endLogValue!);
endLogValue = [];
addLog(log);
try {
receiveLogArr.forEach((m) {
m(log);
});
} catch (e) {
print(e);
}
});
}
if (logData != null && logData.isNotEmpty) {
if (logData.length != 1 || logData[0] != 13) {
String log = ab2StrByType(logData!);
addLog(log);
try {
receiveLogArr.forEach((m) {
m(log);
});
} catch (e) {
print(e);
}
}
}
// 处理逻辑
break;
case 132:
ByteData dv = ByteData.sublistView(Uint8List.fromList(abData));
for (int i = 0; i < abData.length;) {
int len = dv.getUint8(i);
yewuSwitch(dv.getUint8(i + 1), abData.sublist(i + 2, i + 1 + len));
i = i + 1 + len;
}
break;
default:
break;
}
}
String ab2StrByType(List<int> abData) {
// Implement your logic for converting abData to String
String str = "";
if (abData.isNotEmpty) {
try {
str = utf8.decode(abData);
} catch (e) {
str = "解析错误";
}
}
return str;
}
}