From a494f454cb055247c1a08c41514276a3c354ee00 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Wed, 31 Jan 2024 10:25:25 +0300 Subject: [PATCH] Andesfit WeightScale InProgress --- .../diplomaticquarterapp/ble/BleBridge.kt | 9 + lib/config/config.dart | 4 +- ...ndesfit_blood_pressure_connect_screen.dart | 175 +++++++ .../andesfit_weigth_scale_connect_screen.dart | 148 ++++++ .../ble_devices_screen.dart | 45 +- .../all_in_one_tracker_connect_screen.dart | 0 .../bloodpressure_connect_screen.dart | 0 .../bloodsugar_connect_screen.dart | 0 .../ecg_connect_screen.dart | 0 .../oxymeter_connect_screen.dart | 0 .../select_tracker_type.dart | 12 + .../ble_helpers/ble_connect_helper.dart | 29 +- .../ble_models/ble_devices_model.dart | 7 +- .../andesfit_devices/weight_data_model.dart} | 4 +- .../viatom_devices/bp_rt_model.dart | 70 +-- .../blood_pressure/BloodPressureBLE.dart | 164 +++++-- lib/pages/medical/my_trackers/ecg_ble.dart | 2 + .../medical/my_trackers/my_trackers.dart | 2 +- .../my_trackers_view_model.dart | 444 +++++++++++++++++- .../viatom_devices/bp_tracker_ble.dart | 2 +- .../viatom_devices/ekg_tracker_ble.dart | 2 +- .../viatom_devices/oxymeter_ble.dart | 2 +- .../viatom_devices/sp20_pulse_tracker.dart | 2 +- .../medical/my_trackers/weight_scale_ble.dart | 3 +- 24 files changed, 984 insertions(+), 142 deletions(-) create mode 100644 lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_pressure_connect_screen.dart create mode 100644 lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_weigth_scale_connect_screen.dart rename lib/pages/medical/my_trackers/ble_device_type_screens/{device_types => lepu_device_types}/all_in_one_tracker_connect_screen.dart (100%) rename lib/pages/medical/my_trackers/ble_device_type_screens/{device_types => lepu_device_types}/bloodpressure_connect_screen.dart (100%) rename lib/pages/medical/my_trackers/ble_device_type_screens/{device_types => lepu_device_types}/bloodsugar_connect_screen.dart (100%) rename lib/pages/medical/my_trackers/ble_device_type_screens/{device_types => lepu_device_types}/ecg_connect_screen.dart (100%) rename lib/pages/medical/my_trackers/ble_device_type_screens/{device_types => lepu_device_types}/oxymeter_connect_screen.dart (100%) rename lib/pages/medical/my_trackers/ble_models/{weight_scale_data.dart => viatom_devices/andesfit_devices/weight_data_model.dart} (55%) diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt index 4b6bbf8f..b4686dce 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt @@ -62,6 +62,7 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi private const val CHANNEL = "BLE-Platform-Bridge" private const val EVENTCHANNEL = "BLE-Platform-Bridge-Event" private const val SCAN_DEVICE = "scanDevices" + private const val STOP_SCAN = "stopScan" private const val CONNECT_DEVICE = "connectDevice" private const val SCAN_DEVICE_EKG = "scan_ekg" private const val EKG_FILES_LIST = "ecgFilesList" @@ -177,6 +178,8 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi if (methodCall.method == SCAN_DEVICE) { scanDevice() + } else if (methodCall.method == STOP_SCAN) { + stopScan() } else if (methodCall.method == CONNECT_DEVICE) { connectDevice(methodCall.arguments as List) } else if (methodCall.method == DISCONNECT_DEVICE) { @@ -242,6 +245,12 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } + private fun stopScan() { + + BleServiceHelper.BleServiceHelper.stopScan() + } + + @RequiresApi(Build.VERSION_CODES.Q) private fun subscribeToStreams(deviceName: String) { diff --git a/lib/config/config.dart b/lib/config/config.dart index 21c21537..942c1552 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -20,8 +20,8 @@ var PACKAGES_ORDERS = '/api/orders'; var PACKAGES_ORDER_HISTORY = '/api/orders/items'; var PACKAGES_TAMARA_OPT = '/api/orders/paymentoptions/tamara'; // var BASE_URL = 'http://10.50.100.198:2018/'; -// var BASE_URL = 'https://uat.hmgwebservices.com/'; -var BASE_URL = 'https://hmgwebservices.com/'; +var BASE_URL = 'https://uat.hmgwebservices.com/'; +// var BASE_URL = 'https://hmgwebservices.com/'; // var BASE_URL = 'https://orash.cloudsolutions.com.sa/'; // var BASE_URL = 'https://vidauat.cloudsolutions.com.sa/'; diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_pressure_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_pressure_connect_screen.dart new file mode 100644 index 00000000..a4b2d11b --- /dev/null +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_pressure_connect_screen.dart @@ -0,0 +1,175 @@ +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class AndesFitBloodPressureConnectScreen extends StatefulWidget { + final BluetoothDevice deviceModel; + final bool isEcgAvailable; + + const AndesFitBloodPressureConnectScreen({this.deviceModel, this.isEcgAvailable = false}); + + @override + State createState() => _AndesFitBloodPressureConnectScreenState(); +} + +class _AndesFitBloodPressureConnectScreenState extends State { + MyTrackersViewModel myTrackersVm; + + @override + void initState() { + myTrackersVm = context.read(); + myTrackersVm.connectAndesfitBloodPressureDevice(widget.deviceModel); + super.initState(); + } + + @override + void dispose() { + myTrackersVm.andesfitBpCurrentStatus = null; + myTrackersVm.andesfitBpRtMeasuringModel = null; + myTrackersVm.andesfitBpRtResultModel = null; + myTrackersVm.selectedAndesFitScanResult = null; + myTrackersVm.isAndesfitDeviceConnected = null; + myTrackersVm.disConnectAndesfitDevice(widget.deviceModel); + super.dispose(); + } + + Widget buildBloodPressureUI(MyTrackersViewModel myTrackersViewModel) { + return Expanded( + child: ListView( + children: [ + if (myTrackersViewModel.andesfitBpCurrentStatus == kRealTimeDataBPMeasuring) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + mHeight(24.0), + Column( + children: [ + Text(myTrackersViewModel.andesfitBpRtMeasuringModel.pressure.toString(), style: TextStyle(fontSize: 100, fontWeight: FontWeight.bold)), + Text("Pressure", style: TextStyle(fontSize: 20)), + ], + ), + mHeight(24.0), + ], + ), + ] else if (myTrackersViewModel.andesfitBpCurrentStatus == kRealTimeDataBPResult) ...[ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("Sys", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.andesfitBpRtResultModel.sys.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("Dia", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.andesfitBpRtResultModel.dia.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("♥︎", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.andesfitBpRtResultModel.pr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("/min", style: TextStyle(fontSize: 10)), + ], + ), + ], + ), + mHeight(30.0), + // buildStatusForBP(myTrackersViewModel.bpRtResultModel.result), + // mHeight(24.0), + ], + ), + ] else ...[ + Padding( + padding: const EdgeInsets.all(24.0), + child: Center( + child: Text( + "Some animation with the instruction", + style: TextStyle(fontSize: 9.0), + ), + ), + ) + ], + ], + ), + ); + } + + Widget buildStatusForBP(int result) { + String resultStatus = ""; + + if (result == 0) { + resultStatus = "Normal"; + } else if (result == 1) { + resultStatus = "Unable to analyze(cuff is too loose, inflation is slow, slow air leakage, large air volume)"; + } else if (result == 2) { + resultStatus = "Waveform disorder(arm movement or other interference detected during pumping)"; + } else if (result == 3) { + resultStatus = "Weak signal, unable to detect pulse wave(clothes with interference sleeves)"; + } else { + resultStatus = "Equipment error(valve blocking, over-range blood pressure measurement, serious cuff leakage, software system abnormality, hardware system error, and other abnormalities)"; + } + return Column( + children: [ + Center(child: Text("$resultStatus", style: TextStyle(fontSize: 20))), + if (result != 0) ...[ + mHeight(24.0), + Center(child: Text("Press START/STOP Button on the device to restart.", style: TextStyle(fontSize: 15))), + ], + ], + ); + } + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: "${widget.deviceModel.localName}", + showNewAppBar: true, + isShowDecPage: false, + showNewAppBarTitle: true, + backgroundColor: Color(0xffF8F8F8), + body: Padding( + padding: const EdgeInsets.all(24.0), + child: Consumer( + builder: (BuildContext context, MyTrackersViewModel myTrackersViewModel, Widget child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + buildBloodPressureUI(myTrackersViewModel), + if (myTrackersViewModel.isAndesfitDeviceConnected != null && myTrackersViewModel.isAndesfitDeviceConnected) ...[ + Row( + children: [ + Expanded( + child: DefaultButton( + "Disconnect with ${widget.deviceModel.localName}", + () async { + myTrackersVm.disConnectAndesfitDevice(widget.deviceModel); + Navigator.pop(context); + }, + textColor: Colors.white, + ), + ), + ], + ), + ] + ], + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_weigth_scale_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_weigth_scale_connect_screen.dart new file mode 100644 index 00000000..00460ec6 --- /dev/null +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_weigth_scale_connect_screen.dart @@ -0,0 +1,148 @@ +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class AndesFitWeightScaleConnectScreen extends StatefulWidget { + final BluetoothDevice deviceModel; + + const AndesFitWeightScaleConnectScreen({this.deviceModel}); + + @override + State createState() => _AndesFitWeightScaleConnectScreenState(); +} + +class _AndesFitWeightScaleConnectScreenState extends State { + MyTrackersViewModel myTrackersVm; + + @override + void initState() { + myTrackersVm = context.read(); + myTrackersVm.connectAndesfitWeightDevice(widget.deviceModel); + super.initState(); + } + + @override + void dispose() { + myTrackersVm.andesfitWeightScaleData = null; + myTrackersVm.selectedAndesFitScanResult = null; + myTrackersVm.isAndesfitDeviceConnected = null; + myTrackersVm.disConnectAndesfitDevice(widget.deviceModel); + super.dispose(); + } + + Widget buildWeightScaleUI(MyTrackersViewModel myTrackersViewModel) { + return Expanded( + child: ListView( + children: [ + if (myTrackersViewModel.andesfitBpCurrentStatus == kRealTimeDataBPMeasuring) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + mHeight(24.0), + Column( + children: [ + Text(myTrackersViewModel.andesfitBpRtMeasuringModel.pressure.toString(), style: TextStyle(fontSize: 100, fontWeight: FontWeight.bold)), + Text("Pressure", style: TextStyle(fontSize: 20)), + ], + ), + mHeight(24.0), + ], + ), + ] else if (myTrackersViewModel.andesfitBpCurrentStatus == kRealTimeDataBPResult) ...[ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("Sys", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.andesfitBpRtResultModel.sys.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("Dia", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.andesfitBpRtResultModel.dia.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("♥︎", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.andesfitBpRtResultModel.pr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("/min", style: TextStyle(fontSize: 10)), + ], + ), + ], + ), + mHeight(30.0), + // buildStatusForBP(myTrackersViewModel.bpRtResultModel.result), + // mHeight(24.0), + ], + ), + ] else ...[ + Padding( + padding: const EdgeInsets.all(24.0), + child: Center( + child: Text( + "Some animation with the instruction", + style: TextStyle(fontSize: 9.0), + ), + ), + ) + ], + ], + ), + ); + } + + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: "${widget.deviceModel.localName}", + showNewAppBar: true, + isShowDecPage: false, + showNewAppBarTitle: true, + backgroundColor: Color(0xffF8F8F8), + body: Padding( + padding: const EdgeInsets.all(24.0), + child: Consumer( + builder: (BuildContext context, MyTrackersViewModel myTrackersViewModel, Widget child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + buildWeightScaleUI(myTrackersViewModel), + if (myTrackersViewModel.isAndesfitDeviceConnected != null && myTrackersViewModel.isAndesfitDeviceConnected) ...[ + Row( + children: [ + Expanded( + child: DefaultButton( + "Disconnect with ${widget.deviceModel.localName}", + () async { + myTrackersVm.disConnectAndesfitDevice(widget.deviceModel); + Navigator.pop(context); + }, + textColor: Colors.white, + ), + ), + ], + ), + ] + ], + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart index 070775bb..a4471629 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/ble_devices_screen.dart @@ -1,8 +1,8 @@ -import 'dart:developer'; - -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart'; -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart'; -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/device_types/oxymeter_connect_screen.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_pressure_connect_screen.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_weigth_scale_connect_screen.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/bloodpressure_connect_screen.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/ecg_connect_screen.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/oxymeter_connect_screen.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; import 'package:diplomaticquarterapp/widgets/data_display/medical/medical_profile_item.dart'; @@ -29,6 +29,7 @@ class _BleDevicesScreenState extends State { void initState() { myTrackersVm = context.read(); myTrackersVm.startSearchingForTracker(); + myTrackersVm.startTimerForNativeScan(); super.initState(); } @@ -40,23 +41,51 @@ class _BleDevicesScreenState extends State { void onDeviceTapped(BleDeviceModel device) { switch (device.deviceType) { case TrackerTypeEnum.OxymeterTracker: + if (myTrackersVm.isDeviceFromAndesFit(device.name)) { + return; + } myTrackersVm.oxyRtModel = null; Navigator.pushReplacement(context, FadePage(page: OxymeterConnectScreen(deviceModel: device))); break; case TrackerTypeEnum.BloodPressureTracker: - myTrackersVm.bpRtResultModel = null; - myTrackersVm.bpRtMeasuringModel = null; - myTrackersVm.bpCurrentStatus = null; + myTrackersVm.andesfitBpCurrentStatus = null; + myTrackersVm.andesfitBpRtMeasuringModel = null; + myTrackersVm.andesfitBpRtResultModel = null; + myTrackersVm.selectedAndesFitScanResult = null; + myTrackersVm.isAndesfitDeviceConnected = null; + myTrackersVm.bleDevicesStream.cancel(); + if (myTrackersVm.isDeviceFromAndesFit(device.name)) { + Navigator.pushReplacement(context, FadePage(page: AndesFitBloodPressureConnectScreen(deviceModel: device.andesfitBluetoothDevice, isEcgAvailable: false))); + return; + } + Navigator.pushReplacement(context, FadePage(page: BloodPressureConnectScreen(deviceModel: device, isEcgAvailable: getIfECGAvailableInBPDevice(device.name)))); break; case TrackerTypeEnum.BloodSugarTracker: + if (myTrackersVm.isDeviceFromAndesFit(device.name)) { + return; + } // TODO: Handle this case. break; case TrackerTypeEnum.ECGTracker: + if (myTrackersVm.isDeviceFromAndesFit(device.name)) { + return; + } myTrackersVm.ecgRtModel = null; Navigator.pushReplacement(context, FadePage(page: ECGConnectScreen(deviceModel: device))); + break; + case TrackerTypeEnum.WeightScale: + if (myTrackersVm.isDeviceFromAndesFit(device.name)) { + myTrackersVm.andesfitWeightScaleData = null; + Navigator.pushReplacement(context, FadePage(page: AndesFitWeightScaleConnectScreen(deviceModel: device.andesfitBluetoothDevice))); + return; + } + break; case TrackerTypeEnum.AllInOneTracker: + if (myTrackersVm.isDeviceFromAndesFit(device.name)) { + return; + } // TODO: Handle this case. break; } diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/all_in_one_tracker_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/all_in_one_tracker_connect_screen.dart similarity index 100% rename from lib/pages/medical/my_trackers/ble_device_type_screens/device_types/all_in_one_tracker_connect_screen.dart rename to lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/all_in_one_tracker_connect_screen.dart diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/bloodpressure_connect_screen.dart similarity index 100% rename from lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodpressure_connect_screen.dart rename to lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/bloodpressure_connect_screen.dart diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodsugar_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/bloodsugar_connect_screen.dart similarity index 100% rename from lib/pages/medical/my_trackers/ble_device_type_screens/device_types/bloodsugar_connect_screen.dart rename to lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/bloodsugar_connect_screen.dart diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/ecg_connect_screen.dart similarity index 100% rename from lib/pages/medical/my_trackers/ble_device_type_screens/device_types/ecg_connect_screen.dart rename to lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/ecg_connect_screen.dart diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/device_types/oxymeter_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/oxymeter_connect_screen.dart similarity index 100% rename from lib/pages/medical/my_trackers/ble_device_type_screens/device_types/oxymeter_connect_screen.dart rename to lib/pages/medical/my_trackers/ble_device_type_screens/lepu_device_types/oxymeter_connect_screen.dart diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart index b58650ed..6a82f2bc 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/select_tracker_type.dart @@ -59,6 +59,18 @@ class SelectTrackerType extends StatelessWidget { isEnable: true, ), )); + medical.add(InkWell( + onTap: () { + context.read().updateSelectedTrackerType(TrackerTypeEnum.WeightScale); + Navigator.of(context).push(FadePage(page: BleDevicesScreen())); + }, + child: MedicalProfileItem( + title: "Weight", + imagePath: 'tracker.svg', + subTitle: "Scale", + isEnable: true, + ), + )); medical.add(InkWell( onTap: () { context.read().updateSelectedTrackerType(TrackerTypeEnum.AllInOneTracker); diff --git a/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart b/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart index 7c4289d5..9d5d7f46 100644 --- a/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart +++ b/lib/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart @@ -10,15 +10,13 @@ class BleChannel { // static const platform_ios_ekg = MethodChannel('BLE-Platform-Bridge-IOS-EKG'); //BLE-Platform-Bridge - static Future scanResults(List deviceType) async { + static Future scanResultsNative(List deviceType) async { try { String result; print("----------Flutter scanResults -------"); - // if (Platform.isIOS && deviceType[0] == "ekg") { - // result = await platform_ios_ekg.invokeMethod('scanEKG', deviceType); - // } else { + result = await platform.invokeMethod('scanDevices', deviceType); - // } + print("----------Flutter Result -------"); print(result); return result; @@ -27,15 +25,28 @@ class BleChannel { } } + static Future stopNativeScan() async { + try { + String result; + print("----------Flutter stopNativeScan -------"); + + result = await platform.invokeMethod('stopScan'); + + print("----------Flutter Result stopNativeScan -------"); + print(result); + return result; + } catch (e) { + return "Error: $e"; + } + } + static Future connectDevice(List device) async { try { String result; print("----------Flutter init connectDevice -------"); - // if (Platform.isIOS && deviceType[0] == "ekg") { - // result = await platform_ios_ekg.invokeMethod('scanEKG', deviceType); - // } else { + result = await platform.invokeMethod('connectDevice', device); - // } + print("----------Flutter Result connectDevice -------"); print(result); return result; diff --git a/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart b/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart index d9c85342..11f528a3 100644 --- a/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart +++ b/lib/pages/medical/my_trackers/ble_models/ble_devices_model.dart @@ -1,4 +1,5 @@ import 'package:diplomaticquarterapp/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; class BleDeviceModel { String macAddr; @@ -6,8 +7,9 @@ class BleDeviceModel { String name; int rssi; TrackerTypeEnum deviceType; + BluetoothDevice andesfitBluetoothDevice; - BleDeviceModel({this.macAddr, this.model, this.name, this.rssi}); + BleDeviceModel({this.macAddr, this.model, this.name, this.rssi, this.andesfitBluetoothDevice}); BleDeviceModel.fromJson(Map json) { macAddr = json['macAddr']; @@ -15,10 +17,11 @@ class BleDeviceModel { name = json['name']; rssi = json['rssi']; deviceType = TrackerTypeEnum.AllInOneTracker; + andesfitBluetoothDevice = null; } @override String toString() { - return 'BleDeviceModel{macAddr: $macAddr, model: $model, name: $name, rssi: $rssi, deviceType: $deviceType}'; + return 'BleDeviceModel{macAddr: $macAddr, model: $model, name: $name, rssi: $rssi, deviceType: $deviceType, andesfitBluetoothDevice: ${andesfitBluetoothDevice.toString()}'; } } diff --git a/lib/pages/medical/my_trackers/ble_models/weight_scale_data.dart b/lib/pages/medical/my_trackers/ble_models/viatom_devices/andesfit_devices/weight_data_model.dart similarity index 55% rename from lib/pages/medical/my_trackers/ble_models/weight_scale_data.dart rename to lib/pages/medical/my_trackers/ble_models/viatom_devices/andesfit_devices/weight_data_model.dart index 0745fc3e..c89e339c 100644 --- a/lib/pages/medical/my_trackers/ble_models/weight_scale_data.dart +++ b/lib/pages/medical/my_trackers/ble_models/viatom_devices/andesfit_devices/weight_data_model.dart @@ -6,4 +6,6 @@ class WeightScaleData { String water; String muscle; String bmr; -} \ No newline at end of file + + WeightScaleData({this.weight, this.bmi, this.fat, this.bone, this.water, this.muscle, this.bmr}); +} diff --git a/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart b/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart index 2ccacdd9..dbd6a4c4 100644 --- a/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart +++ b/lib/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart @@ -31,8 +31,20 @@ class BpRtResultModel { int pressure; int result; int sys; - - BpRtResultModel({this.deflate, this.dia, this.mean, this.pr, this.pressure, this.result, this.sys}); + bool isBpHigh; + bool isPulseHigh; + + BpRtResultModel({ + this.deflate, + this.dia, + this.mean, + this.pr, + this.pressure, + this.result, + this.sys, + this.isBpHigh, + this.isPulseHigh, + }); BpRtResultModel.fromJson(Map json) { deflate = json['deflate']; @@ -42,18 +54,8 @@ class BpRtResultModel { pressure = json['pressure']; result = json['result']; sys = json['sys']; - } - - Map toJson() { - final Map data = new Map(); - data['deflate'] = this.deflate; - data['dia'] = this.dia; - data['mean'] = this.mean; - data['pr'] = this.pr; - data['pressure'] = this.pressure; - data['result'] = this.result; - data['sys'] = this.sys; - return data; + isBpHigh = false; + isPulseHigh = false; } } @@ -71,15 +73,6 @@ class ECGRtMeasuringModelFromBP { leadOff = json['leadOff']; poolSignal = json['poolSignal']; } - - Map toJson() { - final Map data = new Map(); - data['curDuration'] = this.curDuration; - data['hr'] = this.hr; - data['leadOff'] = this.leadOff; - data['poolSignal'] = this.poolSignal; - return data; - } } class ECGRtResultModelFromBP { @@ -100,19 +93,6 @@ class ECGRtResultModelFromBP { qtc = json['qtc']; result = json['result']; } - - Map toJson() { - final Map data = new Map(); - if (this.diagnosis != null) { - data['diagnosis'] = this.diagnosis.toJson(); - } - data['hr'] = this.hr; - data['pvcs'] = this.pvcs; - data['qrs'] = this.qrs; - data['qtc'] = this.qtc; - data['result'] = this.result; - return data; - } } class Diagnosis { @@ -160,22 +140,4 @@ class Diagnosis { isSlowHr = json['isSlowHr']; isWideQrs = json['isWideQrs']; } - - Map toJson() { - final Map data = new Map(); - data['bytes'] = this.bytes; - data['isFastHr'] = this.isFastHr; - data['isFibrillation'] = this.isFibrillation; - data['isHeartPause'] = this.isHeartPause; - data['isIrregular'] = this.isIrregular; - data['isLeadOff'] = this.isLeadOff; - data['isPoorSignal'] = this.isPoorSignal; - data['isProlongedQtc'] = this.isProlongedQtc; - data['isPvcs'] = this.isPvcs; - data['isRegular'] = this.isRegular; - data['isShortQtc'] = this.isShortQtc; - data['isSlowHr'] = this.isSlowHr; - data['isWideQrs'] = this.isWideQrs; - return data; - } } diff --git a/lib/pages/medical/my_trackers/blood_pressure/BloodPressureBLE.dart b/lib/pages/medical/my_trackers/blood_pressure/BloodPressureBLE.dart index 75d61dcc..0ab0c0f1 100644 --- a/lib/pages/medical/my_trackers/blood_pressure/BloodPressureBLE.dart +++ b/lib/pages/medical/my_trackers/blood_pressure/BloodPressureBLE.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'dart:io'; import 'package:diplomaticquarterapp/theme/colors.dart'; @@ -24,11 +25,20 @@ class _BloodPressureBLEState extends State { StreamSubscription bloodPressureReadingStream; + StreamSubscription bleDevicesStream; + StreamSubscription bleDeviceConnectionStream; + + final bleConnectionStatus = ValueNotifier("Disconnected"); + Timer _timer; @override void dispose() { super.dispose(); + if (bleDevicesStream != null) bleDevicesStream.cancel(); + if (currentConnectedDevice != null) currentConnectedDevice.disconnect(); + bleConnectionStatus.dispose(); + if (bleDeviceConnectionStream != null) bleDeviceConnectionStream.cancel(); if (bloodPressureReadingStream != null) bloodPressureReadingStream.cancel(); if (currentConnectedDevice != null) currentConnectedDevice.disconnect(); if (_timer != null && _timer.isActive) _timer.cancel(); @@ -94,68 +104,146 @@ class _BloodPressureBLEState extends State { void startBLEConnection() { if (FlutterBluePlus.isScanningNow == false) { - setState(() { - connectionStatus = "Connecting..."; - }); + bleConnectionStatus.value = "Connecting..."; - FlutterBluePlus.startScan(timeout: const Duration(seconds: 5), androidUsesFineLocation: false).then((value) { - // List blueToothDevices = value; - List blueToothDevices = []; + bleDevicesStream = FlutterBluePlus.scanResults.listen((results) { + List blueToothDevices = results; blueToothDevices.forEach((element) async { if (element.device.localName.isNotEmpty) { - if (element.device.localName.toLowerCase() == "bpm") { - element.device.connectionState.listen((BluetoothConnectionState state) async { - setState(() { - connectionStatus = state.toString(); + log("blueToothDevices: ${element.device.localName}"); + if (element.device.localName.toLowerCase() == "pm101897") { + bleDevicesStream.cancel(); + 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(); + } }); - if (state == BluetoothConnectionState.disconnected) { - // typically, start a periodic timer that tries to periodically reconnect. - // Note: you must always re-discover services after disconnection! + FlutterBluePlus.stopScan(); - // _timer = Timer.periodic(Duration(seconds: 2), (Timer timer) { - // startBLEConnection(); - // }); - } - if (state == BluetoothConnectionState.connected) { - currentConnectedDevice = element.device; - // _timer.cancel(); - List services = await element.device.discoverServices(); + 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.BLOOD_PRESSURE_SERVICE) { + if (service.serviceUuid.toString().toLowerCase() == BLEUtils.ECG_SERVICE) { print(service.serviceUuid); service.characteristics.forEach((characteristic) async { - if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.BLOOD_PRESSURE_CHARACTERISTIC) { + if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.ECG_READ_CHARACTERISTIC) { print(characteristic.characteristicUuid); - bloodPressureReadingStream = characteristic.onValueReceived.listen((event) { - print("onValueReceived Stream"); + print(characteristic.properties.toString()); + + characteristic.onValueReceived.listen((event) { + print("onValueReceived 1e4d Stream"); print(event); - setState(() { - if (event.length < 12) { - currentBPmmHG = "Measuring..."; - } else { - currentBPmmHG = "Measurement complete!"; - Map results = handleBPResult(event, characteristic); - currentBPmmHG = results["systolic"] + "/" + results["diastolic"] + " - " + (results["isBPHigh"] == "true" ? "High BP" : "Normal BP"); - currentPulse = results["pulse"] + " - " + (results["isPulseHigh"] == "true" ? "High pulse" : "Normal Pulse"); - } + }); + + 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(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----"); }); }); - await characteristic.setNotifyValue(true); } }); - return true; } }); } + }).catchError((onError) { + print("----- ERRORRRR!!!!!! -------"); + print(onError.toString()); }); - await element.device.connect(timeout: Duration(seconds: 35)); - return true; } } + }); }); + FlutterBluePlus.startScan(timeout: const Duration(seconds: 15), androidUsesFineLocation: false); } } + +void startBLEConnectionII() { + if (FlutterBluePlus.isScanningNow == false) { + setState(() { + connectionStatus = "Connecting..."; + }); + + FlutterBluePlus.startScan(timeout: const Duration(seconds: 5), androidUsesFineLocation: false).then((value) { + // List blueToothDevices = value; + List blueToothDevices = []; + blueToothDevices.forEach((element) async { + if (element.device.localName.isNotEmpty) { + if (element.device.localName.toLowerCase() == "bpm") { + element.device.connectionState.listen((BluetoothConnectionState state) async { + 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! + + // _timer = Timer.periodic(Duration(seconds: 2), (Timer timer) { + // startBLEConnection(); + // }); + } + if (state == BluetoothConnectionState.connected) { + currentConnectedDevice = element.device; + // _timer.cancel(); + List services = await element.device.discoverServices(); + services.forEach((service) { + if (service.serviceUuid.toString().toLowerCase() == BLEUtils.BLOOD_PRESSURE_SERVICE) { + print(service.serviceUuid); + service.characteristics.forEach((characteristic) async { + if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.BLOOD_PRESSURE_CHARACTERISTIC) { + print(characteristic.characteristicUuid); + bloodPressureReadingStream = characteristic.onValueReceived.listen((event) { + print("onValueReceived Stream"); + print(event); + setState(() { + if (event.length < 12) { + currentBPmmHG = "Measuring..."; + } else { + currentBPmmHG = "Measurement complete!"; + Map results = handleBPResult(event, characteristic); + currentBPmmHG = results["systolic"] + "/" + results["diastolic"] + " - " + (results["isBPHigh"] == "true" ? "High BP" : "Normal BP"); + currentPulse = results["pulse"] + " - " + (results["isPulseHigh"] == "true" ? "High pulse" : "Normal Pulse"); + } + }); + }); + await characteristic.setNotifyValue(true); + } + }); + return true; + } + }); + } + }); + await element.device.connect(timeout: Duration(seconds: 35)); + return true; + } + } + }); + }); + } +} } Map handleBPResult(List byteArray, BluetoothCharacteristic characteristic) { diff --git a/lib/pages/medical/my_trackers/ecg_ble.dart b/lib/pages/medical/my_trackers/ecg_ble.dart index a928bee7..df3e4a70 100644 --- a/lib/pages/medical/my_trackers/ecg_ble.dart +++ b/lib/pages/medical/my_trackers/ecg_ble.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:diplomaticquarterapp/theme/colors.dart'; import 'package:diplomaticquarterapp/uitl/ble_utils.dart'; @@ -108,6 +109,7 @@ class _ECG_BLEState extends State { List blueToothDevices = results; blueToothDevices.forEach((element) async { if (element.device.localName.isNotEmpty) { + log("blueToothDevices: ${element.device.localName}"); if (element.device.localName.toLowerCase() == "pm101897") { bleDevicesStream.cancel(); element.device.connect(timeout: Duration(seconds: 30), autoConnect: false).then((value) async { diff --git a/lib/pages/medical/my_trackers/my_trackers.dart b/lib/pages/medical/my_trackers/my_trackers.dart index 7f37a0fd..096ee917 100644 --- a/lib/pages/medical/my_trackers/my_trackers.dart +++ b/lib/pages/medical/my_trackers/my_trackers.dart @@ -24,7 +24,7 @@ class MyTrackers extends StatelessWidget { return AppScaffold( appBarTitle: TranslationBase.of(context).myTracker, showNewAppBar: true, - isShowDecPage: true, + isShowDecPage: false, showNewAppBarTitle: true, backgroundColor: Color(0xffF8F8F8), description: TranslationBase.of(context).infoTrackers, diff --git a/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart b/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart index 306e2079..a88346a1 100644 --- a/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart +++ b/lib/pages/medical/my_trackers/my_trackers_view_model/my_trackers_view_model.dart @@ -1,22 +1,26 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/ble_devices_model.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/andesfit_devices/weight_data_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/bp_rt_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_file_detail_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/ecg_rt_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/oxy_rt_model.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/ekg_chart_view.dart'; +import 'package:diplomaticquarterapp/uitl/app_toast.dart'; +import 'package:diplomaticquarterapp/uitl/ble_utils.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/services.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_helpers/ble_connect_helper.dart'; import 'package:flutter/material.dart'; -enum TrackerTypeEnum { OxymeterTracker, BloodPressureTracker, BloodSugarTracker, ECGTracker, AllInOneTracker } +enum TrackerTypeEnum { OxymeterTracker, BloodPressureTracker, BloodSugarTracker, ECGTracker, WeightScale, AllInOneTracker } //NativeEventNames @@ -34,7 +38,7 @@ class MyTrackersViewModel extends ChangeNotifier { List devicesList = []; - var devicesInfoJson = { + var devicesInfoJsonViatom = { "OxymeterTracker": [ {"model": "SP-20"}, // DONE {"model": "POD-1"}, // DONE @@ -45,30 +49,47 @@ class MyTrackersViewModel extends ChangeNotifier { "BloodPressureTracker": [ {"model": "BP2"}, //Done {"model": ""}, - {"model": ""}, - {"model": ""}, ], "BloodSugarTracker": [ {"model": ""}, - {"model": ""}, - {"model": ""}, - {"model": ""}, ], "ECGTracker": [ {"model": "DuoEK"}, {"model": "ER1"}, - {"model": ""}, + ], + "WeightScale": [ {"model": ""}, ], "AllInOneTracker": [ {"model": ""}, + ], + }; + + var devicesInfoJsonAndesfit = { + "OxymeterTracker": [ + {"model": ""} + ], + "BloodPressureTracker": [ + {"model": "BPM"}, //Done + ], + "BloodSugarTracker": [ {"model": ""}, - {"model": ""}, + ], + "ECGTracker": [ + {"model": "PM101897"}, //Done + ], + "WeightScale": [ + {"model": "SDIC"}, + ], + "AllInOneTracker": [ {"model": ""}, ], }; - List ecgEnabledDevices = ["BP2 0567", "DuoEK", "ER1"]; + List ecgEnabledDevices = ["BP2 0567", "DuoEK", "ER1", "PM101897"]; + List andesFitDevices = ["BPM", "PM101897", "SDIC"]; + + StreamSubscription bleDevicesStream; //************************************* OXYMETER ************************************* @@ -199,17 +220,17 @@ class MyTrackersViewModel extends ChangeNotifier { ); } - void filterOutTheSearchedDevices(List allDevices) { + void filterOutTheSearchedDevicesNative(List allDevices) { devicesList.clear(); notifyListeners(); - if (devicesInfoJson.containsKey(currentSelectedTrackerType.name)) { + if (devicesInfoJsonViatom.containsKey(currentSelectedTrackerType.name)) { allDevices.forEach( (foundDevice) { - List devicesInSelectedType = devicesInfoJson[currentSelectedTrackerType.name]; + List devicesInSelectedType = devicesInfoJsonViatom[currentSelectedTrackerType.name]; for (var device in devicesInSelectedType) { - log("foundDevice.name: ${foundDevice.name.toString()}"); + // log("foundDevice.name: ${foundDevice.name.toString()}"); foundDevice.deviceType = currentSelectedTrackerType; - log("device['model']: ${device['model']}"); + // log("device['model']: ${device['model']}"); if (device['model'] != "" && foundDevice.name.contains(device['model'])) { devicesList.add(foundDevice); } @@ -220,6 +241,31 @@ class MyTrackersViewModel extends ChangeNotifier { } } + void filterOutTheSearchedDevicesFlutter(List allDevices) { + if (devicesInfoJsonAndesfit.containsKey(currentSelectedTrackerType.name)) { + for (var foundDevice in allDevices) { + List devicesInSelectedType = devicesInfoJsonAndesfit[currentSelectedTrackerType.name]; + for (var device in devicesInSelectedType) { + if (isAndesfitDeviceConnected != null && isAndesfitDeviceConnected) { + return; + } + log("heres: $devicesInSelectedType"); + foundDevice.deviceType = currentSelectedTrackerType; + log("here1: ${device['model']}"); + log("here2: ${foundDevice.name}"); + if (device['model'] != "" && foundDevice.name.contains(device['model'])) { + if (!ifDeviceAlreadyThere(devicesList, foundDevice)) { + devicesList.add(foundDevice); + notifyListeners(); + } + } + } + } + + notifyListeners(); + } + } + TrackerTypeEnum currentSelectedTrackerType = TrackerTypeEnum.OxymeterTracker; updateSelectedTrackerType(var value) { @@ -245,7 +291,7 @@ class MyTrackersViewModel extends ChangeNotifier { // if(Platform.isIOS) { // parsesDevicesList(json.decode(event['data'])); // } else if(Platform.isAndroid) { - parsesDevicesList(json.decode(event['data']) as List); + parsesDevicesList(json.decode(event['data']) as List); // } } @@ -290,16 +336,20 @@ class MyTrackersViewModel extends ChangeNotifier { } }); - await scanDevices(currentSelectedTrackerType); + await scanDevicesNative(currentSelectedTrackerType); } void parsesDevicesList(List returnData) { var devicesList = List.generate(returnData.length, (index) => BleDeviceModel.fromJson(returnData[index])); - filterOutTheSearchedDevices(devicesList); + log("devicesList: ${devicesList.toString()}"); + filterOutTheSearchedDevicesNative(devicesList); } void resetList() { devicesList.clear(); + bleDevicesStream.cancel(); + FlutterBluePlus.stopScan(); + secondsToWaitForNativeScan = 5; } Future getEcgFilesList(BleDeviceModel device) async { @@ -318,7 +368,359 @@ class MyTrackersViewModel extends ChangeNotifier { await BleChannel.disconnect(); } - Future scanDevices(TrackerTypeEnum currentSelectedTrackerType) async { - await BleChannel.scanResults([currentSelectedTrackerType.name]); + Future scanDevicesNative(TrackerTypeEnum currentSelectedTrackerType) async { + await BleChannel.scanResultsNative([currentSelectedTrackerType.name]); + } + + Future stopNativeScan() async { + await BleChannel.stopNativeScan(); + } + + void startFlutterScan() { + if (FlutterBluePlus.isScanningNow == false) { + bleDevicesStream = FlutterBluePlus.scanResults.listen((results) { + List blueToothDevices = results; + List bleDevices = []; + blueToothDevices.forEach((element) async { + if (element.device.localName.isNotEmpty) { + log("blueToothDevicesFlutter: ${element.device.localName}"); + BleDeviceModel bleDeviceModel = BleDeviceModel(name: element.device.localName, model: 0, rssi: 0, macAddr: '', andesfitBluetoothDevice: element.device); + bleDevices.add(bleDeviceModel); + } + }); + filterOutTheSearchedDevicesFlutter(bleDevices); + }); + FlutterBluePlus.startScan( + timeout: const Duration(seconds: 10), + androidUsesFineLocation: false, + ); + } + } + + bool ifDeviceAlreadyThere(List devicesList, BleDeviceModel device) { + int index = devicesList.indexWhere((element) => element.name.toLowerCase() == device.name.toLowerCase()); + return index != -1; + } + + bool isDeviceFromAndesFit(String deviceName) { + bool isPresent = false; + + for (var value in andesFitDevices) { + if (deviceName.contains(value)) { + isPresent = true; + } + } + return isPresent; + } + + int secondsToWaitForNativeScan = 5; + + set updateSecondsToWaitForNativeScan(int value) { + secondsToWaitForNativeScan = value; + notifyListeners(); + } + + Timer timerToWaitForNativeScan = Timer.periodic(const Duration(seconds: 1), (Timer timer) {}); + + void startTimerForNativeScan() { + const Duration oneSec = Duration(seconds: 1); + timerToWaitForNativeScan = Timer.periodic( + oneSec, + (Timer timer) async { + log("I will stop scan after: $secondsToWaitForNativeScan"); + + if (secondsToWaitForNativeScan == 0) { + secondsToWaitForNativeScan--; + timer.cancel(); + timerToWaitForNativeScan.cancel(); + stopNativeScan(); + startFlutterScan(); + return; + } else { + secondsToWaitForNativeScan--; + } + notifyListeners(); + }, + ); + } + + // *********************** ANDESFIT ************************ + + bool isAndesfitDeviceConnected; + + Future connectAndesfitBloodPressureDevice(BluetoothDevice device) async { + device.connectionState.listen((BluetoothConnectionState state) async { + if (state == BluetoothConnectionState.disconnected) { + isAndesfitDeviceConnected = false; + notifyListeners(); + } + if (state == BluetoothConnectionState.connected) { + isAndesfitDeviceConnected = true; + notifyListeners(); + + List services = await device.discoverServices(); + services.forEach((service) { + if (service.serviceUuid.toString().toLowerCase() == BLEUtils.BLOOD_PRESSURE_SERVICE) { + print(service.serviceUuid); + service.characteristics.forEach((characteristic) async { + if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.BLOOD_PRESSURE_CHARACTERISTIC) { + print(characteristic.characteristicUuid); + characteristic.onValueReceived.listen((event) { + print("onValueReceived Stream"); + print(event); + + handleAndesfitBloodPressureStream(event, characteristic); + }); + await characteristic.setNotifyValue(true); + } + }); + } + }); + } + }); + await device.connect(timeout: Duration(seconds: 35)); + } + + Future disConnectAndesfitDevice(BluetoothDevice device) async { + selectedAndesFitScanResult = null; + isAndesfitDeviceConnected = null; + device.disconnect(); + } + + ScanResult selectedAndesFitScanResult; + + updateSelectedAndesFitScanResult(var value) { + selectedAndesFitScanResult = value; + notifyListeners(); } + + BpRtMeasuringModel andesfitBpRtMeasuringModel; + + void updateAndesfitBpRtMeasuringModel(BpRtMeasuringModel model) { + andesfitBpRtMeasuringModel = model; + notifyListeners(); + } + + BpRtResultModel andesfitBpRtResultModel; + + void updateAndesfitBpRtResultModel(BpRtResultModel model) { + andesfitBpRtResultModel = model; + notifyListeners(); + } + + String andesfitBpCurrentStatus; + + updateAndesfitBpCurrentStatus(var value) { + andesfitBpCurrentStatus = value; + notifyListeners(); + } + + void handleAndesfitBloodPressureStream(List byteArray, BluetoothCharacteristic characteristic) { + if (byteArray.length < 12) { + updateAndesfitBpCurrentStatus(kRealTimeDataBPMeasuring); + int pressure = 0; + if (byteArray.length > 1) { + pressure = byteArray[1]; //pressure value + } + updateAndesfitBpRtMeasuringModel(BpRtMeasuringModel(deflate: false, pr: 0, pressure: pressure)); + } else { + updateAndesfitBpCurrentStatus(kRealTimeDataBPResult); + + int sys = 0; + int dias = 0; + int pulse = 0; + bool idPulseHigh = false; + bool isBPHigh = false; + Map results = Map(); + + if (byteArray[1] != 0 && byteArray[3] != 0) { + isBPHigh = false; + sys = byteArray[1]; + dias = byteArray[3]; + } else { + isBPHigh = true; + sys = byteArray[2]; + dias = byteArray[4]; + } + + if (byteArray[8] != 0) { + pulse = byteArray[8]; + idPulseHigh = true; + } else { + pulse = byteArray[9]; + idPulseHigh = false; + } + + updateAndesfitBpRtResultModel(BpRtResultModel( + deflate: false, + pr: pulse, + pressure: 0, + dia: dias, + sys: sys, + isBpHigh: isBPHigh, + isPulseHigh: idPulseHigh, + )); + + if (characteristic.isNotifying) characteristic.setNotifyValue(false); + + print(results); + } + } + + WeightScaleData andesfitWeightScaleData; + + void updateAndesfitWeightScaleData(WeightScaleData model) { + andesfitWeightScaleData = model; + notifyListeners(); + } + + Future connectAndesfitWeightDevice(BluetoothDevice device) async { + device.connectionState.listen((BluetoothConnectionState state) async { + if (state == BluetoothConnectionState.disconnected) { + isAndesfitDeviceConnected = false; + notifyListeners(); + } + if (state == BluetoothConnectionState.connected) { + isAndesfitDeviceConnected = true; + notifyListeners(); + + List services = await device.discoverServices(); + services.forEach((service) { + if (service.serviceUuid.toString().toLowerCase() == BLEUtils.WEIGHT_MEASUREMENT_SERVICE) { + print(service.serviceUuid); + service.characteristics.forEach((characteristic) async { + if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.WEIGHT_MEASUREMENT_CHARACTERISTIC_FFF1) { + print(characteristic.characteristicUuid); + print(characteristic.properties.toString()); + characteristic.onValueReceived.listen((event) { + print("onValueReceived fff1 Stream"); + print(event); + if (event[0] == 129) { + // Issue result ack command + Future.delayed(Duration(milliseconds: 1000)).then((value) async { + characteristic.write([0x01]).then((value) { + print("----fff1 result ack data written----"); + }); + }); + } + // Error + else if (event[0] == 65) { + AppToast.showErrorToast(message: "Measurement Error Occurred!"); + } else { + //Sample Results + // ----------Result Set 1----------: 42;0;1;0;0;0;0;65;9;b0;d2;0;7f;3;44;0;ac;1;cc;0 + // ----------Result Set 2----------: 42;1;32;0;2c;0;1;3;84;9;1b;0;29;2;9c;0;10;0;e9 + String resultSet1 = ""; + String resultSet2 = ""; + + if (event[1] == 0) { + resultSet1 = convertResultSetToString(event); + print("----------Result Set 1----------: $resultSet1"); + print("----------Result Set 2----------: $resultSet2"); + } else { + resultSet2 = convertResultSetToString(event); + print("----------Result Set 1----------: $resultSet1"); + print("----------Result Set 2----------: $resultSet2"); + parseResultData(resultSet1, resultSet2); + } + } + }); + await Future.delayed(Duration(milliseconds: 500)).then((value) async { + print("Delayed fff1 done"); + if (!characteristic.isNotifying) await characteristic.setNotifyValue(true).catchError((err) {}); + }); + } + + if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.WEIGHT_MEASUREMENT_CHARACTERISTIC_FFF2) { + print(characteristic.characteristicUuid); + print(characteristic.properties.toString()); + characteristic.onValueReceived.listen((event) { + print("onValueReceived fff2 Stream"); + print(event); + }); + + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + print("Delayed fff2 done"); + if (!characteristic.isNotifying) await characteristic.setNotifyValue(true).catchError((err) {}); + }); + + // Write user data to fff2 + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + characteristic.write([0x81, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x19, 0x01, 0x00, 0x00], withoutResponse: true).then((value) { + print("----fff2 user data written----"); + }); + + // Issue get result command + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + characteristic.write([0x41, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00], withoutResponse: true).then((value) { + print("----fff2 get result data written----"); + }); + }); + }); + } + }); + } + }); + } + }); + await device.connect(timeout: Duration(seconds: 35)); + } + + String adjustHexString(String value) { + return value.length == 1 ? "0" + value : value; + } + + void parseResultData(String resultSet1, String resultSet2) { + List hexStringResSet1 = resultSet1.split(";"); + List hexStringResSet2 = resultSet2.split(";"); + + String hexStringWeight = adjustHexString(hexStringResSet1[13]) + adjustHexString(hexStringResSet1[14]); + String hexStringBMI = adjustHexString(hexStringResSet1[15]) + adjustHexString(hexStringResSet1[16]); + String hexStringFat = adjustHexString(hexStringResSet2[3]) + adjustHexString(hexStringResSet2[4]); + String hexStringBone = adjustHexString(hexStringResSet2[11]) + adjustHexString(hexStringResSet2[12]); + String hexStringWater = adjustHexString(hexStringResSet2[13]) + adjustHexString(hexStringResSet2[14]); + String hexStringMuscle = adjustHexString(hexStringResSet2[7]) + adjustHexString(hexStringResSet2[8]); + String hexStringBMR = adjustHexString(hexStringResSet2[9]) + adjustHexString(hexStringResSet2[10]); + + print((int.parse(hexStringWeight, radix: 16) * 0.1).toStringAsFixed(1)); + print((int.parse(hexStringBMI, radix: 16) * 0.1).toStringAsFixed(1)); + print((int.parse(hexStringFat, radix: 16) * 0.1).toStringAsFixed(1)); + print((int.parse(hexStringMuscle, radix: 16) * 0.1).toStringAsFixed(1)); + print((int.parse(hexStringBMR, radix: 16))); + print((int.parse(hexStringBone, radix: 16) * 0.1).toStringAsFixed(1)); + print((int.parse(hexStringWater, radix: 16) * 0.1).toStringAsFixed(1)); + + var weight = (int.parse(hexStringWeight, radix: 16) * 0.1).toStringAsFixed(1); + var bmi = (int.parse(hexStringBMI, radix: 16) * 0.1).toStringAsFixed(1); + var fat = (int.parse(hexStringFat, radix: 16) * 0.1).toStringAsFixed(1); + var muscle = (int.parse(hexStringMuscle, radix: 16) * 0.1).toStringAsFixed(1); + var bmr = (int.parse(hexStringBMR, radix: 16)).toString(); + var bone = (int.parse(hexStringBone, radix: 16) * 0.1).toStringAsFixed(1); + var water = (int.parse(hexStringWater, radix: 16) * 0.1).toStringAsFixed(1); + updateAndesfitWeightScaleData(WeightScaleData(weight: weight, bmi: bmi, fat: fat, muscle: muscle, bmr: bmr, bone: bone, water: water)); + } + + String convertResultSetToString(List byteArray) { + String resSet; + resSet = (byteArray.map( + (x) { + return x.toRadixString(16); + }, + )).join(";"); + return resSet; + } + +// String convertIntListToHex(List byteArray) { +// String b = (byteArray.map((x) { +// return x.toRadixString(16); +// })).join(";"); +// List hexString = b.split(";"); +// print("HexString: $hexString"); +// String returnString = hexString[2] + hexString[3]; +// print("Temp Hex String: $returnString"); +// final number = int.parse(returnString, radix: 16); +// print("Temp Number: ${number * 0.1}"); +// +// return (number * 0.1).toStringAsFixed(1); +// } } diff --git a/lib/pages/medical/my_trackers/viatom_devices/bp_tracker_ble.dart b/lib/pages/medical/my_trackers/viatom_devices/bp_tracker_ble.dart index d679048e..58bb3e83 100644 --- a/lib/pages/medical/my_trackers/viatom_devices/bp_tracker_ble.dart +++ b/lib/pages/medical/my_trackers/viatom_devices/bp_tracker_ble.dart @@ -254,7 +254,7 @@ class _BpTrackerBLEState extends State { bpStatusNotifier.value = "RealTimeDataBP2Result"; } }); - await BleChannel.scanResults(["bloodpressure", "BP2"]); + await BleChannel.scanResultsNative(["bloodpressure", "BP2"]); }); } diff --git a/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart b/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart index beb7be1b..cd4697cb 100644 --- a/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart +++ b/lib/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart @@ -169,7 +169,7 @@ class _EKG_BLEState extends State { // eventChannelIOSEKG.receiveBroadcastStream().listen((event) { // print('Received eventChannelIOSEKG event---: $event'); // }); - await BleChannel.scanResults(["ekg", "DuoEK"]); + await BleChannel.scanResultsNative(["ekg", "DuoEK"]); }, textColor: Colors.white, ), diff --git a/lib/pages/medical/my_trackers/viatom_devices/oxymeter_ble.dart b/lib/pages/medical/my_trackers/viatom_devices/oxymeter_ble.dart index d36a17c9..4518d68b 100644 --- a/lib/pages/medical/my_trackers/viatom_devices/oxymeter_ble.dart +++ b/lib/pages/medical/my_trackers/viatom_devices/oxymeter_ble.dart @@ -110,7 +110,7 @@ class _Oxymeter_BLEState extends State { // POD-1W response: RtParam{spo2=98, pr=104, pi=5.8, isProbeOff=false, isPulseSearching=false} }); - await BleChannel.scanResults(["oximeter", deviceName]); + await BleChannel.scanResultsNative(["oximeter", deviceName]); }); } diff --git a/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart b/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart index c317fbfc..c94ff8c4 100644 --- a/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart +++ b/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart @@ -194,7 +194,7 @@ class _SP20PulseTrackerState extends State { sp20StatusNotifier.value = "EventSp20RtParam"; } }); - await BleChannel.scanResults(["Pulse Oxymeter", "SP-20"]); + await BleChannel.scanResultsNative(["Pulse Oxymeter", "SP-20"]); }); } } diff --git a/lib/pages/medical/my_trackers/weight_scale_ble.dart b/lib/pages/medical/my_trackers/weight_scale_ble.dart index f005f87f..5bf21add 100644 --- a/lib/pages/medical/my_trackers/weight_scale_ble.dart +++ b/lib/pages/medical/my_trackers/weight_scale_ble.dart @@ -1,6 +1,5 @@ import 'dart:async'; - -import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/weight_scale_data.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/viatom_devices/andesfit_devices/weight_data_model.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/ble_utils.dart';