diff --git a/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_sugar_connect_screen.dart b/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_sugar_connect_screen.dart index 77cf829a..6051b754 100644 --- a/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_sugar_connect_screen.dart +++ b/lib/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_blood_sugar_connect_screen.dart @@ -36,7 +36,7 @@ class _AndesFitBloodSugarConnectScreenState extends State createState() => _AndesFitSpirometerConnectScreenState(); +} + +class _AndesFitSpirometerConnectScreenState extends State { + MyTrackersViewModel myTrackersVm; + + @override + void initState() { + myTrackersVm = context.read(); + myTrackersVm.connectAndesfitSpirometerDevice(widget.deviceModel); + super.initState(); + } + + @override + void dispose() { + myTrackersVm.valuePEF = null; + myTrackersVm.valueFEV = null; + myTrackersVm.isAndesfitDeviceConnected = null; + myTrackersVm.disConnectAndesfitDevice(widget.deviceModel); + super.dispose(); + } + + Widget buildSpirometerUI(MyTrackersViewModel myTrackersViewModel) { + return Expanded( + child: ListView( + children: [ + if ((myTrackersViewModel.valuePEF == null && myTrackersViewModel.valueFEV == null) && myTrackersViewModel.isAndesfitDeviceConnected) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + mHeight(24.0), + Column( + children: [ + Text("Please blow gently", style: TextStyle(fontSize: 20)), + ], + ), + mHeight(24.0), + ], + ), + ] else if ((myTrackersViewModel.valuePEF != null && myTrackersViewModel.valueFEV != null)) ...[ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + mHeight(24.0), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text("PEF", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.valuePEF.toString(), style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)), + Text("", style: TextStyle(fontSize: 15)), + ], + ), + Column( + children: [ + Text("FEV", style: TextStyle(fontSize: 20)), + Text(myTrackersViewModel.valueFEV.toString(), style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)), + Text("", style: TextStyle(fontSize: 15)), + ], + ), + ], + ), + ], + ), + ] 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: [ + buildSpirometerUI(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 bef99c5b..4f017bcb 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 @@ -2,6 +2,7 @@ import 'dart:developer'; 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_blood_sugar_connect_screen.dart'; +import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_spirometer_connect_screen.dart'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_device_type_screens/andesfit_device_types/andesfit_temperature_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'; @@ -95,6 +96,14 @@ class _BleDevicesScreenState extends State { return; } break; + + case TrackerTypeEnum.Spirometer: + if (myTrackersVm.isDeviceFromAndesFit(device.name)) { + myTrackersVm.currentTempInCelsius = null; + Navigator.pushReplacement(context, FadePage(page: AndesFitSpirometerConnectScreen(deviceModel: device.andesfitBluetoothDevice))); + return; + } + break; case TrackerTypeEnum.AllInOneTracker: if (myTrackersVm.isDeviceFromAndesFit(device.name)) { return; 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 276717eb..ddf77656 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 @@ -83,6 +83,18 @@ class SelectTrackerType extends StatelessWidget { isEnable: true, ), )); + medical.add(InkWell( + onTap: () { + context.read().updateSelectedTrackerType(TrackerTypeEnum.Spirometer); + Navigator.of(context).push(FadePage(page: BleDevicesScreen())); + }, + child: MedicalProfileItem( + title: "Spirometer", + imagePath: 'tracker.svg', + subTitle: "Tracker", + isEnable: true, + ), + )); medical.add(InkWell( onTap: () { context.read().updateSelectedTrackerType(TrackerTypeEnum.AllInOneTracker); 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 0ee969b6..f593dd34 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 @@ -20,7 +20,7 @@ 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, WeightScale, Temperature, AllInOneTracker } +enum TrackerTypeEnum { OxymeterTracker, BloodPressureTracker, BloodSugarTracker, ECGTracker, WeightScale, Temperature, Spirometer, AllInOneTracker } //NativeEventNames @@ -63,6 +63,9 @@ class MyTrackersViewModel extends ChangeNotifier { "Temperature": [ {"model": ""}, ], + "Spirometer": [ + {"model": "BLE-MSA"}, + ], "AllInOneTracker": [ {"model": ""}, ], @@ -87,13 +90,16 @@ class MyTrackersViewModel extends ChangeNotifier { "Temperature": [ {"model": "TEMP"}, ], + "Spirometer": [ + {"model": "BLE-MSA"}, + ], "AllInOneTracker": [ {"model": ""}, ], }; List ecgEnabledDevices = ["BP2 0567", "DuoEK", "ER1", "PM101897"]; - List andesFitDevices = ["BPM", "PM101897", "SDIC", "TEMP", "Samico GL"]; + List andesFitDevices = ["BPM", "PM101897", "SDIC", "TEMP", "Samico GL", "BLE-MSA"]; StreamSubscription bleDevicesStream; @@ -847,4 +853,138 @@ class MyTrackersViewModel extends ChangeNotifier { return results; } + + BluetoothCharacteristic spirometerReadCharacteristicFf0a; + BluetoothCharacteristic spirometerWriteCharacteristicFf0b; + + String valuePEF; + + String valueFEV; + + Timer timerForSpirometer; + + bool isHistoryCommandWritten = false; + + Future connectAndesfitSpirometerDevice(BluetoothDevice device) async { + device.connectionState.listen((BluetoothConnectionState state) async { + if (state == BluetoothConnectionState.disconnected) { + isAndesfitDeviceConnected = false; + notifyListeners(); + } + if (state == BluetoothConnectionState.connected) { + isAndesfitDeviceConnected = true; + notifyListeners(); + bleDevicesStream.cancel(); + List services = await device.discoverServices(timeout: 5); + services.forEach( + (service) { + if (service.serviceUuid.toString().toLowerCase() == BLEUtils.BLE_TO_MSA100_SERVICE) { + print(service.serviceUuid); + service.characteristics.forEach( + (characteristic) async { + if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.BLE_TO_MSA100_READ_CHARACTERISTIC) { + spirometerReadCharacteristicFf0a = characteristic; + print(spirometerReadCharacteristicFf0a.characteristicUuid); + print(spirometerReadCharacteristicFf0a.properties.toString()); + spirometerReadCharacteristicFf0a.onValueReceived.listen((event) async { + print("onValueReceived ff0a Stream"); + print(event); + + //response received + if (event[0] == 221) { + convertIntListToHexForSpirometer(event); + } + + if (event[0] == 170) { + timerForSpirometer.cancel(); + + // Write get history command to ff0b + if (!isHistoryCommandWritten) { + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + spirometerWriteCharacteristicFf0b.write([0x55, 0x01], withoutResponse: false).then((value) { + print("----ff0b get history command data written----"); + isHistoryCommandWritten = true; + }); + }); + + // Write get 1st history command to ff0b + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + spirometerWriteCharacteristicFf0b.write([0x55, 0x02, 0x01, 0x00], withoutResponse: false).then((value) async { + print("----ff0b get 1st history command data written----"); + isHistoryCommandWritten = true; + + // Write delete history command to ff0b + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + spirometerWriteCharacteristicFf0b.write([0x55, 0x03], withoutResponse: false).then((value) async { + print("----ff0b delete history command data written----"); + isHistoryCommandWritten = true; + await Future.delayed(Duration(milliseconds: 500)).then((value) async { + isHistoryCommandWritten = false; + // Write ACK command to ff0b every 500 ms + startACKCommandToMSA100(); + }); + }); + }); + }); + }); + } + } + }); + + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + print("Delayed ff0a done"); + if (!spirometerReadCharacteristicFf0a.isNotifying) await spirometerReadCharacteristicFf0a.setNotifyValue(true).catchError((err) {}); + }); + } + + if (characteristic.characteristicUuid.toString().toLowerCase() == BLEUtils.BLE_TO_MSA100_WRITE_CHARACTERISTIC) { + spirometerWriteCharacteristicFf0b = characteristic; + print(spirometerWriteCharacteristicFf0b.characteristicUuid); + print(spirometerWriteCharacteristicFf0b.properties.toString()); + + // Write ACK command to ff0b every 500 ms + startACKCommandToMSA100(); + } + }, + ); + } + }, + ); + } + }); + await device.connect(timeout: Duration(seconds: 35)); + } + + void convertIntListToHexForSpirometer(List byteArray) { + String b = (byteArray.map((x) { + return x.toRadixString(16); + })).join(";"); + List hexString = b.split(";"); + print("HexString: $hexString"); + String returnStringPEF = hexString[8] + hexString[7]; + String returnStringFEV = hexString[6] + hexString[5]; + print("Temp Hex String PEF: $returnStringPEF"); + print("Temp Hex String FEV: $returnStringFEV"); + + final numberPEF = int.parse(returnStringPEF, radix: 16); + final numberFEV = int.parse(returnStringFEV, radix: 16); + + print("Temp Number FEV: ${numberFEV * 0.01}"); + print("Temp Number PEF: $numberPEF"); + + valueFEV = (numberFEV * 0.01).toStringAsFixed(2); + valuePEF = numberPEF.toString(); + notifyListeners(); + } + + void startACKCommandToMSA100() async { + // Write ACK command to ff0b every 500 ms + await Future.delayed(Duration(milliseconds: 1000)).then((value) async { + timerForSpirometer = Timer.periodic(Duration(milliseconds: 500), (Timer t) { + spirometerWriteCharacteristicFf0b.write([0x55, 0x06], withoutResponse: false).then((value) { + print("----ff0b ACK command data written----"); + }); + }); + }); + } }