Twitter: raymondcamden


Address: Lafayette, LA, USA

My weekend experiment - PebbleJS

08-24-2014 3,048 views Development, JavaScript 2 Comments

Apparently everyone is expecting the announcement of the iWatch in a few weeks, and wearables are going to be "The Thing" for the next few years. But I've been rocking a Pebble for a while now and I really dig it. It isn't as sexy as some of the newer smart watches, and who knows how it will compare to whatever Apple is doing, but it is affordable (reasonably affordable) and simple. If you are considering picking up a smart watch, definitely check it out.

There has been an SDK for the device since it came out, allowing developers to create watch faces and apps with C. You can read more about that on their developer guide site. Recently though an alternative way to develop for Pebble was released - PebbleJS. As you can imagine, this lets you use JavaScript to create Pebble applications. I thought I'd take it for a spin this weekend.

For the most part, it works pretty easily, especially if you make use of their CloudPebble service. (Why, oh why, must everything be "Cloud" something...) I'm not a big fan of browser-based IDEs, but their editor worked decently enough. The editor has JSHint built in so you get real time syntax and best practices warnings.

Sending the application to your watch is also pretty easy. Remember to enable the developer connection via the mobile app. One thing that tripped me up though was getting CloudPebble to recognize my device. It knew about my original connection via the iPhone app, but it didn't recognize that I had switched to using Android as my primary phone. If you go to the Compilation page of CloudPebble, you can enter the IP address of the phone:

But I wasn't sure how to get my IP. I was about to hit one of those "what is my IP" web pages when I checked the mobile app again. On the Developer panel was my IP:

Another issue I ran into was random transfer errors. This seemed to get worse as I worked on my project, and it may have been related to my app being selected in the Pebble app on my device. Switching to another app, then running my compilation, seemed to help, but I wasn't able to ever figure out exactly what made the process fail. It just slowed me down a bit though.

One cool aspect is that you can view console.log messages directly from the web site. This became more and more useful as I went past the starter app and really began to code something.

For my project I thought I'd build a version of the Death Clock. I figured that kinda made sense on a watch anyway. It is here though that I ran into the biggest problem with PebbleJS - setTimeout and setInterval are discouraged. Now - maybe I'm crazy - but I can't imagine what you could build on Pebble that would actually be useful without having some form of interval based processing. I suppose you could build an app, but any type of watch face or game just wouldn't make sense. There is a good reason for this. From the JavaScript guide:

The JavaScript code is part of the Pebble app and bundled in your pbw file. The phone extracts and installs this code when you install your app on Pebble.
Your JavaScript is executed in a sandbox inside the Pebble mobile app.
Your JavaScript is started by a request from the Pebble app. It will be killed when the user exits your application.
The Pebble mobile app will attempt to keep your app running as long as your Pebble app is running. However, under certain circumstances, the phone may kill the Pebble app and your app. If this occurs, the Pebble mobile app will be automatically restarted.

So - yeah - it is actually being run from the mobile app, not the device. This also has one more huge issue. Because the app runs from the mobile app, any user who is using iOS for Pebble will not be able to download your application until the company resubmits their app to Apple. I guess that's not really their fault, but, honestly, it is enough for me to not recommend using this library. To be clear, I think developing for the Pebble is probably worth your while, but I don't think I can suggest using their JS solution. Maybe for prototyping, but nothing more.

Despite the fact that setInterval was discouraged, I figured, why not go ahead and build it anyway:

You can actually download this right now if you are on Android, and, in up to ten days, iOS as well. Unfortunately, there is no public web interface for the Pebble app library. That is a mistake. Hopefully this will be corrected in the future. Other people have made their own libraries though - basically scraping the same data that the mobile app uses. I used this one - http://pas.cpfx.ca/.

And yes - that looks kinda lame, but that's my fault, not Pebble's. I whipped up the marketing assets in about 2 minutes. In case you're curious, this is what the code looks like. And again, I wrote this rather quickly and this does not demonstrate all the different aspects of what you can do.

/**
 * Welcome to Pebble.js!
 *
 * This is where you write your app.
 */

var UI = require('ui');
var Vector2 = require('vector2');
var Settings = require('settings');

var timeLeft = 2022491029;
var hb;

var wind = new UI.Window();
var textfield = new UI.Text({
    position: new Vector2(0, 50),
    size: new Vector2(144, 30),
    font: 'gothic-24-bold',
    text: 'Time to Live:\n'+String(timeLeft),
    textAlign: 'center'
  });
  wind.add(textfield);

var splash = new UI.Card({
  title: 'Death Clock',
  body: ""
});
splash.show();

function decrCounter() {
  timeLeft--;
  if(timeLeft > 0) {
    textfield.text('Time to Live:\n'+String(timeLeft));
  } else {
    textfield.text("Time is up!");
    clearInterval(hb);
  }
}

setTimeout(function() {
  
  splash.hide();
  wind.show();
  var birthDayStr = localStorage["birthday"];
  if(birthDayStr) {
    console.log("got from local storage");
    var bdParts = birthDayStr.split("/"); 
    var bDate = new Date(bdParts[0], bdParts[1], bdParts[2]);
    console.log('using bdate of '+bDate);
    timeLeft = calculateTimeToDie(bDate);
  }
  hb = setInterval(decrCounter, 1000);
  
}, 2000);

Pebble.addEventListener("showConfiguration", function() {
  console.log("showing configuration");
  Pebble.openURL('http://static.raymondcamden.com/deathclockform.html');
});

Pebble.addEventListener("webviewclosed", function(e) {
  console.log("configuration closed");
  //http://forums.getpebble.com/discussion/15172/pebblejs-cloudpebble-unexpected-token-c-at-object-parse-json-error
  if(e.response !="CANCELLED") {
      var options = JSON.parse(decodeURIComponent(e.response));
      console.log(options.day);
      console.log("Options = " + JSON.stringify(options));
      var dayToSave = options.year + "/" + options.month + "/" + options.day;
      localStorage["birthday"] = dayToSave;
      var bDate = new Date(options.year, options.month, options.day);
      console.log('going to test for '+bDate);
      timeLeft = calculateTimeToDie(bDate);
  }
});

//Given a date, return # of seconds left to live
function calculateTimeToDie(born) {
  var now = new Date();
  var timeAlive = Math.floor((now.getTime() - born.getTime())/1000);
  console.log('time alive is '+timeAlive);
  // 75 years
  var avgTime = 2365200000;
  var timeLeft = avgTime - timeAlive;
  return timeLeft;
}        

Again - I'm not sure I can recommend folks use PebbleJS for their "production" apps, but it was an interesting experiment and kinda cool to see something showing up on my watch so quickly.

One more quick note - I can say that I was impressed by the developer forums at Pebble. Even on a Saturday I got pretty quick answers to my questions.

Edit on August 25: In regards to my note about how PebbleJS required you to wait for an App Store resubmission, it looks like I was wrong. A few hours ago, Jonathan Stark shared this with me:

So... on second thought - maybe my "Cool but not recommended" summary needs to be amended to "Cool and ... maybe!" That's a bit wishy washy still but I'm more open to the possibility of doing more with it now.

2 Comments

  • Bart Louwers #
    Commented on 08-28-2014 at 5:36 AM
    Thanks for your insightful post.
    Nice to see that setInterval is usable!

    Just to be sure, you can actually test your applications yourself on iOS right?
  • Commented on 08-28-2014 at 7:23 AM
    I'm pretty sure you can, but I only tested with Android.

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty