BLE and Python: How to build a simple BLE project on Linux with Python

Slides can be found here: https://drive.google.com/file/d/1rDkSKriobmW71ZMYU6pqdx7Yal1eUgXm/view?usp=sharing

The problem that this talk is addressing is the difficulty of using Bluetooth Low Energy (BLE) with Python, particularly for those who are new to the protocol. One issue is that BLE is not necessarily beginner-friendly, with a steep learning curve that can be intimidating for those who are just starting out. Additionally, there are not many examples available for creating a BLE server using Python, which makes it difficult for people to learn and understand the process. This is most likely due to the fact that writing a BLE (GATT) server is often only done in professional contexts. Finally, complexity is added as one has to interact with the system Bluetooth stack which makes it more complicated, particularly on Linux where the use of DBus is required. Overall, these challenges can make it difficult for people to effectively use BLE and Python together.

The problem of using BLE with Python is relevant to the audience because BLE is a widely-used technology that allows users to add a variety of peripherals to their projects, both personal and professional. Over the years more devices support a configuration or use through BLE. For example, BLE is often used in home automation systems, wearable devices, and Internet of Things (IoT) applications. By understanding how to use BLE with Python, the audience can take advantage of the many possibilities that this technology offers and create innovative projects that leverage the capabilities of many different types of BLE devices.

In this talk, I will introduce the different technologies that are involved in using BLE with Python, including BLE itself, Bluez (the Linux Bluetooth stack), and DBus (a software system for inter-process communication). This is followed by a showcase of a simple GATT server example using Python, which will demonstrate how to use these technologies effectively. In addition to this, I will explain a possible development process for creating BLE projects with Python, including debugging tools and common pitfalls to avoid. Finally, I will point the audience toward further resources that they can use to continue learning about BLE and Python and to help them get started with their own projects.

This session took place in track Programming & Software Engineering and was classified suitable for novice domain / intermediate python by the speaker.

Transcript (auto)

Auto-generated from the recording utilizing Open-Source AI. Speaker labels (Speaker 1, Speaker 2) reflect diarization, not identity. Timestamps refer to the recording.

Speaker 1 [00:02]

Thank you very much. Welcome to my talk today. I'm very happy to give you a little introduction in Bluetooth Low Energy, Python, and how to build a simple project on Linux. A little bit about myself. As I said, my name is Bruno Vollmer. I'm the co-founder and CTO of BiPAD, which I'm going to talk more about later. my background is in pretty much standard computer science from RWTH Aachen and if you have want to know more about biped and everything else you'll find more information on my website as well. Little disclaimer there will be some slides with some more information you will find those also in the description of the talk I've built a little example because we're going to go through some code which you also find later and as a little point here I mean this the whole reason for this talk was me going through that journey from an absolute beginner to somebody having built something with BLE, so I'm not an expert. I would say I pretty much understand everything now, it works in practice, but I'm also not part of Blues or the special interest group which is doing the Bluetooth standard. So what are we talking about today? This whole talk is about a practical perspective on Linux, Python and Bluetooth, but there is still some core concepts that everybody needs to understand to understand my examples later so there will be some basic introduction into Bluetooth, low energy. We'll then go through some code, look at something and then I'm going to finish off with some practical tips, tools and pitfalls to avoid so that you don't have to sit there for hours wondering why stuff doesn't work. We won't have in time to go too much into the code example itself, that's That's why it's on GitHub. We won't have time to go into the protocol details as well. I'm happy to explain some stuff afterwards or answer a question, and there's also no time to go into any kind of communication optimization. Okay, as a little motivation where I'm coming from and why I'm working with this, as I said before, I'm the co-founder of BiPET, which is a device for blind and visually impaired people. The idea is basically you wear it over the shoulders. It consists of a camera module, a computer, and a battery in the back, and the idea is that it can detect, track, and predict the trajectories of all obstacles in your environment, and additionally give you also navigational GPS instructions, so basically to tell you how to go from A to B if you cannot see. And how do we do that is very similar to how a parking assistant of a car would work. So if we detect an obstacle in a certain direction, we will play from that direction a sound which indicates the obstacle with a repetition rate to how close that obstacle is. On top of that, we layer the navigation information and all of that you hear through open headphones, for example, bone conduction headphones where you can still hear your environment, but you also hear the audio cues that we give you. And when we started working on this two years ago, we quite quickly realized that we will need some sort of interface or communication mechanism to configure the device, to work with it, which is not the device itself. So we decided, okay, we need a way to communicate between a phone and the device itself. And if you look at, there is multiple options out there. We decided, okay, we need some sort of requirements. Fairly simple list. It has to be something that we can quickly prototype together to try it. It has to be quite energy efficient because our device is fairly battery restricted. So you don't want like, you want the battery to be used for something else, for mainly the vision perception processing. And then you want it to be fast, because we also wanted to use the app to display some real-time debug information. And I mean, it will not come as a surprise what we decided for. It's like Bluetooth Flow Energy was, in the end, the main reason. And the question I get at this point is usually, why not Bluetooth itself? The main reason being, if you want to work with classic Bluetooth on devices that are produced by Apple, you better have a few lawyers ready and a lot of spare time to prepare this because there's a bunch of legal hoops you have to jump through, while BLE in itself is not at all restricted by Apple. So that's why, including all the other reasons, we decided for BLE. When I then started my journey into BLE, I quite quickly realized there's a lot of information available for implementing. So what I will explain later is there's two sides to the communication in BLE. And what I realized, there's a lot of information and frameworks available to do the site that runs on the phone. But there's not really a lot of information available for running the site that runs on the peripheral. So on the side in case of a device or whatever, a smartwatch whatsoever. And so to get that, like to avoid that somebody else has to go through the same struggle and to give bit of a starting point, that was the basic idea of this talk today. So, as promised, a little reminder of how BLE works and what the core concepts are about. Just to where BLE comes from, BLE is basically a lightweight subset of classic Bluetooth. Classic Bluetooth is what you know, for example, what streams audio to your headphones and it was introduced in the Bluetooth 4.0 standard which is governed by the Bluetooth Special Interest Group. It's an industry group where a lot of like big companies are part of. And the idea was basically to give a simple communication mechanism to communicate between devices and modern mobile platforms. This also includes laptops, but it was mainly designed for phones. And the main difference here is instead of having an open stream that continuously pushes data back and forth, we have a device that sleeps between communications and those communications are also designed to be maximum a few seconds long and that has as a two main side effects is we save a lot of battery so we can run it on very battery restricted devices as well as the fact that the through the design of the protocol our connection and build up of the connection is a lot faster than with classic Bluetooth it does have the big downside though that we can send only very limited data one One of the few things you need to know within BLE is the generic access profile, GAP, which basically controls how connections and advertising works in Bluetooth. This GAP defines two types of devices, which is a central and a peripheral. Central is here the example for a phone, a powerful device with a lot of battery, and then we have a peripheral which could be smartwatch, beacon, all kinds of light bulbs, whatever. And the idea here is that through the definition of the GAP, we only allow to advertise and then later on also connect between a peripheral and a central. There's no way to connect between two peripherals, and there is also no way to connect between two centrals. This is important to know. What it does allow, though, is that one peripheral can advertise to multiple centrals at the same time. And that's basically the idea behind beacons, because if you have, I don't know, some smart homes have these beacons. The idea is basically that because you don't even have to connect to them, you can advertise to multiple phones at the same time, and that's how Bluetooth beacons work. The second important definition is that of the generic attribute profile, or short GATT, which defines how once we have found our device we want to connect to, the whole connection process works. So it describes how the two devices can transfer data back and forth, and I think the first important thing to know is that once you have decided to connect this connection is exclusive so you cannot connect a peripheral to two centrals at the same time but you can only have that once. Then what you have is what is called the attribute protocol ATT and I'm going to stop with these weird as long names for stuff after this which defines basically how the data is shared between those devices and what the structure of this is and the ATT basically has two main definitions and I think those are the most important things to remember from today if you Billy's new to you a service and a characteristic where the service is used to break up data into logical entities and then a service can hold multiple characteristics and a characteristic is then what actually encapsulates the data the single data point so this could be a value imagine like a heartbeat, a battery value, a small string, or some like small array. And this data together is hold in a simple lookup table where each of the services and the characteristics have a UUID that in most cases 128 bits long if it's custom, but the Bluetooth special interest group because we have really something that is really restricted on all the messages you can send, they also define some standard services, standard characteristics and those have a custom 16-bit UUID. So if for example you want to build a heartbeat sensor, the heartbeat service and characteristic have a predefined 16-bit address which is better because then you can send more stuff, other stuff that you want to send. The way it works basically and don't be, I just replaced the names, so basically what we're talking about from now on until the end of the talk is the GATT client and GATT server which I'm I'm just going to call client and server for simplicity, we're still talking about phone and peripheral, is that the phone initiates the connection and then the server or the peripheral actually holds all the information on what kind of data it wants to share, right? And so this is the important part to know, is that you define the data within the server and then you send it back. sends it back it's in reality it's a bit more complicated but I simplified it here okay that's all the concepts you need to know there's obviously more to it but for this example that's all there is to know at the end of the talk there's a list long list of resource which you can go through endless amounts of PDFs if you're more interested in this now we are here to learn how to do that on Linux with Python first thing to know is this only works on Linux doesn't work on macOS, it doesn't work on Windows like this. Basic idea here is we have in this case for example a Raspberry Pi which has a Bluetooth controller, we have Linux running on it and what we use is the Bluetooth stack that is part of the Linux kernel which is called Blues. Blues implements all that logic I told you about, it also implements a lot of more stuff, Bluetooth classic stuff and so we want from our application to talk to Blues to tell it hey create a server whatsoever. We cannot do this directly but as it is I would say fairly common within the Linux kernel is we have to do that through a communication way which is called Dbus which is Dbus is a messaging oriented middleware which just allows multiple processes system or user processes in the Linux kernel to communicate with each other and the fair like basic idea is You put a message on the bus and then some other processes can pick that message up and do whatever they want with it Like little important thing to know because that's what's going to pop up in the examples later on quite a lot is The concept the three important concepts within D bus are service object and interface basically services Use what is read to wrap everything the object is actually what is owned by the process and then the interface is with an object it hurts to, so it's a method, a signal, or a variable. This is how it would look in code. This is strongly simplified, but we're defining here the descriptor class, a descriptor in the context of BLE is what every time you have a characteristic, you have a little text which describes what this characteristic is about. That is basically what the descriptor is. So we're extending the dbus object and then the object in itself then implements the dbus property interface which is used for blues to tell what kind of properties the descriptor has. I was not sure if I should do a live demo or not. Many people told me not to do it because it's probably going to break. So you will just have to trust me. The code worked before, I can also showcase it afterwards. But I'm not going to do the live demo, but we're just going to go through the code. Anyways, the demo would have been pretty boring because you just see some terminal output. Before I go into this general idea, this is one way to design it, right? This is my way that worked for us. This is the simplified version of this. I'm pretty sure there's multiple other ways to do it. In our setup here, what we have is We have our main process, which is super simple in the example, but basically this holds all the logic that is supposed to do something with the data. Then we have the BLE process, which initiates, sets up our server, tells Blues how our GATT server should look like, what characteristics and services we have. and then we basically have, I mean, the phone interacts with Blues but then interacts indirectly with those parts so that we can then communicate them back very classic with queues, right? This is one way to design this. The idea is pretty straightforward and I think the important thing to know is just that the whole BLE process that is based on the Dbus event loop because it's asynchronous and so the idea is basically that we use callbacks and queues. To get this into play and so if we look at our code I mean, this is the main structure, right? This is fairly straightforward. The only thing we're basically doing is we're creating the queue We're then creating the process We're starting it and then the only thing we do is we have a while loop going on and on just checking if there is something Within the queue there that would be the place where you place all kind of logic, whatever you want to do then We have our BLE process and here I think the important part to know is that this is where we create with all the DBus important things and then we create the service manager which is the interface which implements the interface where we actually define our GATT server and then we create an advertisement and here I mean you remember what I showed you about the objects which then implement interfaces and so here we have the interface which is the once again the properties interface which then gives all the information that for example our advertisement has and this could be this is a bunch of stuff that advertisement in BLE allows you it's I mean we've put some fake manufacturer data it's the service UIDs that we actually advertise in this case we just have one service which we advertise a name and all some other things that are not important right now. So we create this advertisement, and then the whole wrapper around the thing is what is called an application here. And so the application, once again, is the, like, is a Dbus object, and the important thing here to know, the function we're overwriting is the object, the getManagedObjects function, which just returns, like, every part, like, service and in every service it returns every characteristic and within every characteristic it returns every descriptor and that's basically all it does and then the interesting part comes this is where we can now create custom services where we add custom characteristics and we can add them to the application add them to the application initialize the advertisement register the application so all everything has to be added before we register the application and then run our blocking call here and the interesting part is in those four functions which we override because this is where the callbacks come into place in the main loop so every time somebody writes for example to a characteristic we will then have this function called where for example we do something super simple which is put that written value into the queue and you can do whatever you want with it. Same goes for the read value where at the moment we just set a default value to each characteristic, we just return that, and I think the important thing to notice here is that when you have what is called notification within Bluetooth Low Energy is where you notify the other side, hey, I've made a change to that peripheral, to that characteristic, that is based on a function which is continuously called. So what I'm doing here is I, every 10 milliseconds, I'm calling this input queue callback. And so that would be one way to implement the fact that you have this input queue where from our main process we can just, whenever something's ready, say, hey, write that value. Then you will have to build some logic that the service gives it to the right characteristic. But in the end, in this function, you can then check, hey, is there a new value available? If yes, then we'll just set that value so that on the next read it also works, and we set the properties changed, which will indicate to the other side, hey, there has been something happening. And that's basically the core idea of the whole project. And so if we go back to our presentation, I want to finish off a bit this with, like, tips tricks and tools because I found especially I mean with a lot of other things you can do with Python there is a lot there's a lot of examples tutorials available where they show you okay this is something how you can do this and this is this and I found this was not the case here and to avoid having been you in the same situation as us where we are completely confused what is happening and we don't really know how to debug this this is basically the idea here. The most important tool arguably is Bluetooth CTL, which is your command line interface with Blues. So basically that comes with Blues, so once you have Blues installed on your Linux machine, which all the standard Linuxes have by default, you can use Bluetooth CTL to do all kinds of operations with Bluetooth. You can do something as simple as powering on and off your Bluetooth, but you can also do stuff like scanning for devices and so on and you can actually create for example a GATT server just from the command line and this is important to know because Bluetooth CTL also just uses Dbus and the idea here really is that basically everything that Bluetooth CTL can do you can do in your application because once you've run Bluetooth CTL and in the second terminal window you turn on the Dbus monitoring which you have to tune a bit so that you don't get all the Dbus messages but just the ones you're interested in, you can actually just see what Bluetooth CTL does and then try to replicate that in your application. So it's basically here, for example, when we wanted to implement some pairing logic where you want to have, for example, ask for a pin or something, I don't know, when you connect to a car, Bluetooth, you have this always. Then what we just did is we replicated that behavior in Bluetooth CTL, looked at what it does under the hood with the dbus monitor and then had this as a starting point on where to attack this on the application side. If you want to go a bit lower level, deeper into it, you use a tool called btmon, also comes with blues, and it's basically your monitoring infrastructure to show you really the low-level HCI traces. First warning, it's quite extensive, so once you have a connection with a device, this will spend hundreds and hundreds of lines within seconds. And so this is only, I would say, usable if you look for something specific. This came in handy for us when we were especially looking on connection stability. So we had some problems with iOS being quite unstable with our device while Android was working fine. And so then we looked at the logs and see what could cause that. And this is always good to have as a backup to look into this. And then I just wanted to give some ideas on like what could be possible problems and what could be possible solutions. Biggest problem in the end is like it's not a joke actually restarting the Bluetooth service on your machine helps I would say in 80% of the cases. Once you have figured that out what I think the biggest thing was for us was okay the advertisement wasn't even showing up on our external device. So you have these test apps, right, which just show all the BLE stuff in your environment, you have it running, you have the app, it's not showing up. That would be basically something where I would monitor the DBus. Because DBus won't tell your application directly, hey, there's something wrong, there's no exception being thrown, but you can have a look within the locks and most of the times you just search for error or something similar to that and then you will find, okay, have Have you forgotten to define something, you miswritten something, or you did something wrong? The second thing I already told is basically once you have this a bit more complex setup between an app and a device and there is some bug in there and you don't know which side it is, what I would usually just do is take one of those test apps available for Android, for example, light blue, or iOS has also some, and then you would just custom, you could connect those to your device and then write custom values to like to each of the characteristics you can see if the definition of the characteristics is correct and so on and then finally if the communication is unstable or certain messages don't arrive I would just look at the Bluetooth monitoring and then some pitfalls at the end I'll just quickly go over it so you can hear all of them really be cautious about the fact that there is some max sizes defined for different parts of the messages sent, especially for the advertisement, for example, it is not possible to advertise two custom services at once. We found that out the hard way because there's not enough space in that message. Second thing is iOS and Android do not behave exactly the same on everything. They have both their own detailed implementations of BLE which I guess they didn't talk to each other but they behave differently. And the big thing here for us that was different is on Android, we do not actually pair the device. We just have the communication. It works fine. And on iOS, if you do not pair, the connection is super unstable. I cannot tell you right now what the reason is, but for example, there is something where you have to see how the different platforms behave, and it also is not enough to just check one or the other. And finally, there are some connection parameters for iOS, but that is also part of this. Thank you very much for listening. I hope it was clear and I'm open to give.

Speaker 2 [23:47]

Thank you so much, Bruno. I'm going to read out some questions on Slido. So is there any hope that Bluetooth on Linux will get better in the future?

Speaker 1 [23:58]

I mean, I have to say it's, I'm a macOS user myself on the computer side, but I guess they're actively working on this. So what you can see is, for example, Ubuntu is always quite far behind on the blues version, so there is a lot of newer versions available. So I would say if you're really annoyed by this, check out their newest, the newest blues versions, update them manually. I mean, I'm not taking any responsibility if it breaks something, but generally I would say there is Always they are actively working on this and they have a very active developer community on slack as well if you're interested in this

Speaker 2 [24:38]

Next question if ble isn't used for any long connections Then how would you for example flash firmware to a device or is it okay, but just not recommended?

Speaker 1 [24:48]

So yeah, that was one of the problems we had what I mean, yes, I would not recommend using BLE for anything data-intensive like this What we do is basically that the person over BLE indicates to the device Hey connect to the Wi-Fi then we do the update over Wi-Fi and then we disconnect the Wi-Fi again

Speaker 2 [25:09]

So Martin Hecker, who's sitting to my right, would like to know, can one device or computer be central and peripheral at the same time to ease development?

Speaker 1 [25:19]

I don't think that's possible, but I would not be a hundred percent certain. I think really to what I've seen so far is that you would really want like a big problem with Bluetooth is that you Really want to try out the actual connection to see to debug it So as I said, for example, what we did in the beginning was we worked a lot with Android only because I assumed please behave the same on iOS and I Tried it on iOS Nothing worked and it took quite some time to adjust it and to do some custom look and I'm I would recommend trying it Directly and I would say it's not possible, but I'm not entirely sure

Speaker 2 [26:02]

So another question you mentioned stability issues with iOS Is was it just a rebooted issue an Apple issue or a you issue?

Speaker 1 [26:14]

It was a combination of an Apple and us issue so The first thing that you like that is not I feel like that could be more proactively Communicated by Apple is the fact that Apple requires you to use like they say okay within a BLE connection There's some parameters you can set and they actively say if you don't set those we don't guarantee anything And so what they do is they would just randomly cut the connection and so on once you set those parameters there was also back from our side which we then found through bt-mon so that's why I'm putting it here but I would say it is a half-half

Speaker 2 [26:52]

James wants to know if I wanted to try this at home, do you know any good starting device that doesn't require VC money?

Speaker 1 [26:59]

Yeah, I mean in the end the but really the point of this was if you want to try this at home Take a Raspberry Pi and do it, right? That's the whole point of it is that I mean, I think Be that the reason why nobody or the way there's Known information about this is the fact that mostly this is done by big companies That produce those peripherals and it's not something that a lot of I would say like people want to do in their free time or open source is there because yeah there was not a lot of interest in our case it was a special case right but I would say super easily tried take a Raspberry Pi at home do it and then it should be fine yep The question was if I have experience with ESP32. I mean, I personally have not with this, but I would say as long, I mean, this stuff should be valid. I mean, I wrote down the version, But as long as blues is part of the kernel, which I guess it is in this case, but I'm not sure, right, then it should work, right? This is specifically targeted toward blues because blues is the most used Bluetooth stack within Linux. But I would assume that because their way to implement the GATT server is following the specification, everything else that would implement like an alternative driver and if they follow the same specification the idea would be the same. I mean the stuff like how characteristics and services work they're predefined so there's not a lot of room I would say to do this differently. I think there is also not much room for Android and iOS implementations. Fair point, fair point. No, fair point. I would say yes, you're right. It's probably still not going to fit exactly right But also with the naming, the DButh, I mean, you saw with DButh you have to give a specific path always, right? The naming will probably not fit because they will probably use another naming.

Speaker 2 [29:27]

Okay, sorry we have to stop now. Yeah, okay. Thank you everybody for your participation. Thank you again, Bruno

Bruno Vollmer

About — in the speaker's own words

I am the CTO of biped.ai, the AI Copilot for blind and visually impaired people that leverage advanced computer vision to guide them.

During my Masters at RWTH Aachen I worked at several Start-Ups as a software engineer. I've gained experience in Computer Vision and Machine Learning as well as general software engineering areas.

Social card for talk: BLE and Python: How to build a simple BLE project on Linux with Python