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 c2279392..585cb5ea 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 @@ -16,6 +16,7 @@ import com.google.gson.Gson //Ble import com.jeremyliao.liveeventbus.LiveEventBus +import com.lepu.blepro.constants.Constant import com.lepu.blepro.event.EventMsgConst import com.lepu.blepro.event.EventMsgConst.Ble.* import com.lepu.blepro.event.InterfaceEvent @@ -30,6 +31,10 @@ 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.ext.sp20.GetConfigResult +import com.lepu.blepro.ext.sp20.RtWave +import com.lepu.blepro.ext.sp20.SetConfigResult +import com.lepu.blepro.ext.sp20.TempResult import com.lepu.blepro.objs.Bluetooth import com.lepu.blepro.objs.BluetoothController import com.lepu.blepro.utils.DateUtil @@ -227,11 +232,10 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi //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) +// ) || b.name.contains("DuoEK", true) || b.name.contains("BP2", true) || b.name.contains("SP-20", true) // ) { - if (b.name.contains("BP2", true)) { - println("connecting bp2") + if (b.name.contains("SP-20", true)) { model = b.model deviceName = b.name @@ -344,11 +348,6 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi if (deviceName.contains("BP2", ignoreCase = true)) { -// br2Handler.removeCallbacks(bp2rtTask) -// br2Handler.post(bp2rtTask) -// println("startRtTask") - - LiveEventBus.get(InterfaceEvent.BP2.EventBp2SyncTime).observe(this.mainActivity) { println("EventBp2SyncTime") // Get Device Info @@ -363,13 +362,10 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi BleServiceHelper.BleServiceHelper.startRtTask(model) } - LiveEventBus.get(InterfaceEvent.BP2.EventBp2FileList).observe(this.mainActivity) { bpFileNames = it.data as ArrayList } - - LiveEventBus.get(InterfaceEvent.BP2.EventBp2ReadFileComplete).observe(this.mainActivity) { val data = it.data as Bp2File // data.type: 1(BP), 2(ECG) @@ -450,6 +446,35 @@ class BleBridge(private var flutterEngine: FlutterEngine, private var mainActivi } + if (deviceName.contains("SP-20", ignoreCase = true)) { + + LiveEventBus.get(InterfaceEvent.SP20.EventSp20SetTime).observe(this.mainActivity) { + println("EventSp20SetTime") + BleServiceHelper.BleServiceHelper.bp2GetInfo(model) + } + + LiveEventBus.get(InterfaceEvent.SP20.EventSp20DeviceInfo).observe(this.mainActivity) { + val data = it.data as com.lepu.blepro.ext.sp20.DeviceInfo + println("EventSp20DeviceInfo: $data") + val returnData = mapOf("type" to "infoData", "data" to data.toString(), "deviceName" to deviceName) + eventSink?.success(returnData) + BleServiceHelper.BleServiceHelper.startRtTask(model) + } + + LiveEventBus.get(InterfaceEvent.SP20.EventSp20RtParam).observe(this.mainActivity) { + val data = it.data as com.lepu.blepro.ext.sp20.RtParam + println("EventSp20RtParam: $data") + val returnData = mapOf("type" to "EventSp20RtParam", "data" to gson.toJson(data)) + eventSink?.success(returnData) + } + LiveEventBus.get(InterfaceEvent.SP20.EventSp20RtWave).observe(this.mainActivity) { + val data = it.data as RtWave + println("EventSp20RtWave: $data") + + } + + } + } val rawFolders = SparseArray() diff --git a/lib/models/ble_devices/viatom_devices/oxy_sp20_rt_param_model.dart b/lib/models/ble_devices/viatom_devices/oxy_sp20_rt_param_model.dart new file mode 100644 index 00000000..f386f684 --- /dev/null +++ b/lib/models/ble_devices/viatom_devices/oxy_sp20_rt_param_model.dart @@ -0,0 +1,33 @@ +class SP20RTParamModel { + int battery; + bool isCheckProbe; + bool isProbeOff; + bool isPulseSearching; + double pi; + int pr; + int spo2; + + SP20RTParamModel({this.battery, this.isCheckProbe, this.isProbeOff, this.isPulseSearching, this.pi, this.pr, this.spo2}); + + SP20RTParamModel.fromJson(Map json) { + battery = json['battery']; + isCheckProbe = json['isCheckProbe']; + isProbeOff = json['isProbeOff']; + isPulseSearching = json['isPulseSearching']; + pi = json['pi']; + pr = json['pr']; + spo2 = json['spo2']; + } + + Map toJson() { + final Map data = new Map(); + data['battery'] = this.battery; + data['isCheckProbe'] = this.isCheckProbe; + data['isProbeOff'] = this.isProbeOff; + data['isPulseSearching'] = this.isPulseSearching; + data['pi'] = this.pi; + data['pr'] = this.pr; + data['spo2'] = this.spo2; + return data; + } +} diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index 7209328e..73499fe9 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -22,6 +22,7 @@ import 'package:diplomaticquarterapp/pages/medical/my_trackers/spirometer.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/bp_tracker_ble.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/ekg_tracker_ble.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/oxymeter_ble.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/weight_scale_ble.dart'; import 'package:diplomaticquarterapp/pages/videocall-webrtc-rnd/webrtc/start_video_call.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; @@ -574,7 +575,8 @@ class _LandingPageState extends State with WidgetsBindingObserver { onLoginClick: () { // login(); // Navigator.push(context, FadePage(page: BpTrackerBLE())); - Navigator.push(context, FadePage(page: EKG_BLE())); + Navigator.push(context, FadePage(page: SP20PulseTracker())); + // Navigator.push(context, FadePage(page: EKG_BLE())); // Navigator.push(context, FadePage(page: Oxymeter_BLE())); }, onMedicalFileClick: () { 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 new file mode 100644 index 00000000..6a00bf74 --- /dev/null +++ b/lib/pages/medical/my_trackers/viatom_devices/sp20_pulse_tracker.dart @@ -0,0 +1,200 @@ +import 'dart:convert'; +import 'package:diplomaticquarterapp/models/ble_devices/viatom_devices/oxy_sp20_rt_param_model.dart'; +import 'package:diplomaticquarterapp/uitl/utils_new.dart'; +import 'package:diplomaticquarterapp/viatom_ble/ble_connect.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class SP20PulseTracker extends StatefulWidget { + @override + State createState() => _SP20PulseTrackerState(); +} + +class _SP20PulseTrackerState extends State { + EventChannel eventChannel = EventChannel('BLE-Platform-Bridge-Event'); + + // final bpDataNotifierMeasuring = ValueNotifier(BpRtDataMeasuringModel()); + final sp20RtParamNotifier = ValueNotifier(SP20RTParamModel()); + final sp20StatusNotifier = ValueNotifier(""); + final bpDeviceDataNotifier = ValueNotifier(""); + String deviceName = "SP20"; + + @override + void dispose() { + // bpDataNotifierMeasuring.dispose(); + sp20RtParamNotifier.dispose(); + sp20StatusNotifier.dispose(); + super.dispose(); + BleChannel.disconnect(); + } + + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + Widget build(BuildContext context) { + return AppScaffold( + appBarTitle: "Pulse Tracker", + showNewAppBar: true, + isShowDecPage: false, + showNewAppBarTitle: true, + backgroundColor: Color(0xffF8F8F8), + body: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: ListView( + children: [ + 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), + ), + ], + ); + }, + ), + ValueListenableBuilder( + valueListenable: sp20StatusNotifier, + builder: (context, value, _) { + if (value == "EventSp20RtParam") { + return ValueListenableBuilder( + valueListenable: sp20RtParamNotifier, + builder: (context, SP20RTParamModel sp20RtModel, _) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (sp20RtModel.isProbeOff) ...[ + Text("Check Probe", style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + ] else ...[ + Column( + children: [ + Text("SPO₂", style: TextStyle(fontSize: 20)), + Text(sp20RtModel.spo2.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("%", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("Pulse", style: TextStyle(fontSize: 20)), + Text(sp20RtModel.pr.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("bpm", style: TextStyle(fontSize: 10)), + ], + ), + Column( + children: [ + Text("PI", style: TextStyle(fontSize: 20)), + Text(sp20RtModel.pi.toString(), style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)), + Text("%", 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), + ), + ), + ); + }, + ), + ], + ), + ), + ValueListenableBuilder( + valueListenable: sp20StatusNotifier, + builder: (context, value, _) { + if (value == null || value.isEmpty) { + return Row( + children: [ + Expanded( + child: DefaultButton( + "Start Scan", + () async { + checkBLEPermissions(); + }, + textColor: Colors.white, + color: Colors.green, + ), + ), + ], + ); + } + return Row( + children: [ + Expanded( + child: DefaultButton( + "Disconnect with $deviceName", + () async { + sp20RtParamNotifier.dispose(); + sp20StatusNotifier.dispose(); + + BleChannel.disconnect(); + }, + textColor: Colors.white, + ), + ), + ], + ); + }, + ), + ], + ), + ), + ); + } + + void checkBLEPermissions() async { + [Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan].request().then((status) async { + // startBLEConnection(); + + eventChannel.receiveBroadcastStream().listen((event) { + print('Received event---: $event'); + print(event['type']); + if (event['type'] == "infoData") { + sp20StatusNotifier.value = "infoData"; + bpDeviceDataNotifier.value = event['deviceName']; + } + + if (event['type'] == "EventSp20RtParam") { + sp20RtParamNotifier.value = SP20RTParamModel.fromJson(json.decode(event['data'])); + sp20StatusNotifier.value = "EventSp20RtParam"; + } + }); + await BleChannel.getScanningResult(["Pulse Oxymeter", "SP-20"]); + }); + } +} diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index 486a760f..9f514518 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -494,6 +494,16 @@ class Utils { ), )); + medical.add(InkWell( + onTap: () => projectViewModel.havePrivilege(24) ? Navigator.push(context, FadePage(page: MyTrackers())) : null, + child: MedicalProfileItem( + title: "Connect", + imagePath: 'tracker.svg', + subTitle: "BLE", + isEnable: projectViewModel.havePrivilege(24), + ), + )); + medical.add(InkWell( onTap: () => projectViewModel.havePrivilege(30) ? Navigator.push(context, FadePage(page: SmartWatchInstructions())) : null, child: MedicalProfileItem(