Developer Blog

From One Platform to Another : Tales of a Pebble Refugee

01/25/17 @ 03:15 PM

Today’s post was written by Franco Trimboli, an Australian developer who has published a number of apps for the Pebble platform. He’s recently begun developing apps for Connect IQ and has written this guest post about his experiences.

For many, the Pebble was the first smartwatch they would own. With all the fanfare of a record-breaking Kickstarter campaign, the original Pebble opened up a world of notifications - right there on your wrist. And of course, custom apps. Most developers, including me, jumped at the opportunity to be part of this new community of user friendly, wearable computing.

Fast forward to the present, and sadly Pebble is no more. The health features and long battery life had me keen on replacing my Pebble with something similar.

Being a wearable tech nut, I purchased a Garmin fēnix® 3 right around the same time as my Pebble Time. Like it’s namesake, the fēnix emerged from the dark corner of my drawer and became my daily watch. Now while I love my fēnix 3, other hardware in Garmin’s wheelhouse delivers a more Pebble-esque experience; I recently played around with a vívoactive® HR and it’s like the love child of a Pebble Time and Pebble 2 with an always on color touch screen.

Previously, my reluctance to wear the Garmin rather than the Pebble came from my initial experience with Garmin’s back then embryonic ecosystem. Well, I’m happy to say much has changed since. I was immediately surprised with how far Garmin’s ecosystem has evolved. In particular, Garmin’s SDK — Connect IQ (CIQ) — has come a long way. The discovery of Garmin’s Forum, which delivered helpful insights by seasoned CIQ developers, was a turning point for me. It clearly made me understand how rich the Garmin ecosystem is — widgets, data fields, wireless sensors, apps, and of course, watch faces.

The CIQ learning curve isn’t too hard. If you’ve ever built a Pebble watch face — either in C, or Rocky.js — you’ll find the transition relatively straightforward. Monkey C is an OO language, and unlike C on the Pebble, Monkey C runs in it’s own VM and performs it’s own memory management through reference counting. The CIQ dev environment is integrated with Eclipse. However, I’m not a fan — so I tend to code in a shell, just like the Pebble cmdline and QEMU.

If you’re curious, here are some of the watch faces that I’ve built over the past few weeks.

More Similar Than Different

If you’ve developed apps on Pebble’s SDK — or even if you’ve just messed around with a few watch faces — building on Garmin’s CIQ should be a cinch. In this post, I’ve tried to outline a few helpful hints on the similarities and differences of both platforms:

Package.json is now Manifest.xml

Analogous to Pebble’s package.json, the manifest.xml in CIQ provides essential information about your app. At a high-level, it allows you to define the devices, the access privileges, as well as the device capabilities to be supported — it also instructs the run time on the entry point of your your app (think main() on the Pebble).

Battery Life

Garmin’s background is in making wearables for athletes, where long battery life is essential. CIQ devices run in a low power mode most of the time, and return to high power mode when the user wakes up the device with a button tap or gesture. As such, watch faces only (usually) update on minute increments. 

On a Pebble, you have the flexibility of managing the update interval with tick_timer_service_subscribe with the granularity of a second. In CIQ, watch faces implement the onUpdate method to handle display update events from the system. While this seems like a limitation, it makes sense when your objective is to save battery. The good news is that CIQ provides the onExitSleep and onEnterSleep events so that developers can trigger something useful on the screen like a field update or animation. It’s analogous to the accel_tap_service_subscribe event on a Pebble.


Continuing with the theme of battery life, watch faces are limited to certain API features so they can’t do things like retrieve weather or stock data. While this may seem limiting, Garmin’s approach is to use purpose built widgets to deliver weather and news. Widgets in CIQ take us back to Pebble OS 1.0 — where you could flick through different “apps” by scrolling up and down. Widgets are a great way of accessing data without having to bake it all into a watch face or launch an app.

However, CIQ does have some tricks up its sleeve. Widgets or apps can do things like make web requests in ways you’re familiar with — but with less setup and coding. Normally, on the Pebble you would offload this via XMLHttpRequest through pebble-js and then handle the event with events_app_message_register_inbox_received. With CIQ, this is managed neatly in one place with makeWebRequest with an async callback, allowing you to do some interesting things like manage the request payload from within the logic of your app without having to manage code in two different codebases/languages. 

CIQ can also grab, downsample and render an image from the network using makeImageRequest. So you can build cool things, such as grabbing the latest frame from a network security camera, without having to do all the heavy lifting.


As Pebble apps are built in C, they require careful management of memory. Pebble’s SDK uses functions suffixed with _destroy to do this, ie; to remove a typical screen from memory, you’ll be running bitmap_layer_destroy, gbitmap_destroy, and text_layer_destroy — as a minimum.

As CIQs runtime is reference counted, the Monkey C VM manages most of this for you. Clearing objects usually only requires that you set them to “null”. Also, as an object-oriented language, you gain the advantage of objects, class inheritance, etc. That being said, CIQ has helper methods to keep an eye on the memory ceiling.

While, both Pebble and CIQ support 64kb per watchface, more recent Garmin devices offer up to 128kb of memory for apps.


Just like on a Pebble, you can define and access custom image bitmaps and fonts. On the Pebble platform, you’d define resources - and their corresponding IDs - within the resources item in package.json. You would then access those resources via their names or handle IDs within your code.

Similarly, CIQ defines resources this way, but within an XML file known as resources.xml. CIQ also allows you to define platform specific resources using separate resource directories - for example, using resources-round-218x218 to support all round watches with a resolution of 218 x 218.


Likewise with Pebble, images are converted and stored internally as 1, 4, or 8-bit formats. This allows you to support many devices and bit depths from 2 colors to 64 colors.

On the Pebble, you’d manage the bit-depth of images via memoryFormat in package.json. Within CIQ, it’s a little easier. All you need to do is define the colors you want to display (as hex values) within a <palette> node from within your resources.xml file. The nice thing about CIQs approach is that the resource compiler handles the rest, including the re-sampling and dithering. This saves you generating many different image types and bit depths.

In your code, loading bitmaps uses the unified resource method; loadResource(Rez.Drawables.RESOURCE_ID) which corresponds to Pebble’s more specific gbitmap_create_with_resource(RESOURCE_ID) method.


Pebble made it easy to include TrueType fonts within your app. You’d define unique resource identifiers - ie; FONT_VERDANA_BOLD_42 - and the compiler would go away and create a 1-bit bitmapped version of the font. Multiple resource identifiers (BOLD_16, BOLD_42) were needed for each glyph size which increased memory usage.

It’s a little more involved with Garmin. CIQ requires that you first convert the TTF to a bitmap font in the FNT format. This generates an image bitmap, with the font glyphs, and a descriptor file. Luckily, the Garmin folks reference a conversion tool, and there’s a number of open source FNT converters out there. Personally, I prefer the Garmin way, as you can edit the bitmap, and add custom glyphs and icons. In fact, my Segment watch face is built pixel-perfect from a bitmap font I hand-crafted.

On a Pebble you access your fonts through fonts_load_custom_font(resource_get_handle(RESOURCE_ID)). On CIQ, you use the unified resource method, as before, to load your fonts; loadResource(Rez.Fonts.RESOURCE_ID).

Frame Buffer

Unlike Pebble devices, you don’t have direct access to the frame buffer / canvas. You can only write to the screen using text, bitmaps, and dot / line / polygon primitives. While this seems limiting, the reality is that you seldom need to do any hardware level byte-blitting on the screen.

Layout engine

One of the advantages of Garmin’s platform, is the built-in layout engine. Unlike the Pebble ecosystem, Garmin has many different devices with a multitude of screen sizes and resolutions. The layout engine makes it easy to define one or more responsive views, including text fields, data fields, and images.

Properties and Settings

CIQ allows watchfaces and apps to define and store their own properties. This is handy to store and edit user settings. Pebble has a 4kb limit, while CIQ allows up to 8kb per app.

With Pebble, there’s a few ways to do this - through the Persistent Storage API, or via Clay. Using Clay you’d define your apps properties using messageKeys within package.json - and then define how they’re configured through a Clay config.json file. Then within your app, you’d define the values within a struct, and register app_message_register_inbox_received to read tuples from a dictionary. To persist settings, you’d then call persist_write_data to store your properties.

On CIQ, it’s a magnitude easier. Properties have unique keys and types (Number, String, etc) which are defined within a properties.xml file. The corresponding settings are defined within a settings.xml file, referencing the property keys you wish to expose to your users. Accessing properties and settings is as simple as calling a getProperty method in your app. Whenever a user changes a setting, the onSettingsChanged method is called, allowing you to register any callbacks to update your app.

Starting with examples

There’s nothing like traversing through other people’s code when you’re learning the ropes of a new platform. Garmin recently published a three part series (part 1/part 2/part 3) that overviews creating an app from recording metrics to UI development, as well as a sample on using the OAUTH system. You can also download a free e-Book that gives an overview of the Connect IQ system.

I’ve made my Nyan Cat watch face open source — feel free to grab it on GitHub and play around with it.


While it’s too soon to tell, the team at Garmin seems responsive and willing to listen to issues and feature requests from both users and developers alike. The CIQ team are great listeners, and are willing to consider features that developers want no matter who proposes them. In many ways, this feels similar to the early days at Pebble. While there’s a smaller dev community, in general folks seem more willing to help out, and share their code & knowledge at the drop of a hat.

This year, Garmin seems poised to give their developer community a new opportunity to flourish. Only recently, they announced a 3-day dev summit at their HQ, and they’re (amazingly) giving away devices like the fēnix 5 to developers! It’s a good opportunity to rub shoulders with like-minded developers, and learn the ropes about building apps in the wearable space.

So, if you’re a Pebble refugee and you’ve got the itch to build something useful — or just plain fun — give the SDK a whirl, and join the emerging group of developers building on this platform.

Categories: Connect IQ SDK