fun with bluetooth

why?

progressive 
 web apps

pwa’s are great !

but...

bluetooth

bluetooth sucks

classic bluetooth the reason everybody 
 hates bluetooth bluetooth low energy vs. control drones and other cool shit

bluetooth low energy also known as BLE Bluetooth LE Bluetooth Smart Bluetooth 4

bluetooth low energy also known as BLE Bluetooth LE Bluetooth Smart Bluetooth 4 and 5

10 million


 bluetooth devices 
 shipping every day

mobile phone

computer

glucose monitor somebody's hand

activity tracker

playbulb sphere playbulb

spherio bb-8

parrot mini drone

fi dget spinner

the boring theoretical stuff

central peripheral

central

generic attribute profile

generic attribute profile ?

generic attribute profile gatt, because gap was already taken

client server

central

peripheral

server service characteristic value array of objects object property value

services and characteristics are identified by uuid’s 16 bit or 128 bit

read write write without response notify each characteristic supports
one or more of these

every value is an array of bytes no fancy datatypes, just bytes

pfew...

fun

with

bluetooth boring facts 
 about

fun with bluetooth

 web


 bluetooth
api still not the fun part :-(

connecting to a device

navigator.bluetooth.requestDevice({ filters: [
{ namePrefix: 'PLAYBULB' }
], optionalServices: [ 0xff0f ] }) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService(0xff0f)) .then(service => service.getCharacteristic(0xfffc)) .then(characteristic => { return characteristic.writeValue( new Uint8Array([ 0x00, r, g, b ]) ); }) we tell the browser what 
 kind of device we want

the user selects
the actual device

navigator.bluetooth.requestDevice({ filters: [
{ namePrefix: 'PLAYBULB' }
], optionalServices: [ 0xff0f ] }) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService(0xff0f)) .then(service => service.getCharacteristic(0xfffc)) .then(characteristic => { return characteristic.writeValue( new Uint8Array([ 0x00, r, g, b ]) ); }) get the characteristic get the service connect to the server

writing data

navigator.bluetooth.requestDevice({ ... }) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService(0xff0f)) .then(service => service.getCharacteristic(0xfffc)) .then(c => { return c.writeValue( new Uint8Array([ 0x00, r, g, b ]) ); }) write some bytes

reading data

navigator.bluetooth.requestDevice({ ... }) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService(0xff0f)) .then(service => service.getCharacteristic(0xfffc)) .then(c => c.readValue()) .then(value => { let r = value.getUint8(1);
let g = value.getUint8(2); let b = value.getUint8(3); }) read some bytes

get notified of changes

navigator.bluetooth.requestDevice({ ... }) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService(0xff0f)) .then(service => service.getCharacteristic(0xfffc)) .then(c => { c.addEventListener('characteristicvaluechanged', e => { let r = e.target.value.getUint8(1);
let g = e.target.value.getUint8(2); let b = e.target.value.getUint8(3); }); c.startNotifications(); }) add event listener don't forget to start listening

custom
characteristics . wtf!

insert xkcd comic about standards here

writing a value: function(r, g, b) { return new Uint8Array([ 0x00, r, g, b ]); } reading a value: function(buffer) { return { 
 r: buffer.getUint8(1), 
 g: buffer.getUint8(2), 
 b: buffer.getUint8(3) 
 } } writing to and reading 
 from the same characteristic

writing a value: function(r, g, b) { return new Uint8Array([
0x01, g, 0x01, 0x00, 0x01, 
 b, 0x01, r, 0x01, 0x00

 ]); } reading the current 
 color is not possible

writing a value: 
 function(r, g, b) { var buffer = new Uint8Array([ 
 0xaa, 0x0a, 0xfc, 0x3a, 0x86, 0x01, 0x0d, 
 0x06, 0x01, r, g, b, 0x00, 0x00, 
 (Math.random() * 1000) & 0xff, 0x55, 0x0d 
 ]); for (var i = 1; i < buffer.length - 2; i++) { buffer[15] += buffer[i]; } return buffer; } reading the current 
 color is not possible

writing a value: 
 function(r, g, b, position) { let buffer = new Uint8Array([
0x07, 0x02, position + 1, r, g, b
]); return buffer; }

writing a value: 
 function(r, g, b, position) { let buffer = new Uint8Array([
0x58, r, g, b, 0x01, position ]); ...

writing a value: 
 function(r, g, b, position) { let buffer = new Uint8Array([
0x58, r, g, b, 0x01, position ]); let payload = new Uint8Array(buffer.length + 4); payload[0] = payload.length - 2; payload[1] = payload.length - 2 >>> 8; payload.set(buffer, 2); let checksum = payload.reduce((a, b) => a + b, 0); payload[payload.length - 2] = checksum; payload[payload.length - 1] = checksum >>> 8; let extra = payload.filter(value => { 
 value === 0x01 || value === 0x02 || value == 0x03 


        message[m] = 0x03; 
        message[m + 1] = 0x05; 
        m += 2; 
    } 
    else if (payload[i] === 0x03) { 
        message[m] = 0x03; 
        message[m + 1] = 0x06; 
        m += 2; 
    } 
    else { 
        message[m] = payload[i]; 
        m++; 
    } 
} 
message[0] = 0x01; 
message[message.length - 1] = 0x02; 
return message; 

}

adafruit 
 bluetooth 
 sniffer

decompiling


 the apk don't tell anyone!

demofinally the fun part

warning experimental technology 
 setting low expectations

warning wifi interference 
 lowering them even further

https://bluetooth.rocks/lightbulb 
 https://github.com/BluetoothRocks/Lightbulb change the colour 
 of a lightbulb

https://bluetooth.rocks/pixel 
 https://github.com/BluetoothRocks/Matrix draw pixel art on 
 a led matrix display

https://bluetooth.rocks/racer https://github.com/BluetoothRocks/Racer control a lego racer 
 using a gamepad use css animations to 
 define a path

https://bluetooth.rocks/drone 
 https://github.com/BluetoothRocks/Drone control a drone 
 from your browser

https://bluetooth.rocks/pulse 
 https://github.com/BluetoothRocks/Pulsefind out your 
 current heartbeat

fun with bluetooth !

questions? @html5test