fun with bluetooth

why?

progressive web apps

pwa’s ! are great

but...

bluetooth

bluetooth s k c su

classic bluetooth vs. y d o b y r h e t v o e o t n e o u s l a b e s r e t e th ha control dr on es and oth bluetooth low energy er cool shi t

bluetooth low energy also known as B l Bluetooth Smar t uetooth LE B l u e t o o t h 4 and 5 BLE

10 million bluetooth devices shipping every day

m e n o h p e obil

computer

r o t i n o m e s o c u gl e m o s d n a h s ' y bod

activity tracker

u b y a pl s lb e r e h p b l u b y a l p

8 b b o i r e h p s

e n o r d i n parrot mi

r e n n i p s t fidge

the boring theoretical stuff

central peripheral

central

generic attribute profile

generic attribute profile ?

generic attribute profile a w p a g e s u a c e b , t t a g n e k a t y d a e r l a s

central peripheral client server

server service characteristic value array of objects object property value

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

128 d i u u t bi 0000180F-0000-1000-8000-00805F9B34FB

180F d i u u t i b 16

s t r o p p u s c i t s i r e t e c s a e r h a t h f c o each one or more read write write without response notify

every value is an array of bytes s e t y b st no d y c n fa u j , s e p y t a t a

pfew...

s t c a f g n i r o b t u o ab fun with bluetooth

fun with bluetooth

web bluetooth still not t he fun pa rt :-( api

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)) t a h w r e s w o r b e h t l l e we t t n a w e w e c i v e d f o d kin .then(characteristic => { return characteristic.writeValue( new Uint8Array([ 0x00, r, g, b ); }) ])

s t c e l e s r e s u e th al device u t c a the

navigator.bluetooth.requestDevice({ filters: [ { namePrefix: 'PLAYBULB' } ], optionalServices: [ 0xff0f ] }) .then(device => { .... }) .then(device => device.gatt.connect()) .then(server => server.getPrimaryService(0xff0f)) .then(service => service.getCharacteristic(0xfffc)) 7 1 0 2 o s e r a .then(characteristic => e{ s s i m o r return characteristic.writeValue( p new Uint8Array([ 0x00, r, g, b ); ])

let device = await 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 ); }) ])

let device = await navigator.bluetooth.requestDevice({ filters: [ { namePrefix: 'PLAYBULB' } ], optionalServices: [ 0xff0f ] }); r e v r e s e h t o ect t conn let server = await device.gatt.connect()); let service = await server.getPrimaryService(0xff0f)); let characteristic = await service.getCharacteristic(0xfffc)); e c i v r e s get the .then(characteristic => { return characteristic.writeValue( new Uint8Array([ 0x00, r, g, b ); }) ]) c i t s i r e t c a r a h c e h get t

writing data

w s e t y b e m o s e rit let let let let device = await navigator.bluetooth.requestDevice({ ... }); server = await device.gatt.connect()); service = await server.getPrimaryService(0xff0f)); characteristic = await service.getCharacteristic(0xfffc)); characteristic.writeValue( new Uint8Array([ 0x00, r, g, b ); ])

reading data

e m o s d er a s e t y b let let let let device = await navigator.bluetooth.requestDevice({ ... }); server = await device.gatt.connect()); service = await server.getPrimaryService(0xff0f)); characteristic = await service.getCharacteristic(0xfffc)); let value = await characteristic.readValue(); let r = value.getUint8(1); let g = value.getUint8(2); let b = value.getUint8(3);

get notified of changes

add r e n e t s i l t n e v e let let let let device = await navigator.bluetooth.requestDevice({ ... }); server = await device.gatt.connect()); service = await server.getPrimaryService(0xff0f)); characteristic = await service.getCharacteristic(0xfffc)); characteristic.addEventListener( 'characteristicvaluechanged', e => { let r = e.target.value.getUint8(1); let g = e.target.value.getUint8(2); let b = e.target.value.getUint8(3); } ); don't forget to star t listen ing characteristic.startNotifications();

things you need to know: • the webbluetooth api • promises (or async await) • typed arrays d ! h u

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) } } fro g n i d a e r d n a o t g writin c i t s i r e t c a r a h c e m a s e h t m

writing a value: function(r, g, b) { return new Uint8Array([ 0x01, g, 0x01, 0x00, 0x01, b, 0x01, r, 0x01, 0x00 ]); } t n e r r u c e h t g n i read e l b i s s o p t o n s i r colo

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; } t n e r r u c e h t g n i read e l b i s s o p t o n s i r colo

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 => {

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

log all bluetooth packets on your phone o t b d a e g s o l u e d n a nsfer th a r t

o t k r a h s a e t r a i d w e e s u k at th o o l

decompiling the apk t ' n do ! e n o y n a l tel

finally t he fun p ar t demo

warning experimental technology w o l g n i t set s n o i t a t c e p x e

warning wifi interference r e h t r u f n e v e m e h t g n loweri

questions? @htm l5test