WebSerial API¶
Het is mogelijk om data uit een extern apparaat, bijvoorbeeld je microcontroller, via een seriële verbinding uit te lezen in een webpagina. Dit kan je doen door gebruik te maken van de WebSerial API.
WebSerial API browser ondersteuning
De WebSerial API is nog in ontwikkeling en wordt nog niet door alle browsers ondersteund. Je kan de API wel al gebruiken in Chrome en Edge.
WebSerial API gebruiken¶
De WebSerial API is een JavaScript API die werkt in je webbrowser. Om deze te gebruiken heb je een HTML pagina nodig met JavaScript code. Gebruik de volgende code als basis voor je HTML pagina:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSerial API</title>
</head>
<body>
<h1>WebSerial API</h1>
<script>
// JavaScript code
</script>
</body>
Ondersteuning checken¶
Om te controleren of je browser de WebSerial API ondersteunt kan je de volgende code gebruiken:
Een verbinding maken¶
Vanuit veiligheidsoverwegingen is het niet toegestaan om een website zonder toestemming data via een seriële verbinding te laten uitlezen. Die toestemming geeft de gebruiker door deze een knop te laten indrukken.
In de <body>
van je HTML pagina maak je een knop aan.
Het onclick
attribuut verwijst in dit voorbeeld naar de functie connect()
. Deze functie moet je nog aanmaken in je JavaScript code.
// Define port and reader globally to be used in other functions
let port;
let reader
// Request a port and open a connection.
async function connect() {
port = await navigator.serial.requestPort();
await port.open({ baudRate: 9600 });
reader = port.readable.getReader();
console.log("Port is open!");
}
Wanneer de gebruiker op de knop drukt zal er een pop-up verschijnen:
Pop-up om toestemming te geven voor het gebruik van de WebSerial API |
Je programma kan niet verder totdat de gebruiker een poort heeft geselecteerd. Om die reden moet je de connect()
functie async
maken. De await
keyword zorgt ervoor dat de code wacht totdat de gebruiker een poort heeft geselecteerd.
Data ontvangen¶
Als je een verbinding hebt gemaakt dan kan je data ontvangen. Dit doe je door een while
loop te gebruiken die blijft wachten totdat er data binnenkomt.
// Read data
async function readLoop() {
// loop until reader.cancel() is called
while (true) {
// Wait for data
const { value, done } = await reader.read();
// Show the received data in the console
if (value) {
console.log(value);
}
// Exit the loop when done
if (done) {
console.log('[readLoop] DONE', done);
reader.releaseLock();
break;
}
}
}
async en await
Ook deze functie wordt async
gemaakt. De functie blijft draaien parallel aan de rest van je programma. De while-loop zal altijd blijven draaien totdat de reader.cancel()
functie wordt aangeroepen. Het await
keyword zorgt ervoor dat deze functie wacht totdat er data binnenkomt. Omdat de functie async
is, zal de rest van je programma wel gewoon blijven draaien.
De readLoop()
functie wordt aangeroepen nadat de verbinding is gemaakt door de volgende regel aan het einde van de connect()
functie toe te voegen:
Poort sluiten¶
Om de verbinding te verbreken kan je nog een knop toevoegen aan je HTML pagina:
Deze knop verwijst naar de disconnect()
functie die je nog moet aanmaken in je JavaScript code:
// Close the port
async function disconnect() {
await reader.cancel();
await port.close();
console.log("Port is closed!");
}
Testen¶
Om de verbinding te testen zal je je microcontroller moeten programmeren om data te versturen. Upload de volgende Arduino code naar je microcontroller:
// Send a counter value every 200 ms
int counter = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(counter);
counter++;
delay(200);
}
Let op
Het uploaden van code gebeurd ook via je seriële verbinding. Als die in gebruik is door je eigen applicatie kan je geen code uploaden. Zorg er dus voor dat je de verbinding in je eigen applicatie verbreekt voordat je code gaat uploaden.
Als de code is geupload en je microcontroller is aangesloten op je computer dan kan je de webpagina openen. Druk op de Connect
knop en selecteer de juiste poort. Als alles goed is gegaan dan zal je het volgende in je javascript console zien verschijnen:
Console output van de ontvangen data |
Dit lijkt niet op een teller. Wat je ziet is een representatie van de losse bytes die per keer worden verstuurd. Neem als voorbeeld de eerste regel:
[52, 13, 10]
De waarden hebben de volgende betekenis:
waarde | betekenis |
---|---|
52 | ASCII code voor het karakter 4 |
13 | ASCII code voor het karakter CR (Carriage Return) |
10 | ASCII code voor het karakter LF (Line Feed) |
De Arduino println()
functie voegt een CR
en een LF
toe aan het einde van de regel. Dit is nodig om aan te geven dat de regel is afgelopen. De CR
en LF
karakters worden ook wel de end-of-line karakters genoemd.
Lees het artikel over tekst representatie om meer te leren over de verschillende manieren waarop tekst kan worden gerepresenteerd in het geheugen.
Data vertalen¶
De data wordt nu ontvangen als een array van bytes. Om de data te kunnen gebruiken zal je deze moeten vertalen naar een ander data type.
Vertalen naar tekst (string)¶
Als je de data wilt zien in een HTML element dan zal je de data moeten vertalen naar een string. Dit kan je doen met de TextDecoder
class.
Voeg de volgende regel toe aan het begin van je JavaScript code:
De TextDecoder
class heeft een decode()
functie die een array van bytes omzet naar een string. Je kan deze functie gebruiken in de readLoop()
functie.
In de readLoop()
functie vervang je de regel
door de regel:
De output in de console zal nu de counter laten zien.
Weergeven in een HTML element¶
De data wordt nu ontvangen als een string. Om deze te kunnen weergeven in een HTML element zal je de string moeten toevoegen aan de innerHTML
property van het HTML element.
Voeg de volgende regel toe aan je HTML pagina:
De id
van het HTML element is counter
. Je kan dit element selecteren in je JavaScript code met de volgende regel:
De counterElement
variabele verwijst nu naar het HTML element. Je kan de innerHTML
property van het element aanpassen met de volgende regel in de readLoop()
functie:
Vertalen naar een getal¶
Als je de data wilt gebruiken in een berekening dan zal je de data moeten vertalen naar een getal. Dit kan je doen met de DataView
class maar het is makkelijker om de TextDecoder
class te gebruiken. Je kan de volgende stappen ondernemen:
- Vertaal de data naar een string met de
TextDecoder
class. - Vertaal de string naar een getal met de
parseInt()
functie.
// In de readLoop() functie
// Convert the data to a string
let counterString = decoder.decode(value);
// Convert the string to a number
let counterNumber = parseInt(counterValue);