Since the last update not a lot has gotten done. That isn’t to say there’s been no work happening on the project, just that the progress has been slow and tedious almost every step of the way. I recently upgraded my phone to the OnePlus 8 running android 10 which resulted in my companion app all but breaking completely. In some cases, it would work alright, when the app was open in the background and I was actively using my phone the smartwatch would sometimes grab the notifications over Bluetooth serial. On my previous phone (a Galaxy Note 5) the app just needed to open a thread that attempted to connect to the device occasionally and that worked well enough for a while. I’ve been wanting to change the way the app works for awhile but getting my newer phone kind of forced my hand.
Now that I’m running Android 10 there’s been no real way to get around it. BLE is the way to go with a project such as this, while Bluetooth serial has some definite benefits in ease-of-use, the pairing time takes too long to be practical. The biggest problem I’ve experienced with BLE in the past is the lack of good documentation. Luckily this time around I stumbled across two incredible resources for creating a BLE GATT Server in the form of straight forward examples (https://stackoverflow.com/questions/37181843/android-using-bluetoothgattserver and https://riptutorial.com/android/example/30768/using-a-gatt-server). Both examples allowed me to get some code running and configure a GATT server to present data to the ESP32 Smartwatch.
Now for anyone interested in the code here’s a quick overview of how all the major functions work along with a flow chart. If you’re interested in creating something similar or adapting the code yourself, I hope this helps. If you’re not really interested in the code, then just skip to the last paragraph.
The above diagram starts from the onCreate() method which initializes all the required elements in the code. UI elements and the notification listener service used to read the notification-bar notifications are registered (notification listener is also registered in the manifest). Next the BLE server needs to be configured, first we set up the advertiser then we open the GATT server and register the required callbacks. Almost all of the useful functionality in this app comes from the two callbacks registered in the onCreate() method. Finally, we add the BLE Service and the BLE characteristics, both have their own UUID hardcoded into MainActivity.java.
The callbacks used by the GATT server are shown in the diagram. Since we don’t know when the watch will connect using these callbacks allows for the watch to initiate a connection, give commands, and receive the data it needs. For the moment the only data requested by the watch is the notification data but by adding more characteristics or commands the watch could read anything forwarded through the app. When the smartwatch connects the first thing it does is write to the available characteristic which triggers the onCharacteristicWriteRequest() (let’s say CWR from here on out) callback. When CWR is called it triggers it first obtains a new String to represent the notifications of the android device including the current date and time (I plan to use that information later). The next thing the CWR does is reset the currentIndex variable which I used to cut the notification string down into 16-character long packets to be sent over Bluetooth.
After sending a write request the smartwatch then needs to trigger the onCharacteristicReadRequest() (CRR) callback. Essentially all this callback does is reply to the read request with a 16-character string which is a part of the larger notification string. Every read will yield a different substring of the notification data which can be concatenated back together on the smartwatch’s end of things. The end of the notification data is indicated by 3 asterisks (*), but to keep things simple data packets stay as 16 characters and any empty space is filled by asterisks. The smartwatch will stop reading the data from the GATT server as soon as it detects that the string ends with “***”.
Changing over to BLE should increase the battery performance of the watch and the companion smart phone. I’m sure in the next few days I’ll find a few issues with the BLE implementation here but for the most part I expect that the code will function as shown above for quite a while. This project has been challenging every step of the way and I’m glad that it’s all coming together as well as it is. Either way thanks for reading, see you in the next log!