Merge pull request #11 from oob-provisioning-for-iot/justin

Merging to have a usable version
This commit is contained in:
Konjiki No Yami 2023-01-08 02:52:29 +01:00 committed by GitHub
commit 449c0c73c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 221 additions and 288 deletions

View File

@ -56,7 +56,7 @@ jobs:
name: Android APK name: Android APK
path: | path: |
build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/app-release.apk
build/app/outputs/flutter-apk/app-release.sha1 build/app/outputs/flutter-apk/app-release.apk.sha1
- name: Upload APK as release - name: Upload APK as release
uses: "marvinpinto/action-automatic-releases@latest" uses: "marvinpinto/action-automatic-releases@latest"
@ -67,4 +67,4 @@ jobs:
title: "Android APK" title: "Android APK"
files: | files: |
build/app/outputs/flutter-apk/app-release.apk build/app/outputs/flutter-apk/app-release.apk
build/app/outputs/flutter-apk/app-release.sha1 build/app/outputs/flutter-apk/app-release.apk.sha1

View File

@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.6.10' ext.kotlin_version = '1.7.20'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()

View File

@ -17,7 +17,9 @@ class BluetoothDeviceEntry extends ListTile {
onTap: onTap, onTap: onTap,
onLongPress: onLongPress, onLongPress: onLongPress,
enabled: enabled, enabled: enabled,
leading: Icon(bluetoothObject.isConnected ? Icons.bluetooth_connected : Icons.bluetooth), leading: bluetoothObject.isConnected
? const Icon(Icons.bluetooth_connected, color: Colors.blue)
: const Icon(Icons.bluetooth),
title: Text(bluetoothObject.name), title: Text(bluetoothObject.name),
subtitle: Text(bluetoothObject.address.toString()), subtitle: Text(bluetoothObject.address.toString()),
trailing: Row( trailing: Row(

View File

@ -16,15 +16,16 @@ class BluetoothObject {
String id = ""; String id = "";
String _primaryThumbprint = ""; String _primaryThumbprint = "";
String _secondaryThumbprint = ""; final String _secondaryThumbprint = "";
late BluetoothConnection? _connection; late BluetoothConnection? _connection;
late Stream<Uint8List> _connectionStream; late Stream<Uint8List> _connectionStream;
late StreamSubscription<Uint8List> _connectionStreamSubscription; late StreamSubscription<Uint8List> _connectionStreamSubscription;
late BuildContext _context;
CloudServiceAPI _cloudServiceAPI = CloudServiceAPI(); final CloudServiceAPI _cloudServiceAPI = CloudServiceAPI();
late Uint8List _messageBufferBits; //late Uint8List _messageBufferBits;
late String _messageBufferChars = ""; late String _messageBufferChars = "";
bool _isDisconnecting = false; bool _isDisconnecting = false;
@ -69,7 +70,7 @@ class BluetoothObject {
_connection = null; _connection = null;
} }
Future<void> bondDevice() async { Future<void> bondDevice(BuildContext context) async {
try { try {
bool bonded = false; bool bonded = false;
if (_device.isBonded) { if (_device.isBonded) {
@ -81,22 +82,7 @@ class BluetoothObject {
bonded = (await FlutterBluetoothSerial.instance.bondDeviceAtAddress(_address))!; bonded = (await FlutterBluetoothSerial.instance.bondDeviceAtAddress(_address))!;
debugPrint('Bonding with $_address has ${bonded ? 'succed' : 'failed'}.'); debugPrint('Bonding with $_address has ${bonded ? 'succed' : 'failed'}.');
} }
/*setState(() {
_discoveryResults[_discoveryResults.indexOf(
result)] =
BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: address,
type: device.type,
bondState: bonded
? BluetoothBondState.bonded
: BluetoothBondState.none,
),
rssi: result.rssi);
});*/
} catch (ex) { } catch (ex) {
/*
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
@ -114,7 +100,7 @@ class BluetoothObject {
], ],
); );
}, },
);*/ );
} }
} }
@ -133,12 +119,15 @@ class BluetoothObject {
_connection = null; _connection = null;
} }
try {
_connection = await BluetoothConnection.toAddress(_address); _connection = await BluetoothConnection.toAddress(_address);
debugPrint("Connected to the device"); debugPrint("Connected to the device");
_connectionStream = _connection!.input!; _connectionStream = _connection!.input!;
_connectionStreamSubscription = _connectionStream.listen(_connectionOnListen); _connectionStreamSubscription = _connectionStream.listen(_connectionOnListen);
_connectionStreamSubscription.onDone(_connectionOnDone); _connectionStreamSubscription.onDone(_connectionOnDone);
} catch (ex) {
debugPrint("$ex");
}
} }
void _connectionOnDone() { void _connectionOnDone() {
@ -151,113 +140,58 @@ class BluetoothObject {
Future<void> _connectionOnListen(Uint8List data) async { Future<void> _connectionOnListen(Uint8List data) async {
final String dataDecoded = const AsciiDecoder().convert(data); final String dataDecoded = const AsciiDecoder().convert(data);
debugPrint("received: $data");
debugPrint("received decoded: $dataDecoded"); debugPrint("received decoded: $dataDecoded");
_messageBufferChars += dataDecoded; _messageBufferChars += dataDecoded;
if (data[data.length - 1] == 10) { if (!(data[data.length - 1] == 10)) {
debugPrint("received buffer: $_messageBufferChars"); return;
int spaceIndex = _messageBufferChars.indexOf(" ");
String firstParameter = "";
String secondParameter = "";
try {
firstParameter = _messageBufferChars.substring(0, spaceIndex);
secondParameter = _messageBufferChars.substring(spaceIndex + 1, _messageBufferChars.length - 2);
} catch (ex) {
debugPrint(ex.toString());
} }
debugPrint("we still go on!"); if (!_messageBufferChars.contains(" ")) {
_messageBufferChars = ""; _messageBufferChars = "";
debugPrint("first: $firstParameter"); return;
debugPrint("second: $secondParameter"); }
if (firstParameter == "fingerprint") {
debugPrint("received final buffer: $secondParameter"); List<String> input = _messageBufferChars.split(" ");
_primaryThumbprint = secondParameter; if (input[0] == "fingerprint") {
debugPrint("{ _secondaryThumbprint: $_secondaryThumbprint }"); _primaryThumbprint = input[1].trim();
debugPrint("{ id: $id, _primaryThumbprint: $_primaryThumbprint, _secondaryThumbprint: $_secondaryThumbprint }"); debugPrint("_primaryThumbprint: ${const AsciiEncoder().convert(_primaryThumbprint)}");
debugPrint("id: ${const AsciiEncoder().convert(id)}");
debugPrint("_secondaryThumbprint: $_secondaryThumbprint");
await _registerDevice(); await _registerDevice();
} }
_messageBufferChars = "";
} }
/* Future<void> sendData(BuildContext context, String output) async {
// Allocate buffer for parsed data
int backspacesCounter = 0;
for (var byte in data) {
if (byte == 8 || byte == 127) {
backspacesCounter++;
}
}
Uint8List buffer = Uint8List(data.length - backspacesCounter);
int bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
String dataString = String.fromCharCodes(buffer);
int index = buffer.indexOf(13);
if (~index != 0) {
_messageBuffer = dataString.substring(index);
} else {
_messageBuffer = (backspacesCounter > 0
? _messageBuffer.substring(0, _messageBuffer.length - backspacesCounter)
: _messageBuffer + dataString);
}
*/
}
Future<void> sendData(String output) async {
if (_connection == null) return; if (_connection == null) return;
bool nameAvailable = await _cloudServiceAPI.checkNameAvailability(output); bool nameAvailable = await _cloudServiceAPI.checkNameAvailability(output);
// String output = "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ";// !§%&()=?#!?";
// String output = "myDevice123";// !§%&()=?#!?";
if (!nameAvailable) return; if (!nameAvailable) return;
id = output; id = output;
_connection!.output.add(Uint8List.fromList(const AsciiEncoder().convert("$output \r\n"))); _connection!.output.add(Uint8List.fromList(const AsciiEncoder().convert("$output \r\n")));
await _connection!.output.allSent; await _connection!.output.allSent;
_context = context;
debugPrint("sent: $output"); debugPrint("sent: $output");
} }
Future<void> _registerDevice() async { Future<void> _registerDevice() async {
bool registered = false; bool registered = false;
registered = await _cloudServiceAPI.createDevice(id, _primaryThumbprint, ""); registered = await _cloudServiceAPI.createDevice(id, _primaryThumbprint, "");
_confirmRegistration(registered);
String statusText =
registered ? "das Gerät wurde erfolgreich registriert" : "das Gerät konnte nicht registriert werden";
Fluttertoast.showToast(
msg: statusText,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 2,
backgroundColor: Colors.grey[200],
textColor: Colors.black,
fontSize: 16.0);
}
} }
/*setState(() { void _confirmRegistration(bool registered) {
_discoveryResults[_discoveryResults.indexOf( showDialog<String>(
result)] = context: _context,
BluetoothDiscoveryResult( builder: (BuildContext context) => AlertDialog(
device: BluetoothDevice( title: const Text('Device Info'),
name: device.name ?? '', content: Text(registered ? "das Gerät wurde erfolgreich registriert" : "das Gerät konnte nicht registriert werden"),
address: address, backgroundColor: Colors.white,
type: device.type, actions: <Widget>[
isConnected: connected, TextButton(onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('OK'),
), ),
rssi: result.rssi); ],
}); ),
*/ );
}
}

View File

@ -1,6 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
@ -24,6 +23,7 @@ class CloudServiceAPI {
static String _password = ""; static String _password = "";
static late Map<String, String> _headers; static late Map<String, String> _headers;
static bool _initState = false; static bool _initState = false;
static List<DeviceModel> devices = List<DeviceModel>.empty(growable: true);
CloudServiceAPI() { CloudServiceAPI() {
if (!_initState) { if (!_initState) {
@ -44,6 +44,7 @@ class CloudServiceAPI {
'accept': 'application/json', 'accept': 'application/json',
}; };
log("init Config $_headers"); log("init Config $_headers");
await updateDeviceList();
} }
Future<void> reloadConfig() async { Future<void> reloadConfig() async {
@ -64,7 +65,6 @@ class CloudServiceAPI {
List<DeviceModel> remoteObjectsList = remoteObjectsMap.toList(); List<DeviceModel> remoteObjectsList = remoteObjectsMap.toList();
return remoteObjectsList; return remoteObjectsList;
} }
Future<DeviceInfoModel> getDeviceInfo(String deviceID) async { Future<DeviceInfoModel> getDeviceInfo(String deviceID) async {
Uri url = Uri.https(_address, '/api/devices/$deviceID'); Uri url = Uri.https(_address, '/api/devices/$deviceID');
Response response = await get(url, headers: _headers); Response response = await get(url, headers: _headers);
@ -72,12 +72,31 @@ class CloudServiceAPI {
DeviceInfoModel deviceInfoModel = DeviceInfoModel.fromJson(jsonObject); DeviceInfoModel deviceInfoModel = DeviceInfoModel.fromJson(jsonObject);
return deviceInfoModel; return deviceInfoModel;
} }
Future<List<DeviceInfoModel>> getDevicesInfo() async {
updateDeviceList();
List<DeviceInfoModel> deviceInfoModelList = List<DeviceInfoModel>.empty(growable: true);
for(DeviceModel tmp in devices){
deviceInfoModelList.add(await getDeviceInfo(tmp.id));
}
return deviceInfoModelList;
}
Future updateDeviceList() async {
devices = await getDevices();
}
Future<Map<String, dynamic>> getInformation() async { Future<Map<String, dynamic>> getInformation() async {
Uri url = Uri.https(_address, '/api/app'); Uri url = Uri.https(_address, '/api/app');
Response response = await get(url, headers: _headers); Response response = await get(url, headers: _headers);
return json.decode(response.body) as Map<String, dynamic>; return json.decode(response.body) as Map<String, dynamic>;
} }
Future<bool> deleteDevice(String clientId) async {
Uri url = Uri.https(_address, '/api/devices/$clientId');
Response response = await delete(url, headers: _headers);
if(response.statusCode == 204){
return true;
}
return false;
}
Future<bool> createDevice(String id, String primaryThumbprint, String secondaryThumbprint) async { Future<bool> createDevice(String id, String primaryThumbprint, String secondaryThumbprint) async {
Uri url = Uri.https(_address, '/api/devices'); Uri url = Uri.https(_address, '/api/devices');
@ -114,7 +133,7 @@ class CloudServiceAPI {
String statusText = status ? "die eingegebene ID ist verfügbar" : "die eingegebene ID ist nicht verfügbar"; String statusText = status ? "die eingegebene ID ist verfügbar" : "die eingegebene ID ist nicht verfügbar";
Fluttertoast.showToast( Fluttertoast.showToast(
msg: statusText, msg: statusText,
toastLength: Toast.LENGTH_SHORT, toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM, gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 2, timeInSecForIosWeb: 2,
backgroundColor: Colors.grey[200], backgroundColor: Colors.grey[200],
@ -148,4 +167,7 @@ class CloudServiceAPI {
_password = input; _password = input;
reloadConfig(); reloadConfig();
} }
List<dynamic> getLoadedDevices(){
return devices;
}
} }

View File

@ -14,8 +14,8 @@ class BluetoothDeviceSettings extends StatefulWidget {
class BluetoothDeviceSettingsState extends State<BluetoothDeviceSettings> { class BluetoothDeviceSettingsState extends State<BluetoothDeviceSettings> {
late BluetoothObject _bluetoothObject; late BluetoothObject _bluetoothObject;
bool _isRegistering = false;
String _messageBuffer = ""; String _textInput = ""; // 0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ
@override @override
void initState() { void initState() {
@ -23,9 +23,6 @@ class BluetoothDeviceSettingsState extends State<BluetoothDeviceSettings> {
_bluetoothObject = widget.bluetoothObject; _bluetoothObject = widget.bluetoothObject;
} }
String _textInput = "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String _textOuput = "";
ButtonStyle buttonStyle = ElevatedButton.styleFrom( ButtonStyle buttonStyle = ElevatedButton.styleFrom(
foregroundColor: Colors.black, foregroundColor: Colors.black,
backgroundColor: const Color(0xFFFDE100), // Text Color (Foreground color) backgroundColor: const Color(0xFFFDE100), // Text Color (Foreground color)
@ -53,13 +50,13 @@ class BluetoothDeviceSettingsState extends State<BluetoothDeviceSettings> {
), ),
ListTile( ListTile(
title: const Text("Device Connection State"), title: const Text("Device Connection State"),
subtitle: subtitle: Text(
Text(_bluetoothObject.isConnected ? "ConnectionState.DISCONECTED" : "ConnectionState.CONNECED"), _bluetoothObject.isConnected ? "ConnectionState.DISCONNECTED" : "ConnectionState.CONNECTED"),
), ),
], ],
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 0.0),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
// const EdgeInsets defaultContentPadding = EdgeInsets.symmetric(horizontal: 16.0); // const EdgeInsets defaultContentPadding = EdgeInsets.symmetric(horizontal: 16.0);
Expanded( Expanded(
@ -85,30 +82,42 @@ class BluetoothDeviceSettingsState extends State<BluetoothDeviceSettings> {
)) ))
])), ])),
const Divider(), const Divider(),
ElevatedButton( SingleSection(title: "Cloud Registration", children: [
onPressed: () async { Padding(
_bluetoothObject.sendData(_textInput); padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 0.0),
}, child: TextFormField(
style: buttonStyle, obscureText: false,
child: const Text("Send Data"), decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: 'Enter the device name',
labelText: "Device Name",
filled: false,
suffixIcon: _isRegistering
? FittedBox(
child: Container(
height: 10,
width: 10,
margin: const EdgeInsets.all(8.0),
child: const CircularProgressIndicator(
strokeWidth: 2.0,
), ),
ElevatedButton( ),
) // : const I
: IconButton(
icon: const Icon(Icons.login),
onPressed: () async { onPressed: () async {
FocusScopeNode currentFocus = FocusScope.of(context);
currentFocus.unfocus();
setState(() { setState(() {
_textOuput = ""; _isRegistering = true;
});
await _bluetoothObject.sendData(context, _textInput);
setState(() {
_isRegistering = false;
}); });
}, },
style: buttonStyle, )),
child: const Text("Clear Output"), keyboardType: TextInputType.text,
),
Text(_textOuput),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: TextField(
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter the device name',
),
onChanged: (String newValue) { onChanged: (String newValue) {
_textInput = newValue; _textInput = newValue;
}, },
@ -116,6 +125,7 @@ class BluetoothDeviceSettingsState extends State<BluetoothDeviceSettings> {
), ),
]), ]),
]), ]),
]),
)); ));
} }
} }

View File

@ -50,21 +50,36 @@ class _BluetoothScreen extends State<BluetoothScreen> {
_activeObject = null; _activeObject = null;
_streamSubscription = null; _streamSubscription = null;
if (widget.start) { if (widget.start) {
_startDiscovery(); _initAsync();
} }
} }
Future<void> _initAsync() async {
await _enablePermissions();
await _enableBluetooth();
await _startDiscovery();
}
@override @override
void dispose() { void dispose() {
// Avoid memory leak (`setState` after dispose) and cancel discovery // Avoid memory leak (`setState` after dispose) and cancel discovery
_streamSubscription?.cancel(); debugPrint("called dispose");
_activeObject?.disconnectDevice(); _disposeAsync();
super.dispose();
}
Future<void> _disposeAsync() async {
await _streamSubscription?.cancel();
await _activeObject?.disconnectDevice();
List<BluetoothDevice> bondedDevices = await FlutterBluetoothSerial.instance.getBondedDevices();
debugPrint(bondedDevices.toString());
super.dispose(); super.dispose();
debugPrint("called dispose"); debugPrint("called dispose");
} }
Future<void> _enablePermissions() async { Future<void> _enablePermissions() async {
debugPrint("Test");
PermissionStatus bluetoothScan = await Permission.bluetoothScan.request(); PermissionStatus bluetoothScan = await Permission.bluetoothScan.request();
PermissionStatus bluetoothConnect = await Permission.bluetoothConnect.request(); PermissionStatus bluetoothConnect = await Permission.bluetoothConnect.request();
bool granted = bluetoothScan.isGranted && bluetoothConnect.isGranted; bool granted = bluetoothScan.isGranted && bluetoothConnect.isGranted;
@ -74,7 +89,14 @@ class _BluetoothScreen extends State<BluetoothScreen> {
} }
Future<void> _enableBluetooth() async { Future<void> _enableBluetooth() async {
if (!_enabledPermissions) { if (_enabledBluetooth) {
return;
}
BluetoothState state = await FlutterBluetoothSerial.instance.state;
if (state == BluetoothState.STATE_ON) {
setState(() {
_enabledBluetooth = true;
});
return; return;
} }
bool? enabled = await FlutterBluetoothSerial.instance.requestEnable(); bool? enabled = await FlutterBluetoothSerial.instance.requestEnable();
@ -85,7 +107,8 @@ class _BluetoothScreen extends State<BluetoothScreen> {
} }
Future<void> _startDiscovery() async { Future<void> _startDiscovery() async {
if (!_enabledPermissions) { debugPrint("enabled: $_enabledPermissions");
if (!_enabledPermissions && !_enabledBluetooth) {
return; return;
} }
setState(() => _isDiscovering = true); setState(() => _isDiscovering = true);
@ -137,9 +160,6 @@ class _BluetoothScreen extends State<BluetoothScreen> {
_activeObject!.isConnected ? await bluetoothObject.disconnectDevice() : await bluetoothObject.connectDevice(); _activeObject!.isConnected ? await bluetoothObject.disconnectDevice() : await bluetoothObject.connectDevice();
} }
//stty -F /dev/service 19200 parenb -parodd -cstopb cs8
//cat /dev/service | xargs -n 1 /home/script/automaticcloud.sh
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -173,6 +193,7 @@ class _BluetoothScreen extends State<BluetoothScreen> {
CustomListTile( CustomListTile(
title: _enabledBluetooth ? "Bluetooth Enabled" : "Please Enable Bluetooth (click me)", title: _enabledBluetooth ? "Bluetooth Enabled" : "Please Enable Bluetooth (click me)",
icon: _enabledBluetooth ? Icons.check_circle_outline_rounded : Icons.info_outline_rounded, icon: _enabledBluetooth ? Icons.check_circle_outline_rounded : Icons.info_outline_rounded,
iconColor: _enabledPermissions ? Colors.green : Colors.red,
onTap: () async { onTap: () async {
await _enableBluetooth(); await _enableBluetooth();
}, },
@ -180,6 +201,7 @@ class _BluetoothScreen extends State<BluetoothScreen> {
CustomListTile( CustomListTile(
title: _enabledPermissions ? "Permissions Granted" : "Please Grant Permissions (click me)", title: _enabledPermissions ? "Permissions Granted" : "Please Grant Permissions (click me)",
icon: _enabledPermissions ? Icons.check_circle_outline_rounded : Icons.info_outline_rounded, icon: _enabledPermissions ? Icons.check_circle_outline_rounded : Icons.info_outline_rounded,
iconColor: _enabledPermissions ? Colors.green : Colors.red,
onTap: () async { onTap: () async {
await _enablePermissions(); await _enablePermissions();
}, },
@ -193,38 +215,6 @@ class _BluetoothScreen extends State<BluetoothScreen> {
), ),
], ],
), ),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
// const EdgeInsets defaultContentPadding = EdgeInsets.symmetric(horizontal: 16.0);
Expanded(
child: ElevatedButton(
onPressed: () async {
/*await Permission.bluetoothConnect.request();
await Permission.bluetoothScan.request();
if (await Permission.bluetoothScan.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
debugPrint("Location Permission is granted");
} else {
debugPrint("Location Permission is denied.");
}*/
},
style: buttonStyle,
child: const Text("Get BT Permissions"),
),
),
const SizedBox(width: 16.0),
Expanded(
child: ElevatedButton(
onPressed: () async {
_restartDiscovery();
},
style: buttonStyle,
child: const Text("Restart Scan"),
),
)
]),
),
const Divider(), const Divider(),
SingleSection( SingleSection(
title: "Bluetooth Devices", title: "Bluetooth Devices",
@ -252,9 +242,11 @@ class _BluetoothScreen extends State<BluetoothScreen> {
bluetoothObject: bluetoothObject, bluetoothObject: bluetoothObject,
onTap: () async { onTap: () async {
await _toggleConnection(bluetoothObject); await _toggleConnection(bluetoothObject);
await _restartDiscovery();
}, },
onLongPress: () async { onLongPress: () async {
await bluetoothObject.bondDevice(); await bluetoothObject.bondDevice(context);
await _restartDiscovery();
}, },
); );
}, },

View File

@ -1,61 +0,0 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../objects/cloud_service_api.dart';
import '../widgets/sidebar.dart';
Future<Map<String, dynamic>> readJson() async {
final String data = await rootBundle.loadString('config/credentials.json');
final Map<String, dynamic> dataMap = json.decode(data);
log("loaded json input $dataMap");
return dataMap;
}
class CloudService extends StatefulWidget {
const CloudService({Key? key}) : super(key: key);
@override
State<CloudService> createState() => _CloudService();
}
class _CloudService extends State<CloudService> {
late final Map<String, dynamic> credentials;
CloudServiceAPI cloudServiceAPI = CloudServiceAPI();
static SharedPreferences? preferencesInstance;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Cloud Service"),
),
body: Center(
child: TextButton(
onPressed: () async {
// List<BluetoothObjectRemote> respond1 = await cloudServiceAPI.getDevices();
// debugPrint('Devices: ${respond1[0].toString()}');
// debugPrint('Devices: ${respond1[0].toString()}');
//dynamic respond2 = await cloudServiceAPI.getInformation();
//debugPrint('Information: ${respond2.toString()}');
// dynamic respond3 = await cloudServiceAPI.createDevice('1', 'asdas', 'sdwe1');
// debugPrint('CreateDevice: ${respond3.toString()}');*/
//dynamic respond4 = await cloudServiceAPI.getDeviceInfo("PFC200V3-430EB3");
//debugPrint('Information: ${respond4.toString()}');
//bool respond5 = await cloudServiceAPI.createDevice("PFC200V3-430EB2", "60987668030DF277AD7706D7C1FA683F37230D202A80EE5135B05EF928E3BF88", "");
//debugPrint('Information: ${respond5.toString()}');
},
child: const Text("Example"),
),
),
drawer: const Sidebar(),
);
}
}

View File

@ -63,6 +63,21 @@ class _RegisteredDevicesScreen extends State<RegisteredDevicesScreen> {
super.initState(); super.initState();
} }
Future searchDevice(String clientId) async {
List<DeviceInfoModel> searchResult = List<DeviceInfoModel>.empty(growable: true);
for(DeviceInfoModel tmp in _registeredInfoDevices!){
if(clientId == ""){
// _fetchRegisteredDevices();
// break;
// missing implementation
}
if(tmp.id.contains(clientId)){
searchResult.add(tmp);
}
}
_registeredInfoDevices = searchResult;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -99,17 +114,17 @@ class _RegisteredDevicesScreen extends State<RegisteredDevicesScreen> {
obscureText: false, obscureText: false,
decoration: InputDecoration( decoration: InputDecoration(
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
hintText: 'Enter the server password', hintText: 'Search for Devices',
labelText: "Search", labelText: "Search",
suffixIcon: IconButton( suffixIcon: IconButton(
icon: const Icon(Icons.search), icon: const Icon(Icons.search),
onPressed: () { onPressed: () {
setState(() { setState(() {
// TODO Suchfunktion searchDevice(_searchText);
}); });
}, },
), ),
filled: true, filled: false,
), ),
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
onChanged: (String newValue) { onChanged: (String newValue) {
@ -130,8 +145,39 @@ class _RegisteredDevicesScreen extends State<RegisteredDevicesScreen> {
DeviceInfoModel entry = _registeredInfoDevices![index]; DeviceInfoModel entry = _registeredInfoDevices![index];
//DeviceInfoModel entryInfo = await _cloudServiceAPI.getDeviceInfo(entry.id); //DeviceInfoModel entryInfo = await _cloudServiceAPI.getDeviceInfo(entry.id);
return CustomListTile( return CustomListTile(
title: "${entry.id} \nentrypoint: ${entry.endpoint} \nstatus: ${entry.status} \nconnection: ${entry.connectionState} \nlast activity: ${entry.lastActivityTime}", title: entry.id,
icon: Icons.devices, icon: Icons.devices,
onTap: () => showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Device Info'),
content: Text("ID: ${entry.id} "
"\n\nentrypoint: ${entry.endpoint} "
"\n\nstatus: ${entry.status} "
"\n\nconnection: ${entry.connectionState} "
"\n\nlast activity: ${entry.lastActivityTime}"
"\n\nprimaryThumbprint: ${entry.primaryThumbprint}"),
backgroundColor: Colors.white,
actions: <Widget>[
TextButton(onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
_cloudServiceAPI.deleteDevice(entry.id);
Navigator.pop(context, 'delete device');
},
child: const Text('Delete Device'),
),
],
),
)
/*
Navigator.push(context,
MaterialPageRoute(
builder: (context) => DeviceOptions(deviceInfoModel: entry)));
*/
); );
}, },
), ),

View File

@ -85,6 +85,7 @@ class _SettingsState extends State<Settings> {
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
hintText: 'Enter the server password', hintText: 'Enter the server password',
labelText: "Password", labelText: "Password",
filled: false,
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon(_passwordVisible ? Icons.visibility : Icons.visibility_off), icon: Icon(_passwordVisible ? Icons.visibility : Icons.visibility_off),
onPressed: () { onPressed: () {
@ -93,7 +94,6 @@ class _SettingsState extends State<Settings> {
}); });
}, },
), ),
filled: true,
), ),
initialValue: Settings.password, initialValue: Settings.password,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
@ -105,10 +105,6 @@ class _SettingsState extends State<Settings> {
), ),
], ],
), ),
const SingleSection(
title: "Theme Settings",
children: <Widget>[],
)
]), ]),
) )
]), ]),

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
class CustomListTile extends StatelessWidget { class CustomListTile extends StatelessWidget {
final String title; final String title;
final IconData icon; final IconData icon;
final Color? iconColor;
final VoidCallback? onTap; final VoidCallback? onTap;
//final Widget? trailing; //final Widget? trailing;
@ -11,6 +12,7 @@ class CustomListTile extends StatelessWidget {
Key? key, Key? key,
required this.title, required this.title,
required this.icon, required this.icon,
this.iconColor,
this.onTap, this.onTap,
//this.trailing, //this.trailing,
}) : super(key: key); }) : super(key: key);
@ -19,7 +21,7 @@ class CustomListTile extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListTile( return ListTile(
title: Text(title), title: Text(title),
leading: Icon(icon), leading: Icon(icon, color: iconColor),
onTap: onTap, onTap: onTap,
//trailing: trailing, //trailing: trailing,
); );

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../screens/bluetooth_screen.dart'; import '../screens/bluetooth_screen.dart';
import '../screens/cloud_service_ui.dart';
import '../screens/main_screen.dart'; import '../screens/main_screen.dart';
import '../screens/registered_devices_screen.dart'; import '../screens/registered_devices_screen.dart';
import '../screens/settings.dart'; import '../screens/settings.dart';
@ -50,13 +49,6 @@ class Sidebar extends StatelessWidget {
Navigator.push(context, MaterialPageRoute(builder: (context) => const Settings())); Navigator.push(context, MaterialPageRoute(builder: (context) => const Settings()));
}, },
), ),
ListTile(
leading: const Icon(Icons.cloud),
title: const Text("Cloud Service"),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const CloudService()));
},
),
], ],
), ),
); );

View File

@ -5,10 +5,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: app_settings name: app_settings
sha256: "7a5b880e2dd41dba8877108180380a1d28d874c231f7c0f9022127a4061b88e1" sha256: "66715a323ac36d6c8201035ba678777c0d2ea869e4d7064300d95af10c3bb8cb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.8" version: "4.2.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -340,18 +340,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_linux name: shared_preferences_linux
sha256: "28aefc1261746e7bad3d09799496054beb84e8c4ffcdfed7734e17b4ada459a5" sha256: fbc3cd6826896b66a5f576b025e4f344f780c84ea7f8203097a353370607a2c8
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
shared_preferences_macos: shared_preferences_macos:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_macos name: shared_preferences_macos
sha256: fbb94bf296576f49be37a1496d5951796211a8db0aa22cc0d68c46440dad808c sha256: "81b6a60b2d27020eb0fc41f4cebc91353047309967901a79ee8203e40c42ed46"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.4" version: "2.0.5"
shared_preferences_platform_interface: shared_preferences_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -372,10 +372,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_windows name: shared_preferences_windows
sha256: "97f7ab9a7da96d9cf19581f5de520ceb529548498bd6b5e0ccd02d68a0d15eba" sha256: "07c274c2115d4d5e4280622abb09f0980e2c5b1fcdc98ae9f59a3bad5bfc1f26"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -449,10 +449,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: ca121dbbadb3e43b449053feab0cdf3f2bff93b107cacf0290e3d29f717374b6 sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@ -9,12 +9,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_provisioning_for_iot/screens/main_screen.dart'; import 'package:flutter_provisioning_for_iot/screens/main_screen.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_provisioning_for_iot/main.dart';
void main() { void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async { testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
await tester.pumpWidget(const MainPage()); await tester.pumpWidget(const MainScreen());
// Verify that our counter starts at 0. // Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget); expect(find.text('0'), findsOneWidget);