RoboPapa — Build, Code, Create, Repeat

« Coding

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(); //Turn green light
    if(level>75) LED2.set(); //Turn blue light
    else if(level > 40) LED3.set(); //Turn red light
    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); // in case we fail do the retry
                }
            }).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); // execute will be a recursive function
    }, 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

Puck Controlling Other Pucks Using NRF | RoboPapa