Marco's Blog

All content personal opinions or work.
en eo

Creating Pebble Apps: A Guide for the Novice (Like Me)

2015-12-07 13 min read Howto marco

Great News! The intro I had written about smartwatches in general and why the Pebble is better than others is gone! Now more Pebble App Development tips!

Developing for Pebble is fun! No, really! It’s complicated, but it’s fun. It has lots of moving parts, but it’s fun!

I am going to skip the part where I tell you why you should develop for Pebble. Because it’s fun! And that’s all anyone needs to know, really.

The first decision to make is not easy: develop online or on your machine? CloudPebble or local SDK? The good news (more good news!) is that both give you essentially the same results. The difference is mainly one of trust and access. With CloudPebble, you have to have an Internet connection (access) and you have to trust Pebble with your code. With the local SDK, development works on Linux and iOS (not Windows) and you have to trust yourself with the installation.

I chose to go the SDK route, but if you are just trying things out, you should go for CloudPebble. It’s much easier, and you can do pretty much the same things there. If you do so, follow the instructions on CloudPebble. If you do the SDK, you’ll end up having more control, but will also need to get your hands dirty with the command line. You can, incidentally, still run the SDK if you are a Windows user. You just have to install Linux on your Windows machine, which is really easy. Pebble (and I) suggest that you do so by installing a virtual machine (think VirtualBox) on your Windows computer and run Linux on it.

Instead of telling you how to do things, I will first tell you about the architecture of a Pebble app. That gives you an idea of the skills involved, and you can decide if you want to take a bite of all this complexity. Hint: It’s fun!

The Pebble is controlled by a microcontroller. If you have ever done anything on an Arduino or the like, you know what you are in for. You need to develop in C, because that’s the only thing those poor critters can run. C is brutal, in that it has all those ancient problems with resource allocation and deallocation we used to deal with when we only had ones and zeroes. That means there is a lot of debugging until something works the way it’s supposed to.

You don’t have to develop in C. There is a community project called Pebble.js with the aim of doing the entire development in JavaScript. It is at a relatively early stage, at this point – my first attempts with it resulted in the phone getting so confused, it reloaded the stock factory image every few tries. But in the future, that might be the way to go.

The fact you could, though, hints at another important fact: the watch is in constant communication with a phone. While C apps can run stand-alone, JavaScript never runs on the watch. It is run by the Pebble app on your phone.

The two are a great couple, really. The watch does its thing, displaying information like time and, I don’t know, weather. The phone backs up the watch with it much greater power. The watch is limited in battery size, processing power, storage space, input capability. The phone isn’t, and can run complex tasks faster, store results almost indefinitely, and allow for all sorts of input.

But that requires the watch and the phone to talk. From C to JavaScript and back. A good chunk of the APIs provided by Pebble deal with that. Sadly, the encapsulation is slightly tragic on both the C and the JavaScript side, and I hope they are going to improve. For instance, I had to implement my own queuing mechanism for messages on the JavaScript side because Pebble doesn’t provide it.

Aside from that, the collaboration is wonderful. The easiest way for the phone and the watch to talk is for them to agree on a series of key/value pairs. Whenever one side changes one, the other is notified and can react. This is called app_sync. app_sync is so easy to use, I kidnapped it to do one-way notifications, as well: the watch changes one of the values for no reason, just so the JavaScript side if compelled to fetch new data.

On the JavaScript side, the benefit of using the phone is that you are able to do whatever your phone is able to do. Since mobile is the big push of the day, everything you want or so is available for phone browsers or as phone content. In particular, you can access external web sites (if you have an Internet connection, that is). Many Pebble apps and watch faces use that functionality to get content, like weather or movie times. You also have access to everything the browser has access to on the phone, including location data. In fact, this is the only way to get access to your location, since the watch doesn’t have a GPS receiver.

Things get more complicated. Does your app have options, like different background colors or the surf break you like to go to? That’s done on a web page you have to provide. I am not sure why they chose to do it this way, as they could have just as well handled that inside the app. Maybe the browser on the phone doesn’t allow local javascript execution. In any case, if you want your app to have configuration options, you have to provide (and of course) host a web page. So now you need to add HTML to the set of skills. Although, granted, this is very basic HTML.

In addition to the configuration, you probably want to create proxy points for the external APIs you use. Pebble doesn’t do that in their examples, they go straight to the external source. As I learned, the problem is that APIs and their availability do change, and whenever they do, they require your app to update. If you create a proxy point, you can keep the API on the watch constant (no update required!) while you can change the proxy point that you control.

You want more complication? You can have it! If you want, you can create a companion app. That’s an app that runs on the phone independently of the Pebble app. This companion app can talk to the watch app and vice versa. The advantage? You can do with this app anything that apps on your phone can do (including sending messages, taking pictures, retrieving information, etc.). Pebble JavaScript only does what the browser can do.

(Hint to the Pebble people: maybe you want to think about incorporating Cordova into your app. That would open a whole new world of APIs to the browser.)

So, how do you get started? The easiest way is to go to CloudPebble and try out one of the examples. The simplest app you can create is a watchface. That’s an app that is run by the watch as a sort of home page. It’s what the watch does when nothing else is happening. Watch faces are much simplified, because they don’t interact with the user. In fact, there isn’t any way for the watch face to interact with the user, since the system takes control. All a watch face is allowed to do is draw on the screen, read internal sensors, and connect to the phone.

The examples, incidentally, are all available on github. If you are working with the local SDK, git clone the examples you like. You can also look at a series of projects that are not from the Pebble folks, open source that someone else created. Frankly, some of these projects are much better as examples than the Pebble ones, in that they tie the components all together.

Creating a new project in either CloudPebble or the SDK is easy. It’s quite obvious what to do in CloudPebble. With the local SDK, you run the tool pebble with the option new-project. When you look at the generated directory, you’ll find it contains a bunch of files and folders. The ones that matter at first are:

  • appinfo.json
  • src/main.c
  • src/js/pebble-js-app.js

(If the last one is missing, it’s because the type of project you created doesn’t require it.)

appinfo.json helps the system define the project. It specifies things like the human readable name of the project and a description, as well as things like which images should be packaged up, and what type of application we are dealing with. The documentation on the Pebble site is very readable, so I’ll refer you to it.

src/main.c is a C language file. In it, you’ll find a skeleton of an app. What is important (no: vital) is that it contain a function called main(). This is the function called by the system to start your app. If it’s missing, no app. You simply add functions to that file if you need more functionality. You can also split up the file into several. The system will pick them up, but that’s an advanced topic.

src/js/pebble-js-app.js is the JavaScript run on the phone. It communicates with the phone using messages, but it communicates with the Pebble phone app using the Pebble JavaScript object. Typically, you would define event listeners on the object to get your functionality running. For instance, the main entry point of your JavaScript shouldn’t be straight execution, but a handler for the ready event on the object. In other words, your code will have a line like this:

Pebble.addEventListener("ready", function(e) {
    // do something
});

(If the syntax looks wonky to you, it’s because you haven’t done enough JavaScript in your life.)

The ready event functions in many ways like the main() in the C world and you should think of them as the main entry points to your app in both worlds.

In the JavaScript portion, you can do whatever you like and are able to implement. Much of the functionality in the examples deals with retrieving data from the Internet, so there is no need for me to explain how that works. The examples also cover pretty well how you deal with communicating the data you got from JavaScript to the C app. The only thing you need to know is that the connection in the C side requires initialization of the values you want passed around, and requires a handler to deal with them. Also, a good reason why things sometimes fail is that you have to specifically declare a message buffer size, and if the messages are longer, you get an error.

Once you are happy with the functionality, you can build the project. On CloudPebble, that’s a button. In the SDK, you type pebble build. I should note that the build tool seems to be really bad at detecting when JavaScript code changes. If that happens to you, run pebble clean; pebble build. The build will generate lots of output statements, and if everything goes well, you’ll see no red output. If there is red, the compiler/linker is unhappy and there is a problem with your C code. It is important to note that the build tool has no idea about your JavaScript code and won’t warn you if there is something wrong with it.

Now it’s all built. How do you run it? You have two surprising options: one is to run on your own Pebble(s), the other to run in an emulator. Amazingly, this works both in CloudPebble and the SDK without a hitch. In CloudPebble, you activate your watch from your smartphone. CloudPebble will then send the built app to the phone. In the SDK, the smartphone has to be connected to the computer. You can also (miracle of miracles) run the emulator in CloudPebble. That is quite the amazing feat – hats off to the Pebble guys! Mostly, though, I use the local emulator.

To run locally, you either specify the IP address of the phone that is connected (follow instructions) or the emulator type with the –emulator option. In the former case, notice that the phone might think its address is 127.0.1.1, or localhost, instead of the local network IP; in that case, figure out what the local network IP is. In the latter case, you need to know that there are currently three variants of the emulator:

  1. aplite: for the “classic” first generation Pebble
  2. basalt: for the Pebble Time
  3. chalk: for Pebble Round

You absolutely need to test your app on all three platforms before you push it out, unless you declare in appinfo.json that you only target specific platforms. The reason is that the three platforms are subtly different: APLITE is black and white only while BASALT introduces color. CHALK has the round form factor, which means you work with fewer pixels per line at the top and bottom than in the center.

(If you have trouble remembering which is which, the platforms are named alphabetically: aplite is the first, chalk the third generation.)

To test the app, you first install it typing pebble install from the root directory of your project (the one that contains appinfo.json). This will install the app on the phone or emulator and run it. You can now test the app to your heart’s content.

Once you test the app, you want to deal with configuration. That’s usually an important item for all but non-trivial apps, as there is not a whole lot of input you want to do on the watch. It’s much easier to deal with configuration by setting properties on the phone and running with them.

The configuration page is typically done using Slate, a styling library provided by Pebble. You must host this configuration page somewhere, and your app has to open a URL to this page when the show_configuration event is triggered. Again, the examples are pretty easy to follow, you only need to know that this page has to be somewhere on the Internet. (Tip: you can point to localhost from the emulator.)

Debugging is performed both on the watch and the phone using debug statements. The C code typically looks like this:

APP_LOG(APP_LOG_LEVEL_DEBUG, "Done initializing, created %d windows", num_windows);

(If that looks unfamiliar, you need to do more C coding 😉 )

In JavaScript, you use console.log("message");

To access the logs, you run pebble logs. That’s either pebble logs --phone X.Y.Z.W or pebble logs --emulator basalt. The last one could of course also be aplite or chalk, depending on what emulator you want to follow.

Last but not least, I strongly suggest you create proxy points for all your Internet information needs. Say you have a watchface that requests weather info for the current location. It gets the location information from the phone (so far, so good) but then it has to go and fetch current weather data from somewhere. Pebble examples use openweathermap.org, a great resource. I would definitely create a proxy on the same host as where you host the configuration page and have it make the request for you.

There are two main reasons for this: (1) APIs and providers can change. If they change abruptly, your app will stop working until it is updated, which happens at the leisure of the user. (2) APIs usually require access keys. Unless you want a copy of your access key to be stored on all phones that have your app installed, you probably want to do without that.

That’s pretty much it! In summary, there are lots of moving parts to a Pebble app, but that makes the development that much more fun!