Attila Vago

Writer of codes, blogs and things that live on the web. Loves craft beer!

How I Hacked Puck.js Into a Bluetooth PowerPoint Presenter

The most beautiful Puck.js photo out there — taken with my Fujifilm X70

Other people’s pain inspires me.

OK. Before you Array.prototype.push() me into the same category you’d find people like Hitler, Trump and Putin, hang on for a second. Pain can indeed be inspirational. It’s what pushed medicine to its state of the art status. But I am not talking about literal pain, but rather a “pain in the behind” kind of situation.

During the last presentation I’ve attended at HMH — Dublin, which was naturally all about innovation, and how to turn good into great, and great into undeniably awesome, I couldn’t help but notice that funnily enough scrolling through the presentation, required an extra hand — a lovely assistant of sorts. In 2017. Which made me think of solving a real problem, one that might seem trivial at first, but when you’re a very hands on type of presenter, like I would be, if I did not have to fiddle with keyboards, that is — it’s a real pain. A real struggle some might say…

Well, it just so happens that a few weeks ago I purchased on a whim — which I rarely do — a tiny beacon called Puck.js. I was one of the few lucky ones who acted fast enough before the initial batch sold out on Pimoroni.

Now, my initial experience was not the greatest with it, something which I documented on their Web IDE Github page. Thankfully, the fix was very quickly added, and off I was coding the solution for …

The problem

When presenting in Microsoft PowerPoint, you either have an assistant, or you attach yourself to the keyboard while presenting, unless you have a remote of sorts that you can click back and forth.

The proposed solution

Use Puck.js as a remote to solve the problem. Having Puck.js as a remote opens up two solutions actually, given the fact that it features both Bluetooth and IR. But IR … I don’t know, I was never a fan of IR. Everything I own is Bluetooth. I must keep the trend up, right?

Going backwards is not innovative. One does not not innovate!

The challenge

I initially knew nothing about programming a Puck, or the Espruino API so I just went blindly into it — well, as blindly as someone who has written JavaScript for a few years, can do. Fail fast, fail early? Maybe. Anyhow, the first head-scratcher was actually not getting the Puck’s single button advertise a one letter string — namely “n” for next, and “p” for previous, but making both of those work. While normally people present progressively, at times you have situations when you have to back a slide or two, so while I got the “next” function going quite quickly, making the “previous” one work became more of a challenge than I thought.

My first go at it was timing my “clicks”

setWatch(function(e) {
if(e.time-e.lastTime < 1){
}, BTN, {edge:”rising”, debounce:50, repeat:true});
setWatch(function(e) {
if(e.time-e.lastTime > 1){
}, BTN, {edge:”rising”, debounce:50, repeat:true});

But the results were flaky enough for me not to be confident taking this into the boardroom for half the engineers to see. Buggy implementations are one thing, bad ones are another.

So what does an engineer do when plan A fails? Well, I have this SIGG bottle that says not to worry when plan A fails, as there’s plenty letters in the Alphabet.

Tru dat! Looking around me, I started thinking what I tend to have with or around me whenever I do a presentation. One would be my mug off coffee but I am not going to dip my Puck into the coffee no matter how much it looks like a turned inside-out Oreo. The only other thing is my phone…

My phone! Yes. That’s it! My phone has a magnetic Torro flip-case. The operative word here is magnetic. Besides temperature, NFC and light sensors, the Puck also has a magnetometer. I love magnets! They stick together! Like the wallpaper sticks to the wall, like the seashore clings to the sea … You get the picture. :) So I swiftly tried this bit of code out to test the readings:

Puck.on('mag', function(xyz) {

Turns out the values are returned as X, Y and Z values. When the Puck is at least 1cm away from my case, the reading is below zero on the X values. As soon as the Puck gets close enough, the X value jumps way above zero. What does that mean? An if statement of course!

Puck.on(‘mag’, function(value) {
if(value.x > 0){
sendPrev(); // fire the “p” character

The implementation

It worked. It bloody worked! The moment I get close to my phone with the Puck, the presentation goes back one slide. Of course the final code is slightly more complex, as I wanted to make sure the magnetometer is not permanently on, and only gets turned on if it’s not already on and turns itself off after 30 minutes to conserve energy. You know, like you and the missus before bed on your birthday… ;)

If you haven’t pressed the button for half an hour, chances are you’re either done and dusted with the presentation or you’ve been abducted by friendly aliens to an outer-galaxy party. That being said, the magnetometer turns on as soon as you first press the button. The final “production” code is below. Sunday afternoon hacking at its best, right? :)

The above code now has a revised version as well, kindly offered by Espruino forum member oesterle, involving the following improvements:

  • Ensure BLE is turned on when Puck is powered on or battery is replaced.
  • Ensure mag turning off doesn’t happen in the middle of presenting.
  • Puck.magOn() doesn’t return a boolean to check if on/off; added code to fix this.
  • Simplified character sending code to remove duplicate code.
  • Added catchy keyboard Bluetooth device name. :-)

The 2nd implementation

Given the fact that I very proudly shared my code, and this article on the Espruino forum, I’ve gotten some feedback from a forum member and Gordon, one of the Puck.js developers. This resulted in some code evolution and implementation fixes. Turns out, my initial plan was actually a very sound approach, my only fault being timing the button’s release rather than its press. Sorting that out results the following code — and the ideal production scenario, where a short press (< 0.5s) means “next”, and a long press (>0.5s) means “previous”, making the magnetic sensor workaround unnecessary. Yay!

More by Attila Vago

Topics of interest

More Related Stories