In this short codelab, you'll learn how to discover and interact with a nearby Bluetooth device thanks to Polymer. Along the way, you'll also take advantage of Polymer's data-binding features.

What you'll learn

What you'll need

How would rate your experience with Polymer?

Novice Intermediate Advanced

Create a new project

The first time you run Chrome Dev Editor it will ask you to setup your workspace environment.

Fire up Chrome Dev Editor and start a new project:

  1. Click to start a new project.
  2. Enter "PolymerBluetoothCodelab" as the Project name.
  3. In the Project type dropdown, select "JavaScript web app (using Polymer paper elements)".
  4. Click the CREATE button.

Chrome Dev Editor creates a basic scaffold for your Polymer app. In the background, it also uses Bower to download and install a list of dependencies (including the Polymer core library) into the bower_components/ folder. You'll learn more about using Bower in the next step.

Your folder structure should look like this:

PolymerBluetoothCodelab/
  bower_components/ <!-- Installed dependencies from Bower -->
  bower.json  <!-- Bower metadata files used for managing deps -->
  index.html  <!-- your app -->
  main.js
  styles.css

Next up

At this point the app doesn't do much. Let's start adding Bluetooth support!

The Polymer Platinum Collection provides the platinum-bluetooth elements for discovering and interacting with nearby Bluetooth devices. To use this collection, you first need to install it using Bower.

Install the <platinum-bluetooth> elements

Chrome Dev Editor does not have a command line for running Bower commands. Instead, you need to manually edit bower.json to include platinum-bluetooth, then run Chrome Dev Editor's Bower Update feature. Bower Update checks the dependencies in bower.json and installs any missing ones.

  1. Edit bower.json and add platinum-bluetooth to the dependencies object:
  ...
  "dependencies": {
    "iron-elements": "PolymerElements/iron-elements#^1.0.0",
    "paper-elements": "PolymerElements/paper-elements#^1.0.1",
    "platinum-bluetooth": "PolymerElements/platinum-bluetooth#^2.1.0"
  }
}
  1. Right-click the bower.json filename in the editor left pane.
  2. Select Bower Update from the context menu.

The download may take a few seconds. You can verify that platinum-bluetooth (and any dependencies) were installed by checking that bower_components/platinum-bluetooth/ was created and populated.

Use the <platinum-bluetooth-device> element

To employ <platinum-bluetooth-device>, you need to:

  1. Use an HTML Import to load it in index.html.
  2. Declare an instance of the element on the page.
  3. Call the request() JavaScript method of this instance on a user gesture.

In index.html, remove all other HTML imports in the <head> and replace them with HTML imports to load paper-button.html and platinum-bluetooth-device.html:

index.html

<head>
  ....
  <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>

  <link rel="import" href="bower_components/paper-button/paper-button.html">

  <link rel="import" href="bower_components/platinum-bluetooth/platinum-bluetooth-device.html">

  <link rel="stylesheet" href="styles.css">
</head>

Next, replace the contents of <body unresolved> with an instance of <platinum-bluetooth-device>, a simple <paper-button> and a script:

index.html

<body unresolved>
  <platinum-bluetooth-device services-filter='["battery_service"]'>
  </platinum-bluetooth-device>

  <section>
    <paper-button raised>Get Device</paper-button>
  </section>

  <script src="main.js"></script>
</body>

Finally, in main.js, replace the contents with the JavaScript below:

main.js

document.addEventListener('WebComponentsReady', function() {

  var batteryDevice = document.querySelector('platinum-bluetooth-device');
  var button = document.querySelector('paper-button');

  button.addEventListener('click', function() {
    console.log('Requesting a bluetooth device advertising a battery service...');
    
    batteryDevice.request().then(function(device) {
      console.log('A bluetooth device has been found!');
      console.log('Device Name: ' + device.name);
    })
    .catch(function(error) {
      console.error('Argh! ', error);
    });
  });
});

Run the app

At this point, select the index.html file and hit the button in the top left corner to run the app. Chrome Dev Editor fires up a local web server and navigates to the index.html page.

If you want to see what this app looks like on your Android phone, you'll need to enable Remote debugging on Android and set up Port forwarding with port number 31999. After that, you can simply open a new Chrome tab to http://localhost:31999/candle-bluetooth/index.html on your Android phone.

You should see a simple "Get Device" button. Click on it, pick the device in the chooser and open your favorite Dev Tools console with Ctrl + Shift + J keyboard shortcut and wait for it...

You might get an error if there are no Bluetooth devices advertising a battery service near you. In this case, grab an Android phone that supports BLE Peripheral Mode (Nexus 6, Nexus 9, Moto E 4G LTE, LG G4, Galaxy S6) and jump to the next step.

Frequently Asked Questions

Once you have an Android phone that supports BLE peripheral mode (Nexus 6, Nexus 9, Moto E 4G LTE, LG G4, Galaxy S6), search for "BLE Peripheral Simulator" in the Google Play Store and install the app on your Android phone if it's not already done.

The app is also available at play.google.com/store/apps/details?id=io.github.webbluetoothcg.bletestperipheral.

Advertise a battery service

Open the BLE Peripheral Simulator app, tap on "Battery" and that's pretty much it! From there, your Android phone will advertise a battery service via Bluetooth while this screen is on.

You can also customize the battery level value with the slider below.

.

Run the app for realz

Now that your Android phone is advertising a battery service, let's jump back to the Polymer Web app, click one more time the "Get Device" button, pick the device in the chooser and open your favorite Dev Tools console with Ctrl + Shift + J keyboard shortcut and notice the BluetoothDevice object logged. Here's what you should get if you use a Nexus 6 for instance:

Next up

Let's read the battery level advertised by your Android app!

Frequently Asked Questions

Reading a Bluetooth characteristic can be easily done by using the <platinum-bluetooth-service> and <platinum-bluetooth-characteristic> elements.

Use the <platinum-bluetooth-service> and <platinum-bluetooth-characteristic> elements

To employ <platinum-bluetooth-service> and <platinum-bluetooth-characteristic> you need to:

  1. Use HTML Import to load them in index.html.
  2. Declare an instance of <platinum-bluetooth-service> as a child of a <platinum-bluetooth-device> element.
  3. Declare an instance of <platinum-bluetooth-characteristic> as a child of a <platinum-bluetooth-service> element.
  4. Call the read() javascript method of the <platinum-bluetooth-characteristic> instance

In index.html, append new HTML imports that load platinum-bluetooth-service.html and platinum-bluetooth-characteristic.html after platinum-bluetooth-device.html:

index.html

  <link rel="import" href="bower_components/platinum-bluetooth/platinum-bluetooth-device.html">
  <link rel="import" href="bower_components/platinum-bluetooth/platinum-bluetooth-service.html">
  <link rel="import" href="bower_components/platinum-bluetooth/platinum-bluetooth-characteristic.html">

Next, add a new <platinum-bluetooth-service> as a child of the previously created <platinum-bluetooth-device> element , and a new <platinum-bluetooth-characteristic> as a child of the <platinum-bluetooth-service> element. Finally rename the "Get Device" button to "Get Battery" to reflect what we want to achieve:

index.html

  <platinum-bluetooth-device services-filter='["battery_service"]'>
    <platinum-bluetooth-service service="battery_service">
      <platinum-bluetooth-characteristic characteristic="battery_level">
      </platinum-bluetooth-characteristic>
    </platinum-bluetooth-service>
  </platinum-bluetooth-device>

  <section>
    <paper-button raised>Get Battery</paper-button>
  </section>

Finally, in main.js, include the battery level reading code in the batteryDevice.request() fulfilled response:

main.js

    batteryDevice.request().then(function(device) {
      console.log('A bluetooth device has been found!');
      console.log('Device Name: ' + device.name);
      
      // Connect to the device and read battery level.
      var batteryLevel = batteryDevice.querySelector('platinum-bluetooth-characteristic');
      return batteryLevel.read().then(function(value) {
        console.log('Battery Level is ' + value.getUint8(0) + '%');
      });

    })
    .catch(function(error) {
      console.error('Argh! ', error);
    });

Read the battery level

Select the index.html file and hit the button in the top left corner to run the app as seen before. Make sure your Android phone is still advertising a battery service first, then click on the "Get Battery" button on the page and check your Dev Tools console:

You can now change the battery level value in the Android app and click again the "Get Battery" button to see how fast it is to read a cached characteristic.

Fill in a data-bound field in response to a read

Using the Polymer's data binding features, it is really easy to fill in a data-bound field in response to a Bluetooth characteristic reading. Let's see how showing a Polymer toast containing the battery level would work.

In index.html, append a new HTML import that loads paper-toast.html after paper-button.html. Note that you don't need to run Bower Update there as paper-toast is already downloaded as part of paper-elements.

index.html

  <link rel="import" href="bower_components/paper-button/paper-button.html">
  <link rel="import" href="bower_components/paper-toast/paper-toast.html">

Next, add a binding annotation value to the previous <platinum-bluetooth-characteristic> element, append a <paper-toast> element with a custom text attribute value, and encapsulate the all thing in an auto-binding template element:

index.html

<body>
  <template is="dom-bind">
    
    <platinum-bluetooth-device services-filter='["battery_service"]'>
    <platinum-bluetooth-service service="battery_service">
      <platinum-bluetooth-characteristic
          characteristic="battery_level"
          value={{batteryLevel}}>
      </platinum-bluetooth-characteristic>
    </platinum-bluetooth-service>
  </platinum-bluetooth-device>
  
  <section>
    <paper-button raised>Get Battery</paper-button>
  </section>
  
  <paper-toast text="{{computeCharacteristic(batteryLevel)}}"></paper-toast>
  
  </template>
  
  <script src="main.js"></script>
</body>

Next, in main.js, let's add the new computeCharacteristic function to the template element and show a toast in the batteryLevel.read() fulfilled response:

main.js

      // Connect to the device and read battery level.
      var batteryLevel = batteryDevice.querySelector('platinum-bluetooth-characteristic');
      return batteryLevel.read().then(function() {
        document.querySelector('paper-toast').show();
      });

main.js

var template = document.querySelector('template');
template.computeCharacteristic = function(batteryLevel) {
  return ('Battery Level is ' + batteryLevel.getUint8(0) + '%');
};

Select the index.html file and hit the button in the top left corner to run the app as seen before. Make sure your Android phone is still advertising a battery service first, then click on the "Get Battery" button on the page and you should see a toast now populated with the battery level:

Congratulations!

You've done well! You have built a simple web app that shows the battery level value advertised by your Android phone over Bluetooth — without needing to know much about Bluetooth.

I'm sure you could easily get the body sensor location of a fake heart rate sensor now by modifying some bits of this existing code. Trust me and follow these rough steps:

  1. Change the <platinum-bluetooth-device> element's services-filter attribute value to ["heart_rate"] in index.html.
  2. Change the <platinum-bluetooth-service> element's service attribute value to "heart_rate" in index.html.
  3. Change the <platinum-bluetooth-characteristic> element's characteristic attribute value to "body_sensor_location" in index.html.
  4. Rename the "Get Battery" button to "Get Body Sensor" in index.html.
  5. Update the computeCharacteristic function to simply map 6 to "foot", 5 to "ear lobe", etc in main.js.
  6. Select the "Heart Rate Monitor" Peripheral in the BLE Peripheral Simulator Android app and change the "Body Sensor Location" value.
  7. Run your app and click the new "Get Body Sensor Location" button.

Next up

Let's summarize what you've learned in the next section and what to explore next.

Frequently Asked Questions

Here we are! You're now in full knowledge of the platinum-bluetooth elements. Full? Not yet, you didn't write to a characteristic... check out the next steps below.

What we've covered

Next Steps