Skip to content

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:

if ('serial' in navigator) {
  // WebSerial API supported
} else {
  // WebSerial API not supported
}

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.

<button onclick="connect()">Connect</button>

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:

(webserial_popup
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:

readLoop();

Poort sluiten

Om de verbinding te verbreken kan je nog een knop toevoegen aan je HTML pagina:

<button onclick="disconnect()">Disconnect</button>

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:

let decoder = new TextDecoder("utf-8");

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

console.log(value);

door de regel:

console.log(decoder.decode(value));

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:

<p id="counter"></p>

De id van het HTML element is counter. Je kan dit element selecteren in je JavaScript code met de volgende regel:

let counterElement = document.getElementById("counter");

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:

let counterValue = decoder.decode(value);
counterElement.innerHTML = counterValue;

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:

  1. Vertaal de data naar een string met de TextDecoder class.
  2. 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);

Bronnen