SlideShare a Scribd company logo
@fischaelameergeildanke.com #webrebels
Using Web APIs 

For Your Own PleasurePleasure
What? Why?
Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
What? Why?
Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
What? Why?
Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
What? Why?
Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
What? Why?
Ahhh
Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
What? Why?
Web Bluetooth API Support
Devices with
Bluetooth 4.0 or higher
Chrome, Chrome on Android,

Samsung Internet, Opera
Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
Three Steps to Happiness
Write Data
via Bluetooth API
Connect
Bluetooth Device
Request Connection
Read
Audio Data
Expose Vowels
Uncover Bluetooth Commands
Web Bluetooth API
Connect to and interact with
Bluetooth Low Energy devices.
Bluetooth Low Energy
Bluetooth LE, BLE, Bluetooth smart
Bluetooth Low Energy
Support
iOS 5+ Android 4.3+ OS X 10.6+ Windows 8+
Harald "Blåtand"
Gormsson
~958-986
King of Denmark and Norway
means Bluetooth
Haglaz
Old Norse: Hagall
Berkanan
Old Norse: Bjarkan
Advertising and Discovery
Peripheral Device Central Device
Frequency Hopping Spread Spectrum (FHSS)
short-wavelength radio waves

~2.4GHz
Advertising and Discovery
Peripheral
Device
Central
Device
scan
response
request
advertising
data
advertising
data
scan
response
data
Advertising as Broadcasting
Peripheral
Device
Central Device
Central Device
Central Device
Central Device
Central DeviceCentral Device
Advertising Data
GATT
Generic Attribute Profile
Defines the way two Bluetooth LE devices 

transfer data back and forth 

using Characteristics and Services.
GATT
Server
GATT 

Client
Communication via GATT
sends

response
sends
request
sends

response
sends
request
sends
reques
Profile
collection of
related services
Service
collection of
related
characteristics
Parts of GATT
Characteristic
Characteristic
Characteristic
read (RX) and
write (TX) data
Connect Bluetooth Device
const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
button.addEventListener('click', () => {
navigator.bluetooth.requestDevice({
filters: [{ services: [LUSH_SERVICE] }]
}).then((device) => {
console.log('Device found. Device: ', device);
return device.gatt.connect();
}).then((server) => {
console.log('Device connected. Server ', server);
});
});
Connect Bluetooth Device
const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
button.addEventListener('click', () => {
navigator.bluetooth.requestDevice({
filters: [{ services: [LUSH_SERVICE] }]
}).then((device) => {
console.log('Device found. Device: ', device);
return device.gatt.connect();
}).then((server) => {
console.log('Device connected. Server ', server);
});
});
const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
button.addEventListener('click', () => {
navigator.bluetooth.requestDevice({
filters: [{ services: [LUSH_SERVICE] }]
}).then((device) => {
console.log('Device found. Device: ', device);
return device.gatt.connect();
}).then((server) => {
console.log('Device connected. Server ', server);
});
});
Connect Bluetooth Device
const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
button.addEventListener('click', () => {
navigator.bluetooth.requestDevice({
filters: [{ services: [LUSH_SERVICE] }]
}).then((device) => {
console.log('Device found. Device: ', device);
return device.gatt.connect();
}).then((server) => {
console.log('Device connected. Server ', server);
});
});
Connect Bluetooth Device
nRF Connect
nRF Connect
Nordic UART
Service
const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
button.addEventListener('click', () => {
navigator.bluetooth.requestDevice({
filters: [{ services: [LUSH_SERVICE] }]
}).then((device) => {
console.log('Device found. Device: ', device);
return device.gatt.connect();
}).then((server) => {
console.log('Device connected. Server ', server);
});
});
Connect Bluetooth Device
const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';
button.addEventListener('click', () => {
navigator.bluetooth.requestDevice({
filters: [{ services: [LUSH_SERVICE] }]
}).then((device) => {
console.log('Device found. Device: ', device);
return device.gatt.connect();
}).then((server) => {
console.log('Device connected. Server ', server);
});
});
Connect Bluetooth Device
Web Audio API
Control audio on the web inside an Audio Context
with linked together Audio Nodes that for an
Audio Routing Graph.
Audio Context
Audio Routing Graph
Source Node
e.g. <audio>
output
Audio Node
Processing Node
e.g. reverb
input
Audio Node
output
Destination Node
e.g. speakers
Audio Node
input
UltrasonicSubsonic
20Hz
Sound Frequencies
heard by human ears
20kHz
What is Sound?
What is Sound?
https://en.wikipedia.org/wiki/Sound#/media/File:Sine_waves_different_frequencies.svg
What is Sound?
https://de.wikipedia.org/wiki/Frequenzspektrum
How to detect Vowels
formants:
f1 = ~800hz
f2 = ~1600hz
https://de.wikipedia.org/wiki/Formant
Vowel Detection within the Web
AudioContext MediaStreamAudioSourceNode AnalyserNode
Create Context and Nodes
Connect Nodes
MediaStreamAudioSourceNode AnalyserNode Destination
Vowel Detection within the Web
let audioContext = new window.AudioContext();
let stream = document.getElementById('video').captureStream();
let audioSource = audioContext.createMediaStreamSource(stream);
let analyser = audioContext.createAnalyser();
audioSource.connect(analyser);
analyser.connect(audioContext.destination);
Vowel Detection within the Web
let audioContext = new window.AudioContext();
let stream = document.getElementById('video').captureStream();
let audioSource = audioContext.createMediaStreamSource(stream);
let analyser = audioContext.createAnalyser();
audioSource.connect(analyser);
analyser.connect(audioContext.destination);
AnalyserNode
Input Node Anaylser Node Output Node
UnchangedFast Fourier
Transformation
Frequency Data
AnalyserNode
analyser.fftSize = 2048;
console.log(analyser.frequencyBinCount); //1024
let dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(dataArray);
AnalyserNode
analyser.fftSize = 2048;
console.log(analyser.frequencyBinCount); //1024
let dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(dataArray);
AnalyserNode
analyser.fftSize = 2048;
console.log(analyser.frequencyBinCount); //1024
let dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(dataArray);
AnalyserNode
analyser.fftSize = 2048;
console.log(analyser.frequencyBinCount); //1024
let dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(dataArray);
Visualize and Analyse Audio
let render = function () {
analyser.getByteFrequencyData(dataArray);
formants = getFormants(dataArray);
vowel = formantsToAh(formants[0], formants[1]);
window.requestAnimationFrame(render);
};
window.requestAnimationFrame(render);
Frequency Data
decibel = value / 256;Get Decibel
frequency = index * 44100 / 2048;Get Frequency
audioContext.sampleRate
FFT Size
Get Formants
let getFormants = function (data) {
let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity;
data.forEach(function (date, i) {
let frequency = i * 44100 / 2048, decibel = date / 256;
if (frequency < 1000) {
if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; }
} else if (frequency < 5000) {
if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; }
}
});
return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }];
};
Get Formants
let getFormants = function (data) {
let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity;
data.forEach(function (date, i) {
let frequency = i * 44100 / 2048, decibel = date / 256;
if (frequency < 1000) {
if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; }
} else if (frequency < 5000) {
if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; }
}
});
return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }];
};
Get Formants
let getFormants = function (data) {
let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity;
data.forEach(function (date, i) {
let frequency = i * 44100 / 2048, decibel = date / 256;
if (frequency < 1000) {
if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; }
} else if (frequency < 5000) {
if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; }
}
});
return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }];
};
Get Formants
let getFormants = function (data) {
let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity;
data.forEach(function (date, i) {
let frequency = i * 44100 / 2048, decibel = date / 256;
if (frequency < 1000) {
if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; }
} else if (frequency < 5000) {
if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; }
}
});
return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }];
};
Get Formants
let getFormants = function (data) {
let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity;
data.forEach(function (date, i) {
let frequency = i * 44100 / 2048, decibel = date / 256;
if (frequency < 1000) {
if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; }
} else if (frequency < 5000) {
if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; }
}
});
return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }];
};
Get Vowels
let formantsToAh = function (f1, f2) {
if (f1.freq > 700 && f1.freq < 1000 && f1.db > 0.4 &&
f2.freq > 1200 && f2.freq < 1800 && f2.db > 0.2) {
return 'a';
}
return null;
};
Real-time Vowel Detection
let render = function () {
analyser.getByteFrequencyData(dataArray);
formants = getFormants(dataArray);
vowel = formantsToAh(formants[0], formants[1]);
if (vowel === 'a') {
console.log('Ah!');
}
window.requestAnimationFrame(render);
};
Next video: https://www.youtube.com/watch?v=-74Tyi-fvi8
Identify Bluetooth Commands
Vibrate:4;
Identify Bluetooth Commands
56 69 62 72 61 74 65 3a 34 3b
Write to a Bluetooth Characteristic
const LUSH_TX_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e';
let txCharacteristic = null;
button.addEventListener('click', () => {
/* … */
}).then((server) => {
return server.getPrimaryService(LUSH_SERVICE);
}).then((service) => {
return service.getCharacteristic(LUSH_TX_CHARACTERISTIC);
}).then((characteristic) => { txCharacteristic = characteristic; });
});
const LUSH_TX_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e';
let txCharacteristic = null;
button.addEventListener('click', () => {
/* … */
}).then((server) => {
return server.getPrimaryService(LUSH_SERVICE);
}).then((service) => {
return service.getCharacteristic(LUSH_TX_CHARACTERISTIC);
}).then((characteristic) => { txCharacteristic = characteristic; });
});
Write to a Bluetooth Characteristic
const LUSH_TX_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e';
let txCharacteristic = null;
button.addEventListener('click', () => {
/* … */
}).then((server) => {
return server.getPrimaryService(LUSH_SERVICE);
}).then((service) => {
return service.getCharacteristic(LUSH_TX_CHARACTERISTIC);
}).then((characteristic) => { txCharacteristic = characteristic; });
});
Write to a Bluetooth Characteristic
if (vowel === 'a') {
let message = new TextEncoder('ASCII').encode('Vibrate:10;');
txCharacteristic.writeValue(message);
} else {
let message = new TextEncoder('ASCII').encode('Vibrate:0;');
txCharacteristic.writeValue(message);
}
Write to a Bluetooth Characteristic
if (vowel === 'a') {
let message = new TextEncoder('ASCII').encode('Vibrate:10;');
txCharacteristic.writeValue(message);
} else {
let message = new TextEncoder('ASCII').encode('Vibrate:0;');
txCharacteristic.writeValue(message);
}
Write to a Bluetooth Characteristic
Next video: https://www.youtube.com/watch?v=-74Tyi-fvi8
@fischaelameergeildanke.com #webrebels
Be Creative!
Use More Web APIs, Experiment, Give Feedback
@fischaelameergeildanke.com #webrebels
More Information
https://developers.google.com/web/updates/2015/07/interact-with-ble-devices-on-the-web
http://nilhcem.com/iot/reverse-engineering-simple-bluetooth-devices
https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API
https://www.bluetooth.com/specifications/gatt/services
Thanks to:
Stefan Judis
https://www.metafetish.com/
https://github.com/gre/zpeech

More Related Content

What's hot

Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2Raghu nath
 
python chapter 1
python chapter 1python chapter 1
python chapter 1Raghu nath
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is coming
Kirill Rozov
 
The Ring programming language version 1.10 book - Part 92 of 212
The Ring programming language version 1.10 book - Part 92 of 212The Ring programming language version 1.10 book - Part 92 of 212
The Ring programming language version 1.10 book - Part 92 of 212
Mahmoud Samir Fayed
 
FPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixirFPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixir
Functional Programming Brno
 
RIA - Entwicklung mit Ext JS
RIA - Entwicklung mit Ext JSRIA - Entwicklung mit Ext JS
RIA - Entwicklung mit Ext JS
Dominik Jungowski
 
Go for the would be network programmer
Go for the would be network programmerGo for the would be network programmer
Go for the would be network programmerEleanor McHugh
 
Corona sdk
Corona sdkCorona sdk
The Ring programming language version 1.5.4 book - Part 46 of 185
The Ring programming language version 1.5.4 book - Part 46 of 185The Ring programming language version 1.5.4 book - Part 46 of 185
The Ring programming language version 1.5.4 book - Part 46 of 185
Mahmoud Samir Fayed
 
Código fuente del software educativo
Código fuente del software educativoCódigo fuente del software educativo
Código fuente del software educativoLeo Chavez Martinez
 
Código fuente del software educativo
Código fuente del software educativoCódigo fuente del software educativo
Código fuente del software educativo
Leo Chavez Martinez
 
Neotool (using py2neo from the command line)
Neotool (using py2neo from the command line)Neotool (using py2neo from the command line)
Neotool (using py2neo from the command line)
Nigel Small
 
Investigating Python Wats
Investigating Python WatsInvestigating Python Wats
Investigating Python Wats
Amy Hanlon
 
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of WranglingPLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
Plotly
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Tobias Pfeiffer
 
T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...
T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...
T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...
Jeroen Baten
 
The Ring programming language version 1.9 book - Part 56 of 210
The Ring programming language version 1.9 book - Part 56 of 210The Ring programming language version 1.9 book - Part 56 of 210
The Ring programming language version 1.9 book - Part 56 of 210
Mahmoud Samir Fayed
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Tobias Pfeiffer
 
The Ring programming language version 1.5.4 book - Part 47 of 185
The Ring programming language version 1.5.4 book - Part 47 of 185The Ring programming language version 1.5.4 book - Part 47 of 185
The Ring programming language version 1.5.4 book - Part 47 of 185
Mahmoud Samir Fayed
 

What's hot (19)

Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2
 
python chapter 1
python chapter 1python chapter 1
python chapter 1
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is coming
 
The Ring programming language version 1.10 book - Part 92 of 212
The Ring programming language version 1.10 book - Part 92 of 212The Ring programming language version 1.10 book - Part 92 of 212
The Ring programming language version 1.10 book - Part 92 of 212
 
FPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixirFPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixir
 
RIA - Entwicklung mit Ext JS
RIA - Entwicklung mit Ext JSRIA - Entwicklung mit Ext JS
RIA - Entwicklung mit Ext JS
 
Go for the would be network programmer
Go for the would be network programmerGo for the would be network programmer
Go for the would be network programmer
 
Corona sdk
Corona sdkCorona sdk
Corona sdk
 
The Ring programming language version 1.5.4 book - Part 46 of 185
The Ring programming language version 1.5.4 book - Part 46 of 185The Ring programming language version 1.5.4 book - Part 46 of 185
The Ring programming language version 1.5.4 book - Part 46 of 185
 
Código fuente del software educativo
Código fuente del software educativoCódigo fuente del software educativo
Código fuente del software educativo
 
Código fuente del software educativo
Código fuente del software educativoCódigo fuente del software educativo
Código fuente del software educativo
 
Neotool (using py2neo from the command line)
Neotool (using py2neo from the command line)Neotool (using py2neo from the command line)
Neotool (using py2neo from the command line)
 
Investigating Python Wats
Investigating Python WatsInvestigating Python Wats
Investigating Python Wats
 
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of WranglingPLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
 
T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...
T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...
T-DOSE 2015: Using Python, PHP, JQuery and Linux to visualize the heartrate a...
 
The Ring programming language version 1.9 book - Part 56 of 210
The Ring programming language version 1.9 book - Part 56 of 210The Ring programming language version 1.9 book - Part 56 of 210
The Ring programming language version 1.9 book - Part 56 of 210
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
 
The Ring programming language version 1.5.4 book - Part 47 of 185
The Ring programming language version 1.5.4 book - Part 47 of 185The Ring programming language version 1.5.4 book - Part 47 of 185
The Ring programming language version 1.5.4 book - Part 47 of 185
 

Similar to Using New Web APIs For Your Own Pleasure – How I Wrote New Features For My Vibrator using the Web Bluetooth API and the Web Audio API

Using New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own PleasureUsing New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own Pleasure
Michaela Lehr
 
Using New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own PleasureUsing New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own Pleasure
GeilDanke
 
Air superiority for Android Apps
Air superiority for Android AppsAir superiority for Android Apps
Air superiority for Android Apps
Saúl Díaz González
 
Arduino and the real time web
Arduino and the real time webArduino and the real time web
Arduino and the real time web
Andrew Fisher
 
Asynchronous Programming at Netflix
Asynchronous Programming at NetflixAsynchronous Programming at Netflix
Asynchronous Programming at Netflix
C4Media
 
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.createRemote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Peter Lehto
 
Getting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browserGetting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browser
Dan Jenkins
 
Going real time with Socket.io
Going real time with Socket.ioGoing real time with Socket.io
Going real time with Socket.io
Arnout Kazemier
 
Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸
Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸
Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸
Alessandro Polidori
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
Fernando Daciuk
 
Server Side Events
Server Side EventsServer Side Events
Server Side Events
thepilif
 
Introduction to Things board (An Open Source IoT Cloud Platform)
Introduction to Things board (An Open Source IoT Cloud Platform)Introduction to Things board (An Open Source IoT Cloud Platform)
Introduction to Things board (An Open Source IoT Cloud Platform)
Amarjeetsingh Thakur
 
Android Wi-Fi Manager and Bluetooth Connection
Android Wi-Fi Manager and Bluetooth ConnectionAndroid Wi-Fi Manager and Bluetooth Connection
Android Wi-Fi Manager and Bluetooth ConnectionJussi Pohjolainen
 
DomCode 2015 - Abusing phones to make the internet of things
DomCode 2015 - Abusing phones to make the internet of thingsDomCode 2015 - Abusing phones to make the internet of things
DomCode 2015 - Abusing phones to make the internet of things
Jan Jongboom
 
Getting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browserGetting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browser
Dan Jenkins
 
Designing for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive StreamsDesigning for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive Streams
Stéphane Maldini
 
WebRTC 101 - How to get started building your first WebRTC application
WebRTC 101 - How to get started building your first WebRTC applicationWebRTC 101 - How to get started building your first WebRTC application
WebRTC 101 - How to get started building your first WebRTC application
Dan Jenkins
 
Can you hear me now?
Can you hear me now?Can you hear me now?
Can you hear me now?
Ida Aalen
 
Windows Phone 8 Sensors
Windows Phone 8 SensorsWindows Phone 8 Sensors
Windows Phone 8 Sensors
David Isbitski
 

Similar to Using New Web APIs For Your Own Pleasure – How I Wrote New Features For My Vibrator using the Web Bluetooth API and the Web Audio API (20)

Using New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own PleasureUsing New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own Pleasure
 
Using New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own PleasureUsing New Web APIs For Your Own Pleasure
Using New Web APIs For Your Own Pleasure
 
Air superiority for Android Apps
Air superiority for Android AppsAir superiority for Android Apps
Air superiority for Android Apps
 
Arduino and the real time web
Arduino and the real time webArduino and the real time web
Arduino and the real time web
 
Asynchronous Programming at Netflix
Asynchronous Programming at NetflixAsynchronous Programming at Netflix
Asynchronous Programming at Netflix
 
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.createRemote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
Remote controlling Parrot AR drone with Vaadin & Spring Boot @ GWT.create
 
Getting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browserGetting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browser
 
Going real time with Socket.io
Going real time with Socket.ioGoing real time with Socket.io
Going real time with Socket.io
 
Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸
Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸
Presentation at ClueCon 2019 - Chicago, IL, USA 🇺🇸
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
 
Server Side Events
Server Side EventsServer Side Events
Server Side Events
 
Introduction to Things board (An Open Source IoT Cloud Platform)
Introduction to Things board (An Open Source IoT Cloud Platform)Introduction to Things board (An Open Source IoT Cloud Platform)
Introduction to Things board (An Open Source IoT Cloud Platform)
 
Android Wi-Fi Manager and Bluetooth Connection
Android Wi-Fi Manager and Bluetooth ConnectionAndroid Wi-Fi Manager and Bluetooth Connection
Android Wi-Fi Manager and Bluetooth Connection
 
DomCode 2015 - Abusing phones to make the internet of things
DomCode 2015 - Abusing phones to make the internet of thingsDomCode 2015 - Abusing phones to make the internet of things
DomCode 2015 - Abusing phones to make the internet of things
 
Getting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browserGetting physical with web bluetooth in the browser
Getting physical with web bluetooth in the browser
 
Designing for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive StreamsDesigning for Distributed Systems with Reactor and Reactive Streams
Designing for Distributed Systems with Reactor and Reactive Streams
 
WebRTC 101 - How to get started building your first WebRTC application
WebRTC 101 - How to get started building your first WebRTC applicationWebRTC 101 - How to get started building your first WebRTC application
WebRTC 101 - How to get started building your first WebRTC application
 
JavaCro'15 - Remote controlling Parrot AR Drone with Spring Boot and Vaadin -...
JavaCro'15 - Remote controlling Parrot AR Drone with Spring Boot and Vaadin -...JavaCro'15 - Remote controlling Parrot AR Drone with Spring Boot and Vaadin -...
JavaCro'15 - Remote controlling Parrot AR Drone with Spring Boot and Vaadin -...
 
Can you hear me now?
Can you hear me now?Can you hear me now?
Can you hear me now?
 
Windows Phone 8 Sensors
Windows Phone 8 SensorsWindows Phone 8 Sensors
Windows Phone 8 Sensors
 

More from GeilDanke

WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...
WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...
WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...
GeilDanke
 
Writing Virtual And Augmented Reality Apps With Web Technology
Writing Virtual And Augmented Reality Apps With Web TechnologyWriting Virtual And Augmented Reality Apps With Web Technology
Writing Virtual And Augmented Reality Apps With Web Technology
GeilDanke
 
Creating Augmented Reality Apps with Web Technology
Creating Augmented Reality Apps with Web TechnologyCreating Augmented Reality Apps with Web Technology
Creating Augmented Reality Apps with Web Technology
GeilDanke
 
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VRHow to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
GeilDanke
 
More Ways to Make Your Users Sick – A talk about WebVR and UX Design
More Ways to Make Your Users Sick – A talk about WebVR and UX DesignMore Ways to Make Your Users Sick – A talk about WebVR and UX Design
More Ways to Make Your Users Sick – A talk about WebVR and UX Design
GeilDanke
 
Goodbye, Flatland! An introduction to WebVR and what it means for web developers
Goodbye, Flatland! An introduction to WebVR and what it means for web developersGoodbye, Flatland! An introduction to WebVR and what it means for web developers
Goodbye, Flatland! An introduction to WebVR and what it means for web developers
GeilDanke
 
Goodbye, Flatland! An introduction to React VR and what it means for web dev...
Goodbye, Flatland! An introduction to React VR  and what it means for web dev...Goodbye, Flatland! An introduction to React VR  and what it means for web dev...
Goodbye, Flatland! An introduction to React VR and what it means for web dev...
GeilDanke
 
An Introduction to WebVR – or How to make your user sick in 60 seconds
An Introduction to WebVR – or How to make your user sick in 60 secondsAn Introduction to WebVR – or How to make your user sick in 60 seconds
An Introduction to WebVR – or How to make your user sick in 60 seconds
GeilDanke
 
2016 First steps with Angular 2 – enterjs
2016 First steps with Angular 2 – enterjs2016 First steps with Angular 2 – enterjs
2016 First steps with Angular 2 – enterjs
GeilDanke
 
2014 HTML und CSS für Designer – Pubkon
2014 HTML und CSS für Designer – Pubkon2014 HTML und CSS für Designer – Pubkon
2014 HTML und CSS für Designer – Pubkon
GeilDanke
 
2013 Digitale Magazine erstellen - Konzeption und Redaktion
2013 Digitale Magazine erstellen - Konzeption und Redaktion2013 Digitale Magazine erstellen - Konzeption und Redaktion
2013 Digitale Magazine erstellen - Konzeption und Redaktion
GeilDanke
 
2014 Adobe DPS Update 29
2014 Adobe DPS Update 292014 Adobe DPS Update 29
2014 Adobe DPS Update 29
GeilDanke
 
2012 Digital Publishing IDUG Stuttgart
2012 Digital Publishing IDUG Stuttgart2012 Digital Publishing IDUG Stuttgart
2012 Digital Publishing IDUG Stuttgart
GeilDanke
 

More from GeilDanke (13)

WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...
WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...
WebXR: A New Dimension For The Web Writing Virtual and Augmented Reality Apps...
 
Writing Virtual And Augmented Reality Apps With Web Technology
Writing Virtual And Augmented Reality Apps With Web TechnologyWriting Virtual And Augmented Reality Apps With Web Technology
Writing Virtual And Augmented Reality Apps With Web Technology
 
Creating Augmented Reality Apps with Web Technology
Creating Augmented Reality Apps with Web TechnologyCreating Augmented Reality Apps with Web Technology
Creating Augmented Reality Apps with Web Technology
 
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VRHow to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
How to Make Your Users Sick in 60 Seconds – About UX Design, WebVR and React VR
 
More Ways to Make Your Users Sick – A talk about WebVR and UX Design
More Ways to Make Your Users Sick – A talk about WebVR and UX DesignMore Ways to Make Your Users Sick – A talk about WebVR and UX Design
More Ways to Make Your Users Sick – A talk about WebVR and UX Design
 
Goodbye, Flatland! An introduction to WebVR and what it means for web developers
Goodbye, Flatland! An introduction to WebVR and what it means for web developersGoodbye, Flatland! An introduction to WebVR and what it means for web developers
Goodbye, Flatland! An introduction to WebVR and what it means for web developers
 
Goodbye, Flatland! An introduction to React VR and what it means for web dev...
Goodbye, Flatland! An introduction to React VR  and what it means for web dev...Goodbye, Flatland! An introduction to React VR  and what it means for web dev...
Goodbye, Flatland! An introduction to React VR and what it means for web dev...
 
An Introduction to WebVR – or How to make your user sick in 60 seconds
An Introduction to WebVR – or How to make your user sick in 60 secondsAn Introduction to WebVR – or How to make your user sick in 60 seconds
An Introduction to WebVR – or How to make your user sick in 60 seconds
 
2016 First steps with Angular 2 – enterjs
2016 First steps with Angular 2 – enterjs2016 First steps with Angular 2 – enterjs
2016 First steps with Angular 2 – enterjs
 
2014 HTML und CSS für Designer – Pubkon
2014 HTML und CSS für Designer – Pubkon2014 HTML und CSS für Designer – Pubkon
2014 HTML und CSS für Designer – Pubkon
 
2013 Digitale Magazine erstellen - Konzeption und Redaktion
2013 Digitale Magazine erstellen - Konzeption und Redaktion2013 Digitale Magazine erstellen - Konzeption und Redaktion
2013 Digitale Magazine erstellen - Konzeption und Redaktion
 
2014 Adobe DPS Update 29
2014 Adobe DPS Update 292014 Adobe DPS Update 29
2014 Adobe DPS Update 29
 
2012 Digital Publishing IDUG Stuttgart
2012 Digital Publishing IDUG Stuttgart2012 Digital Publishing IDUG Stuttgart
2012 Digital Publishing IDUG Stuttgart
 

Recently uploaded

DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
Paul Groth
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 

Recently uploaded (20)

DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 

Using New Web APIs For Your Own Pleasure – How I Wrote New Features For My Vibrator using the Web Bluetooth API and the Web Audio API

  • 1. @fischaelameergeildanke.com #webrebels Using Web APIs 
 For Your Own PleasurePleasure
  • 2. What? Why? Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
  • 3. What? Why? Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
  • 4. Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project What? Why?
  • 5. Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project What? Why?
  • 6. Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project What? Why?
  • 7. Ahhh Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project What? Why?
  • 8.
  • 9.
  • 10. Web Bluetooth API Support Devices with Bluetooth 4.0 or higher Chrome, Chrome on Android,
 Samsung Internet, Opera Created by Ben Davis from the Noun Project, Created by Viktor Vorobyev from the Noun Project
  • 11. Three Steps to Happiness Write Data via Bluetooth API Connect Bluetooth Device Request Connection Read Audio Data Expose Vowels Uncover Bluetooth Commands
  • 12. Web Bluetooth API Connect to and interact with Bluetooth Low Energy devices.
  • 13. Bluetooth Low Energy Bluetooth LE, BLE, Bluetooth smart
  • 14. Bluetooth Low Energy Support iOS 5+ Android 4.3+ OS X 10.6+ Windows 8+
  • 15. Harald "Blåtand" Gormsson ~958-986 King of Denmark and Norway means Bluetooth
  • 17. Advertising and Discovery Peripheral Device Central Device Frequency Hopping Spread Spectrum (FHSS) short-wavelength radio waves
 ~2.4GHz
  • 19. Advertising as Broadcasting Peripheral Device Central Device Central Device Central Device Central Device Central DeviceCentral Device Advertising Data
  • 20. GATT Generic Attribute Profile Defines the way two Bluetooth LE devices 
 transfer data back and forth 
 using Characteristics and Services.
  • 21. GATT Server GATT 
 Client Communication via GATT sends
 response sends request sends
 response sends request sends reques
  • 22. Profile collection of related services Service collection of related characteristics Parts of GATT Characteristic Characteristic Characteristic read (RX) and write (TX) data
  • 23. Connect Bluetooth Device const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; button.addEventListener('click', () => { navigator.bluetooth.requestDevice({ filters: [{ services: [LUSH_SERVICE] }] }).then((device) => { console.log('Device found. Device: ', device); return device.gatt.connect(); }).then((server) => { console.log('Device connected. Server ', server); }); });
  • 24. Connect Bluetooth Device const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; button.addEventListener('click', () => { navigator.bluetooth.requestDevice({ filters: [{ services: [LUSH_SERVICE] }] }).then((device) => { console.log('Device found. Device: ', device); return device.gatt.connect(); }).then((server) => { console.log('Device connected. Server ', server); }); });
  • 25. const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; button.addEventListener('click', () => { navigator.bluetooth.requestDevice({ filters: [{ services: [LUSH_SERVICE] }] }).then((device) => { console.log('Device found. Device: ', device); return device.gatt.connect(); }).then((server) => { console.log('Device connected. Server ', server); }); }); Connect Bluetooth Device
  • 26. const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; button.addEventListener('click', () => { navigator.bluetooth.requestDevice({ filters: [{ services: [LUSH_SERVICE] }] }).then((device) => { console.log('Device found. Device: ', device); return device.gatt.connect(); }).then((server) => { console.log('Device connected. Server ', server); }); }); Connect Bluetooth Device
  • 29. const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; button.addEventListener('click', () => { navigator.bluetooth.requestDevice({ filters: [{ services: [LUSH_SERVICE] }] }).then((device) => { console.log('Device found. Device: ', device); return device.gatt.connect(); }).then((server) => { console.log('Device connected. Server ', server); }); }); Connect Bluetooth Device
  • 30. const LUSH_SERVICE = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; button.addEventListener('click', () => { navigator.bluetooth.requestDevice({ filters: [{ services: [LUSH_SERVICE] }] }).then((device) => { console.log('Device found. Device: ', device); return device.gatt.connect(); }).then((server) => { console.log('Device connected. Server ', server); }); }); Connect Bluetooth Device
  • 31.
  • 32. Web Audio API Control audio on the web inside an Audio Context with linked together Audio Nodes that for an Audio Routing Graph.
  • 33. Audio Context Audio Routing Graph Source Node e.g. <audio> output Audio Node Processing Node e.g. reverb input Audio Node output Destination Node e.g. speakers Audio Node input
  • 34. UltrasonicSubsonic 20Hz Sound Frequencies heard by human ears 20kHz What is Sound?
  • 37. How to detect Vowels formants: f1 = ~800hz f2 = ~1600hz https://de.wikipedia.org/wiki/Formant
  • 38. Vowel Detection within the Web AudioContext MediaStreamAudioSourceNode AnalyserNode Create Context and Nodes Connect Nodes MediaStreamAudioSourceNode AnalyserNode Destination
  • 39. Vowel Detection within the Web let audioContext = new window.AudioContext(); let stream = document.getElementById('video').captureStream(); let audioSource = audioContext.createMediaStreamSource(stream); let analyser = audioContext.createAnalyser(); audioSource.connect(analyser); analyser.connect(audioContext.destination);
  • 40. Vowel Detection within the Web let audioContext = new window.AudioContext(); let stream = document.getElementById('video').captureStream(); let audioSource = audioContext.createMediaStreamSource(stream); let analyser = audioContext.createAnalyser(); audioSource.connect(analyser); analyser.connect(audioContext.destination);
  • 41. AnalyserNode Input Node Anaylser Node Output Node UnchangedFast Fourier Transformation Frequency Data
  • 42. AnalyserNode analyser.fftSize = 2048; console.log(analyser.frequencyBinCount); //1024 let dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray);
  • 43. AnalyserNode analyser.fftSize = 2048; console.log(analyser.frequencyBinCount); //1024 let dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray);
  • 44. AnalyserNode analyser.fftSize = 2048; console.log(analyser.frequencyBinCount); //1024 let dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray);
  • 45. AnalyserNode analyser.fftSize = 2048; console.log(analyser.frequencyBinCount); //1024 let dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray);
  • 46. Visualize and Analyse Audio let render = function () { analyser.getByteFrequencyData(dataArray); formants = getFormants(dataArray); vowel = formantsToAh(formants[0], formants[1]); window.requestAnimationFrame(render); }; window.requestAnimationFrame(render);
  • 47. Frequency Data decibel = value / 256;Get Decibel frequency = index * 44100 / 2048;Get Frequency audioContext.sampleRate FFT Size
  • 48. Get Formants let getFormants = function (data) { let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity; data.forEach(function (date, i) { let frequency = i * 44100 / 2048, decibel = date / 256; if (frequency < 1000) { if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; } } else if (frequency < 5000) { if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; } } }); return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }]; };
  • 49. Get Formants let getFormants = function (data) { let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity; data.forEach(function (date, i) { let frequency = i * 44100 / 2048, decibel = date / 256; if (frequency < 1000) { if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; } } else if (frequency < 5000) { if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; } } }); return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }]; };
  • 50. Get Formants let getFormants = function (data) { let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity; data.forEach(function (date, i) { let frequency = i * 44100 / 2048, decibel = date / 256; if (frequency < 1000) { if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; } } else if (frequency < 5000) { if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; } } }); return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }]; };
  • 51. Get Formants let getFormants = function (data) { let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity; data.forEach(function (date, i) { let frequency = i * 44100 / 2048, decibel = date / 256; if (frequency < 1000) { if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; } } else if (frequency < 5000) { if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; } } }); return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }]; };
  • 52. Get Formants let getFormants = function (data) { let f1, f2, maxF1 = -Infinity, maxF2 = -Infinity; data.forEach(function (date, i) { let frequency = i * 44100 / 2048, decibel = date / 256; if (frequency < 1000) { if (decibel > maxF1) { maxF1 = decibel; f1 = frequency; } } else if (frequency < 5000) { if (decibel > maxF2) { maxF2 = decibel; f2 = frequency; } } }); return [{ db: maxF1, freq: f1}, { db: maxF2, freq: f2 }]; };
  • 53. Get Vowels let formantsToAh = function (f1, f2) { if (f1.freq > 700 && f1.freq < 1000 && f1.db > 0.4 && f2.freq > 1200 && f2.freq < 1800 && f2.db > 0.2) { return 'a'; } return null; };
  • 54. Real-time Vowel Detection let render = function () { analyser.getByteFrequencyData(dataArray); formants = getFormants(dataArray); vowel = formantsToAh(formants[0], formants[1]); if (vowel === 'a') { console.log('Ah!'); } window.requestAnimationFrame(render); }; Next video: https://www.youtube.com/watch?v=-74Tyi-fvi8
  • 55.
  • 57. Vibrate:4; Identify Bluetooth Commands 56 69 62 72 61 74 65 3a 34 3b
  • 58. Write to a Bluetooth Characteristic const LUSH_TX_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'; let txCharacteristic = null; button.addEventListener('click', () => { /* … */ }).then((server) => { return server.getPrimaryService(LUSH_SERVICE); }).then((service) => { return service.getCharacteristic(LUSH_TX_CHARACTERISTIC); }).then((characteristic) => { txCharacteristic = characteristic; }); });
  • 59. const LUSH_TX_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'; let txCharacteristic = null; button.addEventListener('click', () => { /* … */ }).then((server) => { return server.getPrimaryService(LUSH_SERVICE); }).then((service) => { return service.getCharacteristic(LUSH_TX_CHARACTERISTIC); }).then((characteristic) => { txCharacteristic = characteristic; }); }); Write to a Bluetooth Characteristic
  • 60.
  • 61. const LUSH_TX_CHARACTERISTIC = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'; let txCharacteristic = null; button.addEventListener('click', () => { /* … */ }).then((server) => { return server.getPrimaryService(LUSH_SERVICE); }).then((service) => { return service.getCharacteristic(LUSH_TX_CHARACTERISTIC); }).then((characteristic) => { txCharacteristic = characteristic; }); }); Write to a Bluetooth Characteristic
  • 62. if (vowel === 'a') { let message = new TextEncoder('ASCII').encode('Vibrate:10;'); txCharacteristic.writeValue(message); } else { let message = new TextEncoder('ASCII').encode('Vibrate:0;'); txCharacteristic.writeValue(message); } Write to a Bluetooth Characteristic
  • 63. if (vowel === 'a') { let message = new TextEncoder('ASCII').encode('Vibrate:10;'); txCharacteristic.writeValue(message); } else { let message = new TextEncoder('ASCII').encode('Vibrate:0;'); txCharacteristic.writeValue(message); } Write to a Bluetooth Characteristic Next video: https://www.youtube.com/watch?v=-74Tyi-fvi8
  • 64.
  • 65. @fischaelameergeildanke.com #webrebels Be Creative! Use More Web APIs, Experiment, Give Feedback