Fun with Bluetooth

A presentation at Refresh Conference in October 2018 in Groningen, Netherlands by Niels Leenheer

Slide 1

Slide 1

fun with bluetooth

Slide 2

Slide 2

why?

Slide 3

Slide 3

progressive web apps

Slide 4

Slide 4

pwa’s ! are great

Slide 5

Slide 5

but...

Slide 6

Slide 6

Slide 7

Slide 7

bluetooth

Slide 8

Slide 8

bluetooth s k c su

Slide 9

Slide 9

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

Slide 10

Slide 10

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

Slide 11

Slide 11

10 million bluetooth devices shipping every day

Slide 12

Slide 12

m e n o h p e obil

Slide 13

Slide 13

computer

Slide 14

Slide 14

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

Slide 15

Slide 15

activity tracker

Slide 16

Slide 16

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

Slide 17

Slide 17

8 b b o i r e h p s

Slide 18

Slide 18

e n o r d i n parrot mi

Slide 19

Slide 19

r e n n i p s t fidge

Slide 20

Slide 20

the boring theoretical stuff

Slide 21

Slide 21

central peripheral

Slide 22

Slide 22

central

Slide 23

Slide 23

generic attribute profile

Slide 24

Slide 24

generic attribute profile ?

Slide 25

Slide 25

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

Slide 26

Slide 26

central peripheral client server

Slide 27

Slide 27

server service characteristic value array of objects object property value

Slide 28

Slide 28

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

Slide 29

Slide 29

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

Slide 30

Slide 30

180F d i u u t i b 16

Slide 31

Slide 31

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

Slide 32

Slide 32

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

Slide 33

Slide 33

pfew...

Slide 34

Slide 34

Slide 35

Slide 35

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

Slide 36

Slide 36

fun with bluetooth

Slide 37

Slide 37

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

Slide 38

Slide 38

connecting to a device

Slide 39

Slide 39

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 ); }) ])

Slide 40

Slide 40

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

Slide 41

Slide 41

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 ); ])

Slide 42

Slide 42

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 ); }) ])

Slide 43

Slide 43

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

Slide 44

Slide 44

writing data

Slide 45

Slide 45

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 ); ])

Slide 46

Slide 46

reading data

Slide 47

Slide 47

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);

Slide 48

Slide 48

get notified of changes

Slide 49

Slide 49

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();

Slide 50

Slide 50

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

Slide 51

Slide 51

custom characteristics. wtf!

Slide 52

Slide 52

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

Slide 53

Slide 53

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

Slide 54

Slide 54

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

Slide 55

Slide 55

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

Slide 56

Slide 56

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

Slide 57

Slide 57

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

Slide 58

Slide 58

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; }

Slide 59

Slide 59

adafruit bluetooth sniffer

Slide 60

Slide 60

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

Slide 61

Slide 61

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

Slide 62

Slide 62

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

Slide 63

Slide 63

finally t he fun p ar t demo

Slide 64

Slide 64

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

Slide 65

Slide 65

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

Slide 66

Slide 66

Slide 67

Slide 67

questions? @htm l5test