import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; import 'package:fluttertoast/fluttertoast.dart'; import '../objects/cloud_service_api.dart'; class BluetoothObject { late int _rssi = -1; late BluetoothDevice _device; String _address = ""; String _name = ""; String id = ""; String _primaryThumbprint = ""; final String _secondaryThumbprint = ""; late BluetoothConnection? _connection; late Stream _connectionStream; late StreamSubscription _connectionStreamSubscription; late BuildContext _context; final CloudServiceAPI _cloudServiceAPI = CloudServiceAPI(); //late Uint8List _messageBufferBits; late String _messageBufferChars = ""; bool _isDisconnecting = false; String get primaryThumbprint { return _primaryThumbprint; } String get secondaryThumbprint { return _secondaryThumbprint; } int get rssi { return _rssi; } String get name { return _name; } String get address { return _address; } BluetoothDevice get device { return _device; } BluetoothConnection? get connection { return _connection; } bool get isConnected { return (_connection == null ? false : true); } BluetoothObject(BluetoothDiscoveryResult result) { _rssi = result.rssi; _device = result.device; _address = _device.address; _name = _device.name ?? "device.name.UNKNOWN"; _connection = null; } Future bondDevice(BuildContext context) async { try { bool bonded = false; if (_device.isBonded) { debugPrint('Unbonding from $_address...'); await FlutterBluetoothSerial.instance.removeDeviceBondWithAddress(_address); debugPrint('Unbonding from $_address has succed'); } else { debugPrint('Bonding with $_address...'); bonded = (await FlutterBluetoothSerial.instance.bondDeviceAtAddress(_address))!; debugPrint('Bonding with $_address has ${bonded ? 'succed' : 'failed'}.'); } } catch (ex) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text( 'Error occured while bonding'), content: Text(ex.toString()), actions: [ TextButton( child: const Text("Close"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); } } Future disconnectDevice() async { _isDisconnecting = true; if (_connection != null) { await _connection!.finish(); _connection = null; } _isDisconnecting = false; } Future connectDevice() async { if (isConnected) { await _connection!.finish(); _connection = null; } try { _connection = await BluetoothConnection.toAddress(_address); debugPrint("Connected to the device"); _connectionStream = _connection!.input!; _connectionStreamSubscription = _connectionStream.listen(_connectionOnListen); _connectionStreamSubscription.onDone(_connectionOnDone); } catch (ex) { debugPrint("$ex"); } } void _connectionOnDone() { if (_isDisconnecting) { debugPrint("Disconnecting locally!"); } else { debugPrint("Disconnected remotely!"); } } Future _connectionOnListen(Uint8List data) async { final String dataDecoded = const AsciiDecoder().convert(data); debugPrint("received decoded: $dataDecoded"); _messageBufferChars += dataDecoded; if (!(data[data.length - 1] == 10)) { return; } if (!_messageBufferChars.contains(" ")) { _messageBufferChars = ""; return; } List input = _messageBufferChars.split(" "); if (input[0] == "fingerprint") { _primaryThumbprint = input[1].trim(); debugPrint("_primaryThumbprint: ${const AsciiEncoder().convert(_primaryThumbprint)}"); debugPrint("id: ${const AsciiEncoder().convert(id)}"); debugPrint("_secondaryThumbprint: $_secondaryThumbprint"); await _registerDevice(); } _messageBufferChars = ""; } Future sendData(BuildContext context, String output) async { if (_connection == null) return; bool nameAvailable = await _cloudServiceAPI.checkNameAvailability(output); if (!nameAvailable) return; id = output; _connection!.output.add(Uint8List.fromList(const AsciiEncoder().convert("$output \r\n"))); await _connection!.output.allSent; _context = context; debugPrint("sent: $output"); } Future _registerDevice() async { bool registered = false; registered = await _cloudServiceAPI.createDevice(id, _primaryThumbprint, ""); _confirmRegistration(registered); } void _confirmRegistration(bool registered) { showDialog( context: _context, builder: (BuildContext context) => AlertDialog( title: const Text('Device Info'), content: Text(registered ? "das Gerät wurde erfolgreich registriert" : "das Gerät konnte nicht registriert werden"), backgroundColor: Colors.white, actions: [ TextButton(onPressed: () => Navigator.pop(context, 'Cancel'), child: const Text('OK'), ), ], ), ); } }