浏览代码

Added bluetooth connection system

Toby Chui 2 年之前
父节点
当前提交
f51dbcdae7

二进制
res/bluetooth_searching_FILL0_wght400_GRAD0_opsz48.png


二进制
src/pm25go/assets/images/bt.png


二进制
src/pm25go/assets/images/bt.psd


二进制
src/pm25go/assets/images/scanner.png


二进制
src/pm25go/assets/images/scanner.psd


+ 13 - 0
src/pm25go/lib/bluetooth.dart

@@ -0,0 +1,13 @@
+import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
+
+/*
+  Class definations
+*/
+
+class DeviceSelectionWrapper {
+  String deviceName = "";
+  String deviceAddr = "";
+  bool deviceSelected = false;
+  bool deviceConnected = false;
+  late BluetoothConnection connection;
+}

+ 25 - 22
src/pm25go/lib/main.dart

@@ -1,6 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
 import 'package:pm25go/scan.dart';
+import 'bluetooth.dart';
 
 void main() {
   runApp(const MyApp());
@@ -74,35 +75,37 @@ class _MyHomePageState extends State<MyHomePage> {
 
   //Bluetooth Connection
   bool _btConnected = false;
-  var _btAddr = "";
+  DeviceSelectionWrapper connectedBluetoothDevice = DeviceSelectionWrapper();
 
   //Data update for display
   int _pm01 = 0; //No recommended data found
   int _pm25 = 0; //Healthy range: 35, recommend < 15
   int _pm10 = 0; //Healthy range: 150, recommend < 50
-  void _toggleBluetooth() {
-    setState(() {
-      // This call to setState tells the Flutter framework that something has
-      // changed in this State, which causes it to rerun the build method below
-      // so that the display can reflect the updated values. If we changed
-      // _counter without calling setState(), then the build method would not be
-      // called again, and so nothing would appear to happen.
-      Navigator.push(
+  void _toggleBluetooth() async {
+    // This call to setState tells the Flutter framework that something has
+    // changed in this State, which causes it to rerun the build method below
+    // so that the display can reflect the updated values. If we changed
+    // _counter without calling setState(), then the build method would not be
+    // called again, and so nothing would appear to happen.
+    DeviceSelectionWrapper deviceStateToSend = connectedBluetoothDevice;
+    final DeviceSelectionWrapper result = await Navigator.push(
         context,
-        MaterialPageRoute(builder: (context) => const ConnectionPage()),
-      );
-      return;
-      if (_btConnected) {
-        //Disconnect the current bt connection
-        _statusText = "已斷開連接\nDisconnected";
-        _btConnected = false;
-      } else {
-        //Connect to the target bluetooth module
-        _statusText = "正在連接口袋 PM2.5 傳感器…\nConnecting to Pocket PM2.5 Sensor...";
+        MaterialPageRoute(
+            builder: (context) =>
+                ConnectionPage(currentState: deviceStateToSend)));
+    connectedBluetoothDevice = result;
 
-        _connectBluetoothDevice();
-      }
-    });
+    //Update the status text
+    if (result.deviceSelected && result.deviceConnected) {
+      setState(() {
+        _statusText = "已連接到藍牙裝置 " + result.deviceName;
+      });
+    } else {
+      setState(() {
+        _statusText = "選擇無效或未建立連接";
+      });
+    }
+    return;
   }
 
   void _connectBluetoothDevice() {

+ 206 - 62
src/pm25go/lib/scan.dart

@@ -4,16 +4,16 @@ import 'dart:typed_data';
 import 'dart:convert';
 import 'package:flutter/material.dart';
 import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
+import 'bluetooth.dart';
 
 class ConnectionPage extends StatefulWidget {
-  const ConnectionPage({super.key});
+  final DeviceSelectionWrapper currentState;
+  const ConnectionPage({super.key, required this.currentState});
 
   @override
   State<ConnectionPage> createState() => _ConnectionPage();
 }
 
-void printDiscovered() {}
-
 List<BluetoothDiscoveryResult> scanBluetoothDevice(
     List<BluetoothDiscoveryResult> results) {
   print("Scanning started!");
@@ -30,78 +30,222 @@ List<BluetoothDiscoveryResult> scanBluetoothDevice(
   return results;
 }
 
+Widget generateDiscoveredBluetoothList(
+    List<BluetoothDevice> bondedDevices, Function callback) {
+  List<Widget> devs = [];
+  for (int i = 0; i < bondedDevices.length; i++) {
+    BluetoothDevice thisDevice = bondedDevices[i];
+    devs.add(Container(
+        margin: EdgeInsetsDirectional.all(4),
+        color: Colors.white,
+        child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
+          Container(
+              alignment: Alignment.center,
+              padding: EdgeInsetsDirectional.all(14),
+              child: Image.asset('assets/images/bt.png')),
+          Container(
+              alignment: Alignment.center,
+              padding: EdgeInsetsDirectional.all(14),
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  Text(
+                    thisDevice.address,
+                    textAlign: TextAlign.left,
+                  ),
+                  Text(
+                    thisDevice.name!,
+                    textAlign: TextAlign.left,
+                  )
+                ],
+              )),
+          Container(
+              alignment: Alignment.center,
+              padding: EdgeInsetsDirectional.all(14),
+              child: ElevatedButton(
+                style: ElevatedButton.styleFrom(),
+                onPressed: () {
+                  callback(thisDevice.address, thisDevice.name!);
+                },
+                child: const Text('選擇'),
+              ))
+        ])));
+  }
+  return Container(
+      height: 400,
+      padding: EdgeInsetsDirectional.all(4),
+      decoration: BoxDecoration(
+          border: Border.all(
+            color: Color.fromARGB(255, 226, 226, 226),
+          ),
+          borderRadius: BorderRadius.all(Radius.circular(4))),
+      child: SingleChildScrollView(
+          child: Column(
+        children: devs,
+      )));
+}
+
 class _ConnectionPage extends State<ConnectionPage> {
-  late BluetoothConnection connection;
-  bool _isConnected = false;
-  var _latestDiscoveredId = "Nothing Yet";
+  //Bluetooth Connection Related
+  List<BluetoothDevice> bondedDevices = <BluetoothDevice>[];
+  DeviceSelectionWrapper operatingDevice = DeviceSelectionWrapper();
+  String _statusText = "請選擇並連接到一個 Bluetooth Serial 裝置";
 
   @override
   Widget build(BuildContext context) {
+    operatingDevice = widget.currentState;
+    //Check if it is connected
+    if (operatingDevice.deviceConnected) {
+      setState(() {
+        _statusText = "已連接到裝置 " +
+            operatingDevice.deviceName +
+            " (" +
+            operatingDevice.deviceAddr +
+            ")";
+      });
+    }
+    //Load all the bluetooth device on screen load
+    FlutterBluetoothSerial.instance
+        .getBondedDevices()
+        .then((List<BluetoothDevice> deviceLists) {
+      setState(() {
+        bondedDevices = deviceLists;
+      });
+    });
     return Scaffold(
-      appBar: AppBar(
-        title: const Text('Second Route'),
-        backgroundColor: Colors.blueGrey,
-      ),
+      appBar: null,
       body: Column(
         children: [
-          Center(
-            child: ElevatedButton(
-              onPressed: () {
-                if (_isConnected && connection.isConnected) {
-                  connection.close();
-                  print('Connection Closed');
-                  _isConnected = false;
-                }
-              },
-              child: const Text('Disconnect Bluetooth'),
-            ),
-          ),
-          Center(
-            child: ElevatedButton(
-              onPressed: () async {
-                try {
-                  connection =
-                      await BluetoothConnection.toAddress("98:D3:11:FC:39:EC");
-                  print('Connected to the device');
-                  _isConnected = true;
-                  connection.input!.listen((Uint8List data) {
-                    print(data);
-                  });
-                } catch (ex) {
-                  print(ex);
-                }
-              },
-              child: const Text('Connect Bluetooth'),
-            ),
+          //Title banner
+          Image.asset('assets/images/scanner.png'),
+          //Control Buttons
+          Container(
+              alignment: Alignment.topLeft,
+              padding: EdgeInsetsDirectional.all(16),
+              child: Row(
+                children: [
+                  //List Bluetooth Device Button
+                  Container(
+                      padding: EdgeInsets.symmetric(horizontal: 2),
+                      child: ElevatedButton(
+                        onPressed: () {
+                          FlutterBluetoothSerial.instance
+                              .getBondedDevices()
+                              .then((List<BluetoothDevice> deviceLists) {
+                            _statusText = "";
+                            for (var device in deviceLists) {
+                              print(device.address + " / " + device.name!);
+                              setState(() {
+                                _statusText =
+                                    "已更新藍牙裝置列表。如仍無法找到目標模組,請先到藍牙設定嘗試連接一次再載入列表。";
+                              });
+                            }
+
+                            setState(() {
+                              bondedDevices = deviceLists;
+                            });
+                          });
+                        },
+                        child: const Text('載入藍牙裝置列表'),
+                      )),
+                  Container(
+                      padding: EdgeInsets.symmetric(horizontal: 2),
+                      child:
+                          //Connect Device Button
+                          ElevatedButton(
+                        style: ElevatedButton.styleFrom(
+                            backgroundColor: (operatingDevice.deviceSelected &&
+                                    !operatingDevice.deviceConnected)
+                                ? Colors.green
+                                : Color.fromARGB(255, 192, 192, 192)),
+                        onPressed: () async {
+                          if (operatingDevice.deviceSelected &&
+                              !operatingDevice.deviceConnected) {
+                            //Not connected yet. Establish connection
+                            try {
+                              operatingDevice.connection =
+                                  await BluetoothConnection.toAddress(
+                                      operatingDevice.deviceAddr);
+                              print('Connected to the device');
+                              setState(() {
+                                _statusText = "已連接到 " +
+                                    operatingDevice.deviceName +
+                                    " (" +
+                                    operatingDevice.deviceAddr +
+                                    ")";
+                              });
+                              operatingDevice.deviceConnected = true;
+                              operatingDevice.connection.input!
+                                  .listen((Uint8List data) {
+                                print(data);
+                              });
+                            } catch (ex) {
+                              print(ex);
+                            }
+                          } else {
+                            if (!operatingDevice.deviceSelected) {
+                              setState(() {
+                                _statusText = "沒有已選擇之藍牙裝置";
+                              });
+                            } else if (operatingDevice.connection.isConnected) {
+                              setState(() {
+                                _statusText = "藍牙裝置已連接";
+                              });
+                            }
+                          }
+                        },
+                        child: const Text('連接'),
+                      )),
+
+                  Container(
+                      padding: EdgeInsets.symmetric(horizontal: 2),
+                      child: ElevatedButton(
+                        style: ElevatedButton.styleFrom(
+                            backgroundColor: (operatingDevice.deviceSelected &&
+                                    operatingDevice.deviceConnected)
+                                ? Colors.red
+                                : Color.fromARGB(255, 192, 192, 192)),
+                        onPressed: () {
+                          //Disconnect BT devices
+                          if (operatingDevice.deviceConnected &&
+                              operatingDevice.deviceConnected) {
+                            operatingDevice.connection.close();
+                            print('Connection Closed');
+                            setState(() {
+                              _statusText = "已中斷連接";
+                            });
+                            operatingDevice.deviceConnected = false;
+                          }
+                        },
+                        child: const Text('斷開'),
+                      ))
+                ],
+              )),
+          Container(
+            padding: const EdgeInsetsDirectional.all(16),
+            child: Text(
+                //Show the latest found Bluetooth addr
+                _statusText),
           ),
-          Center(
-            child: ElevatedButton(
-              onPressed: () {
-                FlutterBluetoothSerial.instance
-                    .getBondedDevices()
-                    .then((List<BluetoothDevice> bondedDevices) {
-                  _latestDiscoveredId = "";
-                  for (var device in bondedDevices) {
-                    print(device.address + " / " + device.name!);
-                    setState(() {
-                      _latestDiscoveredId +=
-                          "\n" + device.address + " / " + device.name!;
-                    });
-                  }
+          Container(
+              padding: const EdgeInsetsDirectional.all(16),
+              child: generateDiscoveredBluetoothList(bondedDevices,
+                  (String addr, String name) {
+                setState(() {
+                  operatingDevice.deviceAddr = addr;
+                  operatingDevice.deviceName = name;
+                  operatingDevice.deviceSelected = true;
+                  _statusText = "已選擇裝置 " + name + "(" + addr + ")";
                 });
-              },
-              child: const Text('Select Bluetooth'),
-            ),
-          ),
-          Text(
-              //Show the latest found Bluetooth addr
-              _latestDiscoveredId),
+                print("已選擇裝置 " + name + "(" + addr + ")");
+              })),
+
           Center(
             child: ElevatedButton(
               onPressed: () {
-                Navigator.pop(context);
+                Navigator.pop(context, operatingDevice);
               },
-              child: const Text('Go back!'),
+              child: const Text('返回'),
             ),
           )
         ],

+ 2 - 0
src/pm25go/pubspec.yaml

@@ -62,6 +62,8 @@ flutter:
   # To add assets to your application, add an assets section, like this:
   assets:
     - assets/images/banner.png
+    - assets/images/scanner.png
+    - assets/images/bt.png
 
   # An image asset can refer to one or more resolution-specific "variants", see
   # https://flutter.dev/assets-and-images/#resolution-aware