Skip to content

Commit

Permalink
Fix "Same MAC, same name - only difference is LE #1":
Browse files Browse the repository at this point in the history
Add "--type" command line option to specify which (LE or nonLE) device to use.
  • Loading branch information
PolarGoose committed Dec 8, 2020
1 parent 7258e93 commit f17776a
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 80 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ Windows 10 1809 (10.0.17763) or higher<br>
* Discover devices: `BluetoothDevicePairing.exe discover`
* 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`
* 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`

# 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.

# Build
* Use `Visual Studio 2019` to open the solution file and work with the code
Expand Down
2 changes: 1 addition & 1 deletion Src/Command/DiscoverDevices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private static void PrintDevice(Device d)

private static string GetType(Device d)
{
return d.Type == DeviceType.BluetoothLe ? "LE" : "";
return d.Type == Bluetooth.DeviceType.BluetoothLe ? "LE" : "";
}

private static string GetPairedStatus(Device d)
Expand Down
43 changes: 10 additions & 33 deletions Src/Command/PairDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,55 +20,48 @@ public static void Execute(PairDeviceOptions opts)
{
if (!string.IsNullOrEmpty(opts.Mac))
{
PairWithMac(new MacAddress(opts.Mac), opts.DiscoveryTime);
PairWithMac(new MacAddress(opts.Mac), opts.DiscoveryTime, opts.Type);
}
else if (!string.IsNullOrEmpty(opts.DeviceName))
{
PairWithName(opts.DeviceName, opts.DiscoveryTime);
PairWithName(opts.DeviceName, opts.DiscoveryTime, opts.Type);
}
else
{
throw new Exception("Mac or device name must be specified");
}
}

private static void PairWithMac(MacAddress mac, int discoveryTime)
private static void PairWithMac(MacAddress mac, int discoveryTime, Utils.DeviceType deviceType)
{
var devices = DeviceFinder.FindDevicesByMac(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), mac);
var devices = DeviceFinder.FindDevicesByMac(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), mac, deviceType);

if (devices.Count == 1)
{
DevicePairer.PairDevice(devices[0]);
return;
}

if (devices.Count == 2 && devices[0].Type != devices[1].Type && devices[0].Name == devices[1].Name)
if (devices.Count == 2)
{
HandleSituation_2_Bluetooth_devices_with_the_same_mac_and_name_found(devices[0], devices[1]);
return;
throw new Exception(
$"2 devices with the mac '{mac}' found \"{devices[0]}\" and \"{devices[1]}\". Don't know which one to choose.\n");
}

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

private static void PairWithName(string name, int discoveryTime)
private static void PairWithName(string name, int discoveryTime, Utils.DeviceType deviceType)
{
var devices = DeviceFinder.FindDevicesByName(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), name);
var devices = DeviceFinder.FindDevicesByName(DeviceDiscoverer.DiscoverBluetoothDevices(discoveryTime), name, deviceType);
if (devices.Count == 1)
{
DevicePairer.PairDevice(devices[0]);
return;
}

if (devices.Count == 2 && devices[0].Type != devices[1].Type && devices[0].Mac.Equals(devices[1].Mac))
{
HandleSituation_2_Bluetooth_devices_with_the_same_mac_and_name_found(devices[0], devices[1]);
return;
}

if (devices.Count == 2 && devices[0].Type == DeviceType.BluetoothLe &&
devices[1].Type == 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]);
return;
Expand Down Expand Up @@ -98,21 +91,5 @@ private static void HandleSituation_2_BluetoothLe_devices_with_the_same_name_fou

throw new Exception($"2 unpaired devices with the same name found \"{device1}\" \"{device2}\". Don't know which one to choose.");
}

private static void HandleSituation_2_Bluetooth_devices_with_the_same_mac_and_name_found(Device device1,
Device device2)
{
Console.WriteLine(
$"Two devices with the same mac address and name but different bluetooth types found: \"{device1}\" and \"{device1}\". " +
"It is possible that it is one device which advertises itself as Bluetooth and BluetoothLE simultaneously." +
"Pair both of them.");

// for unknown reasons we first need to pair BluetoothLE one. Otherwise non LE device pairing fail
var leDevice = device1.Type == DeviceType.BluetoothLe ? device1 : device2;
var nonLeDevice = device1.Type == DeviceType.Bluetooth ? device1 : device2;

DevicePairer.PairDevice(leDevice);
DevicePairer.PairDevice(nonLeDevice);
}
}
}
52 changes: 12 additions & 40 deletions Src/Command/UnPairDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,66 +19,38 @@ public static void Execute(UnpairDeviceOptions opts)
{
if (!string.IsNullOrEmpty(opts.Mac))
{
UnpairByMac(new MacAddress(opts.Mac), opts.DiscoveryTime);
UnpairByMac(new MacAddress(opts.Mac), opts.DiscoveryTime, opts.Type);
}
else if (!string.IsNullOrEmpty(opts.DeviceName))
{
UnpairByName(opts.DeviceName, opts.DiscoveryTime);
UnpairByName(opts.DeviceName, opts.DiscoveryTime, opts.Type);
}
else
{
throw new Exception("Mac or device name must be specified");
}
}

public static void UnpairByMac(MacAddress mac, int discoveryTime)
public static void UnpairByMac(MacAddress mac, int discoveryTime, Utils.DeviceType deviceType)
{
var devices = DeviceFinder.FindDevicesByMac(DeviceDiscoverer.DiscoverPairedBluetoothDevices(discoveryTime), mac);

if (devices.Count == 1)
{
DevicePairer.UnpairDevice(devices[0]);
return;
}

if (devices.Count == 2 && devices[0].Type != devices[1].Type && devices[0].Name == devices[1].Name)
var devices = DeviceFinder.FindDevicesByMac(DeviceDiscoverer.DiscoverPairedBluetoothDevices(discoveryTime), mac, deviceType);
if (devices.Count > 1)
{
HandleSituation_2_Bluetooth_devices_with_the_same_mac_and_name_found(devices[0], devices[1]);
return;
throw new Exception($"{devices.Count} devices found, don't know which one to choose");
}

throw new Exception($"{devices.Count} devices found, don't know which one to choose");
DevicePairer.UnpairDevice(devices[0]);
}

public static void UnpairByName(string name, int discoveryTime)
public static void UnpairByName(string name, int discoveryTime, Utils.DeviceType deviceType)
{
var devices = DeviceFinder.FindDevicesByName(DeviceDiscoverer.DiscoverPairedBluetoothDevices(discoveryTime), name);

if (devices.Count == 1)
{
DevicePairer.UnpairDevice(devices[0]);
return;
}

if (devices.Count == 2 && devices[0].Type != devices[1].Type && devices[0].Mac.Equals(devices[1].Mac))
var devices = DeviceFinder.FindDevicesByName(DeviceDiscoverer.DiscoverPairedBluetoothDevices(discoveryTime), name, deviceType);
if (devices.Count > 1)
{
HandleSituation_2_Bluetooth_devices_with_the_same_mac_and_name_found(devices[0], devices[1]);
return;
throw new Exception($"{devices.Count} devices found, don't know which one to choose");
}

throw new Exception($"{devices.Count} devices found, don't know which one to choose");
}

private static void HandleSituation_2_Bluetooth_devices_with_the_same_mac_and_name_found(Device device1,
Device device2)
{
Console.WriteLine(
$"Two devices with the same mac address and name but different bluetooth types found: \"{device1}\" and \"{device1}\"." +
"It is possible that it is one device which advertises itself as Bluetooth and BluetoothLE simultaneously." +
"Unpair both of them.");

DevicePairer.UnpairDevice(device1);
DevicePairer.UnpairDevice(device2);
DevicePairer.UnpairDevice(devices[0]);
}
}
}
5 changes: 5 additions & 0 deletions Src/Command/Utils/CommonOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@ internal class PairAndUnpairDeviceOptions : CommonOptions
[Option("name", SetName = "name",
HelpText = "name of a bluetooth device (case sensitive)")]
public string DeviceName { get; set; }

[Option("type", Default = DeviceType.Any,
HelpText =
"type of bluetooth device. You can use this flag if you want to explicitly specify what type of bluetooth devices you want to work with. Possible values (case sensitive): Bluetooth, BluetoothLE, Any")]
public DeviceType Type { get; set; }
}
}
12 changes: 6 additions & 6 deletions Src/Command/Utils/DeviceFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ namespace BluetoothDevicePairing.Command.Utils
{
internal sealed class DeviceFinder
{
public static List<Device> FindDevicesByMac(List<Device> devices, MacAddress mac)
public static List<Device> FindDevicesByMac(List<Device> devices, MacAddress mac, DeviceType deviceType)
{
var res = devices.FindAll(d => d.Mac.Equals(mac));
var res = devices.FindAll(d => d.Mac.Equals(mac) && DeviceTypeExtensions.Equals(deviceType, d.Type));
if (res == null)
{
throw new Exception($"Couldn't find any devices with '{mac}' mac address");
throw new Exception($"Couldn't find any devices with '{mac}' mac address and device type '{deviceType}'");
}

return res;
}

public static List<Device> FindDevicesByName(List<Device> devices, string name)
public static List<Device> FindDevicesByName(List<Device> devices, string name, DeviceType deviceType)
{
var res = devices.FindAll(d => d.Name == name);
var res = devices.FindAll(d => d.Name == name && DeviceTypeExtensions.Equals(deviceType, d.Type));

if (res.Count == 0)
{
throw new Exception($"Couldn't find any devices with '{name}' name");
throw new Exception($"Couldn't find any devices with '{name}' name and device type '{deviceType}'");
}

return res;
Expand Down
28 changes: 28 additions & 0 deletions Src/Command/Utils/DeviceType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace BluetoothDevicePairing.Command.Utils
{
enum DeviceType
{
Bluetooth,
BluetoothLE,
Any
}

static class DeviceTypeExtensions
{
public static bool Equals(DeviceType type1, Bluetooth.DeviceType type2)
{
if (type1 == DeviceType.Any)
{
return true;
}

if ( type1 == DeviceType.Bluetooth && type2 == Bluetooth.DeviceType.Bluetooth
|| type1 == DeviceType.BluetoothLE && type2 == Bluetooth.DeviceType.BluetoothLe)
{
return true;
}

return false;
}
}
}

0 comments on commit f17776a

Please sign in to comment.