How to programmatically pair a bluetooth device

GuiTeK picture GuiTeK · Mar 9, 2017 · Viewed 15.8k times · Source

I recently bought a Lilypad Simblee BLE Board and I'd like to pair it programmatically to my computer (using the 32feet.NET library in C#).

I'm aware the "How to programmatically pair a bluetooth device" has already been asked on StackOverflow (here for example), however for some reason, all my attempts to pair the device programmatically have failed. Indeed, I successfully paired the device with the "Manage Bluetooth devices" window in Windows 10 Settings panel (Settings > Devices > Bluetooth).

Firstly, I don't know the pairing method (either legacy or SSP) to use with my device. Windows never asked me for a PIN or something, so I guess it's SSP, but I'm unsure.

I searched on Google how to do a SSP pairing request with 32feet.NET: I found this.

However, once it discovered my device (the device discovery works properly), the pairing request instantly fails.

My code:

using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
using System;
using System.Collections.Generic;

namespace HLK_Client
{
    class HLKBoard
    {
        public event HLKBoardEventHandler HLKBoardConnectionComplete;
        public delegate void HLKBoardEventHandler(object sender, HLKBoardEventArgs e);

        private BluetoothClient _bluetoothClient;
        private BluetoothComponent _bluetoothComponent;
        private List<BluetoothDeviceInfo> _inRangeBluetoothDevices;
        private BluetoothDeviceInfo _hlkBoardDevice;
        private EventHandler<BluetoothWin32AuthenticationEventArgs> _bluetoothAuthenticatorHandler;
        private BluetoothWin32Authentication _bluetoothAuthenticator;


        public HLKBoard()
        {
            _bluetoothClient = new BluetoothClient();
            _bluetoothComponent = new BluetoothComponent(_bluetoothClient);
            _inRangeBluetoothDevices = new List<BluetoothDeviceInfo>();
            _bluetoothAuthenticatorHandler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(_bluetoothAutenticator_handlePairingRequest);
            _bluetoothAuthenticator = new BluetoothWin32Authentication(_bluetoothAuthenticatorHandler);

            _bluetoothComponent.DiscoverDevicesProgress += _bluetoothComponent_DiscoverDevicesProgress;
            _bluetoothComponent.DiscoverDevicesComplete += _bluetoothComponent_DiscoverDevicesComplete;
        }


        public void ConnectAsync()
        {
            _inRangeBluetoothDevices.Clear();
            _hlkBoardDevice = null;
            _bluetoothComponent.DiscoverDevicesAsync(255, true, true, true, false, null);
        }


        private void PairWithBoard()
        {
            Console.WriteLine("Pairing...");

            bool pairResult = BluetoothSecurity.PairRequest(_hlkBoardDevice.DeviceAddress, null);

            if (pairResult)
            {
                Console.WriteLine("Success");
            }

            else
            {
                Console.WriteLine("Fail"); // Instantly fails
            }
        }


        private void _bluetoothComponent_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e)
        {
            _inRangeBluetoothDevices.AddRange(e.Devices);
        }

        private void _bluetoothComponent_DiscoverDevicesComplete(object sender, DiscoverDevicesEventArgs e)
        {
            for (int i = 0; i < _inRangeBluetoothDevices.Count; ++i)
            {
                if (_inRangeBluetoothDevices[i].DeviceName == "HLK")
                {
                    _hlkBoardDevice = _inRangeBluetoothDevices[i];
                    PairWithBoard();

                    return;
                }
            }

            HLKBoardConnectionComplete(this, new HLKBoardEventArgs(false, "Didn't found any \"HLK\" discoverable device"));
        }

        private void _bluetoothAutenticator_handlePairingRequest(object sender, BluetoothWin32AuthenticationEventArgs e)
        {
            e.Confirm = true; // Never reach this line
        }
    }
}

Why does the pairing request fail?

Answer

caesay picture caesay · Mar 9, 2017

The answer to the question you linked has a plausible suggestion... did you read it?

Also you should look at this question as well.

32feet library is built around legacy pairing, so that you either need to know the pin of the device you are connecting to, or you supply it with a null to get a popup window to enter a pin.

It also says that the windows function used by 32feet is deprecated in newer versions of windows. If that's true, the reason it's failing instantly is because you've passed a null pin in your pairing request and for it to proceed windows needs to show a dialog which no longer exists.

What happens if you try to connect with the pin "0000" or "1234" ?

I'm looking at the source code of WindowsBluetoothSecurity.cs in 32feet.net and I see if a pairing request fails, it logs the error code to Debug.WriteLine, any chance you could post that error code here?

One good work around to this problem might be to import BluetoothAuthenticateDeviceEx and use that manually to complete the pairing request. If you don't want to do this manually, it looks like in the latest version of the 32feet source, there is actually a SSP pairing method that utilises this method but it's not public and it's not used anywhere so you'll need to access it via reflection:

typeof(BluetoothSecurity)
    .GetMethod("PairRequest", BindingFlags.Static | BindingFlags.NonPublic)
    .Invoke(null, new object[] { _hlkBoardDevice.DeviceAddress, BluetoothAuthenticationRequirements.MITMProtectionNotRequired });