Contenidos
Die serielle API ermöglicht Websites die Kommunikation mit seriellen Geräten.
Aktualisiert
Was ist die serielle API?
Eine serielle Schnittstelle ist eine bidirektionale Kommunikationsschnittstelle, über die Sie Daten byteweise senden und empfangen können.
Die serielle API bietet Websites die Möglichkeit, mit JavaScript auf einem seriellen Gerät zu lesen und zu schreiben. Serielle Geräte werden über eine serielle Schnittstelle im System des Benutzers oder über entfernbare USB- und Bluetooth-Geräte verbunden, die eine serielle Schnittstelle emulieren.
Mit anderen Worten, die serielle API verbindet das Web und die physische Welt, indem sie Websites die Kommunikation mit seriellen Geräten wie Mikrocontrollern und 3D-Druckern ermöglicht.
Diese API ist auch ein großartiger Begleiter für WebUSB Da Betriebssysteme erfordern, dass Anwendungen mit einigen seriellen Ports über ihre native serielle API der obersten Ebene anstelle der USB-API auf niedriger Ebene kommunizieren.
Dieser Artikel spiegelt die in Chrome 86 und höher implementierte serielle API wider. Einige Eigenschaftsnamen wurden gegenüber früheren Versionen geändert.
Vorgeschlagene Anwendungsfälle
In den Bereichen Bildung, Hobby und Industrie verbinden Benutzer Peripheriegeräte mit ihren Computern. Diese Geräte werden häufig von Mikrocontrollern über eine serielle Verbindung gesteuert, die von kundenspezifischer Software verwendet wird. Einige benutzerdefinierte Software zur Steuerung dieser Geräte basiert auf Web-Technologie:
In einigen Fällen kommunizieren Websites mit dem Gerät über eine native Agentenanwendung, die Benutzer manuell installiert haben. In anderen Fällen wird die Anwendung in einer nativen Anwendung bereitgestellt, die über ein Framework wie Electron gepackt ist. In anderen Fällen muss der Benutzer einen zusätzlichen Schritt ausführen, z. B. das Kopieren einer kompilierten Anwendung auf das Gerät über ein USB-Flash-Laufwerk.
In all diesen Fällen wird die Benutzererfahrung verbessert, indem eine direkte Kommunikation zwischen der Website und dem von ihr gesteuerten Gerät bereitgestellt wird.
Tatsächlicher Zustand
Verwenden der seriellen API
Aktivieren Sie die Unterstützung während der Herkunftsnachweisphase
Die serielle API ist auf allen Desktop-Plattformen (Chrome OS, Linux, macOS und Windows) als Ursprungsnachweis für Chrome 80 verfügbar. Der Ursprungsnachweis wird voraussichtlich kurz vor der Einstellung von Chrome 89 im Februar 2021 abgeschlossen sein. Die API kann dies auch durch ein Flag aktiviert werden.
Mit Origin-Tests können Sie neue Funktionen testen und der Community für Webstandards Feedback zu deren Benutzerfreundlichkeit, Praktikabilität und Effektivität geben. Weitere Informationen finden Sie in der Origin-Testhandbuch für Webentwickler. Um sich für diesen oder einen anderen Herkunftsnachweis anzumelden, besuchen Sie die Registrierungsseite.
Registrieren Sie sich für den Herkunftsnachweis
- Fordern Sie einen Token an von Ihrer Herkunft.
- Fügen Sie das Token Ihren Seiten hinzu. Es gibt zwei Möglichkeiten, dies zu tun:
- Füge hinzu ein
Ursprungsversuch
Tag zum Header jeder Seite. Dies könnte beispielsweise folgendermaßen aussehen:
- Wenn Sie Ihren Server konfigurieren können, können Sie das Token auch mit a hinzufügen
Origin-Trial
HTTP-Header. Der resultierende Antwortheader sollte folgendermaßen aussehen:Origin-Trial: TOKEN_GOES_HERE
- Füge hinzu ein
Aktivierung über chrome: // flags
Aktivieren Sie die Option, um auf allen Desktop-Plattformen ohne Quelltest-Token lokal mit der seriellen API zu experimentieren #experimental-Web-Plattform-Funktionen
Flagge an
chrome://flags
.
Funktionserkennung
Verwenden Sie Folgendes, um zu überprüfen, ob die serielle API unterstützt wird:
if ( "serial" im Navigator ) {
}}
Öffnen Sie eine serielle Schnittstelle
Die serielle API ist vom Design her asynchron. Dies verhindert, dass die Benutzeroberfläche der Website abstürzt, wenn Eingaben erwartet werden. Dies ist wichtig, da serielle Daten jederzeit empfangen werden können und eine Möglichkeit zum Abhören erforderlich sind.
Um eine serielle Schnittstelle zu öffnen, greifen Sie zuerst auf a zu Serielle Schnittstelle
Objekt. Zu diesem Zweck können Sie den Benutzer auffordern, eine einzelne serielle Schnittstelle auszuwählen, indem Sie anrufen
navigator.serial.requestPort ()
oder wählen Sie eine von navigator.serial.getPorts ()
Hiermit wird eine Liste der seriellen Schnittstellen zurückgegeben, auf die die Website zuvor zugegriffen hat.
const port = warte auf Navigator . seriell . requestPort ( ) ;
const ports = warte auf Navigator . seriell . getPorts ( ) ;
das navigator.serial.requestPort ()
Die Funktion verwendet ein optionales Objektliteral, das Filter definiert. Sie werden verwendet, um jedes über USB angeschlossene serielle Gerät einem obligatorischen USB-Anbieter zuzuordnen (usbVendorId
) und optionale USB-Produktkennungen (usbProductId
).
const filter = [
{ usbVendorId : 0x2341 , usbProductId : 0x0043 } ,
{ usbVendorId : 0x2341 , usbProductId : 0x0001 }
] ;
const port = warte auf Navigator . seriell . requestPort ( { Filter } ) ;
const { usbProductId , usbVendorId } = Port . getInfo ( ) ;
Berufung requestPort ()
fordert den Benutzer auf, ein Gerät auszuwählen, und gibt a zurück
Serielle Schnittstelle
Objekt. Sobald Sie eine haben Serielle Schnittstelle
Objektaufruf port.open ()
Mit der gewünschten Baudrate wird die serielle Schnittstelle geöffnet. das Baudrate
Das Wörterbuchmitglied gibt an, wie schnell Daten über eine serielle Leitung gesendet werden. Sie wird in Einheiten von Bits pro Sekunde (bps) ausgedrückt. Überprüfen Sie Ihre Gerätedokumentation auf den korrekten Wert, da alle Daten, die Sie senden und empfangen, Kauderwelsch sind, wenn dies falsch angegeben wird. Bei einigen USB- und Bluetooth-Geräten, die eine serielle Schnittstelle emulieren, kann dieser Wert sicher auf einen beliebigen Wert eingestellt werden, da er von der Emulation ignoriert wird.
const port = warte auf Navigator . seriell . requestPort ( ) ;
warte auf den Hafen . open ( { baudRate : 9600 } ) ;
Sie können beim Öffnen einer seriellen Schnittstelle auch eine der folgenden Optionen angeben. Diese Optionen sind optional und haben vorgegebene Werte.
Daten Bits
: Die Anzahl der Datenbits pro Frame (7 oder 8).Stopp-Bits
: Die Anzahl der Stoppbits am Ende eines Frames (1 oder 2).Parität
: Der Paritätsmodus (entweder"keiner"
,"sogar"
oder"seltsam"
).Puffergröße
: Die Größe der zu erstellenden Lese- und Schreibpuffer (muss weniger als 16 MB betragen).Ablaufsteuerung
: Der Durchflussregelungsmodus (entweder"keiner"
oder"Hardware"
).
Lesen Sie von einer seriellen Schnittstelle
Die Eingabe- und Ausgabestreams in der seriellen API werden von der Streams-API verarbeitet.
Wenn die Streams für Sie neu sind, sehen Sie Streams API-Konzepte. Dieser Artikel berührt nur die Oberfläche von Streams und deren Verwaltung.
Sobald die serielle Schnittstelle hergestellt ist, lesbar
y schreibbar
Eigentum von Serielle Schnittstelle
Objekt gibt a zurück ReadableStream und ein
WritableStream. Sie werden zum Empfangen von Daten und zum Senden von Daten an das serielle Gerät verwendet. Sie beide verwenden Uint8Array
Instanzen für die Datenübertragung.
Wenn neue Daten vom seriellen Gerät eingehen, port.readable.getReader (). read ()
gibt zwei Eigenschaften asynchron zurück: die Wert
und ein erledigt
Boolescher Wert. Ja
erledigt
Es ist wahr, die serielle Schnittstelle wurde geschlossen oder es gehen keine Daten mehr ein. Berufung port.readable.getReader ()
Erstellen Sie einen Reader und blockieren Sie lesbar
es. Während lesbar
ist gesperrtkann die serielle Schnittstelle nicht geschlossen werden.
const reader = port . lesbar . getReader ( ) ;
while ( wahr ) {
const { value , done } = warte auf den Leser . read ( ) ;
if ( erledigt ) {
Leser . releaseLock ( ) ;
Pause ;
}}
Konsole . log ( Wert ) ;
}}
Einige nicht schwerwiegende Fehler beim Lesen der seriellen Schnittstelle können unter bestimmten Bedingungen auftreten, z. B. Pufferüberlauf, Rahmenfehler oder Paritätsfehler. Diese werden als Ausnahmen ausgelöst und können durch Hinzufügen einer weiteren Schleife über der vorherigen, die überprüft wird, abgefangen werden port.readable
. Dies funktioniert, weil, solange die Fehler nicht schwerwiegend sind, eine neue ReadableStream es wird automatisch erstellt. Wenn ein schwerwiegender Fehler wie das Entfernen des seriellen Geräts auftritt, port.readable
wird null.
while ( Port . lesbar ) {
const reader = port . lesbar . getReader ( ) ;
versuche {
while ( wahr ) {
const { value , done } = warte auf den Leser . read ( ) ;
if ( erledigt ) {
Leser . releaseLock ( ) ;
Pause ;
}}
if ( Wert ) {
Konsole . log ( Wert ) ;
}}
}}
} catch ( Fehler ) {
}}
}}
Wenn das serielle Gerät Text zurücksendet, können Sie eine Pipe erstellen port.readable
durch ein
TextDecoderStream
Wie nachfolgend dargestellt. EIN TextDecoderStream
ist ein Strom umwandeln
das packt alles Uint8Array
Fragmente und verwandelt sie in Strings.
const textDecoder = neuer TextDecoderStream ( ) ;
const readableStreamClosed = Port . lesbar . pipeTo ( textDecoder . beschreibbar ) ;
const reader = textDecoder . lesbar . getReader ( ) ;
while ( wahr ) {
const { value , done } = warte auf den Leser . read ( ) ;
if ( erledigt ) {
Leser . releaseLock ( ) ;
Pause ;
}}
Konsole . log ( Wert ) ;
}}
Schreiben Sie an eine serielle Schnittstelle
Übergeben Sie die Daten an, um Daten an ein serielles Gerät zu senden
port.writable.getWriter (). write ()
. Berufung releaseLock ()
im
port.writable.getWriter ()
Die serielle Schnittstelle muss später geschlossen werden.
const writer = port . beschreibbar . getWriter ( ) ; const data = new Uint8Array ( [ 104 , 101 , 108 , 108 , 111 ] ) ;
erwarte Schriftsteller . schreiben ( Daten ) ;
Schriftsteller . releaseLock ( ) ;
Senden Sie Text an das Gerät über a TextEncoderStream
kanalisiert zu port.writable
Wie nachfolgend dargestellt.
const textEncoder = neuer TextEncoderStream ( ) ;
const writableStreamClosed = textEncoder. lesbar . pipeTo ( port . beschreibbar ) ; const writer = textEncoder . beschreibbar . getWriter ( ) ;
erwarte Schriftsteller . schreiben ( "Hallo" ) ;
Schließen Sie eine serielle Schnittstelle
port.close ()
Schließen Sie die serielle Schnittstelle, wenn Ihre lesbar
y schreibbar
Die Mitglieder sind freigeschaltetSinn releaseLock ()
Es wurde von seinem jeweiligen Leser und Verfasser gerufen.
warte auf den Hafen . close ( ) ;
Wenn Sie jedoch kontinuierlich Daten von einem seriellen Gerät mithilfe einer Schleife lesen,
port.readable
Es wird immer blockiert, bis ein Fehler auftritt. In diesem Fall anrufen reader.cancel ()
zwingen zu reader.read ()
sofort zu lösen mit {Wert: undefiniert, erledigt: wahr}
und somit die Schleife aufrufen lassen reader.releaseLock ()
.
const reader = port . lesbar . getReader ( ) ;
while ( wahr ) {
const { value , done } = warte auf den Leser . read ( ) ;
if ( erledigt ) {
Leser . releaseLock ( ) ;
Pause ;
}}
Konsole . log ( Wert ) ;
}}
erwarte Leser . cancel ( ) ;
warte auf den Hafen . close ( ) ;
Das Schließen einer seriellen Schnittstelle ist bei Verwendung komplizierter Streams transformieren (Ich mag
TextDecoderStream
y TextEncoderStream
). Anruf reader.cancel ()
wie früher. Dann ruf an writer.close ()
y port.close ()
. Dadurch werden die Fehler über die Transformationsströme an die zugrunde liegende serielle Schnittstelle weitergegeben. Da die Fehlerausbreitung nicht sofort erfolgt, sollten Sie die verwenden readableStreamClosed
y
writableStreamClosed
zuvor erstellte Versprechen zu erkennen, wann port.readable
y port.writable
wurden freigeschaltet. Sage ab Leser
bewirkt, dass die Sequenz abgebrochen wird; Deshalb müssen Sie den resultierenden Fehler abfangen und ignorieren.
const textDecoder = neuer TextDecoderStream ( ) ;
const readableStreamClosed = Port . lesbar . pipeTo ( textDecoder . beschreibbar ) ;
const reader = textDecoder . lesbar . getReader ( ) ;
while ( wahr ) {
const { value , done } = warte auf den Leser . read ( ) ;
if ( erledigt ) {
Leser . releaseLock ( ) ;
Pause ;
}}
Konsole . log ( Wert ) ;
}}
const textEncoder = neuer TextEncoderStream ( ) ;
const writableStreamClosed = textEncoder. lesbar . pipeTo ( port . beschreibbar ) ;
Leser . cancel ( ) ;
Warten Sie auf readableStreamClosed . catch ( ( ) => { } ) ;
Schriftsteller . close ( ) ;
warte auf writableStreamClosed ;
warte auf den Hafen . close ( ) ;
Hören Sie die Verbindung und Trennung
Wenn ein USB-Gerät eine serielle Schnittstelle bietet, kann dieses Gerät an das System angeschlossen oder von diesem getrennt werden. Wenn der Website die Berechtigung zum Zugriff auf eine serielle Schnittstelle erteilt wurde, sollte sie die Website überwachen verbinden
y trennen
Veranstaltungen.
Navigator . seriell . addEventListener ( "connect" , ( event ) => {
} ) ; Navigator . seriell . addEventListener ( "trennen" , ( Ereignis ) => {
} ) ;
Signale verarbeiten
Nach dem Herstellen der seriellen Schnittstelle können Sie die von der seriellen Schnittstelle bereitgestellten Signale explizit abfragen und konfigurieren, um Geräte zu erkennen und den Fluss zu steuern. Diese Signale werden als Boolesche Werte definiert. Beispielsweise wechseln einige Geräte wie Arduino in einen Programmiermodus, wenn das DTR-Signal (Data Terminal Ready) aktiviert ist.
Einstellung Ausgangsschilder und bekomme Eingangssignale werden jeweils durch Aufruf gemacht port.setSignals ()
y port.getSignals ()
. Siehe die folgenden Verwendungsbeispiele.
warte auf den Hafen . setSignals ( { break : false } ) ;
warte auf den Hafen . setSignals ( { dataTerminalReady : true } ) ;
warte auf den Hafen . setSignals ( { requestToSend : false } ) ;
const- Signale = Port warten . getSignals ( ) ;
Konsole . log ( ` Clear To Send: $ { Signale . clearToSend } ` ) ;
Konsole . log ( ` Datenträgererkennung: $ { Signale . dataCarrierDetect } ` ) ;
Konsole . log ( ` Datensatz bereit: $ { Signale . dataSetReady } ` ) ;
Konsole . log ( ` Ring Indicator: $ { signalisiert . ringIndicator } ` ) ;
Streams transformieren
Wenn Sie Daten vom seriellen Gerät empfangen, erhalten Sie nicht unbedingt alle Daten auf einmal. Es kann beliebig fragmentiert werden. Weitere Informationen finden Sie unter
Streams API-Konzepte.
Um dies zu bewältigen, können Sie einige integrierte Transformations-Streams verwenden, wie z
TextDecoderStream
oder erstellen Sie Ihren eigenen Transformationsfluss, mit dem Sie den eingehenden Fluss analysieren und analysierte Daten zurückgeben können. Der Transformationsstrom befindet sich zwischen dem seriellen Gerät und der Leseschleife, die den Strom verbraucht. Sie können eine beliebige Transformation anwenden, bevor die Daten verbraucht werden. Stellen Sie es sich wie ein Fließband vor - wenn sich ein Widget entlang der Linie bewegt, ändert jeder Schritt in der Linie das Widget so, dass es ein voll funktionsfähiges Widget ist, wenn es sein endgültiges Ziel erreicht.
Überlegen Sie beispielsweise, wie Sie eine Transformations-Stream-Klasse erstellen, die einen Stream verbraucht und ihn basierend auf Zeilenumbrüchen aufteilt. Ihr transform ()
Die Methode wird jedes Mal aufgerufen, wenn der Flow neue Daten empfängt. Sie können die Daten in die Warteschlange stellen oder für später speichern. das Flush ()
Die Methode wird aufgerufen, wenn der Stream geschlossen wird, und verarbeitet alle Daten, die noch nicht verarbeitet wurden.
Um die Transformations-Stream-Klasse zu verwenden, müssen Sie einen eingehenden Stream durch sie leiten. Im dritten Codebeispiel in Lesen von einer seriellen Schnittstelle wurde der ursprüngliche Eingabestream nur durch a geleitet TextDecoderStream
dann müssen wir anrufen pipeThrough ()
um es durch unsere neuen zu kanalisieren LineBreakTransformer
.
Klasse LineBreakTransformer {
Konstruktor ( ) {
das . chunks = "" ;
}} transformieren ( Chunk , Controller ) {
das . Chunks + = Chunk ;
const lines = this . Brocken . split ( "rn" ) ;
das . Chunks = Zeilen . pop ( ) ;
Linien . forEach ( ( line ) => controller . enqueue ( line ) ) ;
}}
Flush ( Controller ) {
Controller . Enqueue ( dies . Brocken ) ;
}}
}}
const textDecoder = neuer TextDecoderStream ( ) ;
const readableStreamClosed = Port . lesbar . pipeTo ( textDecoder . beschreibbar ) ;
const reader = textDecoder . lesbar
. pipeThrough ( neuer TransformStream ( neuer LineBreakTransformer ( ) ) )
. getReader ( ) ;
Verwenden Sie zum Debuggen von Kommunikationsproblemen mit seriellen Geräten die Tee ()
Methode von
port.readable
um die Übertragungen zum oder vom seriellen Gerät zu teilen. Die beiden erstellten Flows können unabhängig voneinander verwendet werden. Auf diese Weise können Sie einen zur Überprüfung auf der Konsole drucken.
const [ appReadable , devReadable ] = Port . lesbar . tee ( ) ;
Codelab
Beim Google Developer Code Labverwenden Sie die serielle API, um mit a zu interagieren
BBC micro: bit Board, um Bilder auf seiner 5 × 5 LED-Matrix anzuzeigen.
Polyfill
Unter Android können USB-basierte serielle Ports über die WebUSB-API und unterstützt werden Polyfill API-Serie. Diese Polyfüllung ist auf Hardware und Plattformen beschränkt, auf die über die WebUSB-API auf das Gerät zugegriffen werden kann, da sie nicht von einem integrierten Gerätetreiber beansprucht wurde.
Sicherheit und Privatsphäre
Die Spezifikationsautoren haben die serielle API unter Verwendung der in definierten Grundprinzipien entworfen und implementiert Steuern Sie den Zugriff auf leistungsstarke Funktionen der Webplattform, einschließlich Benutzerkontrolle, Transparenz und Ergonomie. Die Fähigkeit, diese API zu verwenden, wird hauptsächlich durch ein Berechtigungsmodell gesteuert, das jeweils nur Zugriff auf ein serielles Gerät gewährt. In Reaktion auf eine Benutzeranforderung muss der Benutzer aktive Schritte unternehmen, um ein bestimmtes serielles Gerät auszuwählen.
Informationen zu den Sicherheits-Kompromissen finden Sie in der Sicherheit y Privatsphäre
Serial API Explainer-Abschnitte.
Feedback
Das Chrome-Team würde gerne Ihre Gedanken und Erfahrungen mit der seriellen API hören.
Erzählen Sie uns etwas über das API-Design
Gibt es etwas in der API, das nicht wie erwartet funktioniert? Oder fehlen Ihnen Methoden oder Eigenschaften, die Sie zur Umsetzung Ihrer Idee benötigen?
Legen Sie ein Spezifikationsproblem auf der GitHub-Repository der seriellen API oder fügen Sie Ihre Gedanken zu einem bestehenden Problem hinzu.
Melden Sie ein Problem mit der Bereitstellung
Haben Sie einen Fehler bei der Chrome-Implementierung gefunden? Oder unterscheidet sich die Implementierung von der Spezifikation?
Einen Fehler einreichen https://new.crbug.com. Stellen Sie sicher, dass Sie so viele Details wie möglich angeben, einfache Anweisungen zum Reproduzieren des Fehlers bereitstellen und
Komponenten (bearbeiten) angepasst an Blinken> Seriennummer
. Fehler funktioniert hervorragend für das schnelle und einfache Teilen von Wiederholungen.
Unterstützung zeigen
Planen Sie die Verwendung der seriellen API? Ihr öffentlicher Support hilft dem Chrome-Team bei der Priorisierung von Funktionen und zeigt anderen Browser-Anbietern, wie wichtig es ist, diese zu unterstützen.
Senden Sie einen Tweet an @Cromodev mit dem Hashtag
#SerialAPI
und lassen Sie uns wissen, wo und wie Sie es verwenden.
Nützliche Links
Population:
Vielen Dank
Dank an Reilly-Stipendium y Joe Medley für ihre Bewertungen dieses Artikels. Flugzeugfabrik Foto von Birmingham Museums Trust im Unsplash.