Commit ab52b8d

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-03-23 00:12:37
prototype ble measurement input logic
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent b293c0b
Changed files (3)
app/lib/components/ble_input/ble_input_bloc.dart
@@ -0,0 +1,85 @@
+import 'dart:async';
+
+import 'package:blood_pressure_app/components/ble_input/ble_input_events.dart';
+import 'package:blood_pressure_app/components/ble_input/ble_input_state.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
+
+// TODO: docs
+class BleInputBloc extends Bloc<BleInputEvent, BleInputState> {
+  final _ble = FlutterReactiveBle();
+  final Set<DiscoveredDevice> _availableDevices = {};
+
+  final _requiredServices = [
+    Uuid.parse('1810'),
+  ];
+  // TODO: use repo
+
+  BleInputBloc(): super(BleInputClosed()) {
+    on<BleInputOpened>((event, emit) async {
+      try {
+        emit(BleInputLoadInProgress());
+        await _ble.initialize();
+        final deviceStream = _ble.scanForDevices(withServices: _requiredServices,);
+        await emit.forEach(deviceStream, onData: (DiscoveredDevice device) {
+          _availableDevices.add(device);
+          return BleInputLoadSuccess(_availableDevices.toList());
+        },);
+      } catch (e) { // TODO: ask for permission
+        // TODO: check its really this type of exception
+        emit(BleInputLoadFailure());
+      }
+    });
+    on<BleInputDeviceSelected>((event, emit) async {
+      emit(BleConnectInProgress());
+      try {
+        final connectionUpdateStream = _ble.connectToAdvertisingDevice(
+          id: event.device.id,
+          prescanDuration: const Duration(seconds: 5),
+          withServices: _requiredServices,
+          connectionTimeout: const Duration(minutes: 2),
+        );
+        await emit.forEach(connectionUpdateStream,
+          onData: (ConnectionStateUpdate update) {
+            if (update.failure != null) {
+              return BleConnectFailed();
+            } else if (update.connectionState == DeviceConnectionState.connected) {
+              // characteristics IDs (https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Assigned_Numbers/out/en/Assigned_Numbers.pdf?v=1711151578821):
+              // - Blood Pressure Measurement: 0x2A35 (https://bitbucket.org/bluetooth-SIG/public/src/main/gss/org.bluetooth.characteristic.blood_pressure_measurement.yaml)
+              // - Blood Pressure Records: 0x2A36 (https://bitbucket.org/bluetooth-SIG/public/src/main/gss/org.bluetooth.characteristic.blood_pressure_record.yaml)
+              //
+              // A record represents a stored measurement, so in theory we should
+              // search for a measurement.
+              // Definition: https://www.bluetooth.com/specifications/bls-1-1-1/
+              final characteristic = QualifiedCharacteristic(
+                characteristicId: Uuid.parse('2A35'),
+                serviceId: Uuid.parse('1810'),
+                deviceId: event.device.id,
+              );
+              _ble.subscribeToCharacteristic(characteristic).listen((event) {
+                // TODO: decode byte array and create measurement
+              });
+
+              // TODO: move reading code
+
+
+              return BleConnectSuccess();
+            } else if (update.connectionState == DeviceConnectionState.connecting) {
+              return BleConnectInProgress();
+            }
+            return BleConnectFailed();
+          },
+        );
+      } on TimeoutException {
+        emit(BleConnectFailed());
+      }
+
+    });
+    // TODO: use _ble.statusStream
+
+    // TODO: check if information about measurement start can be obtained
+    // through bluetooth
+
+  }
+
+}
\ No newline at end of file
app/lib/components/ble_input/ble_input_events.dart
@@ -0,0 +1,10 @@
+// TODO document
+import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
+
+sealed class BleInputEvent {}
+class BleInputOpened extends BleInputEvent {}
+class BleInputDeviceSelected extends BleInputEvent {
+  BleInputDeviceSelected(this.device);
+
+  final DiscoveredDevice device;
+}
app/lib/components/ble_input/ble_input_state.dart
@@ -0,0 +1,33 @@
+// TODO: doc
+import 'package:blood_pressure_app/model/blood_pressure/record.dart';
+import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
+
+sealed class BleInputState {}
+
+/// The ble input field is inactive.
+class BleInputClosed extends BleInputState {}
+
+/// Scanning for devices.
+class BleInputLoadInProgress extends BleInputState {}
+/// No device available.
+class BleInputLoadFailure extends BleInputState {}
+/// Found devices.
+class BleInputLoadSuccess extends BleInputState {
+  BleInputLoadSuccess(this.availableDevices);
+
+  final List<DiscoveredDevice> availableDevices;
+}
+
+/// Connecting to device.
+class BleConnectInProgress extends BleInputState {}
+/// Couldn't connect to device or closed connection.
+class BleConnectFailed extends BleInputState {}
+/// Is connected with device.
+class BleConnectSuccess extends BleInputState {}
+
+/// A measurement was taken through the bluetooth device.
+class BleMeasureSuccess extends BleInputState {
+  BleMeasureSuccess(this.record);
+
+  final BloodPressureRecord record;
+}