A while ago I followed this article to turn a Raspberry Pi into a Bluetooth HID Keyboard emulator.
I recently tried to repeat this process on Raspbian Jessie and I found that I was unable to get it to work. After a bit of research I discovered that Jessie includes an upgraded version of Bluez, the Linux Bluetooth stack, and that a lot of the instructions in the article were no longer valid.
Here is my attempt to create an updated version of the emulator that will work with Bluez5 and Jessie.
(All credit to the original author of the Linux User Magazine article; I wouldn't have managed to get to the first step without following their instructions.)
Bluez 5 has substantially changed how the bluetooth daemon is configured, how SDP profiles are advertised and how Bluetooth pairing occurs. Therefore there are quite a few changes that need to be made to the process given in the original article and to the scripts.
I've also taken the liberty of introducing my own changes to the scripts to allow a more generic use than a simple keyboard forwarder - I've turned the Bluetooth keyboard emulation script into a DBUS service that will forward any keys it receives to the Bluetooth host. This simplifies the development of multiple clients of different types.
Here are the steps to get things up and running
Set up Raspberry PiObtain a Pi running Raspbian Jessie. Ensure the Pi is running the latest version.
>sudo apt-get update
>sudo apt-get upgrade
Install BluetoothThis step is the same process as for Step 03 of the original article.
> sudo apt-get install python-gobject bluez bluez-tools bluez-firmware python-bluez python-dev python-pip
> sudo pip install evdev
Bluetooth Daemon ConfigurationThis is where things start to diverge. Bluez 5 uses a different mechanism than Bluez 4 to configure plug-ins and SDP profiles. It is no longer possible to disable plug-ins using /etc/bluetooth/main.conf
Instead, I found that the easiest thing to do was to kill the bluetooth daemon and run it in the foreground
- Stop the background process
> sudo /etc/init.d/bluetooth stop
- Open a dedicated terminal and tun the bluetooth daemon in the foreground
> sudo /usr/sbin/bluetoothd --nodetach --debug -p time
Note; This will disable all bluetooth plug-ins except the time plug-in. I found this the easiest way to ensure that plug-ins were not interfering with the keyboard emulator. An improvement would be to identify and disable only the plug-ins that would conflict with the emulator code.
Download the codeClone the yaptb git reposutory
> git clone https://github.com/yaptb/BlogCode.git
The code for the bluetooth keyboard emulator in is in the /btkkeyboard directory. There are three subfolders
server - contains the bluetooth keyboard emulator code
dbus - contains a DBUS system bus configuration for the btkserver
keyboard - contains a btkserver client application that sends local keystrokes to the emulator
Configure DBUSMy reworked version of the keyboard emulator sets itself up as a DBUS system bus server. This allows client applications to use DBUS to send keystrokes to the emulator and allows the simple creation of multiple different types of clients.
For this to work, the DBUS system bus needs to be configured to add the btkserver API. This is enabled by copying a configuration file into the /etc/dbus-1/system.d folder
> cd BlogCode/btkeyboard/dbus
> sudo cp org.yaptb.btkkbservice.conf /etc/dbus-1/system.d
Depending on your system, you may need to manually enable your bluetooth device. The hciconfig utility can be used to control the bluetooth adapter.
>sudo hciconfig hcio
should list the status of your bluetooth adapter. If the status is UP and RUNNING then all is well, otherwise run the following command to enable it
> sudo hciconfig hcio up
Edit the Emulator Server CodeThe emulator server code (btkserver.py) needs to be updated with the Bluetooth Device address of your bluetooth adapter before it will work. First, use hciconfig to find the address:
>sudo hciconfig hcio
Then, use a text editor to edit the code and update the constant MY_ADDRESS in btk_server.py
> cd BlogCode/btkeyboard/server
> leafpad btk_server.py & Change the value of the constant MY_ADDRESS to be the same as the value returned from hciconfig and save the file.
Run Emulator ServerThe bluetooth emulator is a python script that is a modfied version of the one in the original article. The main changes I have made are to adapt to the Bluez5 profile mechanism for advertising the SDP record and to set up a DBUS api for interacting with the emulated keyboard. I've also tweaked the SDP record a little.
Because the script interacts with the system DBUS, it needs to be run as root.
> cd BlogCode/btkeyboard/server
> sudo python btkserver.py
(Remember to have the bluetooth deamon running in a separate terminal window before doing this)
If all goes well, you should see something like the following:
Before the keyboard can talk to a host, it needs to be paired. This can be tricky and I've spent a lot of time trying to get this to work smoothly. Through trial and error, here is the process I use (I am going to assume you are pairing with a Windows 10 host here)
1. Open (yet another) dedicated terminal window and run the bluetoothctl utility,
> sudo /usr/bin/bluetoothctl
2. Type the following commands, pressing enter after each
> agent on
> scan on
> discoverable on
(I am guessing that this puts the bluetooth device in page scan mode and sets up an agent for pairing. Probably time to RTFM to be honest).
You should see something like this:
3. Go to your host machine and look at the Bluetooth Settings. On Windows 10 this is achieved by
Start Menu -> Settings -> Devices -> Bluetooth
If all is going well, you should see the Raspberry Pi keyboard ready to pair:
Click the device and select pair. You will see a dialog with a passcode. Don't click anything yet.
3. Go back to the bluetoothctl window on the Pi and wait a few seconds, You should then be prompted to accept or reject the pairing request from the host:
4. Quickly go back to the Windows host and click OK. If everything has worked the keyboard should pair and Windows will start installing a keyboard driver for the emulator. You should also see a connection message in the btkserver window.
If you get this fair your keyboard emulator is set up and ready to use!
Note: The latest version of rasbian Jessie includes a Bluetooth widget on the desktop. This widget will attempt to 'hijack' the pairing process and will prompt you to complete process through a dialog window. Ignoring this message and using the process above seems to work. Once you have paired through the command line you can safely close this window.
Local Keyboard Mirroring
The code in the original article mirrored the local Pi keyboard events to the emulator. I've adapted this code and used it to create a client for the btkserver to do the same thing.
After setting up the emulator, open another terminal window (that makes 4) and run the keyboard mirroring client
> cd BlogCode/btkeyboard/keyboard
> sudo python kb_client.py
After running this program, any keys typed on the Pi should be mirrored to the Windows host:
Timeouts and DisconnectsSo far this works well, but the Windows Host seems to disconnect the keyboard after a period of inactivity, Unfortunately this means that you often need to restart the emulator and remove and re-add and re-pair the device in Windows to get it to reconnect.
I am still working through this issue, but things seem to improve if you switch the Raspberry Pi bluetooth device to local master mode.
> sudo hciconfig hcio lm master
Your mileage may vary on this. Hopefully someone let me know how to fix this issue. I'll post a follow up if I work it out.
I have written a follow-up to this post showing how to control the keyboard emulator from the Raspberry Pi GPIO bus