Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save HeadHodge/b58ad47c27da8b9d7717fee16ec044f0 to your computer and use it in GitHub Desktop.
Save HeadHodge/b58ad47c27da8b9d7717fee16ec044f0 to your computer and use it in GitHub Desktop.

How I use Hassio as a Bluetooth: Keyboard\MediaControl\Mouse Combo

OVERVIEW:

Hello, 😀

PART 1:

I've been using Hassio for over a year now and am generally happy with it. I use it to control fireplaces, shades, lights, etc., but mainly use it to control my entertainment systems.

I'm a cord cutter and watch all my video with an Amazon FireTV 3rd gen stick and my audio with a Sonos surround sound bar.

For awhile, I was using a Harmony Hub to control both FireTV and Sonos devices with Hassio. But I wasn't happy with the performance and stability with using the Hassio/Harmony units together. It seemed like I was always having to reboot both to keep them talking to each other.

So I switched to using the Hassio android addon for controlling the FireTV and the Sonos addon for my soundbar. It generally worked ok, but because the android addon uses android's ADB over internet interface, it was very and frustratingly unstable. Every day my FireTV would sleep and disconnecting the addon. To reconnect I would have to reboot the FireTV and Hassio to reconnect them. What a major PITA!

FireTV allows for 3rd party bluetooth keyboards to connect to and control it. But other than the Harmony Hub, I could find no other way for Hassio to control the FireTV via bluetooth. So I was stuck deciding to go back to using Harmony or continue with usibg ADB, both bad decisions having to pick the lesser of two evils. :(

Normally I'm basically a retired lazy slob, but I was unhappy enough that I sucked it up and decided to try and make my own Hassio/FireTV bluetooth interface. Not knowing anything about Bluetooth, I didn't realize how long and hard that would ultimately take.

My first attempt was to try using Bluez. Bluez is the official bluetooth stack for linux and is part of the linux kernel. After lots of effort I was eventually able to hack some Bluez API examples for a Heart Rate monitor and get something working (Whew). It worked and was speedy, but very difficult to pair with the FireTV with unstable connections causing me to frequently reboot and re-pair the devices. Rats, after all that, I was no better off than before. In my opinion, Bluez is not ready for prime, their docs and support are all terrible to non-existent :(

Sigh..... Not sure what to do now... When I was working with Bluez, one thing that kept popping up on Google was the term Nordic nRF. After looking into that some more, I discovered they were a semiconductor company making bluetooth wireless SOC chips. I wasn't inclined or felt able to work with raw deviceless chips, so almost threw in the towel. Then, much to my surprise, I found they sold a developers usb dongle (nRF52840 Dongle) and for only $10! https://www.mouser.com/ProductDetail/Nordic-Semiconductor/nRF52840-Dongle?qs=gTYE2QTfZfTbdrOaMHWEZg==&utm_source=OEMSECRETS&utm_medium=aggregator&utm_campaign=nRF52840-Dongle&utm_term=nRF52840DONGLE&utm_content=Nordic%20Semiconductor

Having no experience with ebedded MCU devices, I had to research how to do that. It turns out not to be too bad. They provide you with their own OS written in C code. You basically add your code, using their provided API(Sdk) then compile the code and use an utility to flash the whole thing onto the usb dongle.

Even though I could compile and flash ok, I couldn't figure out how to get the dongle to do what I wanted. It was just a little above my comprehension. :( I looked around some more and found that T.I. and Silicon Labs semiconducters also made similar SOCs and development kits. So I tried both of those too, but with much the same results. They each had their own proprietary OS and bluetooth stacks, none of which I could easily figure out. Rats....

On the verge of crying and worse, admitting defeat, I looked around some more looking for some sort of alternative. A few days later I ran across Zephyr. At first I couldn't figure out what it was without more research. Then I figured out it was a brand new OS, created by some heavy hitters, that is designed as the baby brother of linux, small enough to install and run on any emedded MCU device with the goal of replacing all the disparat ebedded Os's with a single standard linux like OS. So thinking about a standard OS to replace all the proprietary ones, i.e Nordic, TI, and Silicons Labs sounded appealing. Then 'Light Bulb', I wondered if it was something I could use.

I found that not only would the Zephyr OS run on my dev usb dongle, but they were heavily invested in bluetooth and provided their own stack. So I went to work to try and use it. Much to my surprise, working with Zephyr, compared to all the others, was like night and day. They provided just enough documentation and 'working' examples, to keep me chugging away for days on end. Yay!! :)

Finally, in less than a week, I had a working bluetooth server that served HID over BLE Gatt (aka HoG) to provide paired clients (in my case my FireTV stick) with standard HID Reports formatted for either a HID keyboard, or a HID media appliance controller, or a HID mouse. The desired key codes sent to the paired client are inputted to the ddongle via simple linux TTY ccommands.

I was overjoyed after using for a few weeks. Easy to pair using 'Just Works' connections. No codes or replies needed, it just quickly connects and pairs with the client device. No fuss no muss. It stores state and connection info into nvram, so it easily and quickly reconnects with the client device as needed. It communicates at 115200 baud and is speedy. I really feel like I'm using a true commercial product and very happy with it. Zephyr is 'the' way to go.

PART 2:

Compared to what I just went through, getting this to work with Hassio was easy peasy. :)

I wrote some simple python code that runs on the linux box that the usb dongle is plugged into. It connects to dongle via tty on a vitural ADC/CDC COM port at 115200 baud (mine is named ADCM0). Then I use pythons Web Sockets to connect to Hassio's websocket API and use it to subscribe to a custom Scripts service event, named 'publish_note', that I configured on Hassio in the cofiguration yaml file. An example of sending the custom event looks like:

hassio

In the example, I click on the run service button which in turn generates the publish_note event. Since my little python code is connected to Hassio and subscribed to the 'publish_note' event, the code is notified and receives the event via the web sockets connection.

It takes the events controlWord, in this exanple it's 'Ok', and looks it up in a table to get the equivalent HID report data needed to send to the client via the TTY connection. The client receives the HID report from the paired usb dongle and is fooled into thinking you just pressed the 'Ok' key on a keyboard or remote control.

With the FireTV on and on the Home the 'Ok' key selects whichever video is highlighted and starts playing the video.

Repeat sending new Hassio events as needed with various controlWords as needed to control the FireTV stick.

Whew that's it for now. Regards!

@e46lux
Copy link

e46lux commented Oct 24, 2021

@HeadHodge thanks so much for this!

At first I was getting an error at initializing Bluetooth

UART_0 connected to pseudotty: /dev/pts/2
*** Booting Zephyr OS build v2.7.0-rc1-5-g559135721732 ***
Start smartRemotes Ble Input
Uart initialized
Bluetooth init failed (err -5)
bleStart failed (err -1)

hciconfig
hci0: Type: Primary Bus: USB
BD Address: 08:BE:AC:26:66:F5 ACL MTU: 1021:6 SCO MTU: 255:12
DOWN
RX bytes:1389 acl:0 sco:0 events:90 errors:0
TX bytes:2896 acl:0 sco:0 commands:90 errors:0

With your install command you are getting the latest version which do not seem to work properly.

cmake --version
cmake version 3.21.3
python3 --version
Python 3.8.10
dtc --version
Version: DTC 1.5.0

cmake stated it was impossible to downgrade, so I had to revert my snapshot.

Ended up with a functional scenario using the following:

apt install cmake-data=3.20.0-0kitware1ubuntu20.04.1
apt install cmake=3.20.0-0kitware1ubuntu20.04.1

wget http://launchpadlibrarian.net/368667964/device-tree-compiler_1.4.6-1_amd64.deb
dpkg -i device-tree-compiler_1.4.6-1_amd64.deb

apt install --no-install-recommends git ninja-build gperf ccache dfu-util wget python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file make gcc gcc-multilib g++-multilib libsdl2-dev

even though python is running version 3.8.10.

I am able to to get the service up and running and it automagically re-connects to my Fire Stick TV after ubuntu reboot ! 🙌

Going forward need to figure out how to actually send commands using the python code you provided. I'll be delving into all these scripts you already have, but could you share an example of how you go about sending your publish_note using the python script? I'm still a bit hazy on where the table is being pulled from for the script to understand "convert Ok to this hex and and it to the bluetooth device".

Another question - is it possible to connect to multiple endpoints using 1 bluetooth adapter? How would you go about doing that?
If you need additional bluetooth adapters per device, would you just run multiple hogInput.exe's?

Amazing work!

@HeadHodge
Copy link
Author

@e46lux,

Awesome, glad you got it working. I'm very happy someone could replicate my work. Don't really understand what your initial problem was. The only time the Bluetooth wouldn't init for me is if the hci controller was powered UP instead of DOWN or the hci driver/hardware was no good.

You can pair to many peer clients but only one at a time. Use 5 usb controllers for 5 simultaneous connections

Start each controller using their hci number:
/smartRemotes/imports/bt-ble/hogInput.exe --bt-dev=hci0
/smartRemotes/imports/bt-ble/hogInput.exe --bt-dev=hci1
/smartRemotes/imports/bt-ble/hogInput.exe --bt-dev=hci2
/smartRemotes/imports/bt-ble/hogInput. exe --bt-dev=hci3
/smartRemotes/imports/bt-ble/hogInput.exe --bt-dev=hci4

This is the node you want that maps and drives the serial port for me:
\smartRemotes\nodes\ttyNode

You run it with python: #~ python3 -u /smartRemotes/nodes/ttyNode/ttyNode.py

@HeadHodge
Copy link
Author

@e46lux how's it going, did you get enough info to keep you rolling?

@and7ey
Copy link

and7ey commented Dec 4, 2023

@HeadHodge thanks for your research. I would like to emulate bluetooth keyboard from my Home Assistant OS (Bluez is used there) running on x86_64 pc (Intel n100, built-in bluetooth or I can try to use UGreen CM390 - RTL8761BU adapter).

Is there pre-compiled release of your project? Just to download it and try to emulate the keyboard.

@hoanglongutc
Copy link

Hello,
Have you tested connecting the bluetooth server (nRF52840 Dongle) to IOS (Iphone or Ipad)? Can IOS reconnect after bluetooth server restart?.
We hope you will share the results and if possible, please share the detailed installation steps, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment