Puck.js to GCP BigQuery & Data Studio

This tutorial shows you how use Puck.js and a Raspberry Pi to stream data to GCP.

The GCP Tutorial (Temperature data to GCP BigQuery Table & Data Studio Graph):

window

Prerequesites

Raspberry Pi Setup

Note: This tutorial assumes you have EspruinoHub & NodeRed installed on your Raspberry Pi already!

Edit the Raspberry Pi so EspruinoHub will ingest the MQTT messages and NodeRed will publish to the right GCP project

Go into the attributes.js file

cd
cd EspruinoHub/lib
nano attributes.js
exports.names = {
  // https://www.bluetooth.com/specifications/gatt/services/
  "1801": "Generic Attribute",
  "1809": "Temperature",
  "180a": "Device Information",
  "180f": "Battery Service",
  //////////////////////////////
  // Add These /////////////////
  //////////////////////////////
  "182a": "VoltageSensor",
  "182b": "LightSensor",
  "182c": "AccelerationSensor",
  "182d": "GyroscopicSensor",
  "182e": "MovementSensor",
  "182f": "TiltDetection",
  "183a": "MagneticField",
  "183b": "MagneticFieldData",
  "183c": "ButtonPress",
  "183d": "LEDState",
  "183e": "NFCDetection",
  "183f": "NFCData",
  "184a": "BluetoothScanData",
  "184b": "BluetoothScanState",
  //////////////////////////////
  //////////////////////////////
  //////////////////////////////
  // https://github.com/atc1441/ATC_MiThermometer#advertising-format-of-the-custom-fir>
  "181a": "ATC_MiThermometer",
  "181b": "Body Composition",
  "181c": "User Data",
  "181d": "Weight Scale",
  // https://www.bluetooth.com/specifications/gatt/characteristics/
  "2a2b": "Current Time",
  "2a6d": "Pressure",
  "2a6e": "Temperature",
  "2a6f": "Humidity",
  "2af2": "Energy",
  // https://www.bluetooth.com/specifications/assigned-numbers/16-bit-uuids-for-member>
  "fe0f": "Philips",
  "fe95": "Xiaomi",
  "fe9f": "Google",
  "feaa": "Google Eddystone",

  "6e400001b5a3f393e0a9e50e24dcca9e": "nus",
  "6e400002b5a3f393e0a9e50e24dcca9e": "nus_tx",
  "6e400003b5a3f393e0a9e50e24dcca9e": "nus_rx"
};
cd
cd /.
cd lib/systemd/system
sudo nano nodered.service
Environment="GOOGLE_CLOUD_PROJECT=mygooglecloudproject-123456"
systemctl daemon-reload

Flash the Code to Puck.js

var state =1;
NRF.setTxPower(4); // Full Power advertising

//Send MQTT Advertisements & Console Logs Every Minute while Button State === 1
setInterval(function () {
    setTimeout(function(){
        if(state === 1){
            // Sent: 79
            // - /ble/advertise/c3:5a:61:d8:02:05/temp
            // - "1809": "Temperature",
            // 1809 => {"temp":79}
            console.log("temperature : " + [Math.round((E.getTemperature()*9/5)+32)]);
            NRF.setAdvertising({
                0x1809 : [Math.round((E.getTemperature()*9/5)+32)]
            });
        }
    },1);

    setTimeout(function(){
        if(state === 1){
            // Sent: 100
            // - /ble/advertise/c3:5a:61:d8:02:05/battery
            // - "180f": "Battery Service",
            // 180f => {"battery":100}
            console.log("battery : " + [E.getBattery()]);
            NRF.setAdvertising({
                0x180F : [E.getBattery()]
            });
        }
    },5000);

    setTimeout(function(){
        if(state === 1){
            //   "182a": "VoltageSensor",
            console.log("Voltage : " + [String(Math.round(analogRead(D30)*6.6 * 100) / 100)]);
            NRF.setAdvertising({
                0x182a : [String(Math.round(analogRead(D30)*6.6 * 100) / 100)]
            });
        }
    },10000);

    setTimeout(function(){
        if(state === 1){
            console.log("Light : " + [String(Puck.light())]);
            NRF.setAdvertising({
                //   "182b": "LightSensor",
                0x182b : [String(Puck.light())]
            });
        }
    },15000);

    setTimeout(function(){
        if(state === 1){
            console.log("LEDs: " + digitalRead(LED1).toString(16)], [digitalRead(LED2).toString(16)], [digitalRead(LED2).toString(16));
            NRF.setAdvertising({
                //   "183d": "LEDState",
                0x183d : digitalRead(LED1).toString(16)], [digitalRead(LED2).toString(16)], [digitalRead(LED2).toString(16)
            });
        }
    },20000);
},60000);

//Button Press
//Turn Off/On MQTT Advertising
var pressCount = 0;
setWatch(function() {
    pressCount++;
    state = (pressCount+1)%2;
    if ((pressCount+1)%2) digitalPulse(LED3,1,1500); //long flash blue light
    else
        digitalPulse(LED3,1,100); //short flash blue light
    console.log('button_press_count : [' + pressCount + ']');
    console.log('button_state : [' + (pressCount+1) + ']');
    console.log('state: ' + state);
    NRF.setAdvertising({
        0xFFFF : [pressCount],
        0x183c: [((pressCount+1)%2)],
    });
}, BTN, { edge:"rising", repeat:true, debounce:50 });

//Movement Sensor
require("puckjsv2-accel-movement").on();
var idleTimeout;
Puck.on('accel',function(a) {
    digitalWrite(LED1,1); //turn on red light
  if (idleTimeout) clearTimeout(idleTimeout);
  else
    if (state === 1) {
        console.log('movement : 1');
        NRF.setAdvertising({
            0x182e: [1],
        });
    }
    idleTimeout = setTimeout(function() {
        idleTimeout = undefined;
        digitalWrite(LED1,0);//turn off red light
        if (state === 1) {
            console.log('movement : 0');
            NRF.setAdvertising({
                0x182e: [0],
            });
        }
    },500);
});

//Magnetic Field Sensor
require("puckjsv2-mag-level").on();
Puck.on('field',function(m) {
    digitalPulse(LED2, 1, 200);//flash green light
    if (state === 1) {
        console.log('magnetic_field : [' + m.state + ']');
        NRF.setAdvertising({
            0x183a: [m.state],
        });
    }
});

//NFC Detection
NRF.nfcURL("http://espruino.com");
NRF.on('NFCon', function() {
    digitalPulse(LED2, 1, 500);//flash on green light
    console.log('nfc_field : [1]');
    NRF.setAdvertising({
        0x183e: [1],
    });
});
NRF.on('NFCoff', function() {
    digitalPulse(LED2, 1, 200);//flash on green light
    console.log('nfc_field : [0]');
    NRF.setAdvertising({
        0x183e: [0],
    });
});

Setting up GCP Pub/Sub & BigQuery

{
  "type": "record",
  "name": "Avro",
  "fields": [
    {
      "name": "temperature_fahrenheit",
      "type": "int"
    }
  ]
}

Setting up NodeRed

BigQuery & Data Studio

Buying

Puck.js devices can be ordered from here

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