Skip to main content

Bluetooth communication

What we need

To do all the Bluetooth things from in Unity, like connecting, pairing and controlling the media player, a bit of work is needed.

So we need some way to control all the things that are relevant for Bluetooth from in Unity.

How I did it

On Linux there is this nice command line tool bluetoothctl.

So I made a script that uses terminal commands inside of Unity for example this to get the devices.

public List<BluetoothDevice> ListConnectedDevices()
{
string devices = LinuxCommand.Run("bluetoothctl devices Connected");
return BluetoothParser.ParseDevices(devices);
}

And to get events like when a new device is available to connect I'm running an instance of bluetoothctl from in Unity using the Process class from System.Diagnostics.

So I wrote a script that has all the functions we need and events you can subscribe to. I did this by using string.Contains() it is probably not the most optimized, but it works fine.

How you can use it

If you are fine with it probably not being the most optimized code to do this you can just use mine.

I also have the project for Bluetooth Control on GitHub UnityBluetoothControl-Linux, so you can just download it and have a look how it works.

Code example

Here is a code sipped of how a part of the UI code could look like if you are using my BluetoothManager.cs script.

using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Mauznemo.LinuxBluetooth;

public class BluetoothUI : MonoBehaviour
{
[SerializeField] private Button scanButton;
[SerializeField] private Button lockButton;
[SerializeField] private TMP_Text lockButtonText;
[SerializeField] private TMP_Text scanButtonText;

[SerializeField] private DeviceEntry deviceEntryPrefab;
[SerializeField] private Transform deviceEntryParent;
[SerializeField] private Transform transformPaired;
[SerializeField] private Transform transformFound;

private bool blocked;

private void Start()
{
blocked = BluetoothManager.Instance.IsSoftBlocked();
lockButtonText.text = blocked ? "Bluetooth: Off" : "Bluetooth: On";

scanButton.onClick.AddListener(() =>
{
BluetoothManager.Instance.SetScan(true);
scanButtonText.text = "Scanning...";
});
lockButton.onClick.AddListener(() =>
{
blocked = !blocked;
BluetoothManager.Instance.SetBluetoothBlock(blocked);
lockButtonText.text = blocked ? "Bluetooth: Off" : "Bluetooth: On";
});

BluetoothManager.OnDeviceFound += HandleDeviceFound;
BluetoothManager.OnConfirmPasskey += HandleConfirmPasskey;

ShowPairedDevices();
}

private void HandleConfirmPasskey(string obj)
{
ModalWindow.Create().Init("Passkey", $"Confirm passkey: {obj}", ModalWindow.ModalType.YesNo, () =>
{
BluetoothManager.Instance.ConfirmPasskey();
}, () => { });
}

private void HandleDeviceFound((string macAddress, string name, bool paired) device)
{
int index;
if (device.paired)
{
index = transformPaired.GetSiblingIndex();
}
else
{
index = transformFound.GetSiblingIndex();
}

DeviceEntry deviceEntry = Instantiate(deviceEntryPrefab, deviceEntryParent);
deviceEntry.gameObject.SetActive(true);
deviceEntry.transform.SetSiblingIndex(index + 1);
deviceEntry.Init(new BluetoothDevice
{
name = device.name,
macAddress = device.macAddress
});
}

private void ShowPairedDevices()
{
var devices = BluetoothManager.Instance.ListPairedDevices();
foreach (var device in devices)
{
BluetoothManager.Instance.HandleNewDevice(device.name, device.macAddress, true);
}
}
}

You can for example subscribe to the event BluetoothManager.OnDeviceFound to call a function when a new Bluetooth device is available.

Or this to get if Bluetooth is turn on or off:

blocked = BluetoothManager.Instance.IsSoftBlocked();
lockButtonText.text = blocked ? "Bluetooth: Off" : "Bluetooth: On";

And to turn it back on (toggle it) for example you can do:

blocked = !blocked;
BluetoothManager.Instance.SetBluetoothBlock(blocked);
lockButtonText.text = blocked ? "Bluetooth: Off" : "Bluetooth: On";

I also tried keeping the function names similar to the original ones from bluetoothctl.