-
Paul-Winpenny authoredPaul-Winpenny authored
ConnectionPageViewModel.cs 15.20 KiB
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
using Microsoft.Maui.Controls;
using RobobinApp.Views;
using Plugin.BLE;
using Plugin.BLE.Abstractions.Contracts;
using Plugin.BLE.Abstractions.Exceptions;
using Plugin.BLE.Abstractions.EventArgs;
using System.Threading.Tasks;
using Plugin.BLE.Abstractions;
using RobobinApp.Models;
using System.Net.NetworkInformation;
using System.Collections.Generic;
using Windows.Networking.Connectivity;
using Windows.Devices.WiFi;
namespace RobobinApp.ViewModels
{
public class ConnectionPageViewModel : BaseViewModel
{
private BluetoothDevice _selectedDevice;
private IDevice _connectedDevice;
public ICommand GoHomeCommand { get; }
public ObservableCollection<BluetoothDevice> BluetoothDevices { get; }
public ObservableCollection<WifiNetwork> WifiNetworks { get; }
public ICommand ConnectCommand { get; }
public ICommand SendWifiInfoCommand { get; }
public ICommand DisconnectCommand { get; }
private bool _isConnected;
private string ssid;
private string password;
public bool IsBluetoothDeviceSelectionVisible => !IsWifiNetworkSelectionVisible;
public bool IsConnected
{
get => _isConnected;
set
{
_isConnected = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ConnectButtonText)); // Update button text when connection state changes
}
}
public string SSID
{
get => ssid;
set
{
ssid = value;
OnPropertyChanged(nameof(SSID));
}
}
public string Password
{
get => password;
set
{
password = value;
OnPropertyChanged(nameof(Password));
}
}
private readonly IAdapter _adapter;
private readonly IBluetoothLE _bluetoothLE;
public string ConnectButtonText => IsConnected ? "Disconnect" : "Connect";
private bool _isWifiNetworkSelectionVisible;
private WifiNetwork _selectedWifiNetwork;
public bool IsWifiNetworkSelectionVisible
{
get => _isWifiNetworkSelectionVisible;
set
{
_isWifiNetworkSelectionVisible = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsBluetoothDeviceSelectionVisible));
}
}
public ConnectionPageViewModel()
{
BluetoothDevices = new ObservableCollection<BluetoothDevice>();
WifiNetworks = new ObservableCollection<WifiNetwork>();
ConnectCommand = new Command(OnConnect);
DisconnectCommand = new Command(OnDisconnect);
SendWifiInfoCommand = new Command(OnSendWifiInfo);
GoHomeCommand = new Command(async () => await OnGoHome());
ConnectCommand = new Command(OnToggleConnection);
_bluetoothLE = CrossBluetoothLE.Current;
_adapter = _bluetoothLE.Adapter;
_adapter.DeviceDiscovered += OnDeviceDiscovered;
IsWifiNetworkSelectionVisible = false;
Debug.WriteLine("Checking and requesting Bluetooth permissions.");
CheckAndRequestBluetoothPermissions();
ScanForWifiNetworks();
}
private async void ScanForWifiNetworks()
{
WifiNetworks.Clear();
Debug.WriteLine("Scanning for Wi-Fi networks...");
var wifiAdapter = await GetWifiAdapterAsync();
if (wifiAdapter == null)
{
Debug.WriteLine("Wi-Fi adapter not found.");
return;
}
await wifiAdapter.ScanAsync();
Debug.Write("Scanning for networks");
var networks = wifiAdapter.NetworkReport.AvailableNetworks;
var addedSsids = new HashSet<string>(); // To keep track of added SSIDs
foreach (var network in networks)
{
Debug.Write("This network exists: " + network.Ssid);
if (addedSsids.Add(network.Ssid))
{
var wifiNetwork = new WifiNetwork
{
SSID = network.Ssid,
SignalStrength = network.NetworkRssiInDecibelMilliwatts
};
Device.BeginInvokeOnMainThread(() => WifiNetworks.Add(wifiNetwork));
Debug.WriteLine($"Found Wi-Fi network: {wifiNetwork.SSID}, Signal Strength: {wifiNetwork.SignalStrength} dBm");
}
}
}
private async Task<WiFiAdapter> GetWifiAdapterAsync()
{
var result = await WiFiAdapter.FindAllAdaptersAsync();
return result.FirstOrDefault(); // Get the first available Wi-Fi adapter
}
private async void OnSendWifiInfo(object obj)
{
if (SelectedWifiNetwork != null)
{
Debug.WriteLine("Wifi been selected");
}
if (!_isConnected || _connectedDevice == null)
{
Debug.WriteLine("Cannot send WiFi information: No device is connected.");
await Application.Current.MainPage.DisplayAlert("Error", "No device is connected.", "OK");
return;
}
try
{
Debug.WriteLine($"Sending WiFi information to {_connectedDevice.Name}...");
var services = await _connectedDevice.GetServicesAsync();
var uartService = services.FirstOrDefault(s => s.Id == Guid.Parse("6e400001-b5a3-f393-e0a9-e50e24dcca9e"));
if (uartService == null)
{
Debug.WriteLine("UART service not found.");
await Application.Current.MainPage.DisplayAlert("Error", "UART service not found on the device.", "OK");
return;
}
var characteristics = await uartService.GetCharacteristicsAsync();
var rxCharacteristic = characteristics.FirstOrDefault(c => c.Id == Guid.Parse("6e400002-b5a3-f393-e0a9-e50e24dcca9e"));
if (rxCharacteristic == null)
{
Debug.WriteLine("RX characteristic not found.");
await Application.Current.MainPage.DisplayAlert("Error", "RX characteristic not found on the device.", "OK");
return;
}
string wifiInfo = $"{SSID},{Password}";
byte[] data = System.Text.Encoding.UTF8.GetBytes(wifiInfo);
await rxCharacteristic.WriteAsync(data);
Debug.WriteLine("WiFi information sent successfully.");
await Application.Current.MainPage.DisplayAlert("Success", "WiFi information sent successfully.", "OK");
}
catch (Exception ex)
{
Debug.WriteLine($"Error sending WiFi information: {ex.Message}");
await Application.Current.MainPage.DisplayAlert("Error", $"Failed to send WiFi information: {ex.Message}", "OK");
}
}
public BluetoothDevice SelectedDevice
{
get => _selectedDevice;
set
{
_selectedDevice = value;
OnPropertyChanged();
}
}
public WifiNetwork SelectedWifiNetwork
{
get => _selectedWifiNetwork;
set
{
_selectedWifiNetwork = value;
OnPropertyChanged();
}
}
private async void OnToggleConnection()
{
if (IsConnected)
{
OnDisconnect();
}
else
{
OnConnect();
}
}
private async void CheckAndRequestBluetoothPermissions()
{
Debug.WriteLine("Checking Bluetooth permissions.");
var status = await Permissions.CheckStatusAsync<Permissions.Bluetooth>();
if (status != PermissionStatus.Granted)
{
Debug.WriteLine("Bluetooth permission not granted, requesting permission.");
status = await Permissions.RequestAsync<Permissions.Bluetooth>();
}
if (status == PermissionStatus.Granted)
{
Debug.WriteLine("Bluetooth permission granted, proceeding to scan devices.");
ScanDevices();
}
else
{
Debug.WriteLine("Bluetooth permission denied.");
await Application.Current.MainPage.DisplayAlert("Permissions", "Bluetooth scan permission is required to discover devices.", "OK");
}
}
public async Task OnGoHome()
{
Debug.WriteLine("Navigating to home page.");
await Application.Current.MainPage.Navigation.PushAsync(new MainPage());
}
private async void ScanDevices()
{
BluetoothDevices.Clear();
Debug.WriteLine("Cleared existing Bluetooth devices. Starting scan...");
try
{
if (!_bluetoothLE.IsAvailable)
{
Debug.WriteLine("Bluetooth is not available.");
await Application.Current.MainPage.DisplayAlert("Bluetooth", "Bluetooth is not available.", "OK");
return;
}
if (!_bluetoothLE.IsOn)
{
Debug.WriteLine("Bluetooth is turned off.");
await Application.Current.MainPage.DisplayAlert("Bluetooth", "Please turn on Bluetooth.", "OK");
return;
}
Debug.WriteLine("Starting scanning for devices...");
await _adapter.StartScanningForDevicesAsync();
}
catch (Exception ex)
{
Debug.WriteLine($"Error during scanning: {ex.Message}");
await Application.Current.MainPage.DisplayAlert("Error", $"Failed to scan for devices: {ex.Message}", "OK");
}
}
private void OnDeviceDiscovered(object sender, DeviceEventArgs e)
{
Debug.WriteLine($"Discovered device: {e.Device.Name ?? e.Device.Id.ToString()}");
var bluetoothDevice = new BluetoothDevice(
string.IsNullOrWhiteSpace(e.Device.Name) ? e.Device.Id.ToString() : e.Device.Name,
e.Device.Id.ToString()
);
if (!BluetoothDevices.Any(d => d.MacAddress == bluetoothDevice.MacAddress))
{
Device.BeginInvokeOnMainThread(() => BluetoothDevices.Add(bluetoothDevice));
}
}
private async Task<IDevice> TryConnectAsync(Guid deviceId, int retryCount = 3)
{
IDevice device = null;
for (int attempt = 1; attempt <= retryCount; attempt++)
{
try
{
Debug.WriteLine($"Attempt {attempt}: Connecting to device {deviceId}");
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
device = await _adapter.ConnectToKnownDeviceAsync(deviceId, new ConnectParameters(false, true), cancellationTokenSource.Token);
return device;
}
catch (Exception ex)
{
Debug.WriteLine($"Attempt {attempt} failed: {ex.Message}");
if (attempt == retryCount)
{
throw;
}
}
}
return device;
}
private async void OnConnect()
{
if (SelectedDevice == null)
{
Debug.WriteLine("No device selected for connection.");
return;
}
Debug.WriteLine($"Attempting to connect to {SelectedDevice.Name}, MAC Address {SelectedDevice.MacAddress}");
await Application.Current.MainPage.DisplayAlert("Connection", $"Connecting to {SelectedDevice.Name}...", "OK");
try
{
await _adapter.StopScanningForDevicesAsync();
Debug.WriteLine("Stopped scanning for devices.");
IsConnected = true;
// Connect to the selected device
_connectedDevice = await TryConnectAsync(Guid.Parse(SelectedDevice.MacAddress));
Debug.WriteLine($"Successfully connected to {SelectedDevice.Name}.");
// Try to get services
var services = await _connectedDevice.GetServicesAsync();
if (services != null && services.Count > 0)
{
foreach (var service in services)
{
Debug.WriteLine($"Service: ID={service.Id}, Name={service.Name}");
}
}
else
{
Debug.WriteLine("No services found.");
}
}
catch (DeviceConnectionException ex)
{
Debug.WriteLine($"Connection error: {ex.Message}");
await Application.Current.MainPage.DisplayAlert("Connection Error", $"Failed to connect: {ex.Message}", "OK");
}
catch (TaskCanceledException ex)
{
Debug.WriteLine($"TaskCanceledException: {ex.Message}");
await Application.Current.MainPage.DisplayAlert("Connection Error", "Connection timed out.", "OK");
_connectedDevice = null;
IsConnected = false;
}
catch (Exception ex)
{
Debug.WriteLine($"General connection error: {ex.Message}");
await Application.Current.MainPage.DisplayAlert("Connection Error", $"An error occurred: {ex.Message}", "OK");
}
}
private async void OnDisconnect()
{
if (_connectedDevice != null)
{
try
{
Debug.WriteLine($"Attempting to disconnect from {_connectedDevice.Name}");
await _adapter.DisconnectDeviceAsync(_connectedDevice);
Debug.WriteLine("Disconnected successfully.");
IsWifiNetworkSelectionVisible = false;
// Dispose of the device reference
if (_connectedDevice != null)
_connectedDevice.Dispose();
_connectedDevice = null;
IsConnected = false;
await Application.Current.MainPage.DisplayAlert("Disconnected", "Device disconnected successfully.", "OK");
}
catch (Exception ex)
{
Debug.WriteLine($"Error during disconnection: {ex.Message}");
await Application.Current.MainPage.DisplayAlert("Disconnection Error", $"Failed to disconnect: {ex.Message}", "OK");
}
}
else
{
Debug.WriteLine("No device to disconnect.");
}
}
}
}