How to Bind manually to a BlueTooth Low Energy Device in a WinForm using C#?
Asked Answered
D

1

7

This question is mostly answered by: Windows UWP connect to BLE device after discovery

I am writing a custom service and testing,for now, using a C#.NET WinForm on Windows 10 to connect to a Bluetooth Low Energy (BLE) device. I am using Framework 4.6.1. We are using a TI SmartRF06 Evaluation Board with a TI CC2650 BLE daughter card. Another developer is handling the Firmware of the Board.

Currently using methods similar to the reference answer above I am able to connect to an already bound BLE device. This device was manually bound and Windows did require me to enter a PIN. Since the device has no PIN simply entering "0" allowed the device to connect. Once connected, in this manner, I can get to all the GATT services and do what I need to do. So I have no issues with finding and getting a hold of a Advertising BLE device.

The issue is that how do I connect to BLE device that has not already been paired? I have gone through the net and found many examples of BLE code but nothing specific to showing how the pairing in code is done. Not sure I even need it to pair but Windows seems to only show my the GATT services on paired devices.

When I do this with unpaired device:

private void BleWatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{       
    var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
    // dev.DeviceInformation.Pairing.CanPair is true
    // dpr.Status is Failed
    DevicePairingResult dpr = await dev.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.None);
    var service = await GattDeviceService.FromIdAsync(dev.DeviceInformation.Id);
}

The result of dpr is always failed when device has not been manually paired. Which results in the GattDeviceServices being empty. But I am able to get the advertisement and the properties of the BLE device.

There is also this type of method to connect but I can't figure out how to use it:

var prslt = await device.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.ProvidePin, DevicePairingProtectionLevel.None,IDevicePairingSettings);

IdeviceParingSettings is an Interface. Not sure what Class to use with it. I am thinking this is where I can set the PIN of "O" that I might need?

Has anyone had any luck pairing to a BLE device in Windows using C# where the BLE device has no security. Basically it should be wide open. I feel like I am missing something simple or this is simply not possible (which I have seen some posts claiming that is the case. Most of those were many years old).

I did try the methods described in the mentioned post without any difference in result.

Any help is appreciated. If you need more of the code please look at the link I provided at top as that is what I started with. I will be happy to provide all of my actual code if there is, perhaps, a sequence that I am doing out of place.

Danikadanila answered 1/1, 2017 at 23:54 Comment(1)
I included the datasheet links. If these are incorrect, it would be great if you'd fix them.Kneel
D
9

I figured it out. I was on the right track.

After you connect using:

var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);

You need to do a custom Pairing:

var prslt = await device.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.ProvidePin, DevicePairingProtectionLevel.None);

But that would simply give you an error. You must also create a device.DeviceInformation.Pairing.Custom.PairingRequested event handler.

So I created this handler:

private void handlerPairingReq(DeviceInformationCustomPairing CP, DevicePairingRequestedEventArgs DPR)
        {
            //so we get here for custom pairing request.
            //this is the magic place where your pin goes.
            //my device actually does not require a pin but
            //windows requires at least a "0".  So this solved 
            //it.  This does not pull up the Windows UI either.
            DPR.Accept("0");


}

Hooked it up just before the PairAsync call Like:

device.DeviceInformation.Pairing.Custom.PairingRequested += handlerPairingRequested;

Example code for the BlueToothAdvertisementWatcher Code that does my connection:

    private BluetoothLEAdvertisementWatcher BTWatch = new BluetoothLEAdvertisementWatcher();

    private void Inits() 
        {
           BTWatch.Received += new TypedEventHandler<BluetoothLEAdvertisementWatcher, BluetoothLEAdvertisementReceivedEventArgs>(BtAddRx);
           BTWatch.Start();
        }

    private async void BtAddRx(BluetoothLEAdvertisementWatcher bw, BluetoothLEAdvertisementReceivedEventArgs args)
        {
            GattCommunicationStatus srslt;
            GattReadResult rslt;
            bw.Stop();//Stop this while inside.

            device = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
                if (device.DeviceInformation.Pairing.IsPaired == false)
                {   

                    /* Optional Below - Some examples say use FromIdAsync
                    to get the device. I don't think that it matters.   */            
                    var did = device.DeviceInformation.Id; //I reuse did to reload later.
                    device.Dispose();
                    device = null;
                    device = await BluetoothLEDevice.FromIdAsync(did);
                    /* end optional */
                    var handlerPairingRequested = new TypedEventHandler<DeviceInformationCustomPairing, DevicePairingRequestedEventArgs>(handlerPairingReq);
                    device.DeviceInformation.Pairing.Custom.PairingRequested += handlerPairingRequested;
                    log("Pairing to device now...."); 

                    var prslt = await device.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.ProvidePin, DevicePairingProtectionLevel.None);                  
                    log("Custom PAIR complete status: " + prslt.Status.ToString() + " Connection Status: " + device.ConnectionStatus.ToString());

                    device.DeviceInformation.Pairing.Custom.PairingRequested -= handlerPairingRequested; //Don't need it anymore once paired.


                    if (prslt.Status != DevicePairingResultStatus.Paired)
                    { //This should not happen. If so we exit to try again.
                        log("prslt exiting.  prslt.status=" + prslt.Status.ToString());// so the status may have updated.  lets drop out of here and get the device again.  should be paired the 2nd time around?
                        bw.Start();//restart this watcher.
                        return;
                    }
                    else
                    {
                        // The pairing takes some time to complete. If you don't wait you may have issues. 5 seconds seems to do the trick.

                        System.Threading.Thread.Sleep(5000); //try 5 second lay.
                        device.Dispose();
                       //Reload device so that the GATT services are there. This is why we wait.                     
                       device = await BluetoothLEDevice.FromIdAsync(did);

                    }
 var services = device.GattServices;
//then more code to finish it up.
}

If you wish to disconnect just use:

await device.DeviceInformation.Pairing.UnpairAsync();

Sorry for the messy Code. If there is anyone that finds is useful or has question let me know. I could not find any WinForm examples of this code anywhere. Actually I could not find any code to show how to pair with PIN without the UI. So I hope this helps anyone that might get stuck.

Danikadanila answered 2/1, 2017 at 8:57 Comment(6)
See scenario 8 and 9 at github.com/Microsoft/Windows-universal-samples/tree/master/…Spiel
Thanks - i had found examples like that. Was looking for something more windows forms and more direct. This information seems really buried.Danikadanila
@MichaelFrederick helped a lot, thanks! One issue with my implementation though. The paired device does not show in Windows UI (e.g. if you want to unpair without my app). Did you have issues with that?Mediant
Still have issues on that. I can start the watcher, find the device, get through await BluetoothLEDevice.FromBluetoothAddressAsync(addres) but the handlerPairingReq is not being called, so the pairing fails. I added it as you mentioned, but it doesn't work for me :(Ahlers
@MichaelFrederick your code helps me a lot, thank youLoraineloralee
@MichaelFrederick when using the custom pair (provide pin), are you able to implement in-app pairing, or does it prompt a Windows dialog for pairing? For me, I'm experiencing the latter, and I would really like to pair to my BLE device without the windows prompt dialogGan

© 2022 - 2024 — McMap. All rights reserved.