From 5b0161b7764dd43d1b9d7f82544c75a674b7b009 Mon Sep 17 00:00:00 2001
From: Paul-Winpenny <92634321+Paul-Winpenny@users.noreply.github.com>
Date: Tue, 15 Oct 2024 15:30:46 +0100
Subject: [PATCH] Bluetooth connection (potentially) scanning, windows only

---
 .vs/VSWorkspaceState.json                     |   7 ++
 .vs/slnx.sqlite                               | Bin 1175552 -> 1175552 bytes
 App/RobobinApp/MauiProgram.cs                 |  37 ++++----
 App/RobobinApp/RobobinApp.csproj              |  10 +-
 App/RobobinApp/RobobinApp.csproj.user         |   5 +
 .../ViewModels/ConnectionPageViewModel.cs     |  87 +++++++++++++++---
 .../ViewModels/MainPageViewModel.cs           |   4 +-
 7 files changed, 116 insertions(+), 34 deletions(-)
 create mode 100644 .vs/VSWorkspaceState.json

diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json
new file mode 100644
index 00000000..70fefc06
--- /dev/null
+++ b/.vs/VSWorkspaceState.json
@@ -0,0 +1,7 @@
+{
+  "ExpandedNodes": [
+    ""
+  ],
+  "SelectedNode": "\\App.sln",
+  "PreviewInSolutionExplorer": false
+}
\ No newline at end of file
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
index ddce4cda1e8734ebd50cba8503c15bb5c329d3f6..7768cbea50d0c8b6d0079797bfd1b57a875121e4 100644
GIT binary patch
delta 562
zcmZp8;NI}SeS$P&>qHr6#@3AqOZa(Nd1f&1zu-I0x1O(uXS(4B0n^P20zo_+&4sM2
z49@NP(;bajL?nY#i^?*SQ>%Ho6cm&Kit@8klS`aRGjmd=Kbgy@<X8X^QL<71vI}Bj
zfP`LgPM(quNIeKBK~;n#7Nw__0M+G{=Hwt`^QIfjV-%g9K95m?8_BHcf%`a>r%$*m
z$gV_$5f5fFibO*!tOZfAVDpuNOA?DpN(-QlcFW93Ee6^j4V85+Eh<XQD?wERln471
zVJXOGaMy6i<MEABUSjTa#!vxCO$7y@GinuCSQwlIT~d=u(;=QO4lPbC3QjF4$;?YH
z_D-#gj@`UoPG69bb@F|ERX$e!S_b~P{CoK?^Vjmf-z;d5&Cepw?92#`1`TL5u!2PJ
z7|GJS*S>wPJtGh^0WmWWvj8zG5VHX>I}mdKF((jn0Wmia^8hg~5c2^sKM)IS-)k@E
Gya50d*|Qe_

delta 137
zcmZp8;NI}SeS$P&^F$eE#^#L)OZd5%`PMV=zu-I0w|=vt!9u>x>*e$X8JQ>F*H`6W
z=HJV}znA~=W&wj-{>cUcF3o%G+xOZt0x=U1GXpUT5VHa?8xXStF$WNH0x=g5a|1CC
U5c2{t9}x2cvB37d_JYnE05|3`KL7v#

diff --git a/App/RobobinApp/MauiProgram.cs b/App/RobobinApp/MauiProgram.cs
index 90697e0e..df11d1d0 100644
--- a/App/RobobinApp/MauiProgram.cs
+++ b/App/RobobinApp/MauiProgram.cs
@@ -1,24 +1,27 @@
-using Microsoft.Extensions.Logging;
+
+using Shiny;
 
 namespace RobobinApp;
 
+
 public static class MauiProgram
 {
-	public static MauiApp CreateMauiApp()
-	{
-		var builder = MauiApp.CreateBuilder();
-		builder
-			.UseMauiApp<App>()
-			.ConfigureFonts(fonts =>
-			{
-				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
-				fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
-			});
+    public static MauiApp CreateMauiApp()
+    {
+        var builder = MauiApp
+          .CreateBuilder()
+          .UseMauiApp<App>()       
+          .UseShiny()
+
+          .ConfigureFonts(fonts =>
+          {
+              fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+              fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+          });
+
 
-#if DEBUG
-		builder.Logging.AddDebug();
-#endif
+        builder.Services.AddBluetoothLE();
 
-		return builder.Build();
-	}
-}
+        return builder.Build();
+    }
+}
\ No newline at end of file
diff --git a/App/RobobinApp/RobobinApp.csproj b/App/RobobinApp/RobobinApp.csproj
index fe8ef06b..4a445af5 100644
--- a/App/RobobinApp/RobobinApp.csproj
+++ b/App/RobobinApp/RobobinApp.csproj
@@ -58,9 +58,13 @@
 
 	<ItemGroup>
 		<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
-		<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
-		<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
-		<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
+		<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.91" />
+		<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.91" />
+		<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1" />
+		<PackageReference Include="Plugin.BLE" Version="3.1.0" />
+		<PackageReference Include="Shiny" Version="2.7.3" />
+		<PackageReference Include="Shiny.BluetoothLE" Version="3.3.3" />
+		<PackageReference Include="Shiny.Hosting.Maui" Version="3.3.3" />
 	</ItemGroup>
 
 	<ItemGroup>
diff --git a/App/RobobinApp/RobobinApp.csproj.user b/App/RobobinApp/RobobinApp.csproj.user
index 5ac6ce85..d5dbc44f 100644
--- a/App/RobobinApp/RobobinApp.csproj.user
+++ b/App/RobobinApp/RobobinApp.csproj.user
@@ -4,6 +4,11 @@
     <IsFirstTimeProjectOpen>False</IsFirstTimeProjectOpen>
     <ActiveDebugFramework>net8.0-windows10.0.19041.0</ActiveDebugFramework>
     <ActiveDebugProfile>Windows Machine</ActiveDebugProfile>
+    <SelectedPlatformGroup>Emulator</SelectedPlatformGroup>
+    <DefaultDevice>pixel_5_-_api_34</DefaultDevice>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-android|AnyCPU'">
+    <DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
   </PropertyGroup>
   <ItemGroup>
     <MauiXaml Update="Views\ConnectionPage.xaml">
diff --git a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs
index 9802d25e..fe675991 100644
--- a/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs
+++ b/App/RobobinApp/ViewModels/ConnectionPageViewModel.cs
@@ -2,6 +2,9 @@
 using System.Windows.Input;
 using Microsoft.Maui.Controls;
 using RobobinApp.Views;
+using Plugin.BLE;
+using Plugin.BLE.Abstractions.Contracts;
+using Plugin.BLE.Abstractions.Exceptions;
 
 namespace RobobinApp.ViewModels
 {
@@ -12,33 +15,74 @@ namespace RobobinApp.ViewModels
         public ObservableCollection<BluetoothDevice> BluetoothDevices { get; }
         public ICommand ConnectCommand { get; }
 
+        // BLE plugin fields
+        private readonly IAdapter _adapter;
+        private readonly IBluetoothLE _bluetoothLE;
+
         public ConnectionPageViewModel()
         {
             BluetoothDevices = new ObservableCollection<BluetoothDevice>();
             ConnectCommand = new Command(OnConnect);
-            LoadBluetoothDevices(); // Load available devices
             GoHomeCommand = new Command(async () => await OnGoHome());
+
+            // Initialize BLE manager and adapter
+            _bluetoothLE = CrossBluetoothLE.Current;
+            _adapter = _bluetoothLE.Adapter;
+
+            ScanDevices(); // Start scanning for devices
         }
-        public async Task OnGoHome()
-        {
-            await Application.Current.MainPage.Navigation.PushAsync(new MainPage());
-        }
+
         public BluetoothDevice SelectedDevice
         {
             get => _selectedDevice;
             set
             {
                 _selectedDevice = value;
-                OnPropertyChanged(); // Notify UI that SelectedDevice has changed
+                OnPropertyChanged();
             }
         }
 
-        private async void LoadBluetoothDevices()
+        public async Task OnGoHome()
         {
-            // Logic to load available Bluetooth devices
-            // This is a placeholder for your Bluetooth device discovery logic
-            BluetoothDevices.Add(new BluetoothDevice { Name = "Device 1" });
-            BluetoothDevices.Add(new BluetoothDevice { Name = "Device 2" });
+            await Application.Current.MainPage.Navigation.PushAsync(new MainPage());
+        }
+
+        private async void ScanDevices()
+        {
+            // Clear the current list of devices before scanning
+            BluetoothDevices.Clear();
+
+            try
+            {
+                if (!_bluetoothLE.IsAvailable)
+                {
+                    await Application.Current.MainPage.DisplayAlert("Bluetooth", "Bluetooth is not available.", "OK");
+                    return;
+                }
+
+                if (!_bluetoothLE.IsOn)
+                {
+                    await Application.Current.MainPage.DisplayAlert("Bluetooth", "Please turn on Bluetooth.", "OK");
+                    return;
+                }
+
+                _adapter.DeviceDiscovered += (s, a) =>
+                {
+                    // Add discovered devices to the list
+                    BluetoothDevices.Add(new BluetoothDevice
+                    {
+                        Name = a.Device.Name ?? "Unknown Device",
+                        MacAddress = a.Device.Id.ToString()
+                    });
+                };
+
+                // Start scanning for devices
+                await _adapter.StartScanningForDevicesAsync();
+            }
+            catch (Exception ex)
+            {
+                await Application.Current.MainPage.DisplayAlert("Error", $"Failed to scan for devices: {ex.Message}", "OK");
+            }
         }
 
         private async void OnConnect()
@@ -47,12 +91,29 @@ namespace RobobinApp.ViewModels
 
             // Logic to connect to the selected Bluetooth device
             await Application.Current.MainPage.DisplayAlert("Connection", $"Connecting to {SelectedDevice.Name}...", "OK");
-            // Implement actual connection logic here
+
+            try
+            {
+                // Stop scanning before attempting connection
+                await _adapter.StopScanningForDevicesAsync();
+
+                // Find the device using the MAC address
+                var device = await _adapter.ConnectToKnownDeviceAsync(Guid.Parse(SelectedDevice.MacAddress));
+
+                // Display successful connection
+                await Application.Current.MainPage.DisplayAlert("Connected", $"Connected to {SelectedDevice.Name}.", "OK");
+            }
+            catch (DeviceConnectionException ex)
+            {
+                // Handle connection failure
+                await Application.Current.MainPage.DisplayAlert("Connection Error", $"Failed to connect: {ex.Message}", "OK");
+            }
         }
     }
 
-    public class BluetoothDevice // Define this class to represent a Bluetooth device
+    public class BluetoothDevice
     {
         public string Name { get; set; }
+        public string MacAddress { get; set; }
     }
 }
diff --git a/App/RobobinApp/ViewModels/MainPageViewModel.cs b/App/RobobinApp/ViewModels/MainPageViewModel.cs
index d2387784..8665557a 100644
--- a/App/RobobinApp/ViewModels/MainPageViewModel.cs
+++ b/App/RobobinApp/ViewModels/MainPageViewModel.cs
@@ -3,6 +3,7 @@ using System.Runtime.CompilerServices;
 using System.Windows.Input;
 using Microsoft.Maui.Controls;
 using RobobinApp.Views;
+using Shiny.BluetoothLE;
 
 namespace RobobinApp.ViewModels
 
@@ -11,11 +12,12 @@ namespace RobobinApp.ViewModels
     {
         private bool _isBusy;
         private string _statusMessage;
-
+   
         public ICommand ConnectToRobobinCommand { get; }
 
         public MainPageViewModel()
         {
+
             ConnectToRobobinCommand = new Command(async () => await OnConnectToRobobin());
         }
 
-- 
GitLab