Skip to content
Snippets Groups Projects
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.");
            }
        }
   

    }

}