Untitled
unknown
plain_text
2 years ago
9.1 kB
6
Indexable
import 'dart:developer';
import 'dart:async';
import 'dart:io';
import 'package:meta/meta.dart';
import 'package:flutter/material.dart';
import 'package:self_science_station/model/metric_model.dart';
import 'package:self_science_station/model/sensor_model.dart';
import 'package:self_science_station/utils/utils.dart';
import 'package:self_science_station/sensor/polar_api.dart';
import 'package:self_science_station/provider/sensor_provider.dart';
import 'package:provider/provider.dart';
import 'package:polar/polar.dart';
// SensorInstance is the class for all sensor instances and parent-class for all mobile SDKs/APIs
class SensorInstance {
//final sp = Provider.of<SensorProvider>(context, listen: false);
// // The list storing all the child instances
// static List<SensorInstance> sensorInstances = [];
// // Lists of the Sensor Model details -- no need for this i believe
// final List<SensorInstanceModel> _sensorInstances = [];
// final List<SensorTypeModel> _sensorTypes = [];
bool isConnected = false;
bool isConnecting = false;
// InstanceModel and TypeModel are final because their values should not be change once the instance is created
final SensorProvider sp;
final SensorInstanceModel _sInstance;
final SensorTypeModel _sType;
// Allows for executing callbacks for a given sensor state
final Map<SensorState, Function> _callbacks = {};
// SensorState and Availability will describe the accessibility of the sensor
SensorState sState = SensorState.init;
SensorAvailability sAvailability = SensorAvailability.init;
// Constructor (without subclass-instance creation)
SensorInstance(this.sp, this._sInstance, this._sType) {
print("New Sensor created in SensorProvider without any subclass assigned");
print(
"New sensor instance instance created: name ${_sType.vendor} ${_sType.name}: ${_sInstance.deviceID}");
_onSensorChange();
}
// Factory constructor creating a subclass instance for the particular sensor
factory SensorInstance.create(SensorProvider sProvider,
SensorInstanceModel sInstance, SensorTypeModel sType) {
// try {
// // Add sensor type to the list of sensor types
// if (_sensorTypes.any((s) => s.id == sType.id)) {
// // Find the sensor in the list and remove it -- why is this step necessary? to sort list?
// _sensorTypes.removeWhere((s) => s.id == sType.id);
// }
// _sensorTypes.add(sType);
// // Add sensor instance to the list of sensor instances
// if (_sensorInstances.any((s) => s.deviceID == sInstance.deviceID)) {
// // Find the sensor in the list and remove it -- why is this step necessary? to sort list?
// _sensorInstances.removeWhere((s) => s.deviceID == sInstance.deviceID);
// }
// _sensorInstances.add(sInstance);
// } catch (e) {
// log('Error parsing sensor: ${e.toString()}');
// }
// Initialize sensor instance with state and device information
SensorState sState = SensorState.disconnected;
SensorAvailability sAvailability = SensorAvailability.available;
String sVendor = sType.vendor;
String sDeviceName = sType.name;
String sDeviceID = sInstance.deviceID;
// Create and return a child-instance for the particular sensor based on Vendor
SensorInstance sDevice;
switch (sVendor) {
case "fitbit":
// TODO:
log("Fitbit Sensor");
log("Fitbit is webbased");
sDevice = SensorInstance(sProvider, sInstance, sType);
break;
case "withings":
// TODO:
log("Withings Sensor");
log("Withings is webbased");
sDevice = SensorInstance(sProvider, sInstance, sType);
break;
case "polar":
log("Polar Sensor");
sDevice = PolarAPI(
sProvider, sInstance, sType, sInstance.deviceID, sType.name);
break;
default:
// TODO:
log("This sensor has not been initialized correctly.");
sDevice = SensorInstance(sProvider, sInstance, sType);
break;
}
// // Add the new sensor instance to the static list of instances
//SensorProvider.addSensorInstanceToList(sDevice);
return sDevice;
}
// // A method to add a child instance to the list
// static void addSensorInstanceToList(SensorInstance sensor) {
// sensorInstances.add(sensor);
// }
void _onSensorChange() {
sp.updateEverything();
}
Future<bool> startRecording(String? recordingIdentifier) {
print(
"Recording from sensor ${_sInstance.id} with ID $recordingIdentifier");
onRecordingStarted();
return Future.value(true);
}
Future<bool> stopRecording() {
print("Stopping recording from sensor ${_sInstance.id}");
onRecordingStopped();
return Future.value(true);
}
Future<void> emptyRecordings() async {
print('Emptying recordings for sensor ${_sInstance.id}');
return Future.value();
}
Future<bool> isRecording() {
print("Checking if recording from sensor ${_sInstance.id}");
return Future.value(false);
}
Future<bool> connectSensor() async {
print("Connecting sensor ${_sInstance.id}");
onConnected();
return Future.value(true);
}
// Tries to connect, waits for specified timeout, bails if hasn't connected yet
void connectSensorWithTimeout(Duration timeout) async {
print("Connecting sensor ${_sInstance.id} with timeout $timeout");
onConnecting();
Future.delayed(timeout, () {
if (!isConnected) {
onConnectFail();
}
});
}
Future<bool> disconnectSensor() {
print("Disconnecting sensor ${_sInstance.id}");
onDisconnected();
return Future.value(true);
}
Future<void> resetSensor() {
print("Resetting sensor ${_sInstance.id}");
return Future.value();
}
StreamSubscription<dynamic> scanForSensor(Function onDeviceFound) {
print("Scanning for sensor ${_sInstance.id}");
onDeviceFound();
return const Stream.empty().listen((event) {});
}
@protected
void onRecordingStarted() {
print("Started recording from sensor ${_sInstance.id}");
final prevState = sState;
if (sState == SensorState.connected_idle) {
sState = SensorState.connected_acquiring;
} else if (sState == SensorState.disconnected) {
sState = SensorState.disconnected_acquiring;
}
handleStateChange(prevState, sState);
}
@protected
void onRecordingStopped() {
print("Stopped recording from sensor ${_sInstance.id}");
final prevState = sState;
if (sState == SensorState.connected_acquiring) {
sState = SensorState.connected_idle;
} else if (sState == SensorState.disconnected_acquiring) {
sState = SensorState.disconnected;
}
handleStateChange(prevState, sState);
}
@protected
void onConnecting() {
print("Connecting sensor ${_sInstance.id}");
isConnecting = true;
isConnected = false;
final prevState = sState;
sState = SensorState.connecting;
handleStateChange(prevState, sState);
}
@protected
void onConnected() {
print("Connected sensor ${_sInstance.id}");
isConnected = true;
isConnecting = false;
final prevState = sState;
sState = SensorState.connected_idle;
handleStateChange(prevState, sState);
}
@protected
void onDisconnected() {
print("Disconnected sensor ${_sInstance.id}");
isConnected = false;
isConnecting = false;
final prevState = sState;
sState = SensorState.disconnected;
handleStateChange(prevState, sState);
}
@protected
void onConnectFail() {
print("Failed to connect to sensor ${_sInstance.id}");
onDisconnected();
}
@protected
void onSensorError() {
print("Error on sensor ${_sInstance.id}!");
isConnected = false;
isConnecting = false;
final prevState = sState;
sState = SensorState.error;
handleStateChange(prevState, sState);
}
void handleStateChange(SensorState prevState, SensorState newState) {
// Call the callback for the new state
if (_callbacks.containsKey(newState)) {
_callbacks[newState]!(prevState, newState);
}
sp.updateEverything();
}
// Trigger a runtime callback when the sensor enters any state in the list provided
void registerCallback(List<SensorState> states, Function callback) {
for (final state in states) {
_callbacks[state] = callback;
}
}
Future<List<int>> fetchData(String? recordingIdentifier) {
print(
'Fetching from sensor ${_sInstance.id} for recording $recordingIdentifier');
return Future.value([]);
}
SensorInstanceModel getSensorInstance() {
return _sInstance;
}
SensorTypeModel getTypeModel() {
return _sType;
}
void checkSensorAvailability() {
//TODO:
print("Checking Sensor Availability");
}
}
// Structs
enum SensorState {
connecting,
connected_idle,
connected_acquiring,
disconnected_acquiring, // offline acquisition
disconnected,
error,
init
}
enum SensorAvailability {
available, // ready for use
unavailable, // in use
faulty, // cannot be used
init
}
Editor is loading...
Leave a Comment