esense_input.dart (6615B)
1 import 'dart:async'; 2 import 'dart:io'; 3 4 import 'package:esense_flutter/esense.dart'; 5 import 'package:flutter/material.dart'; 6 import 'package:permission_handler/permission_handler.dart'; 7 import 'package:sense_the_rhythm/models/arrow_direction.dart'; 8 import 'package:sense_the_rhythm/models/input_direction.dart'; 9 10 class ESenseInput { 11 // create singleton that is available on all widgets so it does not have to be 12 // carried down in the widget tree 13 static final instance = ESenseInput._(); 14 15 ESenseManager eSenseManager = ESenseManager('unknown'); 16 // valuenotifier allows widgets to rerender when the value changes 17 ValueNotifier<String> deviceStatus = ValueNotifier('Disconnected'); 18 StreamSubscription? _subscription; 19 20 String eSenseDeviceName = ''; 21 bool connected = false; 22 23 final int _sampleRate = 20; 24 25 final InputDirection _inputDirection = InputDirection(); 26 int _x = 0; 27 int _y = 0; 28 int _z = 0; 29 30 ESenseInput._() { 31 _listenToESense(); 32 } 33 34 /// ask and check if permissions are enabled and granted 35 Future<bool> _askForPermissions() async { 36 // is desktop 37 if (!Platform.isAndroid && !Platform.isIOS) return false; 38 // is bluetooth even enabled? 39 if (!await Permission.bluetooth.serviceStatus.isEnabled) { 40 deviceStatus.value = "Bluetooth is disabled!"; 41 return false; 42 } 43 if (!(await Permission.bluetoothScan.request().isGranted && 44 await Permission.bluetoothConnect.request().isGranted && 45 await Permission.bluetooth.request().isGranted)) { 46 print( 47 'WARNING - no permission to use Bluetooth granted. Cannot access eSense device.'); 48 deviceStatus.value = "Insufficiant Permissions"; 49 return false; 50 } 51 // for some strange reason, Android requires permission to location for Bluetooth to work.....? 52 if (Platform.isAndroid) { 53 if (!(await Permission.locationWhenInUse.request().isGranted)) { 54 print( 55 'WARNING - no permission to access location granted. Cannot access eSense device.'); 56 deviceStatus.value = "Insufficiant Permissions"; 57 return false; 58 } 59 } 60 return true; 61 } 62 63 /// listen to connectionEvents and set deviceStatus 64 void _listenToESense() { 65 // if you want to get the connection events when connecting, 66 // set up the listener BEFORE connecting... 67 eSenseManager.connectionEvents.listen((event) { 68 print('CONNECTION event: $event'); 69 70 // when we're connected to the eSense device, we can start listening to events from it 71 // if (event.type == ConnectionType.connected) _listenToESenseEvents(); 72 73 connected = false; 74 switch (event.type) { 75 case ConnectionType.connected: 76 deviceStatus.value = 'Connected'; 77 connected = true; 78 _startListenToSensorEvents(); 79 break; 80 case ConnectionType.unknown: 81 deviceStatus.value = 'Unknown'; 82 break; 83 case ConnectionType.disconnected: 84 deviceStatus.value = 'Disconnected'; 85 _pauseListenToSensorEvents(); 86 break; 87 case ConnectionType.device_found: 88 deviceStatus.value = 'Device_found'; 89 break; 90 case ConnectionType.device_not_found: 91 deviceStatus.value = 'Device_not_found'; 92 break; 93 } 94 }); 95 } 96 97 /// get eSenseEvent stream only containung button events 98 Stream<ButtonEventChanged> buttonEvents() { 99 return eSenseManager.eSenseEvents 100 .where((event) => event.runtimeType == ButtonEventChanged) 101 .cast(); 102 } 103 104 /// sets sampling rate and listens to sensorEvents 105 void _startListenToSensorEvents() async { 106 // // any changes to the sampling frequency must be done BEFORE listening to sensor events 107 print('setting sampling frequency...'); 108 bool successs = await eSenseManager.setSamplingRate(_sampleRate); 109 if (successs) { 110 print('setSamplingRate success'); 111 } else { 112 print('setSamplingRate fail'); 113 } 114 115 // subscribe to sensor event from the eSense device 116 _subscription = eSenseManager.sensorEvents.listen((event) { 117 // print('SENSOR event: $event'); 118 if (event.gyro != null) { 119 _parseGyroData(event.gyro!); 120 } 121 }); 122 } 123 124 /// cancels the sensorEvents listening 125 void _pauseListenToSensorEvents() async { 126 _subscription?.cancel(); 127 } 128 129 /// add up all new gyro [data] in the form of deg/s multiplied by scaling factor 130 /// to get real angles 131 void _parseGyroData(List<int> data) { 132 // Float value in deg/s = Gyro value / Gyro scale factor 133 // The default configuration is +- 500deg/s for the gyroscope. 134 _x = (_x + (15 * data[0] ~/ (500 * _sampleRate))) % 360; 135 _y = (_y + (15 * data[1] ~/ (500 * _sampleRate))) % 360; 136 _z = (_z + (15 * data[2] ~/ (500 * _sampleRate))) % 360; 137 print('$_x, $_y, $_z'); 138 // print('${(z.toDouble() / 500.0 * (1.0 / sampleRate.toDouble())) * 7.5}'); 139 // print('${z.toDouble() / 500.0 * (1.0 / 10.0)}'); 140 } 141 142 /// nulls all angles and reset inputDirection 143 void resetAngles() { 144 _inputDirection.reset(); 145 _x = 0; 146 _y = 0; 147 _z = 0; 148 } 149 150 /// get InputDirection by checking if angels are in defined ranges and 151 /// calibrating based on the [expect]ed direction from ArrowDirection 152 InputDirection getInputDirection(ArrowDirection expect) { 153 // check if angle is in range 154 _inputDirection.up = _z > 180 && _z < 340; 155 _inputDirection.down = _z > 20 && _z < 180; 156 _inputDirection.left = _y > 0 && _y < 180; 157 _inputDirection.right = _y > 180 && _y < 360; 158 159 // calibrate based on expected directoin from ArrowDirection 160 if (expect == ArrowDirection.up && _inputDirection.up || 161 expect == ArrowDirection.down && _inputDirection.down) { 162 _y = 0; 163 } 164 if (expect == ArrowDirection.left && _inputDirection.left || 165 expect == ArrowDirection.right && _inputDirection.right) { 166 _z = 0; 167 } 168 169 return _inputDirection; 170 } 171 172 /// connect to ESense with [deviceName] by first asking for permissions 173 Future<void> connectToESense(String deviceName) async { 174 if (!connected) { 175 bool permissionSuccessfull = await _askForPermissions(); 176 if (!permissionSuccessfull) return; 177 print('Trying to connect to eSense device namend \'$deviceName\''); 178 eSenseDeviceName = deviceName; 179 eSenseManager.deviceName = deviceName; 180 bool connecting = await eSenseManager.connect(); 181 print( 182 'Trying to connect to eSense device namend \'${eSenseManager.deviceName}\''); 183 184 deviceStatus.value = connecting ? 'connecting...' : 'connection failed'; 185 print(deviceStatus.value); 186 } 187 } 188 }