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 19, 2021

Hi! Can you PLEASE provide in depth steps on how you were able to accomplish this (are you using the nRF52840 Dongle / what steps you took to load the Zephyr OS / the code for sending receiving commands on hass io)!? This sounds fantastic and I was just about to attempt to undertake this project myself as there are no other available solutions seems like.

@HeadHodge
Copy link
Author

@e46lux,

I'll be happy to provide a writeup. I wasn't going to until someone expressed interest. So, I'm glad to have found at least one other who sees the great potential in Zephyr. I feel like Zephyr gives me the means to make a commercial like product, instead of the crappy one I can build with Bluez.

Give me a few days to get something together.

@e46lux
Copy link

e46lux commented Oct 20, 2021

🥳🎉 utterly and completely STOKED! I was using Android ADB learn send event for a while but those codes change on a whim and need to be re-learned every week it seems so that was never a long term solution. This would for sure remove the headache! If you can confirm that nRF52840 is the dongle that is working for you - I'm ordering and patiently waiting for your write up! 🙏😁

@HeadHodge
Copy link
Author

I've found 3 ways of using Zephyr that all work well...

  1. Program the compiled image onto any Zephyr supported soc board, like the nRF52840 dongle.. https://docs.zephyrproject.org/latest/boards/index.html#boards
  2. Use the Zephyr support for a native_posix_x86 board to create a linux executable that runs on any linux x86 box and uses the linux kernel distributed hci bluetooth controller to use the onboard bluetooth soc.
  3. Same as option 2 except provide your own usb hci controller and soc for any linux x86 box that doesnt have a supported onboard soc. https://www.amazon.com/dp/B08M1VJHVD?psc=1&ref=ppx_yo2_dt_b_product_details

I have a working nRF52840 dongle, but I'm personally using option 2 in my home using Ubuntu server 20.04 on a BRIX mini https://www.amazon.com/dp/B07DMM7Z7N?psc=1&ref=ppx_yo2_dt_b_product_details

The BRIX comes with an Intel bluetooth/wifi soc that works really well with Ubuntu, as opposed to the junk broadcom/realtec socs that come with many cheapo chinese mini boxes.

@e46lux
Copy link

e46lux commented Oct 20, 2021

Ordered the BT-8500 and planning on passing this USB directly to my Ubuntu 20.04.3 LTS x86_64 VM running hassio supervised (already doing this with my Zigbee, Z-wave, and Wyze bridge dongles). Keeping fingers crossed x86 means it will be able to run on x86_64.

I'm running a number of scripts through shell_command and rest_command along with authenticating to hassio with curl post cookie commands so I'm acquainted with vm to hassio communication (curious how websockets comes into play).

I'm unclear where you have your python scripts running and if you're sending commands hassio > linux > bluetooth > linux > hassio or if the bluetooth is passed directly to hassio (since you mention passing TTY to hassio and running script on linux); but really excited to find out!

@HeadHodge
Copy link
Author

I've verified that the BT-8500 works with Ubuntu 20.04 server running as VM on Win10 using VirtualBox. So think your config 'should' work.

Zephyr supports native_posix_x86 and native_posix_x86_64 boards. But no posix_arm boards yet.

Working on writeup now, warning: my coding is ok, my docs not so

@HeadHodge
Copy link
Author

HeadHodge commented Oct 21, 2021

@HeadHodge
Copy link
Author

@e46lux

I'm pretty much done with my writeup. Let me know if you need more info.

Good Luck!
Home

@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