From 58b2bebe936bdd7239529662ef20b531f2143de4 Mon Sep 17 00:00:00 2001 From: wyf <494641114@qq.com> Date: Wed, 2 Jul 2025 14:33:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8E=A7=E5=88=B6=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/main_page_b_bottom_change.dart | 2 +- .../component/DeviceComponentWidget.dart | 169 ++++++++++++------ lib/pages/mh_page/device/device.dart | 2 +- .../mh_page/device/mht_bind_device_type.dart | 2 +- .../device/mht_blueteeth_device_page.dart | 11 +- lib/pages/mh_page/device/mht_people_info.dart | 8 +- .../component/HomeDeviceStausWidget.dart | 2 +- lib/pages/mh_page/test/WebviewTestModel.dart | 8 +- lib/routers/mh_routers.dart | 2 +- 9 files changed, 131 insertions(+), 75 deletions(-) diff --git a/lib/pages/main_bottom/component/main_page_b_bottom_change.dart b/lib/pages/main_bottom/component/main_page_b_bottom_change.dart index 12d1f4e..5bb2339 100644 --- a/lib/pages/main_bottom/component/main_page_b_bottom_change.dart +++ b/lib/pages/main_bottom/component/main_page_b_bottom_change.dart @@ -138,7 +138,7 @@ class _HomePageState extends State Future dealWebSource(int index) async { WebviewTestController webviewTestController = Get.find(); if (index == 2) { - await webviewTestController.web.jsbridge?.dart.pageActive(); + await webviewTestController.web.jsbridge?.dart.pageActive(true); } else { await webviewTestController.web.jsbridge?.dart.pageInActive(); } diff --git a/lib/pages/mh_page/device/component/DeviceComponentWidget.dart b/lib/pages/mh_page/device/component/DeviceComponentWidget.dart index 869f095..d32ce2f 100644 --- a/lib/pages/mh_page/device/component/DeviceComponentWidget.dart +++ b/lib/pages/mh_page/device/component/DeviceComponentWidget.dart @@ -25,10 +25,12 @@ import 'package:vbvs_app/pages/mh_page/test/WebviewTestModel.dart'; class DeviceComponentWidget extends StatefulWidget { BlueToothDataModel bleDevice; + var deviceType; DeviceComponentWidget({ super.key, required this.bleDevice, + required this.deviceType, }); @override @@ -212,8 +214,8 @@ class _DeviceComponentWidgetState extends State { blueteethBindController.currentDeviceMac.value = widget.bleDevice.mac; blueteethBindController.updateAll(); - String mac = - await getBindTHMAC(context, widget.bleDevice); + String mac = await getBindTHMAC( + context, widget.bleDevice, widget.deviceType); if (mac != null && mac.isNotEmpty) { bool flag = await fillTHMac(mac, widget.bleDevice, context); @@ -481,19 +483,17 @@ class _DeviceComponentWidgetState extends State { ); } - //获取传感器mac + //获取智能床/床垫mac Future getBindTHMAC( - BuildContext context, BlueToothDataModel device) async { + BuildContext context, BlueToothDataModel device, Map deviceType) async { const int maxRetries = 2; const Duration timeout = Duration(seconds: 5); String? macAddress; - try { // 连接设备 THapp bledevice = THapp(device: device.scanResult.device); - await bledevice.connect(); + await bledevice.connect(); var res2 = bledevice.isConnected; - if (!res2) { edm.EasyDartModule.logger.error("蓝牙连接失败"); DailyLogUtils.printLog("蓝牙连接失败"); @@ -504,58 +504,18 @@ class _DeviceComponentWidgetState extends State { ); throw Exception("蓝牙连接失败"); } - blueteethBindController.blueConnectFlag.value = 2; blueteethBindController.currentDevice = bledevice; await Future.delayed(Duration(seconds: 2)); - var read = bledevice.getresource('fff0/fff1'); - await read!.characteristic.setNotifyValue(true); - var write = bledevice.getresource('fff0/fff2'); - for (int attempt = 0; attempt < maxRetries; attempt++) { - var completer = Completer(); - - StreamSubscription? subscription; - subscription = read.characteristic.onValueReceived.listen((onData) { - if (onData.length >= 14) { - // 按照你提供的协议,返回数据长度至少 17字节,这里保险起见 14起步 - String parsedMac = parseMacFromBleResponse(onData); - completer.complete(parsedMac); - } - }); - - // 发送查询命令 - var order = [ - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0x00, - 0x03, - 0x40, - 0x01, - 0x01, - 0x00, - 0x45, - 0xFD - ]; - await write!.characteristic.write(order); - - try { - macAddress = await completer.future.timeout(timeout); - await subscription.cancel(); - break; // 成功拿到,跳出重试 - } catch (e) { - await subscription.cancel(); - if (attempt == maxRetries - 1) { - TopSlideNotification.show( - context, - text: "获取MAC地址超时,请重试".tr, - textColor: themeController.currentColor.sc9, - ); - throw Exception("获取MAC地址失败"); - } - } + if (deviceType['type'] == 3) { + //智能床垫 + macAddress = await getMacFromType3(bledevice, timeout); + } else if (deviceType['type'] == 2) { + //智能床 + macAddress = await getMacFromType2(bledevice, timeout); + } else { + throw Exception("不支持的设备类型"); } if (macAddress == null) { @@ -629,6 +589,87 @@ class _DeviceComponentWidgetState extends State { ); return flag; } + + Future getMacFromType3(THapp bledevice, Duration timeout) async { + final read = bledevice.getresource('fff0/fff1'); + await read!.characteristic.setNotifyValue(true); + final write = bledevice.getresource('fff0/fff2'); + + const int maxRetries = 2; + for (int attempt = 0; attempt < maxRetries; attempt++) { + final completer = Completer(); + final subscription = read.characteristic.onValueReceived.listen((data) { + if (data.length >= 14) { + completer.complete(parseMacFromBleResponse(data)); + } + }); + + final order = [ + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x03, + 0x40, + 0x01, + 0x01, + 0x00, + 0x45, + 0xFD + ]; + await write!.characteristic.write(order); + + try { + final mac = await completer.future.timeout(timeout); + await subscription.cancel(); + return mac; + } catch (_) { + await subscription.cancel(); + if (attempt == maxRetries - 1) rethrow; + } + } + throw Exception("获取MAC超时"); + } + + Future getMacFromType2(THapp bledevice, Duration timeout) async { + try { + final read = bledevice.getresource('ffe0/ffe1'); + await read!.characteristic.setNotifyValue(true); + + final write = + bledevice.getresource('ffe0/ffe1'); // 与 read 同 characteristic + const int maxRetries = 2; + for (int attempt = 0; attempt < maxRetries; attempt++) { + final completer = Completer(); + final subscription = read.characteristic.onValueReceived.listen((data) { + if (data.length >= 17) { + completer.complete(parseMacFromTH2Response(data)); + } + }); + + final order = [0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x0C, 0x0B, 0x0A]; + int checksum = order.reduce((a, b) => a + b) & 0xFFFF; + order.add(checksum & 0xFF); // 低位 + order.add((checksum >> 8) & 0xFF); // 高位 + + await write!.characteristic.write(order); + + try { + final mac = await completer.future.timeout(timeout); + await subscription.cancel(); + return mac; + } catch (_) { + await subscription.cancel(); + if (attempt == maxRetries - 1) rethrow; + } + } + } catch (e) { + ef.log("[获取设备 MAC]:失败:$e"); + } + + throw Exception("获取MAC超时"); + } } String parseMacFromBleResponse(List data) { @@ -650,3 +691,21 @@ String parseMacFromBleResponse(List data) { throw Exception("BLE返回数据格式不正确"); } } + +String parseMacFromTH2Response(List data) { + if (data.length < 17) { + throw Exception("数据长度不足,无法解析MAC"); + } + + int status = data[8]; + if (status != 0x03 && status != 0x04) { + throw Exception("未连接心率带"); + } + + // 提取9~14字节的MAC地址 + List macBytes = data.sublist(9, 15); + return macBytes + .map((b) => b.toRadixString(16).padLeft(2, '0')) + .join(":") + .toUpperCase(); +} diff --git a/lib/pages/mh_page/device/device.dart b/lib/pages/mh_page/device/device.dart index 377314c..99cd31e 100644 --- a/lib/pages/mh_page/device/device.dart +++ b/lib/pages/mh_page/device/device.dart @@ -215,7 +215,7 @@ class DeviceInfoWidget extends GetView { }); await future; await webviewTestController.web.jsbridge?.dart - .pageActive(); + .pageActive(false); MainPageBBottomChange.jumpTo(2); Get.until((route) => Get.currentRoute == diff --git a/lib/pages/mh_page/device/mht_bind_device_type.dart b/lib/pages/mh_page/device/mht_bind_device_type.dart index 41f1b57..2cf32c5 100644 --- a/lib/pages/mh_page/device/mht_bind_device_type.dart +++ b/lib/pages/mh_page/device/mht_bind_device_type.dart @@ -124,7 +124,7 @@ class _MHTBindDeviceTypePageState extends State { bottom: 26.rpx), // 添加每个设备之间的间隔 child: _buildDeviceCard( context, - title: device['name'], // 这里假设 device 是一个 Map + title: device['name'], imageUrl: device['image'], type: device['type'], desc: device['desc'] ?? [], diff --git a/lib/pages/mh_page/device/mht_blueteeth_device_page.dart b/lib/pages/mh_page/device/mht_blueteeth_device_page.dart index dac5edb..e955e1f 100644 --- a/lib/pages/mh_page/device/mht_blueteeth_device_page.dart +++ b/lib/pages/mh_page/device/mht_blueteeth_device_page.dart @@ -19,8 +19,8 @@ import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controlle import 'package:vbvs_app/pages/mh_page/device/model/BlueToothDataModel.dart'; class MHTBlueteethDevicePage extends StatefulWidget { - var data; - MHTBlueteethDevicePage({super.key, required this.data}); + var deviceType; + MHTBlueteethDevicePage({super.key, required this.deviceType}); @override State createState() => _MHTBlueteethDevicePageState(); @@ -146,10 +146,8 @@ class _MHTBlueteethDevicePageState extends State { final filteredResults = results.where((r) { final localName = r.advertisementData.localName; final isTarget = r.rssi > signalThreshold && - isTargetDevice(localName, widget.data['reg'].cast()); - + isTargetDevice(localName, widget.deviceType['reg'].cast()); if (!isTarget) return false; - final name = r.advertisementData.advName.toLowerCase(); String macAddress = r.device.remoteId.str; final mac = macAddress.replaceAll(':', ''); @@ -164,7 +162,7 @@ class _MHTBlueteethDevicePageState extends State { return true; }).map((r) { return BlueToothDataModel.fromScanResult( - r, widget.data['type']?.toInt(), + r, widget.deviceType['type']?.toInt(), bind: false, name: r.advertisementData.localName, mac: r.device.remoteId.str.replaceAll(':', '')); @@ -638,6 +636,7 @@ class _MHTBlueteethDevicePageState extends State { .map((device) { return DeviceComponentWidget( bleDevice: device, + deviceType: widget.deviceType, ); }) .toList() diff --git a/lib/pages/mh_page/device/mht_people_info.dart b/lib/pages/mh_page/device/mht_people_info.dart index d60a111..f54b6e1 100644 --- a/lib/pages/mh_page/device/mht_people_info.dart +++ b/lib/pages/mh_page/device/mht_people_info.dart @@ -379,7 +379,8 @@ class _MHTPeopleInfoPageState extends State { decoration: BoxDecoration(), child: InkWell( onTap: () { - FocusScope.of(context).unfocus(); + FocusScope.of(context) + .requestFocus(FocusNode()); Future.delayed( const Duration(milliseconds: 250), () { @@ -444,13 +445,14 @@ class _MHTPeopleInfoPageState extends State { decoration: BoxDecoration(), child: InkWell( onTap: () { - FocusScope.of(context).unfocus(); + FocusScope.of(context) + .requestFocus(FocusNode()); Future.delayed( const Duration(milliseconds: 250), () { showWeightPickerDialog( context, - initialWeight: "0", + initialWeight: "50", onConfirm: (int selectedWeight) { setState(() { peopleList[index]['weight'] = diff --git a/lib/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart b/lib/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart index 172781f..d97d516 100644 --- a/lib/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart +++ b/lib/pages/mh_page/homepage/component/HomeDeviceStausWidget.dart @@ -86,7 +86,7 @@ class _HomeDeviceStausWidgetState extends State { }); await future; await webviewTestController.web.jsbridge?.dart - .pageActive(); + .pageActive(false); MainPageBBottomChange.jumpTo(2); } catch (e) { DailyLogUtils.writeError("发生异常: $e"); diff --git a/lib/pages/mh_page/test/WebviewTestModel.dart b/lib/pages/mh_page/test/WebviewTestModel.dart index a9d1e2b..ed72f27 100644 --- a/lib/pages/mh_page/test/WebviewTestModel.dart +++ b/lib/pages/mh_page/test/WebviewTestModel.dart @@ -90,6 +90,7 @@ class WebviewTestController extends GetControllerEx { ef.log('updateBlueToothStatus: $args'); // bluetooth = args[0]; MHTHomeController deviceController = Get.find(); + await deviceController.getDeviceList(group: 'room'); final allDevices = deviceController.deviceList.values .expand((list) => list) .toList(); @@ -112,12 +113,7 @@ class WebviewTestController extends GetControllerEx { ef.log('queryInstantData: $args'); // bluetooth = args[0]; return instantData; - }); - bridge.sdk.queryInstantData((args) async { - ef.log('queryInstantData: $args'); - // bluetooth = args[0]; - return instantData; - }); + }); bridge.sdk.startTimer((args) async { ef.log('queryInstantData: $args'); MHTHomeController homeController = Get.find(); diff --git a/lib/routers/mh_routers.dart b/lib/routers/mh_routers.dart index 0ae14e3..603fcd1 100644 --- a/lib/routers/mh_routers.dart +++ b/lib/routers/mh_routers.dart @@ -94,7 +94,7 @@ var mhroutes = { "/deviceListPage": (context) => DeviceListPage(), "/mHTDeviceTypePage": (context, {arguments}) => MHTBindDeviceTypePage(), "/mHTBlueteethDevicePage": (context, {arguments}) => - MHTBlueteethDevicePage(data: arguments), + MHTBlueteethDevicePage(deviceType: arguments), "/mHTwifiPage": (contxt, {arguments}) => MHTWifiPage(deviceInfo: arguments), "/calibrationPage": (contxt) => MHTCalibrationPage(), "/bindDeviceSuccess": (contxt) => MHTBindDeviceSuccess(),