Puck Controlling Other Puck Using NRF

In this coding sample I will show you how to code your puck to control other pucks using Bluetooth connection. In a nutshell the puck is connecting via Bluetooth LE (or to be more percise the nRF51/52 chip). During the connection (as peripheral) the Puck will get both services and characteristics (or Generic Attrivute Profile also known as GATT ) depends on the peripheral, it might broadcast a name (the pucks do) or it will send a URL. Knowing this information we can start design the code.

Here is what I wanted to achieve:

  • Run only with button click - I didn't want to keep connected to the other pucks. From the creator's documentation the puck will draw 200μa if stay connected. I will use setWatch on BTN for events
  • Run battery level function - same function on all the pucks to indicate and visually show (by using LED1,LED2,LED3) battery level
  • Retry option - Because the NRF / bluetooth might fail because of connection option, I wanted to implement retry option with in the code.

In order to achieve these 3 goals i came up with the code as follow

function showBatteryLevel() {
if(digitalRead(LED1) == 1 || digitalRead(LED2) == 1 || digitalRead(LED3) == 1) {
LED1.reset(); LED2.reset(); LED3.reset(); return;
}
let level = Puck.getBatteryPercentage();
if(level>75) LED2.set();
else if(level > 40) LED3.set();
else LED1.set();
}

function execute(devices, index) {
if(index < devices.length) {
console.log(devices[index]);
console.log('index:' + index);
console.log(devices[index].name);
if(devices[index].hasOwnProperty('name') && startWith(devices[index].name, 'Puck.js')) {
let gatt = null;
devices[index].gatt.connect().then(function(g) {
console.log('connect');
gatt = g;
console.log(g);
let ps = null;
try {
ps = gatt.getPrimaryService("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
console.log(ps);
return ps;
} catch(e) {
console.log('error' + e);
execute(devices,index);
}
}).then(function(service) {
console.log('Service');
return service.getCharacteristic("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
}).then(function(characteristic) {
console.log('characteristic');
characteristic.writeValue("showBatteryLevel()\n");
}).then(function() {
if(gatt !== null) {
gatt.disconnect();
}
console.log("Done!:" + devices[index].name);
execute(devices,index+1);
});
} else {
execute(devices,index+1);
return;
}
} else {
console.log('Done!');
return;
}
}

function startWith(str, substr) {
for(let index in substr) {
if(substr[index] !== str[index]) {
return false;
}
}
return true;
}

function broadcast() {
showBatteryLevel();
let devices;
NRF.findDevices(function(d) {
devices = d;
console.log('length:' + devices.length);
execute(devices,0);
}, 2000);
}

setWatch(function() { broadcast(); }, BTN, { repeat: true, edge: 'falling' });

If you need a guide on how to start with puck check out my first Puck video In the decscription i also included links to the documentation.

You can download the javascript code