08/30/2020 at 22:58 •
I've been working on the watch a bit here and there, but it's been rather busy lately even though I'm still at home (paradox of 2020). At the same time there just isn't much to do on the watch at this point, all the core functionality is there and I'm happy with the form factor. All that's left is adding features. So far, I've added 2 more apps to the watch a calculator and a Bluetooth serial receiver.
The calculator app is just a simple 4 function calculator, nothing special about it except it's on a watch. Since this smartwatch has a pretty large screen (compared to other watches) the calculator app is very easy to use. It's also just the convenience factor, since it's on my wrist I find myself using it often. (see video below)
The Bluetooth serial receiver is a simple app that may become useful later. The basic idea is that the watch becomes a standard Bluetooth serial device and allows other devices to connect to it. Once connected the external device can print data directly to the watch's screen. I used to work with a lot of small makers-type robots, so I like the idea of being able to read serial data from the robot while it's in action. (see video below)
On a slightly less related note I got the TTGO T-Watch 2020 a little while ago and I like what it can do. There's only a small community around it that I've been able to find but I'd really like to see the watch become more popular. I made a small port of some of this project's firmware over to the T-Watch, at the moment it only supports reading phone notifications and controlling Spotify music. Open source hardware and software were really the springboard for me when I was getting started with electronics so I'm always looking for ways to give back. The T-Watch port can be downloaded here https://github.com/Bellafaire/T-Watch-2020-Smartwatch-Port and can be uploaded through the Arduino IDE.
And finally, I've created another video log to cover some stuff up to revision 5. The video logs are still parallel to the logs posted here on Hackaday.io so really it just covers the last few logs in 2 minutes.
I think I'll consider this project complete in the coming week, but before that I want to put some polish on a few things here and there. Either way thanks for reading and I'll see you in the next log!
08/19/2020 at 02:03 •
The title really says it all here, the boards for Rev 5 arrived earlier today and I dropped everything to start putting them together. Revision 5 brings a huge reduction in overall volume of the watch while maintaining all the intended functionality. For comparison here is the revision 5 board stacked on top of the revision 4.1 board:
I've talked about the reduction in size in my previous log after the CAD files were finished up. The new size is a noticeable change jumping from the Rev 4. It's also worth noting that the current watch body can be printed entirely without support, this helps with the overall finish since there's no more marks where the supports were removed.
(the overall reduction in height was only about 3.5mm, Rev 4.1 kind of wraps around the wrist rather than sitting on top of it. The "wings" that hold the strap add a few millimeters to the height making the overall size reduction seem more extreme)
The board assembly went well, I opted to get a stencil this time around to save me some time with the current density of the underside of the board. Overall, the assembly took about 2 hours and the debugging/minor firmware changes only took about another 2. I spent more time desoldering the ESP32 module than anything else (seriously that thing takes forever to heat with hot air station) since it kept ending up with bridges between pins. Other than that, the I2C bus got pulled to ground by some extra solder and the voltage regulator didn't seat properly. As hand assembly of a board goes this watch was a breeze.
There were some minor code changes that mostly amounted to changing some pin declarations, I'm only mentioning this because it technically means the code from rev 5 and rev 4.1 are incompatible.
The hardware for this project is now complete. However, I'm not sure whether I'll ever really close this project and consider it finished since I'll continue to add features to the watch as I find a need for them. There's still a lot more to come with this project so stay tuned. Either way see you in the next log!
08/12/2020 at 15:30 •
I'm still in the process of waiting for the new boards to arrive. In the meantime, I decided to fix some of the BLE communication issues. When I originally wrote the BLE code I didn't know much about BLE, so it was time to fix it up. I ripped everything out of the smartwatch source code relating to BLE and did it all over again from the ground up. The new implementation can now perform both the BLE scan and connect functions from within a separate FreeRTOS thread allowing for the ESP32 to connect to the android device through a background process. The connection is also more reliable and easier to use since everything now happens from the sendBLE() function rather than calling one of 4 functions.
I also finally got around to cleaning up the code in the companion app and it's at a state now where I feel like it deserves to be its own project. As a result, I've split the repos up so that people who just want the android app can find and use it. The new repo is found here: https://github.com/Bellafaire/Android-Companion-App-For-BLE-Devices
The majority of the android app is now complete, if anything gets changed now it will likely be adding features rather than changing the core functionality of the app. I also supplied an example Arduino sketch which connects to the android app and reads the phone notifications to help people hit the ground running with the app.
See you in the next log!
08/08/2020 at 20:17 •
This week has been pretty hectic so this log got delayed a bit longer than it should have. After a few designs and minor changes I've finally settled on the design for the Rev 5 case. As with all the previous cases for this project Rev 5 is designed with 3D printing in mind. I only own a cheap FDM 3D printer which has made case design a challenge due to the difficulty of printing small details. Ultimately having a design that prints well and is strong when produced on an FDM printer has been challenging. Early revisions used screws to hold everything together, but from my experience the threads would become weak over time and the screw holes were a major weak point in the design (and threaded inserts are out as an option due to space). Revision 4.1 uses some galvenized steel wire that I found at the hardware store, over the last 2 months this solution has held up well but its not very pretty. I think I've managed to come up with a design that incorporates the best parts of Rev 4.1 while also improving upon it. Without further delay here's the Revision 5 case next to Rev 4.1:
Since the battery no longer sits under the PCB the newest design is able to save considerable vertical space while maintaining the same footprint. Rev 5 cuts a whole ~3.5mm off the previous iteration which may seem like small gains but that's nearly a 25% reduction in height.
The "wings" that were present on the previous revision were also removed, they were more of a stylistic choice to start with anyway.
Here's a view inside the case
Assembly has changed a bit with this design. The hole pairs on the side are for feeding the wire that holds the strap on. This design can accomidate any strap with an open loop up to 26mm. For anyone curious I'm using 19 gauge Galvanized Steel Wire, I've found this to have a good stiffness for this purpose.
The bottom hole in the pair is where the wire actually runs and holds the strap on, the top is intended to hold the wire in place by bending it through that hole. When the wire is longer it's easy to pull the wire through both holes, after cutting all the excess the wire holds on well and doesn't stand out as much as Rev 4.1.
This leaves the bottom entirely wire free!
Either way that's everything for the case design. I've ordered all the components and the PCB for Rev 5 so it's back to the waiting game. I also want to say thank you to Arduino “having11” Guy for featuring this project on hackster.io (Article) in its current state, it means a lot to me to see people taking interest in this project.
08/06/2020 at 01:23 •
Funny story, When I started this project back in October it was because the wrist strap on a $20 digital watch broke. While this was one of those projects I always wanted to do, the actual spark was that watch breaking. To think now, 10 months later, that a $20 digital watch would be the prompt for a project that spanned 6 board revisions and countless hours of writing firmware is kind of insane. With that said this is by far the most challenging personal project I've ever taken on and I have gained invaluable knowledge every step of the way. With all that said it's time to jump into the meat of the matter, the Rev 5 board is now complete.
Since Rev 4.1 is still going strong, now almost 2 months after I originally assembled it (and it's been my daily watch for that time), there's not a lot of changes that needed to be made for Rev 5. There were some minor improvements thrown in with this revision so let’s cover those first.
The power management circuitry has been cleaned up a bit, having two separate LDO's for the watch is entirely redundant. In Rev 5 components are enabled/disabled with MOSFETS which are each connected to pins which can be controlled by the ULP module aboard the ESP32. This way it's possible to have the RTC control whether these pins are on and off. Pulldown resistors are also present on each of the MOSFETS to ensure the default state is off. The pulldowns can be left unpopulated if I choose to use the ULP to control these functions, for the moment I don't have any plans to do so. The accelerometer, LCD Logic, and LCD Backlight each have their own enable signals for controlling the FETs.
Another minor change was the addition of a thermistor to the MAX17260. Using a 10K NTC thermistor should increase the accuracy of the battery readings. However, the datasheet also specifies that this isn't a required component of the application circuit, so I left it as optional by adding a jumper.
Here are the same changes applied to the LCD, I also rearranged the schematic symbol for readability since the last one was kind of a disaster.
In the category of "I should have done this anyway to start with" is the addition of some ESD protection on the USB connector. For this I chose the ESDZV5-1BF4 TVS diode, which should shunt any static discharge or inductive spike from the USB cable safely.
Other than those minor changes (and some pin reassignments for the purposes of layout) the schematic is the same as the last revision. Where this revision makes a radical departure from the last is in board size.
Shrinking the board down was somewhat difficult and necessitated going to a double sided load since the ESP32 is only slightly smaller than the new board itself. Before the layout got started I picked out a new battery to fit with the design (https://www.digikey.com/product-detail/en/jauch-quartz/LP502030JH-PCM-WIRES-50MM/1908-1353-ND/9560976) which mostly set the board dimensions I could get away with. The LCD is about 47mm x 34mm, meaning that both the board and this battery needs to fit within that footprint. This left me with 34mm x 24mm for laying out the board (with some of that space unusable due to the ESP32's antenna). I ended up doing the layout twice, I wasn't very happy with the first attempt, so I started from scratch. With all that said, here's the final render of the PCB:
It's worth noting also that with this reduction in overall volume the battery capacity has decreased. I haven't talked about battery life so far with the current iteration of the smartwatch since I had no intention of keeping the current 600mAh battery. For a normal day of regular use, the watch only uses about 15%-30% of its capacity, this is with the device also polling the smartphone every minute to update its notification data. Switching down to the 270mAh battery linked above should leave the watch with 30% - 60% at the end of the day which can be further improved by reducing the polling rate when in sleep mode (I'm planning some software changes that replace).
Either way that's all for the electrical updates for Rev 5, next log will go over the new form-factor and case design. See you in the next log!
08/03/2020 at 00:49 •
Recently I had some time and put some more work into this project on the BLE side of things. Overall BLE communication with this project isn’t where I would like it to be and there are still a few bugs and issues with reliability, however I’m finding better ways to use BLE as this project progresses. Since the last log I’ve added some functionality to the android app allowing for specific commands to be written by the smartwatch to trigger actions on the android device.
The smartwatch itself will now attempt to connect to the android companion app whenever it comes out of sleep mode by the user tapping the screen. The connection status is indicated by a small square in the upper right-hand side of the screen (red = not connected, green = connected). With this constant connection there are a lot more options available to future functionality of the watch since the most time-consuming part of BLE was the scanning and connecting phase. When connected the communication speed between the watch and android device is fast and more than capable of streaming even long sections of text quickly.
With these improvements it’s much easier to communicate between the two devices so I decided to add my favorite feature from my old android ware smartwatches, media control. For the most part I only listen to music on Spotify these days, and unfortunately Spotify seems to enjoy doing things their own way. In order to read the current song being played by Spotify the android app uses a broadcast receiver following the documentation provided by Spotify (https://developer.spotify.com/documentation/android/guides/android-media-notifications/). Although I’d much rather read the currently playing song from the notification bar it seems Spotify doesn’t really allow for this, meaning implementation with other players will have to be implemented separately. The media controls triggered from the smartwatch are simple key-events which the companion app creates when it receives a command over BLE. I haven’t yet investigated reading media information from other android media players, so I’m not sure whether Spotify works very differently from other apps.
The media control interface itself was meant to be simple and easy to use while locating itself directly on the home screen. The media buttons will appear only when the android app detects that Spotify is currently playing. If the smartwatch is connected to the android device then the media controls will work immediately, otherwise the action will be queued until a connection is established. In general, the smartwatch can connect to the android device immediately when the android device's screen is on, otherwise it can take a few seconds or fail outright.
There have been a lot of improvements to BLE recently in this project, however there is still a lot of work to be done in this area. I've noticed that the ESP32 connects unreliably when the android device is in doze mode. By taking a look using some android BLE apps available on the play store I've been able to determine that the android device is advertising properly. Most likely the issue is on the ESP32 side of things, as a result I’m planning on redoing a lot of the BLE code to try and improve the overall reliability of the project.
I also realized recently that the last video update for the project is now nearly a month old, and a lot of work has happened in that time. I've decided to try and do regular video updates for the project, since so much of what is happening in this project at this point has to do with the user interaction it’s much easier to show rather than write about. The video logs are meant to be parallel to these project logs and represent a short overview of improvements to the project. Anyway, here's the third project video log:
Either way thanks for reading and I'll see you in the next log!
07/20/2020 at 03:27 •
Since the last log I’ve been using this watch more and more as my daily smartwatch, in that time I’ve come across a few issues which are now resolved. A lot of these changes are minor but both the smartwatch’s firmware and the android app have undergone some changes.
Android App Changes
After the previous log I kept a close eye on the android app to make sure that everything was working properly. Android 10 tends to kill processes happening in the background when they’re not being actively used by the user. To combat this, I had to move the BLE GATT server to its own service. With this change it seems that while the android app itself may be inactive the service will continue to run without issue. The notification data is also no longer stored in the UI, this would cause some issues when the app would go to sleep, resulting in the same old notification data being sent multiple times without getting updated. The log shown on the app UI underwent similar changes, having a proper log of when exactly BLE data has been sent makes it much easier to determine when the app isn’t working properly.
There was also an issue with reading specific notifications, specifically Gmail would almost never display properly on the android app. The app can now read the body text of a received email which in turn means the body text can be read from the smart watch.
Smartwatch Firmware Changes
There’s been a lot of minor bug-fixes since the last log including a lot of fixes for random crashes. There is also now a “force put to sleep” option on the smartwatch, tapping the screen 50 times with each tap within 200ms of each other will force the watch into deep sleep. BLE notification receiving is now also an interruptible process, since notifications are generally obtained when the screen is off this prevents the watch from ignoring the wakeup tap on the screen.
One major change made to the smartwatch firmware has to do with timekeeping. This project uses the ESP32’s onboard RTC to keep time, without an external crystal this time would drift by as much as 15 minutes per day. The only way previously to update the time was to use Wi-Fi to obtain the current time, however this was a clunky solution since it had to be done manually and requires a known WIFI connection to be close. To fix time keeping the ESP32 now parses its time directly from the notification string sent from the companion app. Currently the watch updates its notification data every 60 seconds, this makes the RTC drift essentially a non-issue in most cases.
That’s pretty much everything that’s changed since the last log. The core functionality of the watch is finished, all that’s left is adding additional apps and making the watch a bit “smarter”. I’m also looking back into the hardware for potential improvements before I do a final pass on the board layout to try and make the watch thinner, but that’s all in the future. See you in the next log!
07/14/2020 at 02:54 •
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!
07/01/2020 at 03:29 •
In the last log the watch had only basic watch functionality and couldn’t do much outside of telling the time and reading its own battery state. In the last few weeks the functionality has grown to encompass more of what would be expected from a basic smart watch.
Most of the time I’ve spent on this project in the last two weeks has been focused on getting an android app to work with the watch. Until now I’ve never written an android app, although I have a lot of java experience, I found android to be much more of a beast than originally expected. Most of the code that’s used in this project comes from open-source projects or stack overflow posts. Data is communicated between the watch and my phone over a standard Bluetooth serial connection using a library by harry1453 (https://github.com/harry1453/android-bluetooth-serial) which massively simplifies the Bluetooth code. In order to actually get the notifications themselves I modified an example by kpbird which can be found at: https://github.com/kpbird/NotificationListenerService-Example/.
I ended up writing the app twice just to clean up the code once I had something that kind of worked. For all the effort the app in all its glory looks like:
The app attempts to send data to the ESP32 smartwatch about every 15 seconds over a standard bluetooth serial connection. When it connects it sends across the string that is shown in the middle of the app window. Using this approach is less than ideal but in practice it’s not too bad. Even though the app runs constantly in the background and is constantly trying to send data it appears to only have a negligable power useage according to my phone’s battery monitor. With all that said I’m still planning to rewrite the app to operate more efficently or switch to BLE. I’m open to suggestions on how to use the bluetooth functionality here, I’m new to android and there’s a lot that I still don’t know about.
With the app out of the way lets move onto the updates to the firmware that have been made recently. A major improvement to the watch was a software switch away from drawing individual pixels on the screen directly. I stumbled across the GFXcanvas16 class in the adafruit GFX library (this is the only real documentation I can find on it http://adafruit.github.io/Adafruit-GFX-Library/html/class_g_f_xcanvas16.html). Using the GFXcanvas16 the code can now buffer the image before displaying anything, this cleaned up some flickering that would occur from updating and allowed me to make the UI a bit more lively. Notifications received by the watch are partially displayed on the home screen (app name only) and in the notification menu accessible by the bell icon. The notification window allows all the received data to be viewed in one place for any notification. I put together another short video demonstration of the watch in operation, a picture’s worth a thousand words so here’s 30,000 words per second.
Under the hood the watch opens its Bluetooth serial port every 120 seconds of deep sleep and waits for a connection for a maximum of 10 seconds, when the notifications are received the string is stashed in the RTC ram and the esp32 goes back to sleep. So far this approach doesn’t seem to cause a significant power drain on the watch (maybe 15% every 8 hours?). I haven’t yet been able to give the battery a proper test since I’ve written code to the watch almost everyday giving it time to charge up.
With all that said the project is coming along nicely and I hope to see you in the next log!
06/15/2020 at 23:26 •
I've been working on this project non-stop since I assembled the board yesterday. The fix for the battery monitor I talked about in the previous log seems to have solved the issue of charging not being detected. I've also managed to bring over a majority of the code from the Revision 3 watch to use as a starting point.
Either way, I figure since I've never shown a demonstration of the watch actually working on this project page now's as good a time as any. The code running at the moment can only really handle basic tasks like reading the battery and navigating some menus but it's promising for the future of the project.
See you in the next log!