Skip to content

Commit d086e5c

Browse files
committed
* Implement a different strategy for pairing and unpairing devises using 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.
1 parent a660064 commit d086e5c

29 files changed

+616
-504
lines changed

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ charset = utf-8
88
indent_style = space
99
indent_size = 4
1010

11-
[*.{xml,wxs,cspro,yaml,props}]
11+
[*.{xml,wxs,csproj,yaml,props}]
1212
indent_size = 2

BluetoothDevicePairing.sln

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
1-
2-
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 17
4-
VisualStudioVersion = 17.0.32014.148
5-
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BluetoothDevicePairing", "src\BluetoothDevicePairing.csproj", "{728939B3-82EA-4471-9CC7-3403EAD1E537}"
7-
EndProject
8-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Files", "Files", "{F4EA3749-BB28-4437-8AD6-137D5EBC09DD}"
9-
ProjectSection(SolutionItems) = preProject
10-
.editorconfig = .editorconfig
11-
.gitattributes = .gitattributes
12-
.gitignore = .gitignore
13-
.github\workflows\build.ps1 = .github\workflows\build.ps1
14-
.github\workflows\continuous-integration-workflow.yaml = .github\workflows\continuous-integration-workflow.yaml
15-
README.md = README.md
16-
EndProjectSection
17-
EndProject
18-
Global
19-
GlobalSection(SolutionConfigurationPlatforms) = preSolution
20-
Debug|x86 = Debug|x86
21-
Release|x86 = Release|x86
22-
EndGlobalSection
23-
GlobalSection(ProjectConfigurationPlatforms) = postSolution
24-
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.ActiveCfg = Debug|x86
25-
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.Build.0 = Debug|x86
26-
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.ActiveCfg = Release|x86
27-
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.Build.0 = Release|x86
28-
EndGlobalSection
29-
GlobalSection(SolutionProperties) = preSolution
30-
HideSolutionNode = FALSE
31-
EndGlobalSection
32-
GlobalSection(ExtensibilityGlobals) = postSolution
33-
SolutionGuid = {AFDC97AA-6AE6-428D-A38E-4A4D6335FC0C}
34-
EndGlobalSection
35-
EndGlobal
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.0.32014.148
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BluetoothDevicePairing", "src\BluetoothDevicePairing.csproj", "{728939B3-82EA-4471-9CC7-3403EAD1E537}"
7+
EndProject
8+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Files", "Files", "{F4EA3749-BB28-4437-8AD6-137D5EBC09DD}"
9+
ProjectSection(SolutionItems) = preProject
10+
.editorconfig = .editorconfig
11+
.gitattributes = .gitattributes
12+
.gitignore = .gitignore
13+
.github\workflows\build.ps1 = .github\workflows\build.ps1
14+
.github\workflows\continuous-integration-workflow.yaml = .github\workflows\continuous-integration-workflow.yaml
15+
README.md = README.md
16+
EndProjectSection
17+
EndProject
18+
Global
19+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
20+
Debug|x86 = Debug|x86
21+
Release|x86 = Release|x86
22+
EndGlobalSection
23+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
24+
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.ActiveCfg = Debug|x86
25+
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Debug|x86.Build.0 = Debug|x86
26+
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.ActiveCfg = Release|x86
27+
{728939B3-82EA-4471-9CC7-3403EAD1E537}.Release|x86.Build.0 = Release|x86
28+
EndGlobalSection
29+
GlobalSection(SolutionProperties) = preSolution
30+
HideSolutionNode = FALSE
31+
EndGlobalSection
32+
GlobalSection(ExtensibilityGlobals) = postSolution
33+
SolutionGuid = {AFDC97AA-6AE6-428D-A38E-4A4D6335FC0C}
34+
EndGlobalSection
35+
EndGlobal

README.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# BluetoothDevicePairing
2-
Console utility to discover and pair/connect Bluetooth and Bluetooth LE devices.
2+
Console utility to discover and pair or connect to Bluetooth and Bluetooth Low Energy devices.
33

44
# System requirements
55
Windows 10 1809 (10.0.17763) or higher
@@ -15,40 +15,40 @@ BluetoothDevicePairing.exe discover
1515
```
1616
* Pair and connect to a device using its mac address:
1717
```
18-
BluetoothDevicePairing.exe pair --mac 12:34:56:78:9A:BC
18+
BluetoothDevicePairing.exe pair-by-mac --mac 12:34:56:78:9A:BC --type Bluetooth
1919
```
2020
* Pair and connect to a device using its name:
2121
```
22-
BluetoothDevicePairing.exe pair --name "name of device"
22+
BluetoothDevicePairing.exe pair-by-name --name "MX Ergo" --type BluetoothLE
2323
```
24-
* Pair and connect to a device using its name/mac and device type:
24+
* Pair and connect to a device using its name and pin code:
2525
```
26-
BluetoothDevicePairing.exe pair --name "name of device" --type BluetoothLE
26+
BluetoothDevicePairing.exe pair-by-name --name "Device name" --type BluetoothLE --pin 1234
2727
```
28-
* Pair and connect to a device using its name/mac and pin code:
28+
* Pair and connect to a device using its mac and pin code:
2929
```
30-
BluetoothDevicePairing.exe pair --mac 12:34:56:78:9A:BC --pin 1234
30+
BluetoothDevicePairing.exe pair-by-mac --mac 12:34:56:78:9A:BC --type Bluetooth --pin 1234
3131
```
3232
* Unpair a device using its mac address:
3333
```
34-
BluetoothDevicePairing.exe unpair --mac 12:34:56:78:9A:BC
34+
BluetoothDevicePairing.exe unpair-by-mac --mac 12:34:56:78:9A:BC --type Bluetooth
3535
```
3636
* Unpair a device using its name:
3737
```
38-
BluetoothDevicePairing.exe unpair --name "name of device"
39-
```
40-
* Unpair a device using its name/mac and device type:
41-
```
42-
BluetoothDevicePairing.exe unpair --mac 12:34:56:78:9A:BC --type Bluetooth
38+
BluetoothDevicePairing.exe unpair-by-name --name "MX Ergo" --type BluetoothLE
4339
```
4440

4541
# How it works
4642
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.
4743

48-
# Tips and tricks
49-
* Bluetooth LE devices use mac address randomisation, therefore it is not reliable to pair them using mac address. Use pairing by name instead.
50-
* 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.
51-
* 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.
44+
## Device pairing by mac
45+
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.
46+
47+
## Device pairing by name
48+
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.
49+
50+
# Return values
51+
In case of failure the command returns value `-1`. In case of success the `0` is returned.
5252

5353
# Build
5454
* Use `Visual Studio 2022` to open the solution file and work with the code

src/Bluetooth/Adapters/Adapter.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
3+
namespace BluetoothDevicePairing.Bluetooth.Adapter
4+
{
5+
internal sealed class Adapter
6+
{
7+
private readonly Windows.Devices.Enumeration.DeviceInformation adapterInfo;
8+
private readonly Windows.Devices.Bluetooth.BluetoothAdapter adapterDevice;
9+
private readonly Windows.Devices.Radios.Radio radio;
10+
11+
public Windows.Devices.Radios.RadioState State => radio.State;
12+
public string Name => adapterInfo.Name;
13+
public AdapterMacAddress MacAddress { get; }
14+
public bool IsDefault { get; }
15+
16+
public Adapter(Windows.Devices.Enumeration.DeviceInformation bluetoothAdapterInfo,
17+
AdapterMacAddress defaultAdapterMacAddress)
18+
{
19+
adapterInfo = bluetoothAdapterInfo;
20+
adapterDevice = Windows.Devices.Bluetooth.BluetoothAdapter.FromIdAsync(bluetoothAdapterInfo.Id).GetAwaiter().GetResult();
21+
radio = adapterDevice.GetRadioAsync().GetAwaiter().GetResult();
22+
MacAddress = new AdapterMacAddress(adapterDevice);
23+
IsDefault = MacAddress.Equals(defaultAdapterMacAddress);
24+
}
25+
26+
public override string ToString()
27+
{
28+
return $"name:'{Name}' mac:'{MacAddress}' state:'{State}'";
29+
}
30+
}
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace BluetoothDevicePairing.Bluetooth.Adapter
6+
{
7+
internal static class AdapterFinder
8+
{
9+
public static Adapter FindDefaultAdapter()
10+
{
11+
return FindBluetoothAdapters().Where(adapter => adapter.IsDefault).Single();
12+
}
13+
14+
public static IEnumerable<Adapter> FindBluetoothAdapters()
15+
{
16+
var macOfDefaultAdapter = GetMacAddressOfDefaultAdapter();
17+
return Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(Windows.Devices.Bluetooth.BluetoothAdapter.GetDeviceSelector()).GetAwaiter().GetResult()
18+
.Select(info => new Adapter(info, macOfDefaultAdapter))
19+
.ToList();
20+
}
21+
22+
private static AdapterMacAddress GetMacAddressOfDefaultAdapter()
23+
{
24+
var defaultAdapter = GetDefaultAdapter();
25+
return new(defaultAdapter);
26+
}
27+
28+
private static Windows.Devices.Bluetooth.BluetoothAdapter GetDefaultAdapter()
29+
{
30+
return Windows.Devices.Bluetooth.BluetoothAdapter.GetDefaultAsync().GetAwaiter().GetResult();
31+
}
32+
}
33+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Linq;
3+
using Windows.Devices.Bluetooth;
4+
5+
namespace BluetoothDevicePairing.Bluetooth.Adapter
6+
{
7+
internal sealed class AdapterMacAddress : IEquatable<AdapterMacAddress>
8+
{
9+
public string Address { get; }
10+
11+
public AdapterMacAddress(BluetoothAdapter adapter)
12+
{
13+
Address = string.Join(":", BitConverter.GetBytes(adapter.BluetoothAddress)
14+
.Reverse()
15+
.Skip(2)
16+
.Select(b => b.ToString("x2")));
17+
}
18+
19+
public override string ToString()
20+
{
21+
return Address;
22+
}
23+
24+
public bool Equals(AdapterMacAddress other)
25+
{
26+
if (other is null)
27+
{
28+
return false;
29+
}
30+
31+
if (ReferenceEquals(this, other))
32+
{
33+
return true;
34+
}
35+
36+
return Address == other.Address;
37+
}
38+
39+
public override bool Equals(object obj)
40+
{
41+
return ReferenceEquals(this, obj) || obj is AdapterMacAddress other && Equals(other);
42+
}
43+
44+
public override int GetHashCode()
45+
{
46+
return Address != null ? Address.GetHashCode() : 0;
47+
}
48+
}
49+
}

src/Bluetooth/Device.cs

Lines changed: 0 additions & 72 deletions
This file was deleted.

src/Bluetooth/DeviceDiscoverer.cs

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)