Skip to content

Commit c006e9f

Browse files
committed
Add ability to provide PIN code for pairing. Improve pairing with devices which ask confirmation if PIN code matches.
1 parent f17776a commit c006e9f

File tree

6 files changed

+62
-20
lines changed

6 files changed

+62
-20
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ Windows 10 1809 (10.0.17763) or higher<br>
1414
* Pair and connect to a device using its mac address: `BluetoothDevicePairing.exe pair --mac 12:34:56:78:9A:BC`
1515
* Pair and connect to a device using its name: `BluetoothDevicePairing.exe pair --name "name of device"`
1616
* Pair and connect to a device using its name/mac and device type: `BluetoothDevicePairing.exe pair --name "name of device" --type BluetoothLE`
17+
* Pair and connect to a device using its name/mac and pin code: `BluetoothDevicePairing.exe pair --mac 12:34:56:78:9A:BC --pin 1234`
1718
* Unpair a device using its mac address: `BluetoothDevicePairing.exe unpair --mac 12:34:56:78:9A:BC`
1819
* Unpair a device using its name: `BluetoothDevicePairing.exe unpair --name "name of device"`
1920
* Unpair a device using its name/mac and device type: `BluetoothDevicePairing.exe unpair --mac 12:34:56:78:9A:BC --type Bluetooth`
2021

2122
# Tips and tricks
2223
* Bluetooth LE devices use mac address randomisation, therefore it is not reliable to pair them using mac address. Use pairing by name instead.
2324
* Some devices advertize itself as Bluetooth and BluetoothLE simultaneously while having the same mac and name. To work with such devices explicitly specify to which type of device you want to connect using `--type` parameter.
25+
* Some device require pin code to be paired, use `--pin` parameter to provide PIN code. By default this programm will try to use `0000` as a pin code.
2426

2527
# Build
2628
* Use `Visual Studio 2019` to open the solution file and work with the code

Src/Bluetooth/Device.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace BluetoothDevicePairing.Bluetooth
88
internal enum DeviceType
99
{
1010
Bluetooth,
11-
BluetoothLe
11+
BluetoothLE
1212
}
1313

1414
internal sealed class Device
@@ -35,7 +35,7 @@ public bool IsConnected
3535
case DeviceType.Bluetooth:
3636
var b = BluetoothDevice.FromIdAsync(Info.Id).GetAwaiter().GetResult();
3737
return b.ConnectionStatus == BluetoothConnectionStatus.Connected;
38-
case DeviceType.BluetoothLe:
38+
case DeviceType.BluetoothLE:
3939
var ble = BluetoothLEDevice.FromIdAsync(Info.Id).GetAwaiter().GetResult();
4040
return ble.ConnectionStatus == BluetoothConnectionStatus.Connected;
4141
}
@@ -60,7 +60,7 @@ private static DeviceType GetDeviceType(DeviceInformation device)
6060
case "Bluetooth":
6161
return DeviceType.Bluetooth;
6262
case "BluetoothLE":
63-
return DeviceType.BluetoothLe;
63+
return DeviceType.BluetoothLE;
6464
default:
6565
throw new Exception($"Wrong device type '{type}' extracted from '{device.Id}'");
6666
}

Src/Bluetooth/DevicePairer.cs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace BluetoothDevicePairing.Bluetooth
55
{
66
internal sealed class DevicePairer
77
{
8-
public static void PairDevice(Device device)
8+
public static void PairDevice(Device device, string pin)
99
{
1010
Console.WriteLine($"Request to pair device \"{device}\"");
1111

@@ -21,7 +21,7 @@ public static void PairDevice(Device device)
2121
}
2222

2323
Console.WriteLine("Start pairing");
24-
Pair(device.Info);
24+
Pair(device.Info, pin);
2525
Console.WriteLine("Device has been successfully paired");
2626
}
2727

@@ -47,16 +47,52 @@ private static void Unpair(DeviceInformation device)
4747
}
4848
}
4949

50-
private static void Pair(DeviceInformation device)
50+
private static void Pair(DeviceInformation device, string pin)
5151
{
52-
device.Pairing.Custom.PairingRequested += (sender, args) => { args.Accept(); };
52+
device.Pairing.Custom.PairingRequested += (s, a) => PairingRequestedHandler(s, a, pin);
5353

54-
var res = device.Pairing.Custom.PairAsync(DevicePairingKinds.ConfirmOnly, DevicePairingProtectionLevel.None)
54+
// DeviceInformation.Pairing.PairAsync function doesn't work for non UWP applications. Thus, DeviceInformation.Pairing.Custom.PairAsync is used.
55+
// https://stackoverflow.com/questions/45191412/deviceinformation-pairasync-not-working-in-wpf
56+
57+
// DevicePairingKinds.DisplayPin option conflicts with DevicePairingKinds.ProvidePin: I used "Bluetooth Module HC 05" to test pairing with PIN code.
58+
// This device requires pin code "1234" to be paired. When both DevicePairingKinds.DisplayPin and DevicePairingKinds.ProvidePin flags were used in PairAsync function,
59+
// the PairingRequestedHandler was called with PairingKind equal to DevicePairingKinds.DisplayPin instead of DevicePairingKinds.ProvidePin, which made pairing fail.
60+
// Therefore, I decided not to use DevicePairingKinds.DisplayPin flag.
61+
62+
var res = device.Pairing.Custom
63+
.PairAsync(DevicePairingKinds.ConfirmOnly | DevicePairingKinds.ProvidePin | DevicePairingKinds.ConfirmPinMatch, DevicePairingProtectionLevel.None)
5564
.GetAwaiter().GetResult().Status;
5665
if (res != DevicePairingResultStatus.Paired)
5766
{
5867
throw new Exception($"Failed to pair device. Status = {res}");
5968
}
6069
}
70+
71+
private static void PairingRequestedHandler(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args, string pin)
72+
{
73+
switch (args.PairingKind)
74+
{
75+
case DevicePairingKinds.ConfirmOnly:
76+
Console.WriteLine("Pairing mode: ConfirmOnly");
77+
args.Accept();
78+
return;
79+
80+
case DevicePairingKinds.ProvidePin:
81+
Console.WriteLine("Pairing mode: ProvidePin");
82+
Console.WriteLine($"Pin is requested by the device. Using '{pin}' as a pin code");
83+
args.Accept(pin);
84+
return;
85+
86+
case DevicePairingKinds.ConfirmPinMatch:
87+
Console.WriteLine("Pairing mode: ConfirmPinMatch");
88+
Console.WriteLine($"The device's pin code: '{args.Pin}'");
89+
Console.WriteLine("Waiting for the target device to accept the pairing (you probably need to follow the instructions on the target device's screen)");
90+
args.Accept();
91+
return;
92+
}
93+
94+
Console.WriteLine($"Unexpected pairing type: {args.PairingKind}");
95+
throw new Exception();
96+
}
6197
}
6298
}

Src/Command/DiscoverDevices.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ private static void PrintDevice(Device d)
3030

3131
private static string GetType(Device d)
3232
{
33-
return d.Type == Bluetooth.DeviceType.BluetoothLe ? "LE" : "";
33+
return d.Type == Bluetooth.DeviceType.BluetoothLE ? "LE" : "";
3434
}
3535

3636
private static string GetPairedStatus(Device d)

Src/Command/PairDevice.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ internal sealed class PairDeviceOptions : PairAndUnpairDeviceOptions
1212
[Option("discovery-time", Default = 10,
1313
HelpText = "how long to search for devices. Units: seconds")]
1414
public int DiscoveryTime { get; set; }
15+
16+
[Option("pin", Default = "0000",
17+
HelpText = "pin code to provide to a device if it requires it for pairing")]
18+
public string Pin { get; set; }
1519
}
1620

1721
internal sealed class PairDevice
@@ -20,25 +24,25 @@ public static void Execute(PairDeviceOptions opts)
2024
{
2125
if (!string.IsNullOrEmpty(opts.Mac))
2226
{
23-
PairWithMac(new MacAddress(opts.Mac), opts.DiscoveryTime, opts.Type);
27+
PairWithMac(new MacAddress(opts.Mac), opts.DiscoveryTime, opts.Type, opts.Pin);
2428
}
2529
else if (!string.IsNullOrEmpty(opts.DeviceName))
2630
{
27-
PairWithName(opts.DeviceName, opts.DiscoveryTime, opts.Type);
31+
PairWithName(opts.DeviceName, opts.DiscoveryTime, opts.Type, opts.Pin);
2832
}
2933
else
3034
{
3135
throw new Exception("Mac or device name must be specified");
3236
}
3337
}
3438

35-
private static void PairWithMac(MacAddress mac, int discoveryTime, Utils.DeviceType deviceType)
39+
private static void PairWithMac(MacAddress mac, int discoveryTime, Utils.DeviceType deviceType, string pin)
3640
{
3741
var devices = DeviceFinder.FindDevicesByMac(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), mac, deviceType);
3842

3943
if (devices.Count == 1)
4044
{
41-
DevicePairer.PairDevice(devices[0]);
45+
DevicePairer.PairDevice(devices[0], pin);
4246
return;
4347
}
4448

@@ -52,26 +56,26 @@ private static void PairWithMac(MacAddress mac, int discoveryTime, Utils.DeviceT
5256
$"{devices.Count} devices with the mac '{mac}' found. Don't know which one to choose");
5357
}
5458

55-
private static void PairWithName(string name, int discoveryTime, Utils.DeviceType deviceType)
59+
private static void PairWithName(string name, int discoveryTime, Utils.DeviceType deviceType, string pin)
5660
{
5761
var devices = DeviceFinder.FindDevicesByName(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), name, deviceType);
5862
if (devices.Count == 1)
5963
{
60-
DevicePairer.PairDevice(devices[0]);
64+
DevicePairer.PairDevice(devices[0], pin);
6165
return;
6266
}
6367

64-
if (devices.Count == 2 && devices[0].Type == Bluetooth.DeviceType.BluetoothLe && devices[1].Type == Bluetooth.DeviceType.BluetoothLe)
68+
if (devices.Count == 2 && devices[0].Type == Bluetooth.DeviceType.BluetoothLE && devices[1].Type == Bluetooth.DeviceType.BluetoothLE)
6569
{
66-
HandleSituation_2_BluetoothLe_devices_with_the_same_name_found(devices[0], devices[1]);
70+
HandleSituation_2_BluetoothLe_devices_with_the_same_name_found(devices[0], devices[1], pin);
6771
return;
6872
}
6973

7074
throw new Exception($"{devices.Count} devices with the name '{name}' found. Don't know which one to choose");
7175
}
7276

7377
private static void HandleSituation_2_BluetoothLe_devices_with_the_same_name_found(Device device1,
74-
Device device2)
78+
Device device2, string pin)
7579
{
7680
// BLuetooth LE devices use mac randomization, which can lead to the situation when
7781
// the user already have the device paired but with different mac address.
@@ -85,7 +89,7 @@ private static void HandleSituation_2_BluetoothLe_devices_with_the_same_name_fou
8589
Console.WriteLine($"2 devices with the same name found: \"{oldDevice}\" (paired) and \"{newDevice}\"");
8690
Console.WriteLine("Assume that the device changed its mac address");
8791
DevicePairer.UnpairDevice(oldDevice);
88-
DevicePairer.PairDevice(newDevice);
92+
DevicePairer.PairDevice(newDevice, pin);
8993
return;
9094
}
9195

Src/Command/Utils/DeviceType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public static bool Equals(DeviceType type1, Bluetooth.DeviceType type2)
1717
}
1818

1919
if ( type1 == DeviceType.Bluetooth && type2 == Bluetooth.DeviceType.Bluetooth
20-
|| type1 == DeviceType.BluetoothLE && type2 == Bluetooth.DeviceType.BluetoothLe)
20+
|| type1 == DeviceType.BluetoothLE && type2 == Bluetooth.DeviceType.BluetoothLE)
2121
{
2222
return true;
2323
}

0 commit comments

Comments
 (0)