Commit 6d33e413 authored by Nicolas Richard Walter Boeckh's avatar Nicolas Richard Walter Boeckh 💬

Got BT stream going

parent 4bfa45a6
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"shared_preferences","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-02-23 22:57:47.900365","version":"1.15.4-pre.129"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"android":[{"name":"flutter_blue","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_blue-0.6.3+1\\\\","dependencies":[]},{"name":"geolocator","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\geolocator-5.2.1\\\\","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_api_availability-2.0.2\\\\","dependencies":[]},{"name":"location_permissions","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location_permissions-2.0.4+1\\\\","dependencies":[]},{"name":"path_provider","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\path_provider-1.6.0\\\\","dependencies":[]},{"name":"permission_handler","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\permission_handler-4.2.0+hotfix.3\\\\","dependencies":[]},{"name":"shared_preferences","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\shared_preferences-0.4.3\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\src\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.2.0\\\\","dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_blue","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"shared_preferences","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-02-25 15:01:23.953288","version":"1.14.6"}
\ No newline at end of file
......@@ -39,7 +39,7 @@ Thought of firmware implementation for obfuscation / integrity verification. See
Other option for making the service run in background: make the platform side tick once per second and notify the dart framework, may need to use a sticky notification as well.
Notification turned out to be unnecessary, oops.
User should be able to set service/characteristic UUID manually on fail.
___
......
......@@ -5,6 +5,5 @@ object Channels {
@JvmStatic val BATTERY_CHARGE: String = "logair.application/battery_charge_status";
@JvmStatic val WAKE: String = "logair.application/wake";
@JvmStatic val WAKE_NOTIFICATION: String = "logair.application/wake_notification";
@JvmStatic val BLUETOOTH_ADAPTER: String = "logair.application/bluetooth_adapter";
}
......@@ -50,16 +50,6 @@ class MainActivity: FlutterActivity() {
else -> result.notImplemented()
};
}
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, Channels.BLUETOOTH_ADAPTER).setMethodCallHandler { call, result ->
var btAdapter: BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!btAdapter.isEnabled && call.method == "turnBluetoothOn") {
startActivityForResult(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);
result.success(true);
} else
result.notImplemented();
}
// Method Channel Dart to Platform : result is WakeService Starting
}
......
......@@ -3,12 +3,5 @@ import 'package:uuid/uuid.dart';
class BtleUUID {
// TODO Function for service, characteristics parsing.
static final List<int> bluetoothLeCccd = Uuid().parse("00002902-0000-1000-8000-00805f9b34fb");
static final List<int> bluetoothLeCc254xService = Uuid().parse("0000ffe0-0000-1000-8000-00805f9b34fb");
static final List<int> bluetoothLeCc254xCharRw = Uuid().parse("0000ffe1-0000-1000-8000-00805f9b34fb");
static final List<int> bluetoothLeNrfService = Uuid().parse("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
static final List<int> bluetoothLeNrfCharRw2 = Uuid().parse("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
static final List<int> bluetoothLeNrfCharRw3 = Uuid().parse("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
static final List<int> bluetoothLeRn4870Service = Uuid().parse("49535343-fe7D-4ae5-8fa9-9fafd205e455");
static final List<int> bluetoothLeRn4870CharRw = Uuid().parse("49535343-1e4d-4bd9-ba61-23c647249616");
}
\ No newline at end of file
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:kotlin_flavor/scope_functions.dart';
......@@ -10,15 +11,20 @@ import 'package:logair_application/services/wake_service.dart';
class BTLEHandler {
static final BTLEHandler _singleton = new BTLEHandler._internal();
static bool started = false;
static bool serviceRegistered = false;
static bool characteristicRegistered = false;
BluetoothCharacteristic _characteristic;
static Duration duration = new Duration(seconds: 1);
static final String bluetoothLeCc254xServiceUUID = "0000ffe0-0000-1000-8000-00805f9b34fb";
static final String bluetoothLeCc254xReadUUID = "0000ffe1-0000-1000-8000-00805f9b34fb";
Timer t;
FlutterBlue fblueInstance = FlutterBlue.instance;
static const MethodChannel _btAdapterChannel = const MethodChannel(Channels.BLUETOOTH_ADAPTER);
factory BTLEHandler() => _singleton;
BTLEHandler._internal() {
......@@ -33,46 +39,85 @@ class BTLEHandler {
}
}
Stream<List<BluetoothService>> getDeviceServices() async* {
while (true) {
await Future.delayed(Duration(milliseconds: 750));
yield (this._device != null) ? await this._device.services.first : null;
Future<bool> setupCharacteristics() async {
List<BluetoothService> services = [];
List<BluetoothCharacteristic> characteristics = [];
bool success = false;
if (this._device != null) {
services = await this._device.services.first;
services = services.where((s) => s.uuid.toString() == bluetoothLeCc254xServiceUUID).toList();
if (services.length > 0) {
characteristics = services[0].characteristics;
characteristics = characteristics.where((c) => c.uuid.toString() == bluetoothLeCc254xReadUUID).toList();
if (characteristics.length > 0) {
if (!characteristics[0].isNotifying)
await characteristics[0].setNotifyValue(true);
_characteristic = characteristics[0];
success = true;
}
}
}
return success;
}
Future<bool> setupListener() async {
if (_characteristic != null) {
_characteristic.value.transform(
new StreamTransformer.fromHandlers(
handleData: (List<int> list, EventSink<List<int>> sink) {
if (list.isNotEmpty)
sink.add(list);
else
sink.add([]);
}
)
).listen((event) {
print("Got something");
partialData += String.fromCharCodes(event);
});
}
}
String partialData = "";
Stream<String> getData() async* {
while(true) {
String temp = partialData;
partialData = "";
yield temp;
await Future.delayed(Duration(milliseconds: 500));
}
}
/// Makes the phone connect to the [BluetoothDevice] and initiate [BluetoothService] discovery.
Future<void> connect() => this._device?.let(
(it) {
it.connect();
it.discoverServices();
asyncConnection();
return;
}
);
asyncConnection() async {
await this._device.connect();
if (Platform.isAndroid)
await this._device.requestMtu(517);
await this._device.discoverServices();
await setupCharacteristics();
await setupListener();
}
Future<dynamic> disconnect() => this._device?.let((it) {
_device = null;
return it.disconnect();
});
// TODO turn BTLE on method (platform side)
Future<bool> turnBTLEOn() async {
bool _status;
try {
_status = await _btAdapterChannel.invokeMethod('turnBluetoothOn');
} on PlatformException catch (e) {
print('BLUETOOTH_ON : $e');
}
return _status;
}
String get address => this._device?.let((it) => it.id.toString());
BluetoothDevice _device;
Stream<List<BluetoothService>> getServices() => this._device?.services;
setDevice(BluetoothDevice device) => device?.let((it) => this._device = it);
bool switchState() {
......
......@@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:logair_application/enums/bluetooth_le_serial_uuid.dart';
import 'package:logair_application/handlers/bluetooth_le_handler.dart';
import 'package:logair_application/ui/carousel_card.dart';
......@@ -29,7 +30,6 @@ class DataWidget extends StatelessWidget {
Text("Data", style: TextStyle(fontFamily: "Consolas", fontSize: 22)),
RaisedButton(
onPressed: () => {
// await BTLEHandler().dialog(context)
BTLEHandler().switchState()
},
child: Text('Toggle BTLE Service'),
......@@ -46,14 +46,17 @@ class DataWidget extends StatelessWidget {
return Text("Not connected");
},
),
StreamBuilder<List<BluetoothService>>(
stream: BTLEHandler().getServices(),
initialData: [],
StreamBuilder<String>(
stream: BTLEHandler().getData(),
initialData: "",
builder: (context, snapshot) {
List<BluetoothService> services = snapshot.data;
return Column(
children: services.map((s) => Text(s.uuid.toMac())).toList(),
);
String data = snapshot.data;
print("Data = " + data);
if (data != null && data.length > 0) {
print ((new DateTime.now().millisecondsSinceEpoch.toString()) + " : " + data);
return Text(data);
} else
return Text("No data streaming");
},
)
]
......
......@@ -72,7 +72,7 @@ class _BluetoothSelectionDialogState extends State<BluetoothSelectionDialog> {
trailing: IconButton(
padding: EdgeInsets.all(0),
icon: Icon(Icons.refresh),
onPressed: () => BTLEHandler().fblueInstance.startScan(timeout: Duration(seconds: 5)),
onPressed: () => BTLEHandler().fblueInstance.startScan(timeout: Duration(seconds: 10)),
),
),
Divider(),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment