Untitled
unknown
plain_text
7 months ago
8.4 kB
2
Indexable
Never
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:polar/polar.dart'; import 'package:uuid/uuid.dart'; import 'package:self_science_station/provider/sensor_provider.dart'; import 'package:self_science_station/model/sensor_model.dart'; import 'package:self_science_station/sensor/sensorInstance.dart'; import 'package:flutter/services.dart'; class PolarAPI extends SensorInstance { //Function _onSensorChange; final identifier; final polarModel; final polar = Polar(); final logs = ['Service started']; PolarExerciseEntry? exerciseEntry; //SensorProvider sp; // A constructor that calls the super constructor with the model instance and type parameters // -- this shouldn't be necessary when all child-instances are created by the super-class SensorProvider //PolarAPI(SensorInstanceModel sInstance, SensorTypeModel sType) : super(SensorInstanceModel sInstance, SensorTypeModel sType); PolarAPI(super.sp, super.sInstance, super.sType, this.identifier, this.polarModel) { initState(); } void initState() async { await polar.requestPermissions(); // Disconnect device upon instantiation in case it was connected await disconnectSensor(); polar.batteryLevel.listen((e) => log('Battery: ${e.level}')); polar.deviceConnecting.listen((_) { print("CONNECTING POLAR EVENT"); onConnecting(); }); polar.deviceConnected.listen((_) { print("CONNECTED POLAR EVENT"); onConnected(); }); polar.deviceDisconnected.listen((_) { print("DISCONNECTED POLAR EVENT"); if (!isConnecting) { onDisconnected(); } }); } @override Future<bool> connectSensor() async { await disconnectSensor(); onConnecting(); log('Connecting to device: $identifier'); try { await polar.connectToDevice(identifier); } catch (e) { log('Failed to connect device $identifier: ${e.toString()}'); onConnectFail(); return false; } return true; } @override void connectSensorWithTimeout(Duration timeout) async { print("Connecting sensor $identifier with timeout $timeout"); await disconnectSensor(); print("Disconnected before connecting again"); onConnecting(); await polar.connectToDevice(identifier); print("Called connectToDevice"); Future.delayed(timeout, () { if (!isConnected) { print("Connection timeout reached. Bailing."); onConnectFail(); } }); } @override Future<bool> disconnectSensor() async { log('Disconnecting from device: $identifier'); try { await polar.disconnectFromDevice(identifier); } catch (e) { log('Failed to disconnect device $identifier: ${e.toString()}'); return false; } onDisconnected(); return true; } @override Future<bool> startRecording(String? recordingIdentifier) async { if (recordingIdentifier == null) { log('No recording identifier provided. Aborting recording.'); return false; } log('Starting recording'); await polar.startRecording( identifier, exerciseId: recordingIdentifier, interval: RecordingInterval.interval_1s, sampleType: SampleType.rr, ); onRecordingStarted(); log('Started recording'); return true; } @override Future<bool> stopRecording() async { log('Stopping recording'); await polar.stopRecording(identifier); onRecordingStopped(); log('Stopped recording'); return true; } @override Future<bool> isRecording() async { log('Getting recording status'); try { final status = await polar.requestRecordingStatus(identifier); log('Recording status: $status'); print(status); return status.ongoing; } catch (e) { if (e is PlatformException) { print( "Error when trying to get recording status. isRecording set to false. Error: ${e.message}"); return false; } } return false; } @override Future<List<int>> fetchData(String? recordingIdentifier) async { print('Fetching recording with id $recordingIdentifier'); final entries = await polar.listExercises(identifier); for (var entry in entries) { if (entry.entryId == recordingIdentifier) { final data = await polar.fetchExercise(identifier, entry); print('Fetched recording: $data'); // We no longer need this data to be taking space on the device await polar.removeExercise(identifier, entry); return data.samples; } } return []; } @override Future<void> emptyRecordings() async { print('Emptying recordings'); final entries = await polar.listExercises(identifier); for (var entry in entries) { await polar.removeExercise(identifier, entry); } } @override Future<void> resetSensor() async { print('Resetting sensor $identifier'); await polar.doFactoryReset(identifier, true /* preserve pairing info */); } @override StreamSubscription<PolarDeviceInfo> scanForSensor(Function onDeviceFound) { return polar.searchForDevice().listen((e) { log('Device found from scan: ${e.deviceId}, isConnectable: ${e.isConnectable}'); if (e.isConnectable) { onDeviceFound(e.deviceId); } }); } // For Online Streaming. Polar has an offline API but it doesn't seem available through this flutter wrapper void streamWhenReady() async { await polar.sdkFeatureReady.firstWhere( (e) => e.identifier == identifier && e.feature == PolarSdkFeature .onlineStreaming, // Online, but it continues offline if disconnected by itself ); final availabletypes = await polar.getAvailableOnlineStreamDataTypes(identifier); debugPrint('available types: $availabletypes'); if (availabletypes.contains(PolarDataType.hr)) { polar .startHrStreaming(identifier) .listen((e) => log('Heart rate: ${e.samples.map((e) => e.hr)}')); } if (availabletypes.contains(PolarDataType.ecg)) { polar .startEcgStreaming(identifier) .listen((e) => log('ECG data received')); } if (availabletypes.contains(PolarDataType.acc)) { polar .startAccStreaming(identifier) .listen((e) => log('ACC data received')); } } void log(String log) { // ignore: avoid_print print(log); } Future<void> _handleRecordingAction(RecordingAction action) async { switch (action) { case RecordingAction.start: log('Starting recording'); await polar.startRecording( identifier, exerciseId: const Uuid().v4(), interval: RecordingInterval.interval_1s, sampleType: SampleType.rr, ); onRecordingStarted(); log('Started recording'); break; case RecordingAction.stop: log('Stopping recording'); await polar.stopRecording(identifier); onRecordingStopped(); log('Stopped recording'); break; case RecordingAction.status: log('Getting recording status'); final status = await polar.requestRecordingStatus(identifier); log('Recording status: $status'); // TODO update the sensor state depending on the status break; case RecordingAction.list: log('Listing recordings'); final entries = await polar.listExercises(identifier); log('Recordings: $entries'); // H10 can only store one recording at a time exerciseEntry = entries.first; break; case RecordingAction.fetch: log('Fetching recording'); if (exerciseEntry == null) { log('Exercises not yet listed'); await _handleRecordingAction(RecordingAction.list); } final entry = await polar.fetchExercise(identifier, exerciseEntry!); log('Fetched recording: $entry'); break; case RecordingAction.remove: log('Removing recording'); if (exerciseEntry == null) { log('No exercise to remove. Try calling list first.'); return; } await polar.removeExercise(identifier, exerciseEntry!); log('Removed recording'); break; } } } enum RecordingAction { start, stop, status, list, fetch, remove, }
Leave a Comment