import 'dart:async'; import 'package:diplomaticquarterapp/pages/medical/my_trackers/ble_models/weight_scale_data.dart'; import 'package:diplomaticquarterapp/theme/colors.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/ble_utils.dart'; import 'package:diplomaticquarterapp/uitl/bluetooth_off.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.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_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; class WeightScaleBLE extends StatefulWidget { @override State createState() => _WeightScaleBLEState(); } class _WeightScaleBLEState extends State { String connectionStatus = "disconnected"; String currentWeight = "0.0"; BluetoothDevice currentConnectedDevice; StreamSubscription bleDevicesStream; StreamSubscription weightValuesStream; WeightScaleData weightScaleData = WeightScaleData(); final bleConnectionStatus = ValueNotifier("Disconnected"); String resultSet1 = ""; String resultSet2 = ""; @override void dispose() { super.dispose(); bleConnectionStatus.dispose(); bleDevicesStream.cancel(); weightValuesStream.cancel(); currentConnectedDevice.disconnect(); } @override Widget build(BuildContext context) { return AppScaffold( appBarTitle: TranslationBase.of(context).weight, showNewAppBar: true, isShowDecPage: false, showNewAppBarTitle: true, backgroundColor: Color(0xffF8F8F8), body: SingleChildScrollView( child: StreamBuilder( stream: FlutterBluePlus.adapterState, initialData: BluetoothAdapterState.unknown, builder: (c, snapshot) { final adapterState = snapshot.data; if (adapterState == BluetoothAdapterState.on) { return Container( margin: EdgeInsets.only(top: 200.0, left: 50.0, right: 50.0), child: Column( children: [ Center( child: DefaultButton( TranslationBase.of(context).start.toUpperCase(), () { checkBLEPermissions(); // parseResultData(); }, color: CustomColors.green, ), ), SizedBox( height: 50.0, ), ValueListenableBuilder( valueListenable: bleConnectionStatus, builder: (context, value, _) { return Text("Connection state: $value"); }, ), SizedBox( height: 50.0, ), Column( children: [ Text("Current Weight: ${weightScaleData.weight}" + " kg"), Text("Current BMI: ${weightScaleData.bmi}"), Text("Current Body Fat: ${weightScaleData.fat}" + "%"), Text("Current Bone Weight: ${weightScaleData.bone}" + " kg"), Text("Current Water: ${weightScaleData.water}" + "%"), Text("Current Muscle: ${weightScaleData.muscle}" + "%"), Text("Current BMR: ${weightScaleData.bmr}" + " calories/day"), ], ), // }) ], ), ); } else { FlutterBluePlus.stopScan(); return SizedBox(height: 300.0, child: BluetoothOffScreen(adapterState: adapterState)); } }), ), ); } void checkBLEPermissions() { [Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan].request().then((status) { startBLEConnection(); }); } void startBLEConnection() { if (FlutterBluePlus.isScanningNow == false) { bleConnectionStatus.value = "Connecting..."; bleDevicesStream = FlutterBluePlus.scanResults.listen( (results) { List blueToothDevices = results; blueToothDevices.forEach((element) async { if (element.device.localName.isNotEmpty) { if (element.device.localName.toLowerCase() == "sdic") { bleDevicesStream.cancel(); element.device.connect(timeout: Duration(seconds: 5), autoConnect: false).then((value) async { bleConnectionStatus.value = "Connected..."; print("Device Connected-------"); currentConnectedDevice = element.device; FlutterBluePlus.stopScan(); // await currentConnectedDevice.clearGattCache(); List services = await element.device.discoverServices(timeout: 5); 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 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(); } } }); 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----"); }); }); }); } }); return true; } }); }); return true; } } }); }, // onError(e) => print(e); ); FlutterBluePlus.startScan(timeout: const Duration(seconds: 5), androidUsesFineLocation: false); } } String adjustHexString(String value) { return value.length == 1 ? "0" + value : value; } void parseResultData() { 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)); setState(() { weightScaleData.weight = (int.parse(hexStringWeight, radix: 16) * 0.1).toStringAsFixed(1); weightScaleData.bmi = (int.parse(hexStringBMI, radix: 16) * 0.1).toStringAsFixed(1); weightScaleData.fat = (int.parse(hexStringFat, radix: 16) * 0.1).toStringAsFixed(1); weightScaleData.muscle = (int.parse(hexStringMuscle, radix: 16) * 0.1).toStringAsFixed(1); weightScaleData.bmr = (int.parse(hexStringBMR, radix: 16)).toString(); weightScaleData.bone = (int.parse(hexStringBone, radix: 16) * 0.1).toStringAsFixed(1); weightScaleData.water = (int.parse(hexStringWater, radix: 16) * 0.1).toStringAsFixed(1); }); } 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); } }