Bluetooth LE

ITP | Week 2 | February 12, 2016

Don Coleman

Local Name vs Device Name
void setup() {
  // In Advertising Data 0x09
  blePeripheral.setLocalName("LOCAL NAME");

  // Generic Access Service 0x1800, 0x2A00
  blePeripheral.setDeviceName("DEVICE NAME");

  // ...
}
                

Local Name is 0x09 in Advertising Data

The Generic Access Service 0x1800 contains
the Device Name Characteristic 0x2A00

Callbacks


  try {
    temperature = api.getTemperature();
    console.log(temperature);
  } catch(e) {
    console.log("Error " + e);
  }
                    
synchronous API call
  var success = function(temperature) {
    console.log(temperature);
  };
  var failure = function(err) {
    console.log("Error " + err);
  };
  api.getTemperature(success, failure);
                    
Cordova APIs (usually) end with success and failure callbacks

Bluetooth Low Energy

Cordova Plugin

https://github.com/don/cordova-plugin-ble-central
https://github.com/don/cordova-plugin-ble-central#api

Today we'll build apps to

  • Scan for peripherals
  • Connect to peripheral
  • Control a LED
  • Respond to button input
  • Read temperature sensors

Exercise 1

Scan


    ble.scan(
        [], // any services
        5,  // 5 seconds
        onDiscoverDevice,
        failure
    );
                

  var onDiscoverDevice = function(device) {
      console.log(
          device.name,
          device.id,
          device.rssi
      );
  }
                

Exercise 2

Connect


    ble.connect(
        device.id,
        onConnection,
        failure
    );
                

  var onConnection = function(peripheral) {
      console.log(
          JSON.stringify(peripheral)
      );
  }
                

Exercise 3

LED

Lightbulb Service - FF10


    ble.scan(
        [LED_SERVICE], // only led
        5,  // 5 seconds
        onDiscoverDevice,
        failure
    );
                

  setSwitchValue: function(value) {
      var data = new Uint8Array(1);
      data[0] = value;
      // ...
  },
                
Create typed array in setSwitchValue

  ble.write(
      app.peripheral.id,
      LED_SERVICE,
      SWITCH_CHARACTERISTIC,
      data.buffer,
      success,
      app.onError
  );
                
Write value to switch characteristic in setSwitchValue
  var data = new Uint8Array(1);
  data[0] = brightness.value;
  ble.write(
      app.peripheral.id,
      LED_SERVICE,
      BRIGHTNESS_CHARACTERISTIC,
      data.buffer,
      success,
      app.onError
  );
                
Write value to dimmer characteristic in setBrightness

Exercise 4

Button

Button Service - FFE0


    ble.startNotification(
        device.id,
        BUTTON_SERVICE,
        STATUS_CHARACTERISTIC,
        app.onNotification,
        failure);
                
subscribe to be notified when the button state changes

  onNotification: function(buffer) {
      var data = new Uint8Array(buffer);
      if (data[0] === 0) {
          message = 'Button is released.';
      } else {
          message = 'Button is pressed.';
      }
  },
                

Exercise 5

Thermometer

Thermometer Service - 0xBBB0


    ble.startNotification(
        peripheral.id,
        THERMOMETER_SERVICE,
        TEMPERATURE_CHARACTERISTIC,
        app.onTemperatureChange,
        failure
    );
                
subscribe to be notified when the temperature changes

    ble.read(
        peripheral.id,
        THERMOMETER_SERVICE,
        TEMPERATURE_CHARACTERISTIC,
        app.onTemperatureChange,
        failure
    );
                
read the initial value

  onTemperatureChange: function(buffer) {
      var data = new Float32Array(buffer);
      var celsius = data[0];
      var fahrenheit = (celsius * 1.8 + 32.0);
      var message = "Temperature is " +
                       fahrenheit + " °F";
      statusDiv.innerHTML = message;
  },
                

Exercise 6

Broadcast


// iOS
serviceData = device.advertising.kCBAdvDataServiceData;
if (serviceData && serviceData.BBB0) {
    celsius = new Float32Array(serviceData.BBB0)[0];
}
                
// Android
var advertisingData = parseAdvertisingData(device.advertising);
serviceData = advertisingData[SERVICE_DATA_KEY];
if (serviceData) {
  // first 2 bytes are the 16 bit UUID
  var uuidBytes = new Uint16Array(serviceData.slice(0,2));
  var uuid = uuidBytes[0].toString(16); // hex string
  // remaining bytes are the service data
  var data = new Float32Array(serviceData.slice(2));
  celsius = data[0];
}
                

Multiple BLE Connections https://vimeo.com/140741164
Adafruit Bluefruit LE UART

Debugging

JSHint


$ jshint www/js/index.js
www/js/index.js: line 26, col 33, Expected
 an identifier and instead saw '5'.

1 error
                
Read the console output

 window.onerror = function (e, fileName, lineNumber) {
   console.log(fileName,
         'Line:', lineNumber,
         'Error:', e.message);
   alert(fileName +
         'Line:' + lineNumber,
         'Error:' + e.message);
 };
                
chrome://inspect requires debug version of PhoneGap Developer App
Safari debugging requires debug version of PhoneGap Developer App
Creating Apps without PhoneGap Developer App

 $ cd phonegap/led_v2
 $ phonegap platform add ios
 $ phonegap plugin add cordova-plugin-ble-central
 $ phonegap plugin add cordova-plugin-dialogs
 $ phonegap run ios --device
                

http://bit.ly/bluetooth-book

Don Coleman

dc159@nyu.edu

http://don.github.io/slides/2016-02-12-itp-bluetoothle

 

 

Creative Commons License
Bluetooth LE ITP Week 2 by Don Coleman
is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Based on a work at https://github.com/don/.../2016-02-12-itp-bluetoothle.