I recently bought a PineTime watch on a whim. And I’m still not sure what I’m going to do with it, but it runs an open source operating system (InfiniTime based on FreeRTOS) so I’m lured by the thought of customizing or contributing in some way no matter how small.

The first thing I noticed when booting my watch for the first time is the battery indicator didn’t seem to be working despite the fact that I was actively charging it. I assumed this was a bug in the version of InfiniTime that ships with the watch (0.7 IIRC), so I headed to the wiki to see how to flash a newer version.

The wiki page for updating InfiniTime is well organized, and outlines a few different methods for doing the upgrade. I went with the Siglo option because it seemed to be the simplest and could run on my “test” Linux machine with Pop!_OS LTS. Bluetooth was a little flaky (as always), but it ultimately worked. Once I had upgraded to 1.0.0 I noticed the battery indicator seemed to be working again. Yay! Then I flashed 1.2.0. Sure, it just came out a week or two prior, but I was willing to take the risk and test things out.

The next thing I needed to do was set the time so I could use the PineTime as a watch to start. At the top of the PineTime wiki page is a link for FAQs about the devkit and on that page I found How do I set the time of PineTime?. This section could use some cleanup, but it mentions apps I didn’t really want to use versus using bluez. The bluez option was intriguing because it suggested that setting the time is simple enough that it can be done with simple commands (ie. it doesn’t require custom code). However, the instructions mention dropping into a bluetooth command prompt, and sending over hex values for the time you wanted to set. Ugh! That’s something that needs to be automated.

I put my Bluetooth 4 USB adapter in my Pop!_OS machine, ran bluetoothctl and tried to find the InfiniTime without much luck. The device names didn’t show and I’m not entirely sure why; I could only see MAC addresses. So I tried to use the MAC of the PineTime in order to pair with it, but that didn’t work either. I assumed it was something that only worked in Bluetooth 5, so mustered some patience, ordered an Edimax BT-8500 and waited another day before trying again. On second thought, I should really try the BT4 adapter again. I’ll do that in a bit but I should keep writing for now.

At some point I came across mention of the WebBLEWatch project and the concept of Bluetooth through a browser. That stuck with me, so while waiting for the Edimax to arrive I looked up the Bluetooth Web API on MDN. It’s still very much in development so there aren’t many full examples. However, I found this great Web Bluetooth by example blog post that seemed to be exactly what I needed so I started adapting the code.

When the Edimax adapter arrived I followed the installation instructions for Linux. This meant compiling their kernel module from source, which I wasn’t entirely happy with, but I had no other Linux compatible option for Bluetooth 5 at the moment (heh, turns out I didn’t need to use this adapter after all, more about that at the end). The Edimax adapter installed just fine, though I was a bit confused as to whether I should compile for USB alone, or USB and UART. I tried both, but it failed to compile something in the UART code, so I tried USB. That worked, and following a reboot of my desktop and my PineTime I was able to see the InfiniTime in the bluetooth devices list. Now I could finally start testing the time-syncing JavaScript I’d written.

When I loaded up the webpage and clicked the Sync button to start the Bluetooth interactions Chrome yelled at me (IIRC). Bluetooth was “experimental” and need to be enabled. So I opened a tab for “chrome://flags”, searched for “experimental web platform features” and enabled it. The JavaScript code I cobbled together starts by searching for devices with a specific Bluetooth service UUID. I gleaned the value from the bluez example on the wiki page, but the browser didn’t find any devices with that service, so I added the “InfiniTime” name prefix like I saw in the MDN documentation. Once I did that and refreshed the page I saw the InfiniTime as a pairing option in the browser. I selected the device, clicked Pair, and saw another error that the device didn’t have a service with that UUID. I wasn’t exactly sure how to proceed, so I figured I’d take a look at the InfiniTime code itself to see what sorts of services it sets up. I found the CurrentTimeService code, and some hex values for the service and characteristic. With those values plugged into my code it successfully grabbed a handle to both. Yay! Now I needed to format the time data properly and write it.

The bluez example on the PineTime wiki page nagged at me, specifically the part where you’re supposed to write hex values to the device. Surely you’re not supposed to send hex over the wire! Something told me it should be bytes instead. I recently learned how to use TypedArrays and ArrayBuffers in JavaScript to get the byte array that backs a float 32 array, so that’s the approach I used to decompose a 16-bit year into it’s 2 underlying bytes. And since I was going to send a byte array I needed to create a Uint8Array for the time data. Then I reviewed the Date docs, plugged the date component values into my Uint8Array, fumbled through more errors and landed on writeValueWithResponse() as the correct way to send bytes. It worked! My watch now showed the correct time!

Whew!

Now about the Edimax USB adapter versus the ThinkPenguin Bluetooth 4 USB adapter … I just now tried the BT 4 ThinkPenguin adapter with my time-syncing webpage and it works just fine! I’m guessing it failed the first time because I didn’t reboot the PineTime before attempting to pair. Well that makes everything so much simpler! I can now use any Bluetooth 4-ish adapter readily supported by Linux. It’s good that I’m not limited to the Edimax for setting the time.

See my pinetime-infinitime-time-synchronization GitHub repo if you want to see or try the code.

Thanks for reading!