From 6e97f8556f1509fec84543bb7c0d4ad62516b814 Mon Sep 17 00:00:00 2001 From: Faiz Hashmi Date: Tue, 9 Jan 2024 10:12:14 +0300 Subject: [PATCH] BP tracker Integration Completed --- .../diplomaticquarterapp/MainActivity.kt | 29 +- .../diplomaticquarterapp/ble/BleBridge.kt | 84 +++--- .../ble/utils/RTBP2Data.java | 34 --- .../bp_rt_data_measuring_model.dart | 24 ++ .../bp_rt_data_result_model.dart | 33 +++ .../viatom_devices/bp_tracker_ble.dart | 252 ++++++++++++------ lib/viatom_ble/ble_connect.dart | 2 - 7 files changed, 288 insertions(+), 170 deletions(-) delete mode 100644 android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/utils/RTBP2Data.java create mode 100644 lib/models/ble_devices/viatom_devices/bp_rt_data_measuring_model.dart create mode 100644 lib/models/ble_devices/viatom_devices/bp_rt_data_result_model.dart diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt index cd59f014..64217fc5 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt @@ -1,28 +1,19 @@ package com.ejada.hmg -import android.app.NotificationChannel -import android.app.NotificationManager -import android.content.ContentResolver -import android.media.AudioAttributes -import android.net.Uri -import android.os.Bundle -import android.util.Log -import android.os.Build import android.view.WindowManager -import androidx.annotation.NonNull; import com.ejada.hmg.utils.* import com.ejada.hmg.* import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugin.common.MethodChannel import io.flutter.plugins.GeneratedPluginRegistrant import com.lepu.blepro.observer.BleChangeObserver -class MainActivity : FlutterFragmentActivity(), BleChangeObserver { - override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { +@Suppress("DEPRECATION") +class MainActivity : FlutterFragmentActivity() { + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine); - - + + // Create Flutter Platform Bridge this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) PlatformBridge(flutterEngine, this).create() @@ -50,11 +41,11 @@ class MainActivity : FlutterFragmentActivity(), BleChangeObserver { } - override fun onBleStateChanged(model: Int, state: Int) { - //println( "model $model, state: $state") -// _bleState.value = state == Ble.State.CONNECTED -// Log.d(TAG, "bleState $bleState") - } +// override fun onBleStateChanged(model: Int, state: Int) { +// println("onBleStateChanged") +// println("model $model, state: $state") +// +// } override fun onResume() { super.onResume() 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 4fdd4699..c2279392 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 @@ -1,17 +1,8 @@ package com.ejada.hmg.utils import android.annotation.SuppressLint -import android.content.Context -import android.content.Intent -import android.content.Intent.getIntent -import android.net.Uri import android.os.Build -import android.os.Bundle import android.os.Handler -import android.provider.Settings -import android.util.Log -import android.widget.Toast -import androidx.core.app.ActivityCompat.startActivityForResult import com.ejada.hmg.MainActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall @@ -20,13 +11,11 @@ import io.flutter.plugin.common.EventChannel import android.util.SparseArray import androidx.annotation.RequiresApi import com.cloud.diplomaticquarterapp.ble.utils.EcgData -import com.cloud.diplomaticquarterapp.ble.utils.RTBP2Data import com.google.gson.Gson //Ble import com.jeremyliao.liveeventbus.LiveEventBus -import com.lepu.blepro.constants.Ble import com.lepu.blepro.event.EventMsgConst import com.lepu.blepro.event.EventMsgConst.Ble.* import com.lepu.blepro.event.InterfaceEvent @@ -39,18 +28,15 @@ import com.lepu.blepro.ext.er2.DeviceInfo import com.lepu.blepro.ext.er2.Er2EcgFile import com.lepu.blepro.ext.er2.Er2File import com.lepu.blepro.ext.er2.RtData +import com.lepu.blepro.ext.bp2.* import com.lepu.blepro.ext.pc60fw.RtParam import com.lepu.blepro.objs.Bluetooth import com.lepu.blepro.objs.BluetoothController -import com.lepu.blepro.observer.BleChangeObserver import com.lepu.blepro.utils.DateUtil import com.lepu.blepro.utils.Er1Decompress -import io.flutter.plugin.common.EventChannel.EventSink -import no.nordicsemi.android.ble.observer.ConnectionObserver +import kotlin.reflect.KFunction2 -class BleBridge( - private var flutterEngine: FlutterEngine, private var mainActivity: MainActivity -) { +class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivity: MainActivity) { private lateinit var channel: MethodChannel private lateinit var Echannel: EventChannel @@ -196,14 +182,16 @@ class BleBridge( result.notImplemented() } } - Echannel.setStreamHandler(object : EventChannel.StreamHandler { - override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) { - this@BleBridge.eventSink = eventSink - } + Echannel.setStreamHandler( + object : EventChannel.StreamHandler { + override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) { + this@BleBridge.eventSink = eventSink + } - override fun onCancel(arguments: Any?) { - } - }) + override fun onCancel(arguments: Any?) { + } + }, + ) } @@ -214,8 +202,17 @@ class BleBridge( BleServiceHelper.BleServiceHelper.disconnect(false) } + private fun scanDevice(methodCall: MethodCall, result: MethodChannel.Result) { - println("This is Test of Scanning") + + + LiveEventBus.get(EventMsgConst.Ble.EventServiceConnectedAndInterfaceInit).observe(this.mainActivity) { + // BleService init success + println("EventServiceConnectedAndInterfaceInit---------") + BleServiceHelper.BleServiceHelper.startScan(models) + println("EventServiceConnectedAndInterfaceInit") + } + LiveEventBus.get(EventMsgConst.Ble.EventServiceConnectedAndInterfaceInit).observe(this.mainActivity) { // BleService init success println("EventServiceConnectedAndInterfaceInit---------") @@ -225,11 +222,13 @@ class BleBridge( LiveEventBus.get(EventMsgConst.Discovery.EventDeviceFound).observe(this.mainActivity) { var deviceName: String = "" for (b in BluetoothController.getDevices()) { - // println(b.name) + println(b.name) + + //TODO: UNCOMMENT THIS // if (b.name.contains("POD-1_SN8187", true) || b.name.contains( // "O2M 1670", true // ) || b.name.contains("DuoEK", true) || b.name.contains("BP2", true) -// +// ) { if (b.name.contains("BP2", true)) { println("connecting bp2") @@ -241,6 +240,7 @@ class BleBridge( BleServiceHelper.BleServiceHelper.connect( this.mainActivity.applicationContext, b.model, b.device ) + } } @@ -260,6 +260,7 @@ class BleBridge( val data = it.data as DeviceInfo println("DuoEK INFO DATA: $data") val returnData = mapOf("type" to "infoData", "data" to data.toString()) + eventSink?.success(returnData) } LiveEventBus.get(InterfaceEvent.ER2.EventEr2FileList).observe(this.mainActivity) { @@ -357,7 +358,7 @@ class BleBridge( LiveEventBus.get(InterfaceEvent.BP2.EventBp2Info).observe(this.mainActivity) { val data = it.data as com.lepu.blepro.ext.bp2.DeviceInfo println("BP2 INFO DATA: $data") - val returnData = mapOf("type" to "infoData", "data" to data.toString()) + val returnData = mapOf("type" to "infoData", "data" to data.toString(), "deviceName" to deviceName) eventSink?.success(returnData) BleServiceHelper.BleServiceHelper.startRtTask(model) } @@ -414,7 +415,7 @@ class BleBridge( } LiveEventBus.get(InterfaceEvent.BP2.EventBp2RtData).observe(this.mainActivity) { - val data = it.data as RTBP2Data + val data = it.data as com.lepu.blepro.ext.bp2.RtData // data.status: RtStatus // data.status.deviceStatus: 0(STATUS_SLEEP), 1(STATUS_MEMERY), 2(STATUS_CHARGE), 3(STATUS_READY), // 4(STATUS_BP_MEASURING), 5(STATUS_BP_MEASURE_END), @@ -424,10 +425,27 @@ class BleBridge( // data.param: RtParam // data.param.paramDataType: 0(Bp measuring), 1(Bp end), 2(Ecg measuring), 3(Ecg end) - println("EventBp2RtData FOR BP : $data") - val returnData = mapOf("type" to "RealTimeDataBP2", "data" to gson.toJson(data)) - println(returnData) - eventSink?.success(returnData) + when (data.param.paramDataType) { + 0 -> { + val bpIng = RtBpIng(data.param.paramData) + + val returnData = mapOf("type" to "RealTimeDataBP2Measuring", "data" to gson.toJson(bpIng)) + eventSink?.success(returnData) + + } + + 1 -> { + val bpResult = RtBpResult(data.param.paramData) + val returnData = mapOf("type" to "RealTimeDataBP2Result", "data" to gson.toJson(bpResult)) + println("RealTimeDataBP2Result FOR BP : $returnData") + eventSink?.success(returnData) + + + } + + } + + } } diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/utils/RTBP2Data.java b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/utils/RTBP2Data.java deleted file mode 100644 index 36a61dba..00000000 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/utils/RTBP2Data.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.cloud.diplomaticquarterapp.ble.utils; - -import com.lepu.blepro.ext.bp2.RtParam; -import com.lepu.blepro.ext.bp2.RtStatus; - -public class RTBP2Data { - - private RtStatus status; - private RtParam param; - - public RTBP2Data() { - } - - public RtStatus getStatus() { - return this.status; - } - - public void setStatus(RtStatus var1) { - this.status = var1; - } - - public RtParam getParam() { - return this.param; - } - - public void setParam(RtParam var1) { - this.param = var1; - } - - public String toString() { - return "RtData{status=" + this.status + ", param=" + this.param + '}'; - } - -} diff --git a/lib/models/ble_devices/viatom_devices/bp_rt_data_measuring_model.dart b/lib/models/ble_devices/viatom_devices/bp_rt_data_measuring_model.dart new file mode 100644 index 00000000..4cbf5a16 --- /dev/null +++ b/lib/models/ble_devices/viatom_devices/bp_rt_data_measuring_model.dart @@ -0,0 +1,24 @@ +class BpRtDataMeasuringModel { + bool deflate; + int pr; + int pressure; + bool pulse; + + BpRtDataMeasuringModel({this.deflate, this.pr, this.pressure, this.pulse}); + + BpRtDataMeasuringModel.fromJson(Map json) { + deflate = json['deflate']; + pr = json['pr']; + pressure = json['pressure']; + pulse = json['pulse']; + } + + Map toJson() { + final Map data = new Map(); + data['deflate'] = this.deflate; + data['pr'] = this.pr; + data['pressure'] = this.pressure; + data['pulse'] = this.pulse; + return data; + } +} diff --git a/lib/models/ble_devices/viatom_devices/bp_rt_data_result_model.dart b/lib/models/ble_devices/viatom_devices/bp_rt_data_result_model.dart new file mode 100644 index 00000000..2803691e --- /dev/null +++ b/lib/models/ble_devices/viatom_devices/bp_rt_data_result_model.dart @@ -0,0 +1,33 @@ +class BpRtDataResultModel { + bool deflate; + int dia; + int mean; + int pr; + int pressure; + int result; + int sys; + + BpRtDataResultModel({this.deflate, this.dia, this.mean, this.pr, this.pressure, this.result, this.sys}); + + BpRtDataResultModel.fromJson(Map json) { + deflate = json['deflate']; + dia = json['dia']; + mean = json['mean']; + pr = json['pr']; + 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; + } +} 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 a179e2b1..8b9a246a 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 @@ -1,5 +1,8 @@ +import 'dart:convert'; import 'dart:io'; +import 'package:diplomaticquarterapp/models/ble_devices/viatom_devices/bp_rt_data_measuring_model.dart'; +import 'package:diplomaticquarterapp/models/ble_devices/viatom_devices/bp_rt_data_result_model.dart'; import 'package:diplomaticquarterapp/uitl/utils_new.dart'; import 'package:diplomaticquarterapp/viatom_ble/ble_connect.dart'; import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; @@ -15,16 +18,18 @@ class BpTrackerBLE extends StatefulWidget { class _BpTrackerBLEState extends State { EventChannel eventChannel = EventChannel('BLE-Platform-Bridge-Event'); - String receivedData = ''; - final bpDataNotifier = ValueNotifier("start"); - - // String deviceName = "CheckMeO2"; + final bpDataNotifierMeasuring = ValueNotifier(BpRtDataMeasuringModel()); + final bpDataNotifierResult = ValueNotifier(BpRtDataResultModel()); + final bpStatusNotifier = ValueNotifier("status"); + final bpDeviceDataNotifier = ValueNotifier(""); String deviceName = "BP2"; @override void dispose() { - bpDataNotifier.dispose(); + bpDataNotifierMeasuring.dispose(); + bpDataNotifierResult.dispose(); + bpStatusNotifier.dispose(); super.dispose(); BleChannel.disconnect(); } @@ -43,56 +48,162 @@ class _BpTrackerBLEState extends State { isShowDecPage: false, showNewAppBarTitle: true, backgroundColor: Color(0xffF8F8F8), - body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( + body: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: ListView( children: [ - Expanded( - child: DefaultButton( - "Get Info", - () async { - checkBLEPermissions(); - }, - textColor: Colors.white, - ), + ValueListenableBuilder( + valueListenable: bpDeviceDataNotifier, + builder: (context, value, _) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text( + value == null || value.isEmpty ? "" : "Connected", + style: TextStyle(fontSize: 18), + ), + Text( + "$value", + style: TextStyle(fontSize: 18), + ), + ], + ); + }, ), - mWidth(16.0), - Expanded( - child: DefaultButton( - "Get Files List", - () async { - await BleChannel.getBP2FilesList(["bloodpressure", "BP2"]); - }, - textColor: Colors.white, - ), + ValueListenableBuilder( + valueListenable: bpStatusNotifier, + builder: (context, value, _) { + if (value == "RealTimeDataBP2Measuring") { + return ValueListenableBuilder( + valueListenable: bpDataNotifierMeasuring, + builder: (context, BpRtDataMeasuringModel bpRtDataMeasuringModel, _) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + mHeight(24.0), + Column( + children: [ + Text(bpRtDataMeasuringModel.pressure.toString(), style: TextStyle(fontSize: 100, fontWeight: FontWeight.bold)), + Text("Pressure", style: TextStyle(fontSize: 20)), + ], + ), + mHeight(24.0), + ], + ); + }, + ); + } else if (value == "RealTimeDataBP2Result") { + return ValueListenableBuilder( + valueListenable: bpDataNotifierResult, + builder: (context, BpRtDataResultModel bpRtDataResultModel, _) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("Dia", style: TextStyle(fontSize: 20)), + Text(bpRtDataResultModel.dia.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("Sys", style: TextStyle(fontSize: 20)), + Text(bpRtDataResultModel.sys.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("mmHg", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("♥︎", style: TextStyle(fontSize: 20)), + Text(bpRtDataResultModel.pr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("/min", style: TextStyle(fontSize: 10)), + ], + ), + ], + ), + mHeight(24.0), + ], + ); + }, + ); + } + + return Padding( + padding: const EdgeInsets.all(24.0), + child: Center( + child: Text( + "Some animation with the instruction", + style: TextStyle(fontSize: 9.0), + ), + ), + ); + }, ), ], ), - mHeight(20.0), - // _buildLiveLineChart() - ValueListenableBuilder( - valueListenable: bpDataNotifier, - builder: (context, value, _) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, + ), + ValueListenableBuilder( + valueListenable: bpDeviceDataNotifier, + builder: (context, value, _) { + if (value == null || value.isEmpty) { + return Row( children: [ - Text( - value, - style: TextStyle(fontSize: 9.0), + Expanded( + child: DefaultButton( + "Start Scan", + () async { + checkBLEPermissions(); + }, + textColor: Colors.white, + color: Colors.green, + ), ), - mHeight(24.0), - getFilesListWidget(), - mHeight(20.0), ], ); - }, - ), - ], - ), + } + return Row( + children: [ + Expanded( + child: DefaultButton( + "Disconnect with $value", + () async { + bpDataNotifierMeasuring.dispose(); + bpDataNotifierResult.dispose(); + + bpStatusNotifier.dispose(); + BleChannel.disconnect(); + }, + textColor: Colors.white, + ), + ), + ], + ); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text( + value != null || value.isEmpty ? "" : "Connected", + style: TextStyle(fontSize: 18), + ), + Text( + "$value", + style: TextStyle(fontSize: 18), + ), + ], + ); + }, + ), + ], ), ), ); @@ -125,7 +236,8 @@ class _BpTrackerBLEState extends State { print('Received event---: $event'); print(event['type']); if (event['type'] == "infoData") { - bpDataNotifier.value = event['data']; + bpStatusNotifier.value = "infoData"; + bpDeviceDataNotifier.value = event['deviceName']; } if (event['type'] == "fileList") { // parseEKGFilesList(event['data']); @@ -133,49 +245,25 @@ class _BpTrackerBLEState extends State { if (event['type'] == 'fileDetail') { print("Received file data ---:"); print(event['data']); - // parseEKGFileDetailObject(event['data']); } - if (event['type'] == "RealTimeDataBP2") { - bpDataNotifier.value = event['data']; - // parseEKGRealTimeDataObject(event['data']); + if (event['type'] == "RealTimeDataBP2Measuring") { + parseBpRtMeasuringObject(event['data']); + bpStatusNotifier.value = "RealTimeDataBP2Measuring"; + } + if (event['type'] == "RealTimeDataBP2Result") { + parseBpRtResultObject(event['data']); + bpStatusNotifier.value = "RealTimeDataBP2Result"; } }); await BleChannel.getScanningResult(["bloodpressure", "BP2"]); }); } - String getSPO2(String value) { - return "SpO2: " + value.split(",")[0].replaceAll("{spo2=", ""); + void parseBpRtMeasuringObject(dynamic returnData) { + bpDataNotifierMeasuring.value = BpRtDataMeasuringModel.fromJson(json.decode(returnData)); } - String getPR(String value) { - return "Pulse Rate: " + value.split(",")[1].replaceAll("pr=", ""); + void parseBpRtResultObject(dynamic returnData) { + bpDataNotifierResult.value = BpRtDataResultModel.fromJson(json.decode(returnData)); } - - String getPI(String value) { - return "Perfusion Index: " + value.split(",")[2].replaceAll("pi=", "") + "%"; - } - - String getSPO2iOS(String value) { - return "SpO2: " + value.split(",")[0]; - } - - String getPRiOS(String value) { - return "Pulse Rate: " + value.split(",")[1]; - } - -// List setResult(String value) { -// List values = value.split(","); -// -// print(values[0].replaceAll("{spo2=", "")); -// print(values[1].replaceAll("pr=", "")); -// print(values[2].replaceAll("pi=", "")); -// -// values.clear(); -// values.add(values[0].replaceAll("{spo2=", "")); -// values.add(values[1].replaceAll("pr=", "")); -// values.add(values[2].replaceAll("pi=", "")); -// -// return values; -// } } diff --git a/lib/viatom_ble/ble_connect.dart b/lib/viatom_ble/ble_connect.dart index ef9c53a0..4284b44e 100644 --- a/lib/viatom_ble/ble_connect.dart +++ b/lib/viatom_ble/ble_connect.dart @@ -5,7 +5,6 @@ class BleChannel { static const platform_ios_ekg = MethodChannel('BLE-Platform-Bridge-IOS-EKG'); - //BLE-Platform-Bridge static Future getScanningResult(List deviceType) async { try { @@ -66,5 +65,4 @@ class BleChannel { return "Error: $e"; } } - }