Met de Web Bluetooth API kunnen websites communiceren met Bluetooth-apparaten.
Wat als ik je vertelde dat websites op een veilige en privacybeschermende manier kunnen communiceren met Bluetooth-apparaten in de buurt? Op deze manier kunnen hartslagmeters, zingende gloeilampen en zelfs schildpadden rechtstreeks communiceren met een website.
Tot nu toe was de mogelijkheid om te communiceren met Bluetooth-apparaten alleen mogelijk voor platformspecifieke apps. De Web Bluetooth API wil dit veranderen en brengt dit ook naar webbrowsers.
Voordat we beginnen
In dit document wordt ervan uitgegaan dat u enige basiskennis heeft van hoe Bluetooth Low Energy (BLE) en het Generieke Attribuutprofiel werken.
Hoewel de Web Bluetooth API-specificatie nog niet definitief is, zijn de spec-auteurs actief op zoek naar enthousiaste ontwikkelaars om deze API uit te proberen en feedback te geven over de specificaties en feedback over de implementatie .
Een subset van de Web Bluetooth API is beschikbaar in ChromeOS, Chrome voor Android 6.0, Mac (Chrome 56) en Windows 10 (Chrome 70). Dit betekent dat u Bluetooth Low Energy-apparaten in de buurt kunt opvragen en er verbinding mee kunt maken, Bluetooth-kenmerken kunt lezen / schrijven , GATT-meldingen kunt ontvangen , kunt weten wanneer de verbinding met een Bluetooth-apparaat wordt verbroken en zelfs Bluetooth-descriptors kunt lezen en schrijven . Zie de browsercompatibiliteitstabel van MDN voor meer informatie.
Voor Linux en eerdere versies van Windows schakelt u de vlag #experimental-web-platform-features
in about://flags
.
Beschikbaar voor herkomstproeven
Om zoveel mogelijk feedback te krijgen van ontwikkelaars die de Web Bluetooth API in het veld gebruiken, heeft Chrome deze functie eerder aan Chrome 53 toegevoegd als een origin-proefversie voor ChromeOS, Android en Mac.
De proef is in januari 2017 succesvol afgerond.
Beveiligingsvereisten
Om de afwegingen op het gebied van beveiliging te begrijpen, raad ik het Web Bluetooth Security Model- bericht aan van Jeffrey Yasskin, een software-ingenieur in het Chrome-team, die aan de Web Bluetooth API-specificatie werkt.
Alleen HTTPS
Omdat deze experimentele API een krachtige nieuwe functie is die aan internet is toegevoegd, wordt deze alleen beschikbaar gesteld om contexten te beveiligen . Dit betekent dat u moet bouwen met TLS in gedachten.
Gebruikersgebaar vereist
Als beveiligingsfunctie moet het ontdekken van Bluetooth-apparaten met navigator.bluetooth.requestDevice
worden geactiveerd door een gebruikersgebaar, zoals een aanraking of een muisklik. We hebben het over het luisteren naar pointerup
, click
en touchend
-gebeurtenissen.
button.addEventListener('pointerup', function(event) {
// Call navigator.bluetooth.requestDevice
});
Verdiep je in de code
De Web Bluetooth API is sterk afhankelijk van JavaScript- beloften . Als je er niet bekend mee bent, bekijk dan deze geweldige Promises-tutorial . Nog een ding, () => {}
zijn ECMAScript 2015 Arrow-functies .
Bluetooth-apparaten aanvragen
Met deze versie van de Web Bluetooth API-specificatie kunnen websites die in de centrale rol draaien, verbinding maken met externe GATT-servers via een BLE-verbinding. Het ondersteunt communicatie tussen apparaten die Bluetooth 4.0 of hoger implementeren.
Wanneer een website toegang vraagt tot apparaten in de buurt met behulp van navigator.bluetooth.requestDevice
, vraagt de browser de gebruiker met een apparaatkiezer waar hij een apparaat kan kiezen of het verzoek kan annuleren.
De functie navigator.bluetooth.requestDevice()
gebruikt een verplicht object dat filters definieert. Deze filters worden gebruikt om alleen apparaten te retourneren die overeenkomen met sommige geadverteerde Bluetooth GATT-services en/of de apparaatnaam.
Dienstenfilter
Om bijvoorbeeld Bluetooth-apparaten aan te vragen die reclame maken voor de Bluetooth GATT Battery Service :
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Als uw Bluetooth GATT-service echter niet op de lijst met gestandaardiseerde Bluetooth GATT-services staat, kunt u de volledige Bluetooth UUID of een korte 16- of 32-bits vorm opgeven.
navigator.bluetooth.requestDevice({
filters: [{
services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
}]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Naamfilter
U kunt ook Bluetooth-apparaten aanvragen op basis van de apparaatnaam waarvoor reclame wordt gemaakt met de name
, of zelfs een voorvoegsel van deze naam met de namePrefix
filtersleutel. Houd er rekening mee dat u in dit geval ook de optionalServices
-sleutel moet definiëren om toegang te krijgen tot services die niet in een servicefilter zijn opgenomen. Als u dat niet doet, krijgt u later een foutmelding wanneer u probeert toegang te krijgen.
navigator.bluetooth.requestDevice({
filters: [{
name: 'Francois robot'
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Fabrikantgegevensfilter
Het is ook mogelijk om Bluetooth-apparaten aan te vragen op basis van de fabrikantspecifieke gegevens die worden geadverteerd met de manufacturerData
-sleutel. Deze sleutel is een array van objecten met een verplichte Bluetooth-bedrijfsidentificatiesleutel met de naam companyIdentifier
. U kunt ook een gegevensvoorvoegsel opgeven waarmee fabrikantgegevens worden gefilterd van Bluetooth-apparaten die daarmee beginnen. Houd er rekening mee dat u ook de optionalServices
-sleutel moet definiëren om toegang te krijgen tot services die niet in een servicefilter zijn opgenomen. Als u dat niet doet, krijgt u later een foutmelding wanneer u probeert toegang te krijgen.
// Filter Bluetooth devices from Google company with manufacturer data bytes
// that start with [0x01, 0x02].
navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: [{
companyIdentifier: 0x00e0,
dataPrefix: new Uint8Array([0x01, 0x02])
}]
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Een masker kan ook worden gebruikt met een gegevensvoorvoegsel om bepaalde patronen in de gegevens van de fabrikant te matchen. Bekijk de uitleg over Bluetooth-gegevensfilters voor meer informatie.
Uitsluitingsfilters
Met de optie exclusionFilters
in navigator.bluetooth.requestDevice()
kunt u bepaalde apparaten uitsluiten van de browserkiezer. Het kan worden gebruikt om apparaten uit te sluiten die aan een breder filter voldoen, maar niet worden ondersteund.
// Request access to a bluetooth device whose name starts with "Created by".
// The device named "Created by Francois" has been reported as unsupported.
navigator.bluetooth.requestDevice({
filters: [{
namePrefix: "Created by"
}],
exclusionFilters: [{
name: "Created by Francois"
}],
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Geen filters
Ten slotte kunt u in plaats van filters
de sleutel acceptAllDevices
gebruiken om alle Bluetooth-apparaten in de buurt weer te geven. U moet ook de optionalServices
-sleutel definiëren om toegang te krijgen tot bepaalde services. Als u dat niet doet, krijgt u later een foutmelding wanneer u probeert toegang te krijgen.
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });
Maak verbinding met een Bluetooth-apparaat
Dus wat doe je nu je een BluetoothDevice
hebt? Laten we verbinding maken met de Bluetooth-afstandsbediening GATT-server die de service en karakteristieke definities bevat.
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => {
// Human-readable name of the device.
console.log(device.name);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });
Lees een Bluetooth-kenmerk
Hier maken we verbinding met de GATT-server van het externe Bluetooth-apparaat. Nu willen we een primaire GATT-service krijgen en een kenmerk lezen dat bij deze service hoort. Laten we bijvoorbeeld proberen het huidige laadniveau van de batterij van het apparaat af te lezen.
In het volgende voorbeeld is battery_level
de gestandaardiseerde karakteristiek voor het batterijniveau .
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => device.gatt.connect())
.then(server => {
// Getting Battery Service…
return server.getPrimaryService('battery_service');
})
.then(service => {
// Getting Battery Level Characteristic…
return service.getCharacteristic('battery_level');
})
.then(characteristic => {
// Reading Battery Level…
return characteristic.readValue();
})
.then(value => {
console.log(`Battery percentage is ${value.getUint8(0)}`);
})
.catch(error => { console.error(error); });
Als u een aangepast Bluetooth GATT-kenmerk gebruikt, kunt u de volledige Bluetooth-UUID of een korte 16- of 32-bits vorm aan service.getCharacteristic
opgeven.
Houd er rekening mee dat u ook een characteristicvaluechanged
gebeurtenislistener aan een kenmerk kunt toevoegen om het lezen van de waarde ervan af te handelen. Bekijk het voorbeeld van Read Characteristic Value Changed om te zien hoe u optioneel ook aankomende GATT-meldingen kunt afhandelen.
…
.then(characteristic => {
// Set up event listener for when characteristic value changes.
characteristic.addEventListener('characteristicvaluechanged',
handleBatteryLevelChanged);
// Reading Battery Level…
return characteristic.readValue();
})
.catch(error => { console.error(error); });
function handleBatteryLevelChanged(event) {
const batteryLevel = event.target.value.getUint8(0);
console.log('Battery percentage is ' + batteryLevel);
}
Schrijf naar een Bluetooth-kenmerk
Schrijven naar een Bluetooth GATT-kenmerk is net zo eenvoudig als het lezen ervan. Laten we deze keer het hartslagcontrolepunt gebruiken om de waarde van het veld Verbruikte energie op een hartslagmeter opnieuw in te stellen op 0.
Ik beloof dat er hier geen magie is. Het wordt allemaal uitgelegd op de pagina Hartslagcontrolepuntkarakteristieken .
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_control_point'))
.then(characteristic => {
// Writing 1 is the signal to reset energy expended.
const resetEnergyExpended = Uint8Array.of(1);
return characteristic.writeValue(resetEnergyExpended);
})
.then(_ => {
console.log('Energy expended has been reset.');
})
.catch(error => { console.error(error); });
Ontvang GATT-meldingen
Laten we nu eens kijken hoe u op de hoogte kunt worden gesteld wanneer de hartslagmetingskarakteristiek op het apparaat verandert:
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_measurement'))
.then(characteristic => characteristic.startNotifications())
.then(characteristic => {
characteristic.addEventListener('characteristicvaluechanged',
handleCharacteristicValueChanged);
console.log('Notifications have been started.');
})
.catch(error => { console.error(error); });
function handleCharacteristicValueChanged(event) {
const value = event.target.value;
console.log('Received ' + value);
// TODO: Parse Heart Rate Measurement value.
// See https://github.com/WebBluetoothCG/demos/blob/gh-pages/heart-rate-sensor/heartRateSensor.js
}
In het meldingenvoorbeeld ziet u hoe u meldingen kunt stoppen met stopNotifications()
en hoe u de toegevoegde characteristicvaluechanged
gebeurtenislistener op de juiste manier kunt verwijderen.
Verbinding met een Bluetooth-apparaat verbreken
Voor een betere gebruikerservaring kunt u luisteren naar gebeurtenissen waarbij de verbinding is verbroken en de gebruiker uitnodigen om opnieuw verbinding te maken:
navigator.bluetooth.requestDevice({ filters: [{ name: 'Francois robot' }] })
.then(device => {
// Set up event listener for when device gets disconnected.
device.addEventListener('gattserverdisconnected', onDisconnected);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });
function onDisconnected(event) {
const device = event.target;
console.log(`Device ${device.name} is disconnected.`);
}
U kunt ook device.gatt.disconnect()
aanroepen om uw webapp los te koppelen van het Bluetooth-apparaat. Hierdoor worden bestaande gattserverdisconnected
gebeurtenislisteners geactiveerd. Houd er rekening mee dat de communicatie met het Bluetooth-apparaat NIET wordt gestopt als een andere app al met het Bluetooth-apparaat communiceert. Bekijk het voorbeeld van het ontkoppelen van het apparaat en het voorbeeld van het automatisch opnieuw verbinden om dieper te duiken.
Lezen en schrijven naar Bluetooth-descriptors
Bluetooth GATT-descriptors zijn attributen die een karakteristieke waarde beschrijven. U kunt ze op dezelfde manier lezen en schrijven als Bluetooth GATT-kenmerken.
Laten we bijvoorbeeld eens kijken hoe we de gebruikersbeschrijving van het meetinterval van de gezondheidsthermometer van het apparaat kunnen lezen.
In het onderstaande voorbeeld is health_thermometer
de Health Thermometer-service , measurement_interval
het meetintervalkenmerk en gatt.characteristic_user_description
de karakteristieke gebruikersbeschrijving .
navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => descriptor.readValue())
.then(value => {
const decoder = new TextDecoder('utf-8');
console.log(`User Description: ${decoder.decode(value)}`);
})
.catch(error => { console.error(error); });
Nu we de gebruikersbeschrijving van het meetinterval van de gezondheidsthermometer van het apparaat hebben gelezen, gaan we kijken hoe we deze kunnen bijwerken en een aangepaste waarde kunnen schrijven.
navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => {
const encoder = new TextEncoder('utf-8');
const userDescription = encoder.encode('Defines the time between measurements.');
return descriptor.writeValue(userDescription);
})
.catch(error => { console.error(error); });
Voorbeelden, demo's en codelabs
Alle onderstaande Web Bluetooth-voorbeelden zijn met succes getest. Om optimaal van deze voorbeelden te kunnen genieten, raad ik u aan de [BLE Peripheral Simulator Android App] te installeren, die een BLE-randapparaat simuleert met een batterijservice, een hartslagservice of een gezondheidsthermometerservice.
Beginner
- Apparaatinfo - haal basisapparaatinformatie op van een BLE-apparaat.
- Batterijniveau - haal batterij-informatie op van een BLE-apparaat dat batterij-informatie adverteert.
- Energie resetten - reset de energie die wordt verbruikt door een BLE-apparaat dat hartslag adverteert.
- Karakteristieke eigenschappen - toon alle eigenschappen van een specifiek kenmerk van een BLE-apparaat.
- Meldingen - start en stop karakteristieke meldingen van een BLE-apparaat.
- Apparaat loskoppelen - verbreek de verbinding en ontvang een melding wanneer een BLE-apparaat wordt verbroken nadat er verbinding mee is gemaakt.
- Kenmerken verkrijgen - verkrijg alle kenmerken van een geadverteerde service van een BLE-apparaat.
- Haal descriptors op - haal de descriptors van alle kenmerken van een geadverteerde service op van een BLE-apparaat.
- Fabrikantgegevensfilter - haal basisapparaatinformatie op van een BLE-apparaat dat overeenkomt met de gegevens van de fabrikant.
- Uitsluitingsfilters - haal basisapparaatinformatie op van een BLE-apparaat met basisuitsluitingsfilters.
Het combineren van meerdere operaties
- GAP-kenmerken - bekijk alle GAP-kenmerken van een BLE-apparaat.
- Kenmerken apparaatinformatie - bekijk alle apparaatinformatiekenmerken van een BLE-apparaat.
- Linkverlies - stel het waarschuwingsniveau van een BLE-apparaat in (readValue & writeValue).
- Ontdek services en kenmerken - ontdek alle toegankelijke primaire services en hun kenmerken vanaf een BLE-apparaat.
- Automatisch opnieuw verbinden - maak opnieuw verbinding met een losgekoppeld BLE-apparaat met behulp van een exponentieel uitstelalgoritme.
- Kenmerkwaarde lezen gewijzigd - lees het batterijniveau en ontvang een melding van wijzigingen vanaf een BLE-apparaat.
- Descriptors lezen - lees alle karakteristieke descriptors van een service vanaf een BLE-apparaat.
- Schrijf descriptor - schrijf naar de descriptor "Karakteristische gebruikersbeschrijving" op een BLE-apparaat.
Bekijk ook onze samengestelde Web Bluetooth-demo's en officiële Web Bluetooth Codelabs .
Bibliotheken
- web-bluetooth-utils is een npm-module die enkele gemaksfuncties aan de API toevoegt.
- Een Web Bluetooth API-shim is beschikbaar in noble , de meest populaire Node.js BLE centrale module. Hierdoor kunt u noble webpacken/browserifyen zonder dat u een WebSocket-server of andere plug-ins nodig hebt.
- angular-web-bluetooth is een module voor Angular die al het standaardwerk wegneemt dat nodig is om de Web Bluetooth API te configureren.
Hulpmiddelen
- Aan de slag met Web Bluetooth is een eenvoudige webapp die alle JavaScript-standaardcode genereert om interactie met een Bluetooth-apparaat te starten. Voer een apparaatnaam, een service en een kenmerk in, definieer de eigenschappen ervan en u bent klaar om te gaan.
- Als u al een Bluetooth-ontwikkelaar bent, genereert de Web Bluetooth Developer Studio Plugin ook de Web Bluetooth JavaScript-code voor uw Bluetooth-apparaat.
Tips
Er is een Bluetooth Internals- pagina beschikbaar in Chrome op about://bluetooth-internals
zodat u alles kunt bekijken over Bluetooth-apparaten in de buurt: status, services, kenmerken en beschrijvingen.
Ik raad ook aan om de officiële pagina met Web Bluetooth-bugs op te slaan, omdat het debuggen van Bluetooth soms moeilijk kan zijn.
Wat is het volgende
Controleer eerst de implementatiestatus van de browser en het platform om te weten welke delen van de Web Bluetooth API momenteel worden geïmplementeerd.
Hoewel het nog steeds onvolledig is, is hier een voorproefje van wat u in de nabije toekomst kunt verwachten:
- Het scannen naar BLE-advertenties in de buurt gebeurt met
navigator.bluetooth.requestLEScan()
. - Een nieuwe
serviceadded
-gebeurtenis zal nieuw ontdekte Bluetooth GATT-services volgen, terwijlserviceremoved
gebeurtenis de verwijderde zal volgen. Er wordt een nieuweservicechanged
gebeurtenis geactiveerd wanneer een kenmerk en/of descriptor wordt toegevoegd aan of verwijderd uit een Bluetooth GATT-service.
Toon ondersteuning voor de API
Bent u van plan de Web Bluetooth API te gebruiken? Uw publieke steun helpt het Chrome-team prioriteiten te stellen voor functies en laat andere browserleveranciers zien hoe belangrijk het is om deze te ondersteunen.
Stuur een tweet naar @ChromiumDev met de hashtag #WebBluetooth
en laat ons weten waar en hoe u deze gebruikt.
Bronnen
- Stapeloverloop
- Chrome-functiestatus
- Chrome-implementatiefouten
- Web Bluetooth-specificatie
- Specificatieproblemen op GitHub
- BLE Randapparatuur Simulator-app
Dankbetuigingen
Met dank aan Kayce Basques voor het beoordelen van dit artikel. Heldenafbeelding van SparkFun Electronics uit Boulder, VS.