Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

Join us at AWS re:Invent 2024! Learn how to use MongoDB for AI use cases.
MongoDB Developer
C++
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
C++chevron-right

Adventures in IoT 5: Me and the Devil Bluez - Part 3

38 min • Published Jan 03, 2024
MongoDBTime seriesC++
Facebook Icontwitter iconlinkedin icon
Rate this video
star-empty
star-empty
star-empty
star-empty
star-empty
search
00:00:04Introduction
The presenter introduces the topic and explains the goal of the tutorial. He also gives a brief overview of the previous episode where they took the first steps to interact with the BLE device.
00:07:36Setting Up the Environment
The presenter explains how to set up the environment for the application. He discusses the use of the SDBUS C++ library and how to use it to send messages to the BLE device.
00:15:08Writing the Code
The presenter starts writing the code for the application. He creates a method to connect to the device and read values from it. He also explains how to use a mutex to protect the data shared among different threads.
00:22:40Testing the Application
The presenter tests the application. He encounters a problem with the BLE device connection and resolves it by using an ethernet cable and disabling the Wi-Fi.
00:30:12Resolving Challenges
The presenter discusses the challenges encountered during the process. He suggests using a USB dongle to ignore the internal hardware for better results.
00:37:44Conclusion
The presenter concludes the tutorial by summarizing the steps taken and the results achieved. He also gives a preview of the next episode where they will explore the alternative MQTT.
The main theme of the video is writing a C++ application to connect to a BLE device and read values from it.
🔑 Key Points
  • The presenter uses the SDBUS C++ library to interact with the BLE device.
  • The presenter creates a method to connect to the device and read values from it.
  • The presenter uses a mutex to protect the data shared among different threads.
  • The presenter uses a conditional variable to signal the main thread that the connection is ready.
  • The presenter encounters a problem with the BLE device connection and resolves it by using an ethernet cable and disabling the Wi-Fi.
  • The presenter suggests using a USB dongle to ignore the internal hardware for better results.
All MongoDB Videos

Full Video Transcript
[Music] in our last episode we spent some time taking the first steps to interact with thebass we use sdb us- C++ library to send messages to thebass and interact with Blu the Bluetooth implementation for Linux we did some friendly basic operations but we wanted to do some more and this is the time to do it in this episode we will try to finally connect and read from the sense so let's get cracking well that looks like progress to me but we're still missing the most important features we need to connect to the device and read values from it we should connect to the mle device from the closure that we use in subscribe to interfaces added and then we should stop scanning however that closure and the method scan and connect which is where the stop scanning should happen are running in two different threads we should find a way to inform the main thread scan and connect one that we have connected to the device so it can stop discovering devices we are going to use a mutex to protect the data that is shared among between these two threads and we will be using a conditional variable to Signal the main thread that the connection is ready is established we're going to declare the private method that we're going to use to connect to a device by name so let's get rid of terminal and let's declare it in the header so we go to heer and here we're going to have this new method that is going to be connect to device and then the object path that we have selected let me remind you that the object path is one part of the data that comes with a signal then it comes at the AR that may have a name so we will be using for the name and the path that we select will be used with this meth the thing is that we want to obtain that from the signal but we need to provide a name and that means that we are going to provide that name through the Constructor and instead of using this Constructor we're going to have this other one that Tes string as the requested sensor name okay now that we have this string we would also like to have a field that holds the data for the name so let's put that here as another string of the object and that will be set by The Constructor and once we have H connected to the selected device we will need another proxy like the two uh that we have already selected like these two and we are going to have this proxy here this proxy is going to be to the device itself okay so now that we have all the infrastructure let's go with the initialization let's go to the CBP and let's change the Constructor that we have so here we're going to have a different initialization let me get rid of the old feather for the method and we are using the Preamble here we don't know we cannot create the the device proxy because don't we don't know what the object path is going to be and even if we knew it we don't have access to it until our Bluetooth is scanning so we initially set it to n pointer so it is empty we cannot use it as for the device names we get that from the parameter that has been passed onto the Constructor okay so now that we have set the two new variables here we can go and Define this private me method let me go to the bottom of the file and here I'm going to create the method what am I going to do here well the thing that I would like to do is now that I have been pass uh a a path for the object that I want to connect to is to change to create actually the device proxy using the path that I have been provided with I am going to also use the service Blues H constant and that was use in the initial Constructor here but since we are going to use it in two places we don't want it here we wanted in the header file so let me go to the header file and let's create a new inline constant let's move this here that contains our rules here now this is available not only to the Constructor but also to the connect method okay so what do we do with that well in order to connect we need to use the device proxy that we have just created let's go there and go to the bottom of the file and here once I have created the proxy I'm going to use it I'm going to invoke a method in this case asynchronously and I'm going to use this connect method from this interface device and upon reply so asynchronously I will be invoking well the library will be invoking the connection call back that I will Define immediately I just print this to know that things have started but have not finished yet so now that we have that we are going to define the gants here the ones that we were using here the method connect and eace device and I would also like to define the closure so I do that here again I'm capturing the instance of the object that I'm working with and this closure is able to receive an error in case it occurs so if something goes wrong with the connection it will receive an error and I will be able to print information about that here the way I'm going to H to use this and I will complete the closure in a moment is when I have a name that matches one of the signals then I will try to conect back to it and if you remember the place I was checking for the names was here in the Subscribe two interface ated that I have this H expression checking that is a device and then I check in the dictionary whether it has a name or not so here I know that what the name is and what I'm going to do is is use this name in order to connect to it so if the name is the one that I have been H told to connect to through the Constructor then I will try to connect to it I will Brint the message and use the method that I have just created and that is all good but we would like to do a little bit more than just connecting once we have connected uh let me go back to the public method that we were using we were doing this we were subscribing to the interfaces that's where we will be connecting we enable scanning and we waited for some random time here T seconds and then we stop scanning what we would actually like to do is to know that we have connected to the device and then stop scanning right away so let's do that let's create the a variables that we are going to need fields that we are going to need in order to implement that functionality so here in the header I'm going to declare a few more fields in this case this is going to be a mutex so a mutual exclusion uh thing for us and a condition variable the condition variable allows us to signal from one place to another H and then we can use the consumer producer ER concurrency pattern in order to implement this so what we're going to do here is to have the right header in order to have this accepted compiled and with this in place we can use it from the method that we were using but before having the method H using it we would like to initialize it so we go to the implementation file and here in the Preamble I was initializing the device name and the device proxy in this case what not this what I'm going to do is I'm going to have this other initialization that is a little bit more complete that takes the device for proxy and initializes to n pointer as before and the device name with the sensor name that we have provided with we have been provided with and then the conditional variable and the mutex are initialize and we have this property that is a flag to H say whether we are already connected to a device or not and it is initialized to false okay so now we can go and er move to the method that we had the connection and in this method we're going to uh get this here this is where we subscribe to the interfaces added then enable scanning hopefully here we get connected and then disable scanning before doing that we are going to obtain H an instance on the lock of the mutex so we will get this lock by H using the mutex that we have created and if the mutex is available if nobody else is running on that zone we will subscribe to the interfaces and enable scanning and here instead of waiting for the connection to happen and a little bit longer maybe we are going to replace this with uh sorry because this is duplicated so let me remove the things that are not required so here can remove this can remove this and I can remove this so I have the same enabl scanning true and false that I had before but instead of the delay now I have uh wait for the condition and variable to be H notified to be signaled and it uses the log to be able to have access to the information and it uses this closure that takes the instance of the object and verifies if these objects connect the flag that is a field of this object has been changed to true if it is that means that I'm connected and then I will H stop scanning pretty is isn't it so let's go and do the other part of this contract on the closure for the connection let's go to where the connection was happening and here in the connect to the device method we're going to work in the closure that we haven't completed yet so the first thing that we're going to do is to deal with the error in case it happens if we have an error with don't want to continue we want to print the information and that should be it but if there is no error what we're going to do is to work with the data that we have and here we are going to obtain a look for the mtic say that we are connected say that the connected H flag is now true then we unlock because we want it to have exclusive access to connected while modifying it but now we don't need that anymore and then we notify the closures sorry the closures the threads that are waiting for this to happen in this case the main threat and we just print the message saying hey we're done here so that should be all we need the only thing that H has to be changed in the ER implementation of main CPP that as you can see there is in red now is that now we need some value to create an instance of the BL sensor so we're going to r that and provide the name of our sensor here and that should be more than enough to have our sensor selected let's go and run this first let's compile and if we can connect to the device then the scanning will stop immediately the only thing that we are not doing here is that it will wait forever if we cannot connect to the device so it has detected the rp2 essor and we are waiting for the connection to be finished the connection has started but it is taking a while to happen and then it has connected and immediately we get the stop scanning message now that we have a connection to the BL device we will be receiving signals about interfaces added those interfaces will be the services the characteristics and the descriptors of the Bluetooth stack and we want to be listening to the signals we already have a closure that is paying attention to the signals however that closure is focusing on devices on ble devices we are going to change the code so it will also be listening to characteristics so we can find the right characteristic using it uid and then use the read method to get the value from from it we are already receiving information about the devices that we connect to and using the same subscription we will be receiving information about the paths but we need to deal with it in a in a different way so let's go to that method that is in the implementation and we should go to the subscrip cribe to interfaces add it that is where we are listening to the signals thing here is that we are going to behave differently if we are already connected than if we are not because if we are not connected yet then we will be trying to get a a information about a path of a new device that has been added while if we have have already been connected and I'm going to write that here then we will be paying attention to the things that we were doing before which is H the listening to devices but in this case that have information about the characteristic or the attributes of the Bluetooth uh low energy device so we are going to have this H compression here it complains about the match not being available so we're going to move the match here and now that we have the match ready we need to let me go down there Define the regular expression that we are using here so let's as we did before let's define the regular expression here and in this case the regular expression is going to be similar it includes like the MAC address and so on but it's also looking for a service and a characteristic and if we find a match here then we're going to bring that we have found a characteristic with this path and then we will try to look in its dictionary to see if it belongs to this type of thing and we will try to check the uid that is the uuid of the character that we want to read uh if you remember that that was the temperature measurement so by searching into this we can now point to the characteristic that we were looking in order to have this character istic red we need to have yeah you guessed uh another proxy so let's have this proxy created here using the same uh format as we were doing before s the bass create proxy and we need to declare it as a field here so let's have it declare in our hether and that is going to be our last one I promise so here we have this temp temperature attribute proxy and we need to initialize it as we were doing before in the Constructor so we go to the Constructor and let's go to the beginning in the Constructor we are going to Define this new initialization that now uses the preamble to not only initialize the device proxy but also the temperature attribute proxy here also H to null pointer because initially we don't know what is going to be the device path to the characteristic the object path to the characteristic now that we have that created and we have in place we can go and Define a couple of methods one private one public as we were doing before so we go to the feather and here we're going to Define one that is going to be the public one [Music] and one that is going to be the private one so here we have these two two methods and now we can Implement them let's go to the implementation and here we go to the end of the file and we create the Declaration for the public uh this is the public meth so this is going to be this one I'm going to move later but and here we create the private one the private one is invoking a method as in most other cases and here we have method read interface CH some arguments and where we want to store the result so let's go step by step and fill the blanks here and the first thing that we want to do is to initialize the constants that we are using here then we want to give value to those arguments that we have here in this case we need to say that the offset that we want to read is zero and we will be reading this offset and Stor in the result in this variant here oh sorry and Stor the result on this u in 8 here so this is an array of H bytes that will be holding the value that we read from the sensor now that we have that in place we can go and try to use this H information and print it so how do we get this value out well the thing that we can do is just show the content of these results and the part that we care about is the last four bytes so it start on zero so we want from one to the fifth bite because those are the pieces that contain the temperature the first one was a flag that was saying whether we had a temperature in Celsius or in Fahrenheit and whether we have a time stamp or not we are not interest is that we just want the value so now that we have this number containing just the things that we want for the temperature we can try to create a new private method that is going to be let me go to the Heather here and in this case we're going to have this oh sorry this new method that transforms from an e i triple 11073 format into a float it takes this bite array that we have extracted from the temperature and converts it into a regular float so now that we have that created we can go to the in implementation and here we can have this method implemented and not going to go a step by step on the transformation because it's very similar to what we did in episode number two for a implementing the blle firmware in python microp python so same transformation but the other way around the first three h bytes contain the value and the last one contain CHS the H power to 10th that it is used to transform this value into something meaning it is complaining here because we don't have ER the math header H included here so this is the next thing that we're going to do and now that we have that we should be fine so now power should be available power and is a function that is now visible here and the only thing that we have to do is to use the value that we have read how do we do that well what we are going to do is here after invoking this H method of that we have retrieved here we're going to transform the value using the the method the private method that we have just defined and printed as the value of the texture and now that we have that done we can ER run this in the main thread ER so we can get the value out there so let's go to the CPP the main CPP file and here I'm going to to add the reading notice that ER first let me include what is missing here so it doesn't complain sorry we need to include thread and now that we have that should be perfectly fine and I'm using theay here again because I should be using the another conditional variable in order to know that I have connected and that I have seen that I am a I have a proxy connected to the actual characteristic but I haven't done that because I don't want to make this longer than it should be and that is it that's why I need these two methods here these two implementations of a delay before and after getting the value so that should be it now we should be running it and it should work let's try that and let's compile it and now we are going to run it again trying to connect to our blle device that I have black here on my table so we have the binary ready and we use it it start scanning it doesn't show my sensor and why is that well let me tell you why it is let me H stop this program and if you have this problem what you need to do is you go to Bluetooth CTL and you see that you are still connected to the device so the first thing that you have to do here is connect and now you have to wait for a second now that the prom is Bluetooth you can power off if you want the device and you can leave this interface and try again and now you can see that the rp2 sensor is available here it is trying to connect we are still waiting for the connection to happen once it connects it stops scanning but it reads all the characteristic that we have information about things that are not a characteristic as is printed but it's not totally irrelevant here and once it has found the characteristic that it Wass H to read it reads the value these are the bytes and this is the final temperature 37 81 uh degrees Celsius don't worry it's quite cold here so it is just the temperature on the board okay so that's it finally we need to disconnect from the device to leave the things the way we found them we are great boys Cuts if we don't the next time we run the pram it won't work because the sensor will still be connected and busy let's Implement a method to disconnect from the device so we come back to the initial status and in order to do that let's implement it that's the the fact find it in the header and we start by creating a public method here that is going to be called disconnect and a private one that is going to be called disconnect from device again the message will be the private one the public one will just H offer the public interface so now that we have both methods available we're going to go and implement the code here so we go to the implementation and here I'm going to go to the bottom of the file and I'm going to create the disconnect from Dev viice method I haven't gone step by step because it's the same thing we're going to H have this call method synchronous and we will be invoking this disconnect disconnection call back once this finishes so what we're going to do next is to work on the content of this method that is going to be first dealing with the error if we get an error here we want to print it and exit and if everything goes fine what we are going to do is to get the Unique Look H the mutex that we have we are going to lock it and we're going to disconnect and access this thing that was the thing that we want to access h exclusively once we have done that the device proxy is also set to n pointer and then we can ER easily lock unlock sorry the the mutex so the rest of the threads can access to this data and we just print this message to say hey we are done that's basically it not much so let's try to indent this to verify that everything is fine and now that we have done this what we would like to do is to have an implementation of the that right we were missing an uh ah it was here so we're going to do the implementation of the public method which is basically going to be a an invocation of the private one with a new message and that's it now that we have both pieces we can go to the main file and here we're going to disconnect from the device using the public method and that should be it let's go and compile sorry not this one but this one and we compile the project we generate a new binary with the disconnect method and with that binary place we're going to invoke it and hopefully everything will be ready but in order to avoid any kind of trouble we're going to first use Bluetooth CTL and disconnect again because it hasn't been disconnected because the method has been just added but we are going to disconnect from the device wait for it to happen and then power of the Bluetooth stack now that everything is in place let's run this we find the rp2 sensor the connection starts we are still getting signals from other devices oh and I got a correction error that something happens and if that is the case one thing that you can do is you can do pseudo service Bluetooth restart and then try again we find the rp2 sensor we'll wait for the connection to happen if the connection is successful we will be get in oh it is successful we find the characteristic we read from it and then we get the temperature value that's all good and we disconnect from the device and that was it in this episode I wrote a C++ application to connect to a building device and read values from the Sens I have realized that writing C C++ is not like riding a mic a lot has changed since the last time I was writing C++ code that got into production but I hope I did a decent job at using it for this small application feel free to make any comments the biggest challenge wasn't the paring language though I bound my head against a brick wall every time I tried to connect to the device from my code in the beginning I didn't know whether it was my code to play the language the library or what but then I started taking traces with BT Moon searching in the internet and after a while of not finding much I realized that the problem wasn't the code but rather the fact that I was sharing the radio frequency in a chip with a very small antenna so the BCM 43438 that is the chip that we use for Bluetooth and Wi-Fi in the Raspberry Pi was creating this interferences for me for free and once I used a uh an EET cable upgrading from a Raspberry Pi 3A plus to a Raspberry Pi 4B uh and connected it to connecting it to the internet using an ethernet cable and disabling the Wi-Fi all of a sudden things started to work even though the implementation wasn't too complex and the proof of concept was passed uh the problem with the Bluetooth raise some concerns it could only get worse if I talk to several B sensors instead of just one I could still use uh USB dongle and ignore the internal Hardware but before I take that road I would like to explore the alternative them mqtt and that is going to be our next episode stay curious hack your code see you next time

Facebook Icontwitter iconlinkedin icon
Rate this video
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Red Mosquitto: Implement a Noise Sensor With an MQTT Client in an ESP32


Sep 17, 2024 | 25 min read
Tutorial

Me and the Devil BlueZ: Reading BLE Sensors From C++


Sep 17, 2024 | 16 min read
Tutorial

Me and the Devil BlueZ: Implementing a BLE Central in Linux - Part 1


Dec 14, 2023 | 10 min read
Tutorial

CMake + Conan + VS Code


Sep 04, 2024 | 6 min read