Skip to content

Commit

Permalink
* Implement a different strategy for pairing and unpairing devises us…
Browse files Browse the repository at this point in the history
…ing a mac address. Device discovering phase before pairing is no longer needed.

* Improve console interface
* Require providing type of a bluetooth device for pairing and unpairing to avoid collisions when devices have the same name and mac address but different device types.
  • Loading branch information
PolarGoose committed Jan 16, 2022
1 parent a660064 commit d086e5c
Show file tree
Hide file tree
Showing 29 changed files with 616 additions and 504 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ charset = utf-8
indent_style = space
indent_size = 4

[*.{xml,wxs,cspro,yaml,props}]
[*.{xml,wxs,csproj,yaml,props}]
indent_size = 2
70 changes: 35 additions & 35 deletions BluetoothDevicePairing.sln
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BluetoothDevicePairing", "src\BluetoothDevicePairing.csproj", "{728939B3-82EA-4471-9CC7-3403EAD1E537}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Files", "Files", "{F4EA3749-BB28-4437-8AD6-137D5EBC09DD}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
.github\workflows\build.ps1 = .github\workflows\build.ps1
.github\workflows\continuous-integration-workflow.yaml = .github\workflows\continuous-integration-workflow.yaml
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.ActiveCfg = Debug|x86
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.Build.0 = Debug|x86
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.ActiveCfg = Release|x86
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AFDC97AA-6AE6-428D-A38E-4A4D6335FC0C}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BluetoothDevicePairing", "src\BluetoothDevicePairing.csproj", "{728939B3-82EA-4471-9CC7-3403EAD1E537}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Files", "Files", "{F4EA3749-BB28-4437-8AD6-137D5EBC09DD}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitattributes = .gitattributes
.gitignore = .gitignore
.github\workflows\build.ps1 = .github\workflows\build.ps1
.github\workflows\continuous-integration-workflow.yaml = .github\workflows\continuous-integration-workflow.yaml
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.ActiveCfg = Debug|x86
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.Build.0 = Debug|x86
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.ActiveCfg = Release|x86
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AFDC97AA-6AE6-428D-A38E-4A4D6335FC0C}
EndGlobalSection
EndGlobal
34 changes: 17 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# BluetoothDevicePairing
Console utility to discover and pair/connect Bluetooth and Bluetooth LE devices.
Console utility to discover and pair or connect to Bluetooth and Bluetooth Low Energy devices.

# System requirements
Windows 10 1809 (10.0.17763) or higher
Expand All @@ -15,40 +15,40 @@ BluetoothDevicePairing.exe discover
```
* Pair and connect to a device using its mac address:
```
BluetoothDevicePairing.exe pair --mac 12:34:56:78:9A:BC
BluetoothDevicePairing.exe pair-by-mac --mac 12:34:56:78:9A:BC --type Bluetooth
```
* Pair and connect to a device using its name:
```
BluetoothDevicePairing.exe pair --name "name of device"
BluetoothDevicePairing.exe pair-by-name --name "MX Ergo" --type BluetoothLE
```
* Pair and connect to a device using its name/mac and device type:
* Pair and connect to a device using its name and pin code:
```
BluetoothDevicePairing.exe pair --name "name of device" --type BluetoothLE
BluetoothDevicePairing.exe pair-by-name --name "Device name" --type BluetoothLE --pin 1234
```
* Pair and connect to a device using its name/mac and pin code:
* Pair and connect to a device using its mac and pin code:
```
BluetoothDevicePairing.exe pair --mac 12:34:56:78:9A:BC --pin 1234
BluetoothDevicePairing.exe pair-by-mac --mac 12:34:56:78:9A:BC --type Bluetooth --pin 1234
```
* Unpair a device using its mac address:
```
BluetoothDevicePairing.exe unpair --mac 12:34:56:78:9A:BC
BluetoothDevicePairing.exe unpair-by-mac --mac 12:34:56:78:9A:BC --type Bluetooth
```
* 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
BluetoothDevicePairing.exe unpair-by-name --name "MX Ergo" --type BluetoothLE
```

# How it works
The program uses [Windows.Devices.Enumeration API](https://docs.microsoft.com/en-us/uwp/api/Windows.Devices.Enumeration?redirectedfrom=MSDN&view=winrt-22000) to work with 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.
* 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.
## Device pairing by mac
The utility gets the default bluetooth adapter and generates the bluetooth device id using combination of bluetooth type, adapter mac address and device's mac address. Using this id, it is possible to request to pair or unpair the device.

## Device pairing by name
The utility discovers all available devices (for unpairing only paired devices are checked) and tries to find a device with the required name. After that pairing or unpairing is requested for found device. The command will fail if there are several devices with the same name.

# Return values
In case of failure the command returns value `-1`. In case of success the `0` is returned.

# Build
* Use `Visual Studio 2022` to open the solution file and work with the code
Expand Down
31 changes: 31 additions & 0 deletions src/Bluetooth/Adapters/Adapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

namespace BluetoothDevicePairing.Bluetooth.Adapter
{
internal sealed class Adapter
{
private readonly Windows.Devices.Enumeration.DeviceInformation adapterInfo;
private readonly Windows.Devices.Bluetooth.BluetoothAdapter adapterDevice;
private readonly Windows.Devices.Radios.Radio radio;

public Windows.Devices.Radios.RadioState State => radio.State;
public string Name => adapterInfo.Name;
public AdapterMacAddress MacAddress { get; }
public bool IsDefault { get; }

public Adapter(Windows.Devices.Enumeration.DeviceInformation bluetoothAdapterInfo,
AdapterMacAddress defaultAdapterMacAddress)
{
adapterInfo = bluetoothAdapterInfo;
adapterDevice = Windows.Devices.Bluetooth.BluetoothAdapter.FromIdAsync(bluetoothAdapterInfo.Id).GetAwaiter().GetResult();
radio = adapterDevice.GetRadioAsync().GetAwaiter().GetResult();
MacAddress = new AdapterMacAddress(adapterDevice);
IsDefault = MacAddress.Equals(defaultAdapterMacAddress);
}

public override string ToString()
{
return $"name:'{Name}' mac:'{MacAddress}' state:'{State}'";
}
}
}
33 changes: 33 additions & 0 deletions src/Bluetooth/Adapters/AdapterFinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace BluetoothDevicePairing.Bluetooth.Adapter
{
internal static class AdapterFinder
{
public static Adapter FindDefaultAdapter()
{
return FindBluetoothAdapters().Where(adapter => adapter.IsDefault).Single();
}

public static IEnumerable<Adapter> FindBluetoothAdapters()
{
var macOfDefaultAdapter = GetMacAddressOfDefaultAdapter();
return Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Devices.Bluetooth.BluetoothAdapter.GetDeviceSelector()).GetAwaiter().GetResult()
.Select(info => new Adapter(info, macOfDefaultAdapter))
.ToList();
}

private static AdapterMacAddress GetMacAddressOfDefaultAdapter()
{
var defaultAdapter = GetDefaultAdapter();
return new(defaultAdapter);
}

private static Windows.Devices.Bluetooth.BluetoothAdapter GetDefaultAdapter()
{
return Windows.Devices.Bluetooth.BluetoothAdapter.GetDefaultAsync().GetAwaiter().GetResult();
}
}
}
49 changes: 49 additions & 0 deletions src/Bluetooth/Adapters/AdapterMacAddress.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Linq;
using Windows.Devices.Bluetooth;

namespace BluetoothDevicePairing.Bluetooth.Adapter
{
internal sealed class AdapterMacAddress : IEquatable<AdapterMacAddress>
{
public string Address { get; }

public AdapterMacAddress(BluetoothAdapter adapter)
{
Address = string.Join(":", BitConverter.GetBytes(adapter.BluetoothAddress)
.Reverse()
.Skip(2)
.Select(b => b.ToString("x2")));
}

public override string ToString()
{
return Address;
}

public bool Equals(AdapterMacAddress other)
{
if (other is null)
{
return false;
}

if (ReferenceEquals(this, other))
{
return true;
}

return Address == other.Address;
}

public override bool Equals(object obj)
{
return ReferenceEquals(this, obj) || obj is AdapterMacAddress other && Equals(other);
}

public override int GetHashCode()
{
return Address != null ? Address.GetHashCode() : 0;
}
}
}
72 changes: 0 additions & 72 deletions src/Bluetooth/Device.cs

This file was deleted.

64 changes: 0 additions & 64 deletions src/Bluetooth/DeviceDiscoverer.cs

This file was deleted.

Loading

0 comments on commit d086e5c

Please sign in to comment.