Ho fatto una prova e funziona se si imposta il browser (chrome) in modalità "sperimentale" (chrome://flags/#enable-experimental-web-platform-features e abilitarlo)
Poi il codice è semplice:
codice:
async function sendCommand(command, vel) {
var buffer = new ArrayBuffer(1);
buffer[0] = command;
var port = await navigator.serial.requestPort();
await port.open({ baudrate: vel});
var reader = port.readable.getReader();
var writer = port.writable.getWriter();
writer.write(buffer);
while (true) {
var res = await reader.read();
if (res.done) break;
console.log(res.value);
}
}
.....
<button onclick="sendCommand(1,9600)">Write</button>
in pratica recuperi la porta e la apri (passando la velocità oppure la metti fissa, vedi tu), poi dalla porta ricavi il reader e il writer e tramite quest ultimo invii il comando alla seriale, dopo leggi la seriale per eventuali risposte.
Ovviamente il codice è minimale e va gestito ed adattato per le tue esigenze.
Detto questo il fatto che devi impostare appositamente il browser fa passare tutta la fantasia. Diciamo che va bene se ad usarlo è un utente con device "locale" (tipo fornito da te che ti puoi impostare il browser), ma è ovvio che non è utilizzabile con i mezzi dell'utente, dovrai usare il tuo o impostare il browser dell'utente. Se invece ti serve "in produzione" senza fornire tu il device allora non rimane che un intermediario tra il browser e la seriale come suggerito in precedenza.