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