diff --git a/README.md b/README.md index a75a90b..ab5023f 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Windows 10 1809 (10.0.17763) or higher
* Pair and connect to a device using its mac address: `BluetoothDevicePairing.exe pair --mac 12:34:56:78:9A:BC` * Pair and connect to a device using its name: `BluetoothDevicePairing.exe pair --name "name of device"` * Pair and connect to a device using its name/mac and device type: `BluetoothDevicePairing.exe pair --name "name of device" --type BluetoothLE` +* 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` * Unpair a device using its mac address: `BluetoothDevicePairing.exe unpair --mac 12:34:56:78:9A:BC` * Unpair a device using its name: `BluetoothDevicePairing.exe unpair --name "name of device"` * Unpair a device using its name/mac and device type: `BluetoothDevicePairing.exe unpair --mac 12:34:56:78:9A:BC --type Bluetooth` @@ -21,6 +22,7 @@ Windows 10 1809 (10.0.17763) or higher
# Tips and tricks * Bluetooth LE devices use mac address randomisation, therefore it is not reliable to pair them using mac address. Use pairing by name instead. * 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. +* 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. # Build * Use `Visual Studio 2019` to open the solution file and work with the code diff --git a/Src/Bluetooth/Device.cs b/Src/Bluetooth/Device.cs index 9048ae1..97e1c92 100644 --- a/Src/Bluetooth/Device.cs +++ b/Src/Bluetooth/Device.cs @@ -8,7 +8,7 @@ namespace BluetoothDevicePairing.Bluetooth internal enum DeviceType { Bluetooth, - BluetoothLe + BluetoothLE } internal sealed class Device @@ -35,7 +35,7 @@ public bool IsConnected case DeviceType.Bluetooth: var b = BluetoothDevice.FromIdAsync(Info.Id).GetAwaiter().GetResult(); return b.ConnectionStatus == BluetoothConnectionStatus.Connected; - case DeviceType.BluetoothLe: + case DeviceType.BluetoothLE: var ble = BluetoothLEDevice.FromIdAsync(Info.Id).GetAwaiter().GetResult(); return ble.ConnectionStatus == BluetoothConnectionStatus.Connected; } @@ -60,7 +60,7 @@ private static DeviceType GetDeviceType(DeviceInformation device) case "Bluetooth": return DeviceType.Bluetooth; case "BluetoothLE": - return DeviceType.BluetoothLe; + return DeviceType.BluetoothLE; default: throw new Exception($"Wrong device type '{type}' extracted from '{device.Id}'"); } diff --git a/Src/Bluetooth/DevicePairer.cs b/Src/Bluetooth/DevicePairer.cs index 0d1afff..ef32a85 100644 --- a/Src/Bluetooth/DevicePairer.cs +++ b/Src/Bluetooth/DevicePairer.cs @@ -5,7 +5,7 @@ namespace BluetoothDevicePairing.Bluetooth { internal sealed class DevicePairer { - public static void PairDevice(Device device) + public static void PairDevice(Device device, string pin) { Console.WriteLine($"Request to pair device \"{device}\""); @@ -21,7 +21,7 @@ public static void PairDevice(Device device) } Console.WriteLine("Start pairing"); - Pair(device.Info); + Pair(device.Info, pin); Console.WriteLine("Device has been successfully paired"); } @@ -47,16 +47,52 @@ private static void Unpair(DeviceInformation device) } } - private static void Pair(DeviceInformation device) + private static void Pair(DeviceInformation device, string pin) { - device.Pairing.Custom.PairingRequested += (sender, args) => { args.Accept(); }; + device.Pairing.Custom.PairingRequested += (s, a) => PairingRequestedHandler(s, a, pin); - var res = device.Pairing.Custom.PairAsync(DevicePairingKinds.ConfirmOnly, DevicePairingProtectionLevel.None) + // DeviceInformation.Pairing.PairAsync function doesn't work for non UWP applications. Thus, DeviceInformation.Pairing.Custom.PairAsync is used. + // https://stackoverflow.com/questions/45191412/deviceinformation-pairasync-not-working-in-wpf + + // DevicePairingKinds.DisplayPin option conflicts with DevicePairingKinds.ProvidePin: I used "Bluetooth Module HC 05" to test pairing with PIN code. + // This device requires pin code "1234" to be paired. When both DevicePairingKinds.DisplayPin and DevicePairingKinds.ProvidePin flags were used in PairAsync function, + // the PairingRequestedHandler was called with PairingKind equal to DevicePairingKinds.DisplayPin instead of DevicePairingKinds.ProvidePin, which made pairing fail. + // Therefore, I decided not to use DevicePairingKinds.DisplayPin flag. + + var res = device.Pairing.Custom + .PairAsync(DevicePairingKinds.ConfirmOnly | DevicePairingKinds.ProvidePin | DevicePairingKinds.ConfirmPinMatch, DevicePairingProtectionLevel.None) .GetAwaiter().GetResult().Status; if (res != DevicePairingResultStatus.Paired) { throw new Exception($"Failed to pair device. Status = {res}"); } } + + private static void PairingRequestedHandler(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args, string pin) + { + switch (args.PairingKind) + { + case DevicePairingKinds.ConfirmOnly: + Console.WriteLine("Pairing mode: ConfirmOnly"); + args.Accept(); + return; + + case DevicePairingKinds.ProvidePin: + Console.WriteLine("Pairing mode: ProvidePin"); + Console.WriteLine($"Pin is requested by the device. Using '{pin}' as a pin code"); + args.Accept(pin); + return; + + case DevicePairingKinds.ConfirmPinMatch: + Console.WriteLine("Pairing mode: ConfirmPinMatch"); + Console.WriteLine($"The device's pin code: '{args.Pin}'"); + Console.WriteLine("Waiting for the target device to accept the pairing (you probably need to follow the instructions on the target device's screen)"); + args.Accept(); + return; + } + + Console.WriteLine($"Unexpected pairing type: {args.PairingKind}"); + throw new Exception(); + } } } diff --git a/Src/Command/DiscoverDevices.cs b/Src/Command/DiscoverDevices.cs index 45adc6e..a6068eb 100644 --- a/Src/Command/DiscoverDevices.cs +++ b/Src/Command/DiscoverDevices.cs @@ -30,7 +30,7 @@ private static void PrintDevice(Device d) private static string GetType(Device d) { - return d.Type == Bluetooth.DeviceType.BluetoothLe ? "LE" : ""; + return d.Type == Bluetooth.DeviceType.BluetoothLE ? "LE" : ""; } private static string GetPairedStatus(Device d) diff --git a/Src/Command/PairDevice.cs b/Src/Command/PairDevice.cs index 1bef31e..ca82c5e 100644 --- a/Src/Command/PairDevice.cs +++ b/Src/Command/PairDevice.cs @@ -12,6 +12,10 @@ internal sealed class PairDeviceOptions : PairAndUnpairDeviceOptions [Option("discovery-time", Default = 10, HelpText = "how long to search for devices. Units: seconds")] public int DiscoveryTime { get; set; } + + [Option("pin", Default = "0000", + HelpText = "pin code to provide to a device if it requires it for pairing")] + public string Pin { get; set; } } internal sealed class PairDevice @@ -20,11 +24,11 @@ public static void Execute(PairDeviceOptions opts) { if (!string.IsNullOrEmpty(opts.Mac)) { - PairWithMac(new MacAddress(opts.Mac), opts.DiscoveryTime, opts.Type); + PairWithMac(new MacAddress(opts.Mac), opts.DiscoveryTime, opts.Type, opts.Pin); } else if (!string.IsNullOrEmpty(opts.DeviceName)) { - PairWithName(opts.DeviceName, opts.DiscoveryTime, opts.Type); + PairWithName(opts.DeviceName, opts.DiscoveryTime, opts.Type, opts.Pin); } else { @@ -32,13 +36,13 @@ public static void Execute(PairDeviceOptions opts) } } - private static void PairWithMac(MacAddress mac, int discoveryTime, Utils.DeviceType deviceType) + private static void PairWithMac(MacAddress mac, int discoveryTime, Utils.DeviceType deviceType, string pin) { var devices = DeviceFinder.FindDevicesByMac(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), mac, deviceType); if (devices.Count == 1) { - DevicePairer.PairDevice(devices[0]); + DevicePairer.PairDevice(devices[0], pin); return; } @@ -52,18 +56,18 @@ private static void PairWithMac(MacAddress mac, int discoveryTime, Utils.DeviceT $"{devices.Count} devices with the mac '{mac}' found. Don't know which one to choose"); } - private static void PairWithName(string name, int discoveryTime, Utils.DeviceType deviceType) + private static void PairWithName(string name, int discoveryTime, Utils.DeviceType deviceType, string pin) { var devices = DeviceFinder.FindDevicesByName(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), name, deviceType); if (devices.Count == 1) { - DevicePairer.PairDevice(devices[0]); + DevicePairer.PairDevice(devices[0], pin); return; } - if (devices.Count == 2 && devices[0].Type == Bluetooth.DeviceType.BluetoothLe && devices[1].Type == Bluetooth.DeviceType.BluetoothLe) + if (devices.Count == 2 && devices[0].Type == Bluetooth.DeviceType.BluetoothLE && devices[1].Type == Bluetooth.DeviceType.BluetoothLE) { - HandleSituation_2_BluetoothLe_devices_with_the_same_name_found(devices[0], devices[1]); + HandleSituation_2_BluetoothLe_devices_with_the_same_name_found(devices[0], devices[1], pin); return; } @@ -71,7 +75,7 @@ private static void PairWithName(string name, int discoveryTime, Utils.DeviceTyp } private static void HandleSituation_2_BluetoothLe_devices_with_the_same_name_found(Device device1, - Device device2) + Device device2, string pin) { // BLuetooth LE devices use mac randomization, which can lead to the situation when // 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 Console.WriteLine($"2 devices with the same name found: \"{oldDevice}\" (paired) and \"{newDevice}\""); Console.WriteLine("Assume that the device changed its mac address"); DevicePairer.UnpairDevice(oldDevice); - DevicePairer.PairDevice(newDevice); + DevicePairer.PairDevice(newDevice, pin); return; } diff --git a/Src/Command/Utils/DeviceType.cs b/Src/Command/Utils/DeviceType.cs index d9410a1..c6b8d6c 100644 --- a/Src/Command/Utils/DeviceType.cs +++ b/Src/Command/Utils/DeviceType.cs @@ -17,7 +17,7 @@ public static bool Equals(DeviceType type1, Bluetooth.DeviceType type2) } if ( type1 == DeviceType.Bluetooth && type2 == Bluetooth.DeviceType.Bluetooth - || type1 == DeviceType.BluetoothLE && type2 == Bluetooth.DeviceType.BluetoothLe) + || type1 == DeviceType.BluetoothLE && type2 == Bluetooth.DeviceType.BluetoothLE) { return true; }