It’s been a while since the last post! I guess that’s what happens when you go even deeper into your hobby as your job… I now work on frontend and backend projects and services instead of writing documentation for those at EVRYTHNG, and it’s just about as varied, challenging, and rewarding as I expected, which is great. I’ve been working with many new libraries and technologies including:

  • React with React Redux
  • React Native (to a small degree)
  • Terraform and continuous integration services such as Circle CI pipelines.
  • MongoDB

I’ve also continued to implement a collaborative approach to EVRYTHNG’s open REST API (beyond writing the documentation) with use of OpenAPI 3.0 spec files and tools to generate documentation in the same identical style to what I’d arrived at in the first year and a half curating it by hand. It’s really neat to be able to version and review changes to spec files, then magically generate the same level of quality technical documentation instead of one person writing it all by hand. And of course, contributions to EVRYTHNG’s SDKs and open-source tools.

FitBit Development

In the meantime, I’ve only been sparsely developing software as a hobby, and mostly for the ever-evolving node-microservices project, and keeping my FitBit apps up to date as new devices and features are added to the FitBit ecosystem. As a result, all apps and faces are available for all devices, and as of yesterday I’ve finally started experimenting with the new Always on Display mode available to SDK based apps. Getting closer and closer to Pebble-like functionality!

In fact, you can search for my name to see all of those on offer:

Pebble Development (!?)

In other developments, changes (once again) to Google’s developer program policies meant I had to dust off the codebase for Dashboard to push an update to remove the donation button. Unfortunately this meant that it had to be upgraded to a much newer SDK version. Which meant that extra measures had to be taken to continue to not be killed in the background. Luckily due to the code being open source I had some help. It’s nice to see that app in action again after so long away from it:

That’s all for now, hopefully more projects and FitBit apps to come. I’d like to try and do something interesting and a bit different using the Versa 2’s gorgeous color OLED display…

This one took a while. Weighing in at 38 versions and I-don’t-know-how-many reflected and hacked APIs, Dashboard is now open-source for all to see. This was probably the app that took the most development time until now (still on-going!), and I think the one I’m most proud of.

I’m liking the idea of doing future releases via self-approved pull requests. Could be interesting!

>>> Dashboard source code <<< 

A few days ago, an interesting idea came up in the PebbleDev Slack channel: could a library make it easier for Pebble developers to integrate their apps with Android APIs, but save the pain of each and every one of them needing to publish an app with PebbleKit Android? This would be similar to how Dashboard operates, but by sharing the API access to other apps that are installed.

Turns out, it can! In one of my signature coding bursts I set to work, and prototyped a system that did just this. The result is the Dash API. With it, you can finally (and easily) provide one of the most common watchface widget requests – things like the phone’s battery level, or connectivity status.

How does it work?

The Dash API (named after Dashboard) Pebble package uses AppMessage to send requests to read data (such as WiFi network name, or phone battery level), or write to an API (such as turning off WiFi). Using a unique key to recognise Dash API messages, the Android app can respond to these by reading the data or manipulating the Android API and returning a response code. All the developer needs to do is instruct their users to install my Dash API Android app, and then their app (and any others that use the Dash API) can take advantage of the APIs presented through the library. This approach makes the Dash API an install once, use in many apps service.

The upshot of all this is that a C developer making a watchface that wants to show the phone battery level (such as the demo app Dual Gauge) need only use the Pebble package and not write a single line of Java, let alone go to the trouble of publishing an Android app on Google Play.

But how can one companion app target them all, without knowing they exist?

Luckily, you can extract the UUID of an app that sends an AppMessage packet to the phone from the Intent object broadcast from the Pebble Android app. Most (hopefully app) companion apps that manually register a BroadcastReceiver do a ‘good citizen’ UUID check to make sure they only respond to messages from their corresponding watchapp. This data can be used to simply redirect an incoming message’s result right back at it, without the need to create a PebbleKit Android app with baked in UUID for each individual app.

So how can I use it?

Simple. As explained in the GitHub file, a C developer should first install the package:

$ pebble package install pebble-dash-api

Next, include the single library file and call the initialiser when your app is starting, supplying the app’s name (for presentation in the Android app) and an error callback for receiving any errors that may occur:

#include <pebble-dash-api/pebble-dash-api.h>;
#include <pebble-events/pebble-events.h>

#define APP_NAME "My App"

static void error_callback(ErrorCode code) {
  // Receive error codes here

static void init() {
  dash_api_init(APP_NAME, error_callback);

  /* Other init code */

Next, check the Android app is available and up to date:


The result will be passed to your error_callback. Once you get ErrorCodeSuccess, it is safe to start making queries, such as getting the battery level, etc. Code examples are included in the GitHub file.

What else do I need to know?

As of 1.1 (released today), apps that read data and API states can do so invisibly. However, apps that wish to write to an API (such as turning off WiFi) will cause a notification to appear that will prompt the user to grant it access within the Dash API app. Once this is done, operation will continue without further intervention, unless permission is revoked. This should hopefully prevent any rogue apps messing with the phone, and give users visibility into which Pebble apps they have used are using the Dash API.


GitHub Repo

Dash API Android app (direct your users here!)

NPM Package

Example App (Dual Gauge)

What’s next?

In the future, I’d like to expand the capabilities offered by the Dash API to other popular widget requests, things such as unread SMS count and next Calendar appointment. Perhaps for another day – coordinating GitHub repos, NPM packages, Android apps, and Pebble apps is quite tiring!

That’s right, the latest and greatest update to Dashboard is now live (pending Google Play deployment delay). The new features are (in descending order of number of requests received):

  • A choice of Find Phone sound from system notification sounds. While these are guaranteed to be available, free-form choice of file proved too tricky to handle (see Android file manage content:// URI problems discussed elsewhere).
  • An option to post an Android notification (and by extension, to the watch) when the phone has fully charged (see details below). This approach is better than the original one planned which involved custom UI in the watchapp, but would rely on an assumption about how long PebbleKit Android would take to launch the watchapp before messaging it.
  • Holding down the button now uses repeat button clicks to reduce wear on the Pebble buttons while scrolling through toggles.
  • Since I’m making bigger use of Notifications, installed a proper white notification icon to improve upon the old ‘white circle’.
  • More misc UI improvements in both app components, including a donation link for those inclined, after some minor success in News Headlines.

So how does the new ‘full charge notification’ feature work? I’m glad you asked!

The Short Answer

Once your phone has reached 100% charge (when it was previously 99% or less), an Android notification is posted, which is displayed on Pebble (for free!) unless for some reason Dashboard was disabled in the Pebble app.

The Long Answer

Oh boy, this was a tricky one. While the ACTION_BATTERY_CHANGED Intent is available for apps to know when the battery level changes, it’s a special case that cannot be simply registered in AndroidManifest.xml for spin-up whenever required. It has to be programmatically registered. For an app designed to run with extremely minimal interaction with the Android app component, this is tricky.

So what have I done? When the user toggles the feature on in the Android app, the BroadcastReceiver for the above Intent is registered. Sounds simple, right? Well that works for anywhere between ten minutes and an hour or so. I was charging my phone from 99% in testing, and seeing the notification after a few minutes as expected, but a frustrating lack of notification after leaving the phone idle for couple of hours on longer charges.

For reasons unknown to me, the system kills my programmatically registered BroadcastReceiver at seemingly random intervals. Remember, this wouldn’t happen with a nice and convenient receiver registered in AndroidManifest.xml.

Undeterred by this (because this is a nice feature idea), I found another solution. I made the receiver object a static class member, and used the Android AlarmManager to check it was not null at infrequent intervals (currently half an hour). This seemed to work well, once I realised by trial and error that Android Studio appears to kill BroadcastReceivers and AlarmManager alarms, but not deliver the ACTION_PACKAGE_CHANGED which I use to restore the alarms after a theoretical future app update is installed.

In addition, new users would not have their ‘keep alive’ alarms registered upon first install, since ACTION_PACKAGE_ADDED is not delivered to the app that has just installed (why!?). Fancy another complication? Here you go: AlarmManager alarms are all killed when the device is rebooted, so I make additional use of ACTION_BOOT_COMPLETED to restore them.


So there we go! I’ve always been a vocal proponent of Android’s Intent system for IPC, but after this set of complications (which has still yielded an apparently solid solution), I’m not so sure. Ah, who am I kidding? Still a big fan!

Dashboard can be installed from the Pebble appstore and the Google Play Store.


It’s here! The redesign I’ve been planning since many months ago (the previous colour watchapp design was a bit of a bodge), and I’ve wanted to add in a few extra features:

  • GSM signal strength
  • Wifi network name
  • Phone free space
  • Resync every 30 seconds while the app is open
  • Option to jump straight to a certain toggle when the app is opened

…and all the usual refactoring (I can’t help myself) and some protocol simplification. Here’s a rule of thumb: if your AppMessage protocol uses arithmetic and nested switch statements, ditch it!

I also improved a lot of the Android code, added fail cases, and more logging etc. to better help me diagnose problems when a user sends me a debug log. Finally, I brought a little animation magic to the UI, and relied more heavily on system UI components instead of over-complicating things by rolling my own version of everything.

Download on Google Play and Pebble appstore!

A few weeks ago I wrote about transmitting images to Pebble Time from Android, as a quick and convenient way to open any image via an Intent and display it on the watch. At that time, I had problems sending some types of images, where only the blue channel appeared to make it across correctly. The only exception appeared to be the image bundled in the Android app’s resources, which always displayed correctly.

After a getting and re-write of the flaky transmission system (and a bonus first-time working solution!), I now have the app in a state where any image opened with the Android app from a file manager will be resized to fit the Pebble screen and transmitted for display.

Now, the focus will be to enable cropping and scaling of the image in the Android app to let the user choose which part of the image to display (as a photo shown on the watch loses detail somewhat!). In the meantime, here are some images!

Original Image (credit to gmiezis!)


Imported to the Android app


Image on Pebble Time


Long time no blog! There hasn’t been much time for experimentation (besides creating a couple of color apps for Pebble Time) in the months leading up the Pebble Time Kickstarter. Totally worth the effort though, after seeing the response to the new material on the Pebble Developers site.

This weekend, however, I found some time to bring to reality an idea I have had since I first learned of the ability to make color apps for Pebble. Being a big fan of PebbleKit Android (used in Dashboard, Wristponder, Watch Trigger etc) to remotely control/access the connected phone. The idea is this: create an app for Android that registers as a receptor of opening image files. This app then resizes and reduces the color palette of the file before piping it to an automatically opening watchapp for viewing. This stemmed partly from a desire to avoid constantly changing resource files and recompiling a simple app for viewing PNG files every time I wanted to see how a new image looked on Pebble Time.

The implementation was pretty straightforward: Make a simple Android app that included an Intent filter for image files, and a watchapp that simply accepted data packets and stored them in the image data allocated for a GBitmap of the right size. The difficulty came in the signaling between the two. I’m no stranger to establishing communication schemes between Android and Pebble apps, but I’m only human. For some reason I was trying to use a mix of PebbleDataReceivers and PebbleAckReceivers. The former is for processing messages from the watch, and the latter is for reacting to the event that the watch acknowledges a message from the phone. By sending the next data packet in an ‘ACK’ handler, you can ensure maximum transmission speed as no time is wasted between the watch processing one packet and being ready for the next. This is the same method that apps like Wristponder use for transferring lots of data (try 30 canned responses!). If you’re not careful, mixing these two modes (one of which can be considered manual, the other semi-automatic when set up in a continuous data transmission loop) can result in puzzling behavior that is difficult to debug.

Once debugged, however, the result is an app that sends a complete uncompressed image (save that for another day) 24k image to the watch in about 11 – 16 seconds (approx 2 kB/s) and then displays it on the watch. In the meantime, both the Android and Pebble apps show the progress of the transfer:














The app sends a built-in image of a tree as a default option when it is launched by itself, or another image if presented one using ‘Open With’ actions, such as from file managers or emails. The result of sending the tree image is thus:


For some reason I can’t quite fathom the color reduction process the app uses (admittedly brittle bit shifting) doesn’t handle all files as well, producing discolored results, which I will try and iron out with a better solution, perhaps in the Android SDK itself. When that day comes, I’ll polish both app components and hopefully make another Google Play app of it (free, of course, this doesn’t do anything particularly useful) and also a two-part library generalized to facilitating large data transfers between phone and watch.

Watch this space!


Dashboard for Pebble is now version 1.13. This version contains a new Materially design, as well as fixes to the Data and ringer toggles as a result of the changes in Android 5.0 Lollipop.

The major point to note is that the method reflection I was using to implement the Data relied on an internal API in the ConnectivityManager class (which has existed in Android since very early versions). This API has since been moved to a more system-exclusive location (the Telephony class) that cannot be invoked using method reflection and as such the feature stopped working on Android 5.

Being one of the main features of Dashboard (and half the sole purpose in the original Data Toggle watchapp), this outcome was unacceptable. After searching for an alternative and finding nothing but similarly disgruntled Android developers, I came across a widget developer named Cygery who had found a way to implement this behavior in Android 5, and after a brief email exchange I was informed of his method, which was quite ingenious.

As a result, full functionality has been restored on Android 5, but at a large price – the feature now requires root privileges to change that particular settings. This is obviously not ideal, but the only way I can see the feature working beyond Android 5. Users on KitKat and below remain unaffected and the app should work as it did for them. Therefore, the Dashboard Android app will request root when it starts, as well as post a notification if the Data toggle is used and root access is not given. Most SuperUser apps will allow this access to be given on a per-app basis, so please allow this if you are a Android 5 user and need to use the Data toggle.


Get it on Google Play

Over the last week, there have been have been four version of Dashboard released (9, 10, 11 and now 12) following the inclusion of the Wakeup API. I used this shiny new firmware feature to let users of Dashboard schedule daily wakeups to issue an on/off command to the Dashboard Android app, at times they would use the toggles anyway.

pebble-screenshot_2014-11-08_21-37-47    pebble-screenshot_2014-11-08_21-38-04

pebble-screenshot_2014-11-08_21-38-11    pebble-screenshot_2014-11-08_21-38-21

A new ‘HOLD’ icon prompts access to the scheduling feature, including list of existing events and UI to create new ones.

A personal example of this is that every night at about midnight I turn off WiFi on my phone to save power through the night using Tasker. Now, I can remove the Tasker icon from the status bar and use Dashboard to carry out the action instead. Of course, Tasker didn’t require me to keep my Bluetooth on overnight, but it’s a small price to pay for automated control of Android radios!

When adding such a complex feature (Dashboard itself went from two main code files to eight and ~600 to ~1300 lines of code), bugs will occur. Some will be code-based, such as not handling setting two wakeups for the same time (which the system will not allow) and warning the user, and some are behavioral.

At the moment, the Pebble appstore will not always update the released watchapp when a new version is uploaded. This can make co-ordinating a release with Google Play Store very difficult. Users were prompted to ‘update watchapp from Android app’. What I intended was for them to use the ‘Install Watchapp’ button in the Dashboard Android app to get the bundled compatible version, but in reality they were unloading and reloading the watchapp from the Pebble app locker, which ended up with them still having the old version. And so the loop continued until some concerned users emailed me about it. In all cases I clarified the correct procedure and every case was fixed. So now that process is hopefully a bit more explicit!

Just released Dashboard 1.3!

The major new feature in this version is the ability to dynamically re-order the toggles to suit your preference. The way this works involves selecting each position in an Android Spinner in the ‘Configure’ tab:



Each time a user makes a selection in one of the positions, the rest of the Spinner array is checked to look for a duplicate of the toggle the user has just chosen, and switches the two around. For example, if the user changes the Wi-Fi toggle to Autosync, the first toggle becomes Autosync and then the existing Autosync Spinner duplicate is changed to the only other missing toggle type – Wi-Fi!

This means that the toggles can be any order possible, such as the examples below:


That’s a total of P(8,8) = 40320!