fun with bluetooth

why?

progressive 
 web apps

pwa’s are great !

but...

but...

bluetooth

bluetooth sucks

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

bluetoot h low energy also known as BLE Bluetooth LE Bluetooth Smart Bluetooth 4

playbulb sphere playbulb

spherio bb-8

parrot mini drone

activity tracker

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

§ i device information light multiple services per device

i device information battery flight control

i device information battery steering control

i device information battery heart rate

heart rate

i

device information

battery

i device information battery heart rate

i device information manufacturer
model number serial number hardware revision firmware revision software revision ... multiple characteristics 
 per service

server service characteristic value array of objects object property value

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

0x180A 0000 180A -0000-1000-8000-00805F9B34FB 16 bit 128 bit i device information

0x180 F 0000 180F -0000-1000-8000-00805F9B34FB 16 bit 128 bit battery

not recommended any UUID outside of the range 
 xxxxxxxx -0000-1000-8000-00805F9B34FB 16 bit 128 bit light steering control flight control still, everybody does this

i device information manufacturer
model number serial number hardware revision firmware revision software revision ...

i 0x180A 0x2A29
0x2A24 0x2A25 0x2A27 0x2A26 0x2A28 ... bad for readability, 
 good for saving bandwidth

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 ]) ); }) 1 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 ]) ); }) 2 connect to the server

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 ]) ); }) 3 get the service

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 ]) ); }) 4 get the characteristic

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

things you need to know: • the webbluetooth api • promises • typed arrays duh!

browser support Chrome Opera Samsung 
 (behind flag) Servo 
 (soon)

browser support Chrome Opera Samsung 
 (behind flag) kinda works Servo 
 (soon) WebBLE 
 for iOS

and... npm install node-web-bluetooth

and... the puck.js

custom
characteristics . wtf!

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/NielsLeenheer/BluetoothBulb change the colour 
 of a lightbulb

https://bluetooth.rocks/pixel draw pixel art on 
 a led matrix display

https://bluetooth.rocks/racer

https://github.com/NielsLeenheer/BluetoothRacer control a lego racer 
 using a gamepad use css animations to 
 define a path

https://bluetooth.rocks/drone 
 https://github.com/poshaughnessy/web-bluetooth-parrot-drone control a drone 
 from your browser

https://bluetooth.rocks/ printer print on a receipt printer

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

fun with bluetooth !

questions? @html5test