James Stanley

Bangle.js open source hackable smart watch: first impressions

Wed 17 March 2021
Tagged: banglejs

Bangle.js is an open source hackable smart watch running the Espruino JavaScript interpreter. It includes BLE (Bluetooth Low Energy), heartrate monitor, temperature sensor, 3-axis accelerometer, GPS, compass, and touchscreen (ish), and is designed to be easy to program.

I like the watch. It does exactly what is claimed: it is easy to program using the Espruino IDE. The battery lasts a surprisingly long time (seems like at least 5 days between charges). The display is surprisingly high-resolution: 240x240 pixels doesn't sound like a lot, but it's more than enough for an LCD that is only 24mm wide. It tells the time. Great success, just what I was after.

It costs about £70 which, depending on your perspective, is either a lot of money or not a lot of money to pay for a watch.

Comparison to Moto 360

Last year I bought a secondhand Moto 360 to run AsteroidOS on. I ended up regretting that purchase and selling the watch. The Moto 360 runs a full-blown Linux system (!), and has substantially more memory and a more powerful CPU than Bangle.js. It has a (almost) circular display with full touch support. On paper, it's better than Bangle.js in almost every way.

In practice, the battery only lasted about a day, and the development workflow was just so annoying and time-consuming that I couldn't be bothered with anything more than "Hello world". To connect the Moto 360 to the PC, you need to prise off the (glued) back cover and solder USB wires on to the PCB, then plug it into the PC, work out how to get networking working over a USB modem, develop your program using Qt and QML, then install it to the watch over SSH. Then undo your soldering and stick the back cover back on. Such a hassle. And that's after you've got past the step of replacing the stock OS with AsteroidOS!

AsteroidOS is a great project, but developing for it is more of a time investment than I'm after.

(To be clear: this picture shows how you connect to the Moto 360; the watch pictured here is not the Bangle.js)

Bangle.js is the antithesis of the Moto 360 experience. It's simple. Easy to use and easy to program, and you don't have to feel like you're doing something "naughty" just by trying to run your own code on your own device. I've already fixed a bug in an app I downloaded, and I haven't had to flash the firmware, break-and-enter past a glued-on cover, or even get my soldering sponge wet. Bangle.js for the win.


The watch is quite big, but not intolerably so. Here's a picture of it next to the watch I've been wearing for the past 7 or so years:

(The pictured watchface is Morphing Clock Plus)

It felt very big at first, but I got used to it quite quickly.

I'm not quite sure what the "N,E,S,W" markings on the bezel are for. They can't be rotated, and seem to bear no relation to anything else.

The screen can sense touch, but only in 2 zones. A touch on the left half of the screen is communicated to software as a press of "BTN4", and the right half is "BTN5". This is OK, and is sufficient to detect swiping left and right, but it would obviously be better if it could sense a grid of 16 or so zones instead of just left vs right.

The weirdest part of the watch is that the screen is actually square, despite the circular housing. I think this is an improvement over making a watch with a square housing, but obviously it would be better if the display were circular as well. I guess circular displays were too expensive or inconvenient to procure.

(The pictured watchface is Animated Clock)

The watch has a really nice and convenient magnetic charging connector, but it seems like a slightly flawed design. The charging cable has a sticker on it warning you to plug the connector in the right way around! The connector itself is totally symmetrical, so it is just as easy to plug it in backwards as forwards. It does not specify what happens if you plug it in backwards, and I'm too afraid to try. Hopefully it just doesn't charge, rather than damaging anything.

(In case you lose your sticker and need to find out which way around it goes: try to remember "the wire goes the same side as the buttons")

The instructions that came with the watch also cautioned against leaving the USB cable plugged in while the watch is not charging, because the magnets and the exposed pins mean the connector is almost perfectly designed to seek out nearby conductive objects and short itself out on them! There is a laser-cut charging dock available on the Espruino shop. This seems like a good candidate for 3d printing, and indeed there are various designs available on Thingiverse.

I found that the watch is very slow to get a GPS fix. After 3 minutes of waiting, Beer Compass still couldn't tell me the direction to the nearest pub:

I expect the GPS will work better outdoors. Although, it's not like the pubs are open at the moment anyway.

I also found that the BLE range is surprisingly short. I have a Bluetooth dongle which I use for wireless headphones, and I can walk most of the way around the house and still hear my music playing. But for some reason, I can't program the Bangle.js unless I hold the watch within about 30cm of the dongle. The BLE range on the watch is not sufficient to reach from my keyboard to the PC under my desk. I don't know why.


The LCD configuration is quite comprehensive. It gives very fine-grained control over the circumstances in which the screen will wake up, including automatically detecting when you rotate your wrist towards your face. I'm not sure what units the "Twist Threshold" and "Twist Max Y" settings are in, or even exactly what they mean, or which direction is positive, which makes these particular settings less useful than they could be.

It also seems as though the "Timeout" settings, despite having no labelled units, are in different units. "LCD Timeout" is set to 10, and the LCD switches off after 10 seconds. But "Twist Timeout" is set to 1000, and it seems more likely that this is looking for twists that are shorter than 1 second rather than 16 minutes.


There are quite a few apps for the watch available on the Bangle.js App Loader.

Unfortunately the apps do not include screenshots. I guess this is because it's inconvenient to take screenshots of the watch, and the Bangle.js ethos seems to be all about lowering the barrier to entry, so requiring screenshots would be too much work. It's a shame, though, because it makes it hard to know whether you want to use something without installing it first. Fortunately, the barrier to entry to installing apps is also pretty low, so it's not too hard to just test out everything that looks interesting and keep the ones you want.

One effect of the low barrier to entry is that some of the apps are not as polished as you might be used to. This is related to something I wrote about before in the context of 3d printing:

If you spend some time browsing Thingiverse then you might notice that some of the parts are designed very strangely. Parts that have sharp and square edges where rounded edges would look neater, thinner or thicker than appropriate, strength in the wrong places, inappropriate fasteners, and so on.

Your first reaction might be "this is clearly bad, these people are no good at designing things". I think the opposite way of looking at it is more useful: people with no training or experience are now able to design and produce parts that successfully solve their problems. It's not that designing for 3d printing results in worse parts, it's that the barrier to entry for design of working parts is much lower than it ever has been in the past. And I think that is a good thing.

Exactly the same effect is apparent in Bangle.js, and I still think it's a good thing.

One example of an under-polished app is the Counter app. It helps you count things. A number is displayed in the centre of the screen, and you can increase it or decrease it using the side buttons or the touchscreen.

It worked, and was perfectly adequate for counting things. But I noticed that when the "widgets" at the top of the screen are hidden, the counter disappears. Eh? Also, the counter is sometimes displayed in the colour of one of the widgets instead of white.


Fortunately, the low barrier to entry of the Bangle.js ecosystem allowed me to quickly and easily fix these problems myself. (The bug was that the app only set the drawing colour once at startup, instead of every time it draws the screen - if the widgets are redrawn and leave black as the active colour, then the counter information is drawn in black as well, and similarly if the widgets leave another colour active then the counter is drawn in that colour).

I was disappointed to find that the Espruino web IDE can't connect to the watch from Firefox. You need to use Chromium. The reason is that Firefox does not implement "Web Bluetooth". I think I'd prefer a local development envrionment to a web IDE anyway. There is an espruino CLI tool, but it's "very javascript", which means it has a million dependencies, and half of them consider various parts of my system deprecated and therefore don't work properly.

It is possible to run the web IDE locally in electron, which I'll probably look into.

I know that I want to write some apps to run on the watch, but I haven't yet figured out what I want them to do. I think a chess clock watch face might be doable, if not entirely practical. I also think a seasonal clock face might be fun.

I'm not completely sure about the state of the BLE security. It seems as if the default condition of the watch is 100% open, and anybody within (the admittedly short!) bluetooth range can run arbitrary code on the watch with no user interaction required. I think it might be useful to write an app for the watch that keeps BLE switched off except when explicitly connected, and times out after 30 minutes or so. You'd then perform some incantation to tell it you want BLE on, and it would allow BLE for 30 minutes before switching it off again. There is a setting in the menu to turn off BLE, but if you forget to turn it off, you're obliviously walking around with arbitrary remote code execution on your wrist. There is an option in the menu to whitelist specific devices:

But I don't know enough about BLE to know if this is foolproof (e.g. can you spoof it? how long does it take to brute-force the set of all likely device IDs? I should look into this). Regardless, I'd be more comfortable with BLE simply off while not in use.


Running JavaScript on a microcontroller is a really interesting way to make hackable devices. Compared to native machine code programs, the JavaScript model makes it substantially easier for unrelated apps to coexist happily, and even run at the "same" time (e.g. the widgets). Nothing is going to trample over the top of the memory of another app when it isn't working directly with pointers, and nothing is going to hog the CPU when everything is event-driven (where an Arduino project would use a while loop, or the loop() function, Espruino apps use setInterval()).

The downside of running JavaScript is obviously the reduced performance and increased memory usage, but I think it is more than worth it. It's a perfect example of the worse is better model, applied to hardware design:

Hardware quality does not necessarily increase with functionality: there is a point where less functionality ("worse") is a preferable option ("better") in terms of practicality and usability. Hardware that is limited, but simple to use, may be more appealing to the user and market than the reverse. from Wikipedia, but with "software" changed to "hardware"

If you like my blog, please consider subscribing to the RSS feed or the mailing list: