Wearables Development With Pebble

It often feels like I’m wrestling an octopus while I’m dressing my son after bath time. Checking the overnight low on my phone to help me choose pyjamas that are warm enough to last him through the night only added to my handicap. I’ve cunningly evened the playing field slightly by writing a Pebble app to check the overnight low with two taps of the device already on my wrist.

What is Pebble?

Pebble is a smart watch that was born from a Kickstarter project.  The project had a goal of $100,000 but ended up making over $10 million.  The biggest advantage over its competitors is its price point – starting at $99, and up to $199 for the steel model (pictured).  The screen is e-paper which means that it’s only black and white, but you get about 7 days of battery life out of the watch.

The Phone App

The watch functionality is tightly coupled with the companion Pebble app running on your smartphone (available for iPhone or Android).  The Pebble app on your phone shows the list of apps installed on your watch.  You can have up to 8 apps installed on the watch at a time. Other apps which you’ve downloaded to the phone but aren’t installed on the watch live in a section called the “locker”.

iPhone My Pebble app

The Pebble phone app also includes a section for browsing and searching through the huge range of available apps.


The Pebble itself doesn’t have an internet connection or GPS chip, so it relies on the phone for the heavy lifting.  The watch communicates via Bluetooth LE to the Pebble app which stays running in the background on your phone.  When you start an app on your watch it automatically starts any JavaScript components installed on the phone for that app.  You can also write a dedicated app on the phone to communicate directly with the watch app so you are not limited to JavaScript running within the Pebble phone app.

Pebble app communications


The program running on the watch is written in C, there is also an option to create apps using only JavaScript but I haven’t played with that yet.  The code that runs on the Pebble phone app is JavaScript.

Pebble app technology

Creating a Pebble App

The easiest way to get up and running is using the cloudpebble.net web based IDE.  Once you’re logged in and have your phone connected, click “Create” on the “Projects” page, give it a name, choose “Pebble C API” with the “Empty project” template then click “Create”.  Once your new project opens, click “Add new” next to “Source files”, chose “C file”, give it any name (with “.c” on the end) and click create.

The basic layout of the app is shown below:

#include <pebble.h>
int main(void) {
// setup
// start run loop
// cleanup

view rawpebble_dev_1_basic_layout.c hosted with ❤ by GitHub

To start off with we’ll create a blank window, push it onto the stack, enter the run loop, then clean up our window when the app closes:

#include <pebble.h>
int main(void) {
// setup
Window *first_window = window_create();
window_stack_push(first_window, true);
// start run loop
// cleanup

view rawpebble_dev_2_blank_window.c hosted with ❤ by GitHub

Clicking the big green play button near the top right of the page will start the compile and deploy process.  If all goes well, you should feel a buzz on your wrist and see your app with a blank canvas staring expectantly back at you.

The IDE success message gives you the opportunity to navigate to the logs.  This is a good time to familiarise yourself with them.  If you exit the app on your Pebble, you should see a line of blue text appear in the logs showing you the available, used and allocated memory.  It’s a good idea to keep an eye on the “Still allocated” amount to make sure you’re cleaning up your memory when the app closes.

Adding some text

To display some text on the screen we add a TextLayer to our new window.  Add the following code in between creating and showing the window.

TextLayer *hello_text_layer = text_layer_create(GRect(10, 10, 100, 40));
text_layer_set_text(hello_text_layer, “Hello”);
layer_add_child(window_get_root_layer(first_window), text_layer_get_layer(hello_text_layer));

view rawpebble_dev_3_text_layer.c hosted with ❤ by GitHub

This GRect is stipulating that we want the text offset 10 pixels from the left and 10 pixels from the top, with a width of 100 pixels and a height of 40 pixels.  These values would normally be more dynamic, based off the screen size or other elements on the screen.

Also don’t forget to clean up the memory before the app exits by making the following call after the event loop finishes:


view rawpebble_dev_4_text_layer_cleanup.c hosted with ❤ by GitHub

Next time you click the green play button you should see “Hello” on your watch. Things just got real.

JavaScript Running on the Phone

The watch doesn’t have direct access to the internet so it relies on JavaScript running on the phone to access the internet and send palatable sized chunks of data back to the watch over the bluetooth connection.  Starting an app on the watch will also start executing any JavaScript on the phone associated with that app.

To add some JavaScript to your app go back to the “Add New” dialog in CloudPebble, choose “JavaScript file”, name it “pebble-js-app.js” (I’m not sure if it needs to be this name, but that’s what they use in the documentation), and click “Create”.  An extremely simple example is shown below:

Pebble.addEventListener(“ready”, function (event) {
console.log(“*** Our JavaScript Running”);

view rawpebble_dev_5_simple.js hosted with ❤ by GitHub

This sets up some code to be called once the app is in flight.  Any messages sent to console.log() will be displayed in the logs screen we saw earlier.  When you run the project now, you should see this message getting displayed in the latest logs.

Sending a Message From the Phone to the Watch

Adding the following line of code inside the “read” callback will attempt to send data from the phone to the watch:

Pebble.sendAppMessage({ 0: “From JavaScript” });

view rawpebble_dev_6_js_send.js hosted with ❤ by GitHub

The message being sent must:

  • be a JavaScript Map/Object
  • have an integer for each key
  • have values that are strings, numbers or byte arrays (nested data structures are not supported)
  • not exceed the maximum message size on the watch

This means you have to be quite careful about how you structure the data being sent from the phone to the watch.

Receiving this message on the watch end also requires some changes.  The first thing we create is a callback that will be called whenever a new message is received, something like below:

static void message_received(DictionaryIterator *iterator, void *context) {
char *message = dict_find(iterator, 0)->value->cstring;
APP_LOG(APP_LOG_LEVEL_DEBUG, “Got message: %s”, message);

view rawpebble_dev_7_message_received.c hosted with ❤ by GitHub

The function can have any name, but the rest of the signature should be the same.  This callback gets the “0” message out of the iterator as a string and logs it out.  Placing the next two lines at the start of the main method will register our callback, and set the inbox size:

app_message_open(app_message_inbox_size_maximum(), 0);

view rawpebble_dev_8_message_setup.c hosted with ❤ by GitHub

The parameters to app_message_open() are the inbox size and the outbox size. Here we are setting the inbox size to the maximum size available for this device, and we’re not using the outbox so we’re setting it to zero.

Running the project now should result in the watch logging out the message that was sent over from the JavaScript running on the phone.

Melbourne Overnight Low

Now that I’ve covered the basics of creating a Pebble app, let’s get back to my idea for an app to check the overnight low in Melbourne. To achieve this I modified the JavaScript to do an XHR request to the BOM website and pull tomorrow’s minimum temperature from the response using a regular expression. The code is as follows:

Pebble.addEventListener(“ready”, function(event) {
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
var firstMin = request.response.match(/class=”min”>([0-9]+)</)[1];
Pebble.sendAppMessage({ 0: firstMin });
request.open(“GET”, “http://www.bom.gov.au/vic/forecasts/melbourne.shtml”, true);

view rawpebble_dev_9_BOM_XHR.js hosted with ❤ by GitHub

Running the project now should show the overnight low displayed as a log message.

To display the value on the watch we just need to modify the text layer in our message received callback in the C code (I made the text layer global so it was accessible from inside the callback). The complete C program should now look something like this:

#include <pebble.h>
static TextLayer *hello_text_layer;
static void message_received(DictionaryIterator *iterator, void *context) {
char *message = dict_find(iterator, 0)->value->cstring;
text_layer_set_text(hello_text_layer, message);
text_layer_set_font(hello_text_layer, fonts_get_system_font(FONT_KEY_ROBOTO_BOLD_SUBSET_49));
int main(void) {
app_message_open(app_message_inbox_size_maximum(), 0);
Window *first_window = window_create();
hello_text_layer = text_layer_create(GRect(10, 10, 124, 148));
text_layer_set_text(hello_text_layer, “Loading…”);
layer_add_child(window_get_root_layer(first_window), text_layer_get_layer(hello_text_layer));
window_stack_push(first_window, true);

view rawpebble_dev_10_display_message.c hosted with ❤ by GitHub

Note that the “hello” text has been modified to act as a loading message.

Too easy!

Wrap Up

The app works great, I’m like a pyjama ninja now. If you’re planning to develop a Pebble app, there are a couple of user experience considerations to keep in mind. Firstly, you can’t type on the watch – so stuff like search queries don’t really work.  Secondly, it needs to be something that you wouldn’t just use your phone to do. There are lots of Pebble apps, but I don’t use many of them because they provide functionality that I’m just as comfortable whipping out my phone for.

Want to know more about how DiUS can help you?



Level 3, 31 Queen St
Melbourne, Victoria, 3000
Phone: 03 9008 5400

Level 2, 50 York St
Sydney, NSW, 2000
Phone: 02 8014 6640

DiUS wishes to acknowledge the Traditional Custodians of the lands on which we work and gather at both our Melbourne and Sydney offices. We pay respect to Elders past, present and emerging and celebrate the diversity of Aboriginal peoples and their ongoing cultures and connections to the lands and waters of Australia.

Subscribe to updates from DiUS

Sign up to receive the latest news, insights and event invites from DiUS straight into your inbox.

© 2023 DiUS®. All rights reserved.

Privacy  |  Terms