Files
tuiche/lib/pages/device_bind/blueteeth_device_page.dart
2025-04-18 18:13:21 +08:00

1054 lines
40 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 '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:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:permission_handler/permission_handler.dart'; // 引入permission_handler
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/model/BleDeviceData.dart';
import 'package:vbvs_app/pages/common/selectDialog.dart';
import 'package:vbvs_app/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart';
import 'package:vbvs_app/common/util/Ble.dart' as ble;
class BlueteethDevicePage extends StatefulWidget {
int tid = -1;
BlueteethDevicePage({super.key, this.tid = -1});
@override
State<BlueteethDevicePage> createState() => _EPageState();
}
class _EPageState extends State<BlueteethDevicePage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
late FlutterBluePlus flutterBlue; // 声明 flutterBlue 实例
List<ScanResult> scanResults = []; // 存储扫描到的设备
bool isScanning = false; // 扫描状态控制
Timer? _timer; // 定时器,用于重复扫描
bool _isDialogShowing = false;
var currentConnectedDeviceProp;
var connectDeviceCurrent = null;
List bleDevice = [];
String currentMsg = "寻找设备中...";
Timer? connectTimer;
bool isFind = false;
List bindArrBackup = [];
List bindArr = ["", "", ""];
@override
void initState() {
super.initState();
flutterBlue = FlutterBluePlus(); // 初始化flutterBlue实例
_checkBluetoothPermission(); // 检查蓝牙权限
Get.find<BlueteethBindController>().startStatusPolling();
}
// 检查蓝牙权限
Future<void> _checkBluetoothPermission() async {
PermissionStatus bluetoothStatus = await Permission.bluetooth.status;
PermissionStatus locationStatus = await Permission.location.status;
if (bluetoothStatus.isGranted && locationStatus.isGranted) {
// 权限已授予,开始扫描
_startScanning();
_startPeriodicScan(); // 开始定时扫描
} else {
// 权限未授予,请求权限
_requestBluetoothPermission();
}
}
Future<void> _requestBluetoothPermission() async {
// Android 13+ 使用新的蓝牙权限
Map<Permission, PermissionStatus> statuses = await [
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.location, // Android 12 及以下仍需要位置权限来进行扫描
].request();
bool allGranted = statuses[Permission.bluetoothScan]?.isGranted == true &&
statuses[Permission.bluetoothConnect]?.isGranted == true &&
statuses[Permission.location]?.isGranted == true;
if (allGranted) {
// 用户授予了权限,开始扫描
_startScanning();
_startPeriodicScan();
} else {
// 权限被拒绝,提示用户
_showPermissionDeniedDialog();
}
}
// 显示权限被拒绝的提示
void _showPermissionDeniedDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("权限提示"),
content: Text("应用需要蓝牙和位置权限才能扫描设备。请授予权限。"),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("确定"),
),
],
);
},
);
}
// 开始扫描蓝牙设备
void _startScanning() async {
var bluetoothState = await FlutterBluePlus.isOn;
if (!bluetoothState && !_isDialogShowing) {
_isDialogShowing = true;
await _showBluetoothNotEnabledDialog();
_isDialogShowing = false;
return;
}
if (!isScanning) {
setState(() {
isScanning = true;
});
await FlutterBluePlus.startScan(timeout: Duration(seconds: 10));
FlutterBluePlus.scanResults.listen((results) {
final signalThreshold = blueteethBindController.model.singal!;
final filteredResults = results
.where((r) =>
r.rssi > signalThreshold &&
r.advertisementData.localName == "AITH-V2" &&
r.advertisementData.manufacturerData.containsKey(0xFFED))
.toList();
// 解析数据
final parsedDeviceList = <BleDeviceData>[];
for (var r in filteredResults) {
try {
List<int> rawData = r.advertisementData.manufacturerData[0xFFED]!;
BleDeviceData deviceData = parseBleData(rawData);
deviceData.name = r.advertisementData.advName;
deviceData.rssi = r.rssi;
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
parsedDeviceList.add(deviceData);
} catch (e) {
print("设备数据解析失败: $e");
}
}
// 使用一个临时变量 lastDeviceList 来比较是否有变化
setState(() {
bool hasChanges = false;
// 如果 devicelist 长度不同或内容有差异,认为有变化
if (blueteethBindController.model.devicelist?.length !=
parsedDeviceList.length) {
hasChanges = true;
} else {
// 深度比较每个设备的属性(比如 mac, rssi
for (int i = 0;
i < blueteethBindController.model.devicelist!.length;
i++) {
if (blueteethBindController.model.devicelist![i].mac !=
parsedDeviceList[i].mac ||
blueteethBindController.model.devicelist![i].rssi !=
parsedDeviceList[i].rssi) {
hasChanges = true;
break;
}
}
}
// 如果有变化,更新 devicelist 和 blelist
if (hasChanges) {
blueteethBindController.model.devicelist = parsedDeviceList;
blueteethBindController.model.blelist = filteredResults;
// blueteethBindController.updateDeviceStatus();
}
});
});
// 等待扫描完成
await Future.delayed(Duration(seconds: 10));
await FlutterBluePlus.stopScan();
setState(() {
isScanning = false;
});
print("扫描完成");
}
}
// 定时每10秒进行一次扫描
void _startPeriodicScan() {
_timer = Timer.periodic(Duration(seconds: 10), (timer) {
if (!isScanning) {
_startScanning(); // 调用扫描函数
}
});
}
// 停止扫描
void _stopScanning() {
if (isScanning) {
FlutterBluePlus.stopScan(); // 停止扫描
setState(() {
isScanning = false; // 更新扫描状态
});
}
}
// 停止定时扫描
void _stopPeriodicScan() {
_timer?.cancel();
}
@override
void dispose() {
super.dispose();
_stopPeriodicScan(); // 停止定时扫描
_stopScanning(); // 确保离开页面时停止扫描
}
connectToDevice(device, {int time = 5}) {
ble.connectToDevice(
{
"device": device,
'success': (ble.ConnectedDeviceProp deviceProp) {
if (deviceProp.connectedDevicePropType ==
ble.ConnectedDevicePropType.JunHe) {
currentConnectedDeviceProp = deviceProp;
deviceProp.write3OfString("blog enable");
deviceProp.write3OfString("blog rlmax=128");
Timer(const Duration(microseconds: 100), () async {
String log = "";
Function logAdd = (l) {
log += l;
};
deviceProp.receiveLogArr.add(logAdd);
deviceProp.encodeType = 1;
deviceProp.deviceType = 1;
Timer.periodic(const Duration(milliseconds: 300), (timer) async {
if (timer.tick > 20) {
ble.disconnect(currentConnectedDeviceProp);
failSelectDialog();
timer.cancel();
}
if (log.contains("GB2312") || log.contains("UTF-8")) {
timer.cancel();
if (log.contains('CHARSET:UTF-8')) {
deviceProp.encodeType = 2;
}
if (log.contains('TARGET:ESPXX')) {
deviceProp.deviceType = 2;
}
log = "";
bool isSuccess = false;
for (var i = 0; i < 4; i++) {
deviceProp.write3OfString("at+system info");
await Future.delayed(const Duration(milliseconds: 400));
RegExp regExp = RegExp(r"Target Mac:(\S*)");
RegExpMatch? regExpMatch = regExp.firstMatch(log);
if (regExpMatch != null && regExpMatch.group(1) != null) {
String? mac = regExpMatch.group(1);
if (mac?.length == 12 && mac != "000000000000") {
bindArr[2] = "$mac".toUpperCase();
}
isSuccess = true;
break;
}
}
deviceProp.receiveLogArr.remove(logAdd);
print("$bindArr");
RegExp regExp = RegExp(
r"WIFI CONNECTED INFO:SSID=([^\t\n]*)\s*,RSSI=(\S*)\s*,");
RegExpMatch? regExpMatch = regExp.firstMatch(log);
if (regExpMatch != null && log.contains("Status=connect")) {
blueteethBindController.model.connectedWifiName =
regExpMatch.group(1) ?? "";
if (int.tryParse("${regExpMatch.group(2)}") != null) {
blueteethBindController.model.connectedRssi =
int.parse("${regExpMatch.group(2)}");
}
blueteethBindController.updateAll();
}
ble.bleParse();
if (bindArr[0] != null &&
bindArr[0] != "" &&
bindArr[1] != "") {
setState(() {
currentMsg = "绑定中...";
});
blueteethBindController.bindDevice({
"tid": widget.tid,
"name": blueteethBindController.model.deviceName,
"mac": bindArr[0],
"macA": bindArr[1],
"macB": bindArr[2]
}).then((d) {
blueteethBindController.model.bindArr = bindArr;
globalController.getDeviceList();
LoadingDialog.hide();
showCustomConfirmDialog(context, "设备添加成功!",
btnName: "打开WIFI配置",
icon: ConfirmDialogIcon.success)
.then((d) {
if (d == "confirm") {
Get.offAndToNamed("/wifi", arguments: deviceProp);
}
});
}).catchError((d) {
print("$d");
currentMsg = "绑定失败: ${d.message}";
ble.disconnect(currentConnectedDeviceProp);
failSelectDialog(title: "${d.message}");
});
} else {
LoadingDialog.hide();
Get.offAndToNamed("/wifi", arguments: deviceProp);
}
} else {
deviceProp.read6();
}
});
});
} else if (deviceProp.connectedDevicePropType ==
ble.ConnectedDevicePropType.QuanShi) {
List receive = [];
Function fun = (d) {
receive.add(d);
};
deviceProp.receiveLogArr.add(fun);
List<int> head = [
255,
255,
255,
255,
1,
0,
12,
17,
];
Timer.periodic(const Duration(seconds: 1), (timer) {
if (timer.tick > 20) {
timer.cancel();
currentMsg = "错误未能获取到MAC";
failSelectDialog();
}
deviceProp.write(
Uint8List.fromList([
0xFF,
0xFF,
0xFF,
0xFF,
0x01,
0x00,
0x0C,
0x0B,
0x0F,
0x23,
0x04
]),
null,
null);
if (receive.length > 0) {
receive.forEach((data) {
if (data.length != 17) {
return;
}
bool r = true;
for (var i = 0; i < head.length; i++) {
if (head[i] != data[i]) {
r = false;
}
}
if (r == false) {
return;
}
bindArr[1] = ble.ab2str(data.sublist(9, 15)).toUpperCase();
timer.cancel();
deviceProp.receiveLogArr.remove(fun);
blueteethBindController.model.deviceName =
deviceProp.connectDevice?.advName;
ble.disconnect(deviceProp);
toFindJunhe();
});
}
});
} else {
List receive = [];
Function fun = (d) {
receive.add(d);
};
deviceProp.receiveLogArr.add(fun);
List<int> head = [255, 255, 255, 255, 0x00, 0x08, 0x40, 0x01];
Timer.periodic(const Duration(seconds: 1), (timer) {
if (timer.tick > 20) {
timer.cancel();
currentMsg = "错误未能获取到MAC";
failSelectDialog();
}
deviceProp.write(
Uint8List.fromList([
255,
255,
255,
255,
0x00,
0x03,
0x40,
0x01,
0x01,
0x00,
0x45,
0xfd
]),
null,
null);
if (receive.length > 0) {
receive.forEach((data) {
if (data.length != 17) {
return;
}
bool r = true;
for (var i = 0; i < head.length; i++) {
if (head[i] != data[i]) {
r = false;
}
}
if (r == false) {
return;
}
bindArr[1] = ble.ab2str(data.sublist(8, 14)).toUpperCase();
print("$bindArr");
timer.cancel();
deviceProp.receiveLogArr.remove(fun);
blueteethBindController.model.deviceName =
deviceProp.connectDevice?.advName;
ble.disconnect(deviceProp);
toFindJunhe();
});
}
});
}
},
'fail': (e) {
print(e);
if (time > 0) {
connectToDevice(device, time: time - 1);
} else {
currentMsg = "蓝牙无法连接上设备";
failSelectDialog(title: currentMsg);
}
}
},
);
}
isBind() {
return !(blueteethBindController.model.bindArr[1]?.length == 12);
}
failSelectDialog({String title = ""}) {
LoadingDialog.hide();
setState(() {});
showCustomConfirmAndCancelDialog(
context, title == "" ? (isBind() ? "绑定失败" : "连接失败") : title,
confirmName: "重试", cancelName: "返回")
.then((d) {
if (d == "confirm") {
if (connectDeviceCurrent != null) {
ble.bleParse();
ble.start((List d) {
setState(() {
bleDevice = d;
});
}, bleOnCall: () {
LoadingDialog.show("连接中...\n靠近设备2米内",
icon:
isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
setState(() {
currentMsg = "连接设备中...";
});
connectToDevice(connectDeviceCurrent);
});
} else {
bleExec();
}
} else if (d == "cancel") {
Get.back();
}
});
}
bleExec() {
ble.bleParse();
connectTimer?.cancel();
int index = 0;
bool isCloseLoadingDialog = false;
isFind = false;
blueteethBindController.model.bindArr = bindArrBackup;
bindArr = ["", "", ""];
ble.start((List d) {
setState(() {
bleDevice = d;
});
if (isBind()) {
if (isCloseLoadingDialog == false &&
bleDevice.indexWhere((item) {
if (widget.tid == 1) {
return ble.isQuanShiDevice(item["name"]);
} else {
return ble.isMHTSWES(item["name"]);
}
}) !=
-1) {
isCloseLoadingDialog = true;
LoadingDialog.hide();
}
}
}, bleOnCall: () {
if (isBind()) {
LoadingDialog.show("搜索蓝牙设备中...\n请打开蓝牙开关、定位开关\n与设备距离在2米内",
icon: isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
Timer.periodic(const Duration(seconds: 1), (t) {
if (t.tick > 15) {
t.cancel();
isCloseLoadingDialog = true;
LoadingDialog.hide();
showCustomConfirmAndCancelDialog(context, "未发现设备",
confirmName: "重试", cancelName: "返回")
.then((d) {
if (d == "confirm") {
bleExec();
} else if (d == "cancel") {
Get.back();
}
});
} else {
if (isCloseLoadingDialog == true) {
t.cancel();
}
}
});
return;
}
LoadingDialog.show(
"${isBind() ? "绑定中...\n与设备距离在2米内" : "连接中...\n请打开蓝牙开关、定位开关\n与设备距离在2米内"}",
icon: isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
connectTimer = Timer.periodic(const Duration(seconds: 1), (t) {
index++;
if (index > 15) {
connectTimer = null;
t.cancel();
failSelectDialog();
}
var d = bleDevice;
if (d != null && d.length > 0) {
if (isBind()) {
var deviceble = d.firstWhere((item) {
bool isFF = false;
if (widget.tid == 1) {
isFF = ble.isQuanShiDevice(item["name"]);
} else {
isFF = ble.isMHTSWES(item["name"]);
}
if (isFF) {
isFF = globalController.model.deviceList.indexWhere(
(d) => d["mac"] == item["adData"]["deviceId"]) ==
-1
? true
: false;
}
return isFF;
}, orElse: () => null);
if (!isFind && deviceble != null) {
print("quanshidevice");
isFind = true;
setState(() {
currentMsg = "连接设备中...";
});
t.cancel();
connectToDevice(deviceble["device"]);
bindArr[0] = deviceble["adData"]["deviceId"];
}
} else {
var deviceble = d.firstWhere(
(item) =>
item["adData"]["deviceId"] ==
blueteethBindController.model.bindArr[1],
orElse: () => null);
if (!isFind && deviceble != null) {
print("junhedevice");
isFind = true;
t.cancel();
setState(() {
currentMsg = "连接设备中...";
});
connectToDevice(deviceble["device"]);
bindArr[1] = deviceble["adData"]["deviceId"];
}
}
}
});
});
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, boxConstraints) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Scaffold(
backgroundColor: Colors.transparent, // 加上这一行
appBar: AppBar(
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
titleSpacing: 0,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
Text(
'蓝牙绑定.标题'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF242835),
borderRadius: BorderRadius.circular(20.rpx),
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 30.rpx, 0, 30.rpx),
child: Text(
'蓝牙绑定.扫描蓝牙设备中…'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE8EEF3),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
),
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF242835),
borderRadius: BorderRadius.circular(20.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
21.rpx, 5.rpx, 21.rpx, 5.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'最小信号强度',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFEEF2F5),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
Expanded(
child: Obx(() {
return Slider(
activeColor: Color(0xFF1FCC9B),
inactiveColor:
FlutterFlowTheme.of(context).alternate,
min: -100,
max: 50,
value: blueteethBindController.model.singal!,
onChanged: (newValue) {
newValue = double.parse(
newValue.toStringAsFixed(0));
blueteethBindController.model.singal =
newValue;
blueteethBindController.updateAll();
},
);
}),
),
Obx(() {
return Text(
'${blueteethBindController.model.singal!.toInt()}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE4E8EB),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
);
}),
].divide(SizedBox(width: 30.rpx)),
),
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(
color: themeController.currentColor.sc3,
borderRadius: BorderRadius.circular(20.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
35.rpx, 0, 35.rpx, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 0.rpx, 0, 0),
child: Container(
width: 25.rpx,
height: 25.rpx,
// width: double.infinity,
decoration: BoxDecoration(),
child: SvgPicture.asset(
'assets/img/icon/query.svg',
fit: BoxFit.cover,
color: stringToColor("#333333"), //固定
),
),
),
Expanded(
child: Container(
width: 100.rpx,
height: 100.rpx,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context)
.secondaryBackground,
),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: TextFormField(
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle:
FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
hintText: '蓝牙绑定.搜索提示'.tr,
hintStyle:
FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
FlutterFlowTheme.of(context)
.error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
focusedErrorBorder:
OutlineInputBorder(
borderSide: BorderSide(
color:
FlutterFlowTheme.of(context)
.error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
filled: false,
fillColor: themeController
.currentColor.sc22,
),
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
cursorColor:
FlutterFlowTheme.of(context)
.primaryText,
// validator: _model
// .textControllerValidator
// .asValidator(context),
),
),
),
),
].divide(SizedBox(width: 6.rpx)),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
26.rpx, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
height: 50.rpx,
child: VerticalDivider(
thickness: 2.rpx,
color: stringToColor("#333333"), //固定
),
),
Text(
'搜索',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: stringToColor("#333333"), //固定
),
),
].divide(SizedBox(width: 26.rpx)),
),
),
],
),
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 60.rpx, 0, 32.rpx),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(19.rpx, 0, 0, 0),
child: Text(
'匹配出的外围设备(${blueteethBindController.model.devicelist!.length}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
),
),
Obx(() {
return Expanded(
child: Container(
width: double.infinity,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
...blueteethBindController.model.blelist!
.map((device) =>
SingleBlueteethDeviceCompoentWidget(
// device: device,
bleDevice: device,
))
.toList()
.divide(SizedBox(height: 30.rpx))
.addToEnd(SizedBox(height: 30.rpx)),
],
),
),
),
);
}),
].divide(SizedBox(height: 30.rpx)),
),
),
),
),
),
),
);
}
_showBluetoothNotEnabledDialog() async {
await showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text("蓝牙未开启"),
content: Text("请先打开蓝牙再进行设备扫描"),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("知道了"),
),
],
),
);
}
toFindJunhe() {
bool isSuccess = false;
int i = 0;
Timer.periodic(const Duration(seconds: 1), (t) async {
i++;
if (isSuccess) {
return;
}
if (i > 8) {
if (!isSuccess) {
currentMsg = "错误:未找到关联设备";
failSelectDialog(title: "绑定失败:未找到关联设备");
}
t.cancel();
return;
}
bleDevice.forEach((item) {
if (isSuccess) {
return;
}
if (item['adData']['deviceId'] == bindArr[1]) {
isSuccess = true;
t.cancel();
setState(() {
currentMsg = "寻找关联设备中...";
});
connectToDevice(item["device"]);
}
});
});
}
}
BleDeviceData parseBleData(List<int> data) {
if (data.length < 18) {
throw Exception('BLE广播数据长度不足18字节');
}
int type = data[0];
int sn = data[1];
// 设备唯一ID (6字节),格式化为 MAC 地址样式
String deviceId =
List.generate(6, (i) => data[2 + i].toRadixString(16).padLeft(2, '0'))
.join(":")
.toUpperCase();
int bre = data[8];
int ht = data[9];
int active = data[10];
int flag = data[11];
// version 是4字节 uint大端字节序
int version =
(data[12] << 24) | (data[13] << 16) | (data[14] << 8) | data[15];
// qsn 是2字节 ushort大端字节序
int qsn = (data[16] << 8) | data[17];
return BleDeviceData(
type: type,
sn: sn,
deviceId: deviceId,
bre: bre,
ht: ht,
active: active,
flag: flag,
version: version,
qsn: qsn,
);
}