Bangle.js Clock Faces

We'll assume you've already been through the Bangle.js Development page and have an idea how to get started.

If so you're now connected and can write some simple code - let's have a go at making a clock!

To do this, it's best to use the right-hand side of the IDE - once uploaded you can tweak values and call functions using the REPL on the left if you want to.

Drawing the time

Copy the following code to the right of the IDE and click Upload ():

function draw() {
  // work out how to display the current time
  var d = new Date();
  var h = d.getHours(), m = d.getMinutes();
  var time = h + ":" + ("0"+m).substr(-2);

  // Reset the state of the graphics library
  g.reset();
  // Clear the area where we want to draw the time
  g.clearRect(50,50,100,120);
  // draw the current time
  g.drawString(time, 50, 50);
}

// Clear the screen once, at startup
g.clear();
// draw immediately at first
draw();
var secondInterval = setInterval(draw, 1000);

You'll now have some tiny text in the middle of the screen, which displays the time.

The slightly odd ("0"+m).substr(-2) code zero-pads the minutes for us (so 1 minute past 12 gets written as "12:01" rather than "12:1").

Why is the code formatted like this? Check out the Code Style page for some tips and the reasoning behind it.

Changing font

First, we'll want to make the text bigger, and properly centered. You have a bunch of options here which you can see on the Fonts page.

We're going to load a custom font for 7 segments called Font7x11Numeric7Seg, which can then be used with g.setFont("7x11Numeric7Seg").

// Load fonts
require("Font7x11Numeric7Seg").add(Graphics);
// position on screen
const X = 160, Y = 140;

function draw() {
  // work out how to display the current time
  var d = new Date();
  var h = d.getHours(), m = d.getMinutes();
  var time = (" "+h).substr(-2) + ":" + ("0"+m).substr(-2);
  // Reset the state of the graphics library
  g.reset();
  // draw the current time (4x size 7 segment)
  g.setFont("7x11Numeric7Seg",4);
  g.setFontAlign(1,1); // align right bottom
  g.drawString(time, X, Y, true /*clear background*/);
  // draw the seconds (2x size 7 segment)
  g.setFont("7x11Numeric7Seg",2);
  g.drawString(("0"+d.getSeconds()).substr(-2), X+30, Y, true /*clear background*/);
}

// Clear the screen once, at startup
g.clear();
// draw immediately at first
draw();
var secondInterval = setInterval(draw, 1000);

Note: To avoid flicker here we're using the 4th argument to drawString, which clears the background (by default only the text itself is drawn).

Finally, let's add the date. For this, we can use the locale library which means that the data will be in the correct language for each user.

Just add the following at the bottom of the draw function:

  // draw the date, in a normal font
  g.setFont("6x8");
  g.setFontAlign(0,1); // align center bottom
  // pad the date - this clears the background if the date were to change length
  var dateStr = "    "+require("locale").date(d)+"    ";
  g.drawString(dateStr, g.getWidth()/2, Y+15, true /*clear background*/);

Extra Clock Features

We now have something that tells the time, but we need to add a few extra bits before we can make this a clock face:

Widgets

Most clocks show widgets. To do this you just need to add the following code to the end of the clock:

Bangle.loadWidgets();
Bangle.drawWidgets();

You can call Bangle.drawWidgets() every time the screen is cleared and widgets need to redraw themselves - but it's good practice to do that as rarely as possible to avoid flicker.

In our example we only clear the screen once (at startup) so that's the only time we call Bangle.drawWidgets()

BTN2 to start the launcher

Every clock needs to be able to start the launcher, and the default for this is BTN2. All you need to do is add this code to the end of the clock code (not in a function):

// Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });

Power saving

Right now, we're redrawing the screen every second regardless of whether it is on or not - that's obviously going to be bad for battery.

To get around this we can listen for when the screen is turned off and cancel our secondInterval interval, then restart it when the screen is turned on (and immediately redraw):

// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower',on=>{
  if (secondInterval) clearInterval(secondInterval);
  secondInterval = undefined;
  if (on) {
    secondInterval = setInterval(draw, 1000);
    draw(); // draw immediately
  }
});

Finally

Your code should now look like this:

// Load fonts
require("Font7x11Numeric7Seg").add(Graphics);
// position on screen
const X = 160, Y = 140;

function draw() {
  // work out how to display the current time
  var d = new Date();
  var h = d.getHours(), m = d.getMinutes();
  var time = (" "+h).substr(-2) + ":" + ("0"+m).substr(-2);
  // Reset the state of the graphics library
  g.reset();
  // draw the current time (4x size 7 segment)
  g.setFont("7x11Numeric7Seg",4);
  g.setFontAlign(1,1); // align right bottom
  g.drawString(time, X, Y, true /*clear background*/);
  // draw the seconds (2x size 7 segment)
  g.setFont("7x11Numeric7Seg",2);
  g.drawString(("0"+d.getSeconds()).substr(-2), X+30, Y, true /*clear background*/);
  // draw the date, in a normal font
  g.setFont("6x8");
  g.setFontAlign(0,1); // align center bottom
  // pad the date - this clears the background if the date were to change length
  var dateStr = "    "+require("locale").date(d)+"    ";
  g.drawString(dateStr, g.getWidth()/2, Y+15, true /*clear background*/);
}

// Clear the screen once, at startup
g.clear();
// draw immediately at first
draw();
var secondInterval = setInterval(draw, 1000);
// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower',on=>{
  if (secondInterval) clearInterval(secondInterval);
  secondInterval = undefined;
  if (on) {
    secondInterval = setInterval(draw, 1000);
    draw(); // draw immediately
  }
});
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();
// Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" });

Making an App

Now we have this, we need to turn it into an app for the watch. To do that we need two basic files on the watch:

  • The app's code in a JS file
  • A JSON info file describing the app (name/etc) for the launcher.

First, come up with a unique ID for your app. Don't use spaces, use lowercase letters, and try and make it reasonably short (under 10 characters is a good idea).

It shouldn't already be listed in https://github.com/espruino/BangleApps/tree/master/apps so that it doesn't interfere with other apps you might install.

App Code: myclock.app.js

We'll use myclock. Now, click the down-arrow below the Upload button, then choose Storage, then New File, and then type myclock.app.js and click Ok.

Now, click the Upload button. The app will be uploaded to the watch and then executed from the file. With this set, you can easily continue to develop your app as it is on the watch.

App Info: myclock.app.info

Now we have the app, but it won't appear in the launcher because there is no app info file. To fix this, just copy and paste the following into the left-hand side of the IDE.

It'll write the relevant info to the file myclock.info

require("Storage").write("myclock.info",{
  "name":"My Clock",
  "type":"clock",
  "src":"myclock.app.js"
});

If you now long-press BTN3 to get to the clock, the press BTN2 to get to the menu, you can scroll down and see My Clock. If you select it, it'll execute your app!

You can also go into Settings, and choose it as the default clock under Select Clock.

Note: The Bangle App Loader automatically generated this file - we're just doing it here so you can create an app without requiring the loader.

Next Steps

Ok, so now we've got a clock!

How about adding it to the Bangle.js App Loader? Check out Adding an app to the Bangle.js App Loader

This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.