From 767f81c8cfbbe3c5abbb813f09a38ee7c669f282 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 27 Sep 2023 11:17:29 +0300 Subject: [PATCH] Spirometer implementation completed --- lib/pages/landing/landing_page.dart | 3 +- lib/pages/medical/my_trackers/ecg_ble.dart | 147 +++++++++++++----- lib/pages/medical/my_trackers/spirometer.dart | 97 +++++++++--- lib/pages/paymentService/payment_service.dart | 14 +- lib/uitl/utils.dart | 31 ++-- .../bottom_navigation_item.dart | 8 +- lib/widgets/others/app_scaffold_widget.dart | 8 +- 7 files changed, 216 insertions(+), 92 deletions(-) diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index 70e683ae..d36878a1 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -17,6 +17,7 @@ import 'package:diplomaticquarterapp/pages/DrawerPages/family/my-family.dart'; import 'package:diplomaticquarterapp/pages/ToDoList/ToDo.dart'; import 'package:diplomaticquarterapp/pages/landing/home_page_2.dart'; import 'package:diplomaticquarterapp/pages/medical/medical_profile_page_new.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ecg_ble.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/spirometer.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/weight_scale_ble.dart'; import 'package:diplomaticquarterapp/pages/videocall-webrtc-rnd/webrtc/start_video_call.dart'; @@ -569,7 +570,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { }, onLoginClick: () { // login(); - Navigator.push(context, FadePage(page: SpirometerBLE())); + Navigator.push(context, FadePage(page: ECG_BLE())); }, onMedicalFileClick: () { changeCurrentTab(1); diff --git a/lib/pages/medical/my_trackers/ecg_ble.dart b/lib/pages/medical/my_trackers/ecg_ble.dart index 3acf33b8..a928bee7 100644 --- a/lib/pages/medical/my_trackers/ecg_ble.dart +++ b/lib/pages/medical/my_trackers/ecg_ble.dart @@ -17,24 +17,28 @@ class ECG_BLE extends StatefulWidget { class _ECG_BLEState extends State { String connectionStatus = "disconnected"; - BluetoothDevice currentConnectedDevice; BluetoothCharacteristic ecgWriteCharacteristic; StreamSubscription bleDevicesStream; + StreamSubscription bleDeviceConnectionStream; + + final bleConnectionStatus = ValueNotifier("Disconnected"); @override void dispose() { super.dispose(); if (bleDevicesStream != null) bleDevicesStream.cancel(); if (currentConnectedDevice != null) currentConnectedDevice.disconnect(); + bleConnectionStatus.dispose(); + if (bleDeviceConnectionStream != null) bleDeviceConnectionStream.cancel(); } @override void initState() { super.initState(); - FlutterBluePlus.setLogLevel(LogLevel.verbose, color: false); + // FlutterBluePlus.setLogLevel(LogLevel.verbose, color: false); } @override @@ -42,7 +46,7 @@ class _ECG_BLEState extends State { return AppScaffold( appBarTitle: "ECG", showNewAppBar: true, - isShowDecPage: true, + isShowDecPage: false, showNewAppBarTitle: true, backgroundColor: Color(0xffF8F8F8), body: SingleChildScrollView( @@ -68,7 +72,12 @@ class _ECG_BLEState extends State { SizedBox( height: 50.0, ), - Text("Connection state: $connectionStatus"), + ValueListenableBuilder( + valueListenable: bleConnectionStatus, + builder: (context, value, _) { + return Text("Connection state: $value"); + }, + ), SizedBox( height: 50.0, ), @@ -93,9 +102,7 @@ class _ECG_BLEState extends State { void startBLEConnection() { if (FlutterBluePlus.isScanningNow == false) { - setState(() { - connectionStatus = "Connecting..."; - }); + bleConnectionStatus.value = "Connecting..."; bleDevicesStream = FlutterBluePlus.scanResults.listen((results) { List blueToothDevices = results; @@ -103,61 +110,123 @@ class _ECG_BLEState extends State { if (element.device.localName.isNotEmpty) { if (element.device.localName.toLowerCase() == "pm101897") { bleDevicesStream.cancel(); - element.device.connectionState.listen((BluetoothConnectionState state) async { - if (mounted) { - setState(() { - connectionStatus = state.toString(); - }); - } - if (state == BluetoothConnectionState.disconnected) { - // typically, start a periodic timer that tries to periodically reconnect. - // Note: you must always re-discover services after disconnection! - } - if (state == BluetoothConnectionState.connected) { - if (FlutterBluePlus.isScanningNow) { - FlutterBluePlus.stopScan(); + element.device.connect(timeout: Duration(seconds: 30), autoConnect: false).then((value) async { + bleConnectionStatus.value = "Connected..."; + print("Device Connected-------"); + currentConnectedDevice = element.device; + bleDeviceConnectionStream = currentConnectedDevice.connectionState.listen((event) { + if (event == BluetoothConnectionState.disconnected) { + bleConnectionStatus.value = "Disconnected..."; + print("Device Disconnected-------"); + // if (_timer.isActive) _timer.cancel(); } - currentConnectedDevice = element.device; - // currentConnectedDevice.clearGattCache(); - // currentConnectedDevice.requestConnectionPriority(connectionPriorityRequest: ConnectionPriority.high); - // currentConnectedDevice.requestMtu(512); - // currentConnectedDevice.mtu.first.then((value) { - // print("MTU Size: $value"); - // }); - List services = await element.device.discoverServices(); + }); + FlutterBluePlus.stopScan(); + + List services = await element.device.discoverServices(timeout: 30).catchError((err) { + print(err.toString()); + element.device.disconnect(timeout: 15); + }); + + if (services != null && services.isNotEmpty) { services.forEach((service) { if (service.serviceUuid.toString().toLowerCase() == BLEUtils.ECG_SERVICE) { print(service.serviceUuid); service.characteristics.forEach((characteristic) async { if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.ECG_READ_CHARACTERISTIC) { print(characteristic.characteristicUuid); + print(characteristic.properties.toString()); + characteristic.onValueReceived.listen((event) { - print("onValueReceived Stream"); + print("onValueReceived 1e4d Stream"); print(event); }); - if (!characteristic.isNotifying) await characteristic.setNotifyValue(true); + + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + print("-----Delayed 1e4d notify true done-----"); + if (!characteristic.isNotifying) await characteristic.setNotifyValue(true).catchError((err) {}); + }); } if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.ECG_WRITE_CHARACTERISTIC) { - print("Write Characteristic: ${characteristic.characteristicUuid}"); - ecgWriteCharacteristic = characteristic; - await ecgWriteCharacteristic.write([0x83]); + print(characteristic.characteristicUuid); + print(characteristic.properties.toString()); + + // Write get cases command to 8841 + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + // 0x90 00 00 00 1 + characteristic.write([0x90, 0x00, 0x00, 0x00, 0x01], withoutResponse: false).then((value) { + print("----8841 get device info command data written----"); + }); + }); } }); - return true; } }); } + }).catchError((onError) { + print("----- ERRORRRR!!!!!! -------"); + print(onError.toString()); }); - await element.device.connect(timeout: Duration(seconds: 35)); - return true; } } + + // if (element.device.localName.isNotEmpty) { + // if (element.device.localName.toLowerCase() == "pm101897") { + // bleDevicesStream.cancel(); + // element.device.connectionState.listen((BluetoothConnectionState state) async { + // if (mounted) { + // setState(() { + // connectionStatus = state.toString(); + // }); + // } + // if (state == BluetoothConnectionState.disconnected) { + // // typically, start a periodic timer that tries to periodically reconnect. + // // Note: you must always re-discover services after disconnection! + // } + // if (state == BluetoothConnectionState.connected) { + // if (FlutterBluePlus.isScanningNow) { + // FlutterBluePlus.stopScan(); + // } + // currentConnectedDevice = element.device; + // // currentConnectedDevice.clearGattCache(); + // // currentConnectedDevice.requestConnectionPriority(connectionPriorityRequest: ConnectionPriority.high); + // // currentConnectedDevice.requestMtu(512); + // // currentConnectedDevice.mtu.first.then((value) { + // // print("MTU Size: $value"); + // // }); + // List services = await element.device.discoverServices(); + // services.forEach((service) { + // if (service.serviceUuid.toString().toLowerCase() == BLEUtils.ECG_SERVICE) { + // print(service.serviceUuid); + // service.characteristics.forEach((characteristic) async { + // if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.ECG_READ_CHARACTERISTIC) { + // print(characteristic.characteristicUuid); + // characteristic.onValueReceived.listen((event) { + // print("onValueReceived Stream"); + // print(event); + // }); + // if (!characteristic.isNotifying) await characteristic.setNotifyValue(true); + // } + // + // if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.ECG_WRITE_CHARACTERISTIC) { + // print("Write Characteristic: ${characteristic.characteristicUuid}"); + // ecgWriteCharacteristic = characteristic; + // await ecgWriteCharacteristic.write([0x83]); + // } + // }); + // return true; + // } + // }); + // } + // }); + // await element.device.connect(timeout: Duration(seconds: 35)); + // return true; + // } + // } }); }); - FlutterBluePlus.startScan(timeout: const Duration(seconds: 15), androidUsesFineLocation: false).then((value) { - print("Scan Finished"); - }); + FlutterBluePlus.startScan(timeout: const Duration(seconds: 15), androidUsesFineLocation: false); } } } diff --git a/lib/pages/medical/my_trackers/spirometer.dart b/lib/pages/medical/my_trackers/spirometer.dart index 1b0bff66..f621051b 100644 --- a/lib/pages/medical/my_trackers/spirometer.dart +++ b/lib/pages/medical/my_trackers/spirometer.dart @@ -20,10 +20,14 @@ class _SpirometerBLEState extends State { BluetoothDevice currentConnectedDevice; StreamSubscription bleDevicesStream; + StreamSubscription bleDeviceConnectionStream; BluetoothCharacteristic spirometerReadCharacteristicFf0a; BluetoothCharacteristic spirometerWriteCharacteristicFf0b; + String valuePEF = "0"; + String valueFEV = "0.0"; + final bleConnectionStatus = ValueNotifier("Disconnected"); Timer _timer; @@ -40,6 +44,7 @@ class _SpirometerBLEState extends State { if (_timerRead != null && _timerRead.isActive) _timerRead.cancel(); bleConnectionStatus.dispose(); if (bleDevicesStream != null) bleDevicesStream.cancel(); + if (bleDeviceConnectionStream != null) bleDeviceConnectionStream.cancel(); } @override @@ -82,7 +87,8 @@ class _SpirometerBLEState extends State { SizedBox( height: 50.0, ), - // Text("Current Temp: $currentTempInCelsius"), + Text("Current PEF: $valuePEF L/min"), + Text("Current FEV: $valueFEV mL"), ], ), ); @@ -117,6 +123,13 @@ class _SpirometerBLEState extends State { bleConnectionStatus.value = "Connected..."; print("Device Connected-------"); currentConnectedDevice = element.device; + bleDeviceConnectionStream = currentConnectedDevice.connectionState.listen((event) { + if (event == BluetoothConnectionState.disconnected) { + bleConnectionStatus.value = "Disconnected..."; + print("Device Disconnected-------"); + if (_timer.isActive) _timer.cancel(); + } + }); FlutterBluePlus.stopScan(); List services = await element.device.discoverServices(timeout: 5); services.forEach( @@ -133,8 +146,10 @@ class _SpirometerBLEState extends State { print("onValueReceived ff0a Stream"); print(event); - //Sample response - // dd14d93d5c1f01a302f8de3d5c1c017302 + //response received + if (event[0] == 221) { + convertIntListToHex(event); + } if (event[0] == 170) { _timer.cancel(); @@ -150,19 +165,24 @@ class _SpirometerBLEState extends State { // Write get 1st history command to ff0b await Future.delayed(Duration(milliseconds: 1000)).then((value) async { - spirometerWriteCharacteristicFf0b.write([0x55, 0x02, 0x01, 0x00], withoutResponse: false).then((value) { + spirometerWriteCharacteristicFf0b.write([0x55, 0x02, 0x01, 0x00], withoutResponse: false).then((value) async { print("----ff0b get 1st history command data written----"); isHistoryCommandWritten = true; + + // Write delete history command to ff0b + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + spirometerWriteCharacteristicFf0b.write([0x55, 0x03], withoutResponse: false).then((value) async { + print("----ff0b delete history command data written----"); + isHistoryCommandWritten = true; + await Future.delayed(Duration(milliseconds: 500)).then((value) async { + isHistoryCommandWritten = false; + // Write ACK command to ff0b every 500 ms + startACKCommandToMSA100(); + }); + }); + }); }); }); - - // Write delete history command to ff0b - // await Future.delayed(Duration(milliseconds: 1000)).then((value) async { - // spirometerWriteCharacteristicFf0b.write([0x55, 0x03], withoutResponse: false).then((value) { - // print("----ff0b delete history command data written----"); - // isHistoryCommandWritten = true; - // }); - // }); } } }); @@ -179,13 +199,15 @@ class _SpirometerBLEState extends State { print(spirometerWriteCharacteristicFf0b.properties.toString()); // Write ACK command to ff0b every 500 ms - await Future.delayed(Duration(milliseconds: 1000)).then((value) async { - _timer = Timer.periodic(Duration(milliseconds: 500), (Timer t) { - spirometerWriteCharacteristicFf0b.write([0x55, 0x06], withoutResponse: false).then((value) { - print("----ff0b ACK command data written----"); - }); - }); - }); + startACKCommandToMSA100(); + + // await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + // _timer = Timer.periodic(Duration(milliseconds: 500), (Timer t) { + // spirometerWriteCharacteristicFf0b.write([0x55, 0x06], withoutResponse: false).then((value) { + // print("----ff0b ACK command data written----"); + // }); + // }); + // }); } }, ); @@ -200,10 +222,45 @@ class _SpirometerBLEState extends State { }, // onError(e) => print(e); ); - FlutterBluePlus.startScan(timeout: const Duration(seconds: 5), androidUsesFineLocation: false); } } + + void startACKCommandToMSA100() async { + // Write ACK command to ff0b every 500 ms + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + _timer = Timer.periodic(Duration(milliseconds: 500), (Timer t) { + spirometerWriteCharacteristicFf0b.write([0x55, 0x06], withoutResponse: false).then((value) { + print("----ff0b ACK command data written----"); + }); + }); + }); + } + + String convertIntListToHex(List byteArray) { + String b = (byteArray.map((x) { + return x.toRadixString(16); + })).join(";"); + List hexString = b.split(";"); + print("HexString: $hexString"); + String returnStringPEF = hexString[8] + hexString[7]; + String returnStringFEV = hexString[6] + hexString[5]; + print("Temp Hex String PEF: $returnStringPEF"); + print("Temp Hex String FEV: $returnStringFEV"); + + final numberPEF = int.parse(returnStringPEF, radix: 16); + final numberFEV = int.parse(returnStringFEV, radix: 16); + + print("Temp Number FEV: ${numberFEV * 0.01}"); + print("Temp Number PEF: $numberPEF"); + + setState(() { + valueFEV = (numberFEV * 0.01).toStringAsFixed(2); + valuePEF = numberPEF.toString(); + }); + + return (numberFEV * 0.01).toStringAsFixed(1); + } } class BluetoothOffScreen extends StatelessWidget { diff --git a/lib/pages/paymentService/payment_service.dart b/lib/pages/paymentService/payment_service.dart index 5bcf4592..3c5cb01f 100644 --- a/lib/pages/paymentService/payment_service.dart +++ b/lib/pages/paymentService/payment_service.dart @@ -1,4 +1,4 @@ -import 'package:badges/badges.dart'; +import 'package:badges/badges.dart' as badge_import; import 'package:diplomaticquarterapp/Constants.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Appointments/toDoCountProviderModel.dart'; @@ -95,11 +95,11 @@ class PaymentService extends StatelessWidget { ? Positioned( left: 8, top: 4, - child: Badge( + child: badge_import.Badge( toAnimate: false, elevation: 0, - position: BadgePosition.topEnd(), - shape: BadgeShape.circle, + position: badge_import.BadgePosition.topEnd(), + shape: badge_import.BadgeShape.circle, badgeColor: secondaryColor.withOpacity(1.0), borderRadius: BorderRadius.circular(8), badgeContent: Container( @@ -111,11 +111,11 @@ class PaymentService extends StatelessWidget { : Positioned( right: 8, top: 4, - child: Badge( + child: badge_import.Badge( toAnimate: false, elevation: 0, - position: BadgePosition.topEnd(), - shape: BadgeShape.circle, + position: badge_import.BadgePosition.topEnd(), + shape: badge_import.BadgeShape.circle, badgeColor: secondaryColor.withOpacity(1.0), borderRadius: BorderRadius.circular(8), badgeContent: Container( diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index ece5613d..486a760f 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -4,7 +4,7 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:auto_size_text/auto_size_text.dart'; -import 'package:badges/badges.dart'; +import 'package:badges/badges.dart' as badge_import; import 'package:cached_network_image/cached_network_image.dart'; import 'package:connectivity/connectivity.dart'; import 'package:crypto/crypto.dart' as crypto; @@ -241,11 +241,11 @@ class Utils { ? Positioned( left: 8, top: 4, - child: Badge( + child: badge_import.Badge( toAnimate: false, elevation: 0, - position: BadgePosition.topEnd(), - shape: BadgeShape.circle, + position: badge_import.BadgePosition.topEnd(), + shape: badge_import.BadgeShape.circle, badgeColor: secondaryColor.withOpacity(1.0), borderRadius: BorderRadius.circular(8), badgeContent: Container( @@ -259,11 +259,11 @@ class Utils { ? Positioned( right: 8, top: 4, - child: Badge( + child: badge_import.Badge( toAnimate: false, elevation: 0, - position: BadgePosition.topEnd(), - shape: BadgeShape.circle, + position: badge_import.BadgePosition.topEnd(), + shape: badge_import.BadgeShape.circle, badgeColor: secondaryColor.withOpacity(1.0), borderRadius: BorderRadius.circular(8), badgeContent: Container( @@ -614,11 +614,11 @@ class Utils { ? Positioned( left: 8, top: 4, - child: Badge( + child: badge_import.Badge( toAnimate: false, elevation: 0, - position: BadgePosition.topEnd(), - shape: BadgeShape.circle, + position: badge_import.BadgePosition.topEnd(), + shape: badge_import.BadgeShape.circle, badgeColor: secondaryColor.withOpacity(1.0), borderRadius: BorderRadius.circular(8), badgeContent: Container( @@ -632,11 +632,11 @@ class Utils { ? Positioned( right: 8, top: 4, - child: Badge( + child: badge_import.Badge( toAnimate: false, elevation: 0, - position: BadgePosition.topEnd(), - shape: BadgeShape.circle, + position: badge_import.BadgePosition.topEnd(), + shape: badge_import.BadgeShape.circle, badgeColor: secondaryColor.withOpacity(1.0), borderRadius: BorderRadius.circular(8), badgeContent: Container( @@ -810,10 +810,7 @@ class Utils { return crypto.md5.convert(utf8.encode(input)).toString(); } - static String generateSignature() { - - } - + static String generateSignature() {} } Widget applyShadow({Color color = Colors.grey, double shadowOpacity = 0.5, double spreadRadius = 2, double blurRadius = 7, Offset offset = const Offset(2, 2), @required Widget child}) { diff --git a/lib/widgets/bottom_navigation/bottom_navigation_item.dart b/lib/widgets/bottom_navigation/bottom_navigation_item.dart index ff085dd9..f7cdafce 100644 --- a/lib/widgets/bottom_navigation/bottom_navigation_item.dart +++ b/lib/widgets/bottom_navigation/bottom_navigation_item.dart @@ -1,4 +1,4 @@ -import 'package:badges/badges.dart'; +import 'package:badges/badges.dart' as badge_import; import 'package:diplomaticquarterapp/core/service/AuthenticatedUserObject.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/locator.dart'; @@ -106,10 +106,10 @@ class BottomNavigationItem extends StatelessWidget { Positioned( right: 18.0, bottom: 28.0, - child: Badge( + child: badge_import.Badge( toAnimate: false, - position: BadgePosition.topEnd(), - shape: BadgeShape.circle, + position: badge_import.BadgePosition.topEnd(), + shape: badge_import.BadgeShape.circle, badgeColor: secondaryColor.withOpacity(1.0), borderRadius: BorderRadius.circular(8), badgeContent: Container( diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index 6865ece5..f433a8e4 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -1,5 +1,5 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:badges/badges.dart'; +import 'package:badges/badges.dart' as badge_import; import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; @@ -494,7 +494,7 @@ class AppBarWidgetState extends State { actions: [ (widget.isPharmacy && widget.showPharmacyCart) ? IconButton( - icon: Badge( + icon: badge_import.Badge( badgeContent: Text( orderPreviewViewModel.cartResponse.quantityCount.toString(), style: TextStyle(color: Colors.white), @@ -507,8 +507,8 @@ class AppBarWidgetState extends State { : Container(), (widget.isOfferPackages && widget.showOfferPackagesCart) ? IconButton( - icon: Badge( - position: BadgePosition.topStart(top: -15, start: -10), + icon: badge_import.Badge( + position: badge_import.BadgePosition.topStart(top: -15, start: -10), badgeContent: Text( _badgeText, style: TextStyle(fontSize: 9, color: Colors.white, fontWeight: FontWeight.normal),