L'API série permet aux sites Web de communiquer avec des périphériques série.
Mise à jour
Qu'est-ce que l'API série?
Un port série est une interface de communication bidirectionnelle qui vous permet d'envoyer et de recevoir des données octet par octet.
L'API série permet aux sites Web de lire et d'écrire sur un périphérique série avec JavaScript. Les périphériques série se connectent via un port série sur le système de l'utilisateur ou via des périphériques USB et Bluetooth amovibles qui émulent un port série.
En d'autres termes, l'API série relie le Web et le monde physique en permettant aux sites Web de communiquer avec des périphériques série, tels que des microcontrôleurs et des imprimantes 3D.
Cette API est également un excellent compagnon pour WebUSB car les systèmes d'exploitation exigent que les applications communiquent avec certains ports série en utilisant leur API série native de premier niveau au lieu de l'API USB de bas niveau.
Cet article reflète l'API série implémentée dans Chrome 86 et versions ultérieures. Certains noms de propriétés ont changé par rapport aux versions précédentes.
Cas d'utilisation suggérés
Dans les secteurs de l'éducation, des loisirs et de l'industrie, les utilisateurs connectent des périphériques à leurs ordinateurs. Ces appareils sont souvent contrôlés par des microcontrôleurs via une connexion série utilisée par un logiciel personnalisé. Certains logiciels personnalisés pour contrôler ces appareils sont construits avec la technologie Web:
Dans certains cas, les sites Web communiquent avec l'appareil via une application d'agent native que les utilisateurs ont installée manuellement. Dans d'autres, l'application est livrée dans une application native conditionnée via un framework tel qu'Electron. Et dans d'autres, l'utilisateur doit franchir une étape supplémentaire, comme la copie d'une application compilée sur l'appareil via une clé USB.
Dans tous ces cas, l'expérience utilisateur sera améliorée en fournissant une communication directe entre le site Web et l'appareil qu'il contrôle.
État actuel
Utilisation de l'API série
Activer le support lors de la phase de preuve d'origine
L'API série est disponible sur toutes les plates-formes de bureau (Chrome OS, Linux, macOS et Windows) comme preuve d'origine sur Chrome 80. La preuve d'origine devrait se terminer juste avant la mise en place de Chrome 89 en février 2021. L'API peut également être activé par un drapeau.
Les tests d'origine vous permettent de tester de nouvelles fonctionnalités et de fournir des commentaires sur leur convivialité, leur caractère pratique et leur efficacité à la communauté des normes Web. Pour plus d'informations, consultez le Guide de test d'origine pour les développeurs Web. Pour vous inscrire à cette preuve d'origine ou à toute autre preuve d'origine, visitez le page d'inscription.
Inscrivez-vous pour obtenir une preuve d'origine
- Demander un jeton par votre origine.
- Ajoutez le jeton à vos pages. Il y a deux façons de le faire:
- Ajouter un
origine-procès
balise à l'en-tête de chaque page. Par exemple, cela pourrait ressembler à ceci:
- Si vous pouvez configurer votre serveur, vous pouvez également ajouter le jeton à l'aide d'un
Essai d'origine
En-tête HTTP. L'en-tête de réponse qui en résulte doit ressembler à ceci:Essai d'origine: TOKEN_GOES_HERE
- Ajouter un
Activation via chrome: // flags
Pour expérimenter l'API série localement sur toutes les plates-formes de bureau, sans jeton de test source, activez le #experimental-web-platform-features
drapeau sur
chrome://flags
.
Détection des fonctionnalités
Pour vérifier si l'API série est prise en charge, utilisez:
si ("serial" dans navigateur) {
}
Ouvrez un port série
L'API série est asynchrone de par sa conception. Cela empêche l'interface utilisateur du site Web de se bloquer lorsque l'entrée est attendue, ce qui est important car les données série peuvent être reçues à tout moment, ce qui nécessite un moyen de les écouter.
Pour ouvrir un port série, accédez d'abord à un Port série
objet. Pour ce faire, vous pouvez demander à l'utilisateur de sélectionner un seul port série en appelant
navigator.serial.requestPort ()
ou choisissez l'un des navigator.serial.getPorts ()
qui renvoie une liste des ports série auxquels le site Web a précédemment accédé.
const port = attendre navigateur.serial.requestPort();
const ports = attendre navigateur.serial.getPorts();
Les navigator.serial.requestPort ()
La fonction prend un littéral d'objet facultatif qui définit les filtres. Ils sont utilisés pour faire correspondre tout périphérique série connecté via USB à un fournisseur USB obligatoire (usbVendorId
) et les identifiants de produit USB en option (usbProductId
).
const filters = [
{ usbVendorId: 0x2341, usbProductId: 0x0043 },
{ usbVendorId: 0x2341, usbProductId: 0x0001 }
];
const port = attendre navigateur.serial.requestPort({ filters });
const { usbProductId, usbVendorId } = port.getInfo();
Vocation requestPort ()
invite l'utilisateur à sélectionner un appareil et renvoie un
Port série
objet. Une fois que vous avez un Port série
appel d'objet port.open ()
avec le débit en bauds souhaité, le port série s'ouvrira. Les baudRate
Le membre du dictionnaire spécifie la vitesse à laquelle les données sont envoyées sur une ligne série. Il est exprimé en unités de bits par seconde (bps). Consultez la documentation de votre appareil pour la valeur correcte car toutes les données que vous envoyez et recevez seront du charabia si cela est spécifié de manière incorrecte. Pour certains périphériques USB et Bluetooth qui émulent un port série, cette valeur peut être définie en toute sécurité sur n'importe quelle valeur car elle est ignorée par l'émulation.
const port = attendre navigateur.serial.requestPort();
attendre port.open({ baudRate: 9600 });
Vous pouvez également spécifier l'une des options suivantes lors de l'ouverture d'un port série. Ces options sont facultatives et ont valeurs prédéterminées.
Bits de données
: Le nombre de bits de données par trame (7 ou 8).bits d'arrêt
: Le nombre de bits d'arrêt à la fin d'une trame (1 ou 2).parité
: Le mode de parité (soit"rien"
,"même"
ou"impair"
).bufferSize
: La taille des tampons de lecture et d'écriture à créer (doit être inférieure à 16 Mo).contrôle de flux
: Le mode de contrôle de flux (soit"rien"
ou"Matériel"
).
Lire à partir d'un port série
Les flux d'entrée et de sortie de l'API série sont gérés par l'API Streams.
Si les flux sont nouveaux pour vous, consultez Concepts de l'API Streams. Cet article touche juste la surface des flux et leur gestion.
Une fois la connexion du port série établie, lisible
y inscriptible
propriétés de Port série
objet renvoie un ReadableStream et un
WritableStream. Ils seront utilisés pour recevoir des données et envoyer des données au périphérique série. Ils utilisent tous les deux Uint8Array
instances de transfert de données.
Lorsque de nouvelles données arrivent du périphérique série, port.readable.getReader (). read ()
renvoie deux propriétés de manière asynchrone: le valeur
et un Fini
booléen. Oui
Fini
c'est vrai, le port série a été fermé ou il n'y a plus de données entrantes. Appel port.readable.getReader ()
créer un lecteur et bloquer lisible
il. Alors que lisible
c'est fermé à clé, le port série ne peut pas être fermé.
const lecteur = port.lisible.getReader();
tandis que (vrai) {
const { valeur, Fini } = attendre lecteur.read();
si (Fini) {
lecteur.releaseLock();
break;
}
console.Journal(valeur);
}
Certaines erreurs de lecture de port série non fatales peuvent se produire dans certaines conditions, telles qu'un dépassement de mémoire tampon, des erreurs de cadrage ou des erreurs de parité. Ceux-ci sont lancés comme des exceptions et peuvent être interceptés en ajoutant une autre boucle au-dessus de la précédente qui vérifie port.lisible
. Cela fonctionne car tant que les erreurs ne sont pas fatales, un nouveau ReadableStream il est créé automatiquement. Si une erreur fatale telle que la suppression d'un périphérique série se produit, port.lisible
devient nul.
tandis que (port.lisible) {
const lecteur = port.lisible.getReader();
try {
tandis que (vrai) {
const { valeur, Fini } = attendre lecteur.read();
si (Fini) {
lecteur.releaseLock();
break;
}
si (valeur) {
console.Journal(valeur);
}
}
} catch (Erreur) {
}
}
Si le périphérique série renvoie du texte, vous pouvez rediriger port.lisible
à travers un
TextDecoderStream
Comme indiqué ci-dessous. ONGLE TextDecoderStream
c'est un transformer le courant
qui saisit tout Uint8Array
fragments et les transforme en chaînes.
const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.lisible.pipeTo(textDecoder.inscriptible);
const lecteur = textDecoder.lisible.getReader();
tandis que (vrai) {
const { valeur, Fini } = attendre lecteur.read();
si (Fini) {
lecteur.releaseLock();
break;
}
console.Journal(valeur);
}
Ecrire sur un port série
Pour envoyer des données à un périphérique série, transmettez les données à
port.writable.getWriter (). write ()
. Vocation releaseLock ()
au
port.writable.getWriter ()
il est nécessaire que le port série soit fermé plus tard.
const writer = port.inscriptible.getWriter();const Les données = new Uint8Array([104, 101, 108, 108, 111]);
attendre writer.write(Les données);
writer.releaseLock();
Envoyez du texte à l'appareil via un TextEncoderStream
canalisé vers port.writable
Comme indiqué ci-dessous.
const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.lisible.pipeTo(port.inscriptible);const writer = textEncoder.inscriptible.getWriter();
attendre writer.write("hello");
Fermer un port série
port.close ()
fermez le port série si votre lisible
y inscriptible
Les membres sont déverrouillé, sens releaseLock ()
Il a été convoqué par ses lecteurs et écrivains respectifs.
attendre port.close();
Cependant, lors de la lecture continue des données d'un périphérique série à l'aide d'une boucle,
port.lisible
il sera toujours bloqué jusqu'à ce qu'il rencontre une erreur. Dans ce cas, appeler reader.cancel ()
obliger à reader.read ()
résoudre immédiatement avec {valeur: undefined, done: true}
et permettant ainsi à la boucle d'appeler reader.releaseLock ()
.
const lecteur = port.lisible.getReader();
tandis que (vrai) {
const { valeur, Fini } = attendre lecteur.read();
si (Fini) {
lecteur.releaseLock();
break;
}
console.Journal(valeur);
}
attendre lecteur.cancel();
attendre port.close();
La fermeture d'un port série est plus compliquée lors de son utilisation transformer les flux (J'aime
TextDecoderStream
y TextEncoderStream
). Appel reader.cancel ()
comme avant. Puis appelez écrivain.close ()
y port.close ()
. Cela propage les erreurs via les flux de transformation vers le port série sous-jacent. Étant donné que la propagation des erreurs ne se produit pas immédiatement, vous devez utiliser le readableStreamClosed
y
writableStreamClosed
précédemment créé promet de détecter quand port.lisible
y port.writable
ont été déverrouillés. Annuler le lecteur
provoque l'annulation de la séquence; c'est pourquoi vous devez attraper et ignorer l'erreur qui en résulte.
const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.lisible.pipeTo(textDecoder.inscriptible);
const lecteur = textDecoder.lisible.getReader();
tandis que (vrai) {
const { valeur, Fini } = attendre lecteur.read();
si (Fini) {
lecteur.releaseLock();
break;
}
console.Journal(valeur);
}
const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.lisible.pipeTo(port.inscriptible);
lecteur.cancel();
attendre readableStreamClosed.catch(() => { });
writer.close();
attendre writableStreamClosed;
attendre port.close();
Écoutez la connexion et la déconnexion
Si un périphérique USB fournit un port série, ce périphérique peut être connecté ou déconnecté du système. Lorsque le site Web a reçu l'autorisation d'accéder à un port série, il doit surveiller le relier
y déconnecter
événements.
navigateur.serial.addEventListener("relier", (un événement) => {
});navigateur.serial.addEventListener("déconnecter", (un événement) => {
});
Gérer les signaux
Après avoir établi la connexion du port série, vous pouvez interroger et configurer explicitement les signaux exposés par le port série pour la découverte de périphériques et le contrôle de flux. Ces signaux sont définis comme des valeurs booléennes. Par exemple, certains appareils comme Arduino passeront en mode de programmation si le signal Data Terminal Ready (DTR) est activé.
Ajustement panneaux de sortie et obtenir signaux d'entrée se font respectivement en appelant port.setSignals ()
y port.getSignals ()
. Consultez les exemples d'utilisation ci-dessous.
attendre port.setSignals({ break: faux });
attendre port.setSignals({ dataTerminalReady: vrai });
attendre port.setSignals({ requestToSend: faux });
const signals = attendre port.getSignals();
console.Journal(`Clear To Send: ${signals.clearToSend}`);
console.Journal(`Data Carrier Detect: ${signals.dataCarrierDetect}`);
console.Journal(`Data Set Ready: ${signals.dataSetReady}`);
console.Journal(`Ring Indicator: ${signals.ringIndicator}`);
Transformer les flux
Lorsque vous recevez des données du périphérique série, vous n'obtiendrez pas nécessairement toutes les données en même temps. Il peut être arbitrairement fragmenté. Pour plus d'informations, consultez
Concepts de l'API Streams.
Pour gérer cela, vous pouvez utiliser certains flux de transformation intégrés, tels que
TextDecoderStream
ou créez votre propre flux de transformation qui vous permet d'analyser le flux entrant et de renvoyer les données analysées. Le flux de transformation se situe entre le périphérique série et la boucle de lecture qui consomme le flux. Vous pouvez appliquer une transformation arbitraire avant que les données ne soient consommées. Considérez-le comme une ligne d'assemblage - lorsqu'un widget se déplace le long de la ligne, chaque étape de la ligne modifie le widget de sorte que lorsqu'il atteint sa destination finale, il soit un widget entièrement fonctionnel.
Par exemple, considérez comment créer une classe de flux de transformation qui consomme un flux et le segmente en fonction des sauts de ligne. Leur transformer ()
la méthode est appelée chaque fois que le flux reçoit de nouvelles données. Vous pouvez mettre les données en file d'attente ou les enregistrer pour plus tard. Les affleurer ()
La méthode est appelée lorsque le flux est fermé et gère toutes les données qui n'ont pas encore été traitées.
Pour utiliser la classe de flux de transformation, vous devez diriger un flux entrant à travers elle. Dans le troisième exemple de code en lecture à partir d'un port série, le flux d'entrée d'origine était uniquement acheminé via un TextDecoderStream
alors nous devons appeler pipeThrough ()
pour le canaliser à travers notre nouveau LineBreakTransformer
.
classer LineBreakTransformer {
constructeur() {
Este.chunks = "";
}transformer(chunk, controller) {
Este.chunks += chunk;
const lines = Este.chunks.split("rn");
Este.chunks = lines.pop();
lines.forEach((line) => controller.enqueue(line));
}
flush(controller) {
controller.enqueue(Este.chunks);
}
}
const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.lisible.pipeTo(textDecoder.inscriptible);
const lecteur = textDecoder.lisible
.pipeThrough(new TransformStream(new LineBreakTransformer()))
.getReader();
Pour déboguer les problèmes de communication des périphériques série, utilisez le tee()
méthode de
port.lisible
pour diviser les transmissions vers ou depuis le périphérique série. Les deux flux créés peuvent être consommés indépendamment et cela vous permet d'en imprimer un sur la console pour inspection.
const [appReadable, devReadable] = port.lisible.tee();
Codelab
Dans le Google Developer Code Lab, vous utiliserez l'API série pour interagir avec un
BBC micro: bit carte pour afficher les images sur sa matrice LED 5 × 5.
Polyfill
Sur Android, les ports série USB peuvent être pris en charge via l'API WebUSB et Série API Polyfill. Ce polyfill est limité au matériel et aux plates-formes où le périphérique est accessible via l'API WebUSB car il n'a pas été revendiqué par un pilote de périphérique intégré.
Sécurité et confidentialité
Les auteurs de la spécification ont conçu et implémenté l'API série en utilisant les principes de base définis dans Contrôlez l'accès aux fonctionnalités puissantes de la plate-forme Web, y compris le contrôle de l'utilisateur, la transparence et l'ergonomie. La possibilité d'utiliser cette API est principalement contrôlée par un modèle d'autorisations qui n'accorde l'accès qu'à un seul périphérique série à la fois. En réponse à une demande de l'utilisateur, l'utilisateur doit prendre des mesures actives pour sélectionner un périphérique série particulier.
Pour comprendre les compromis en matière de sécurité, consultez le sécurité y intimité
Sections Serial API Explainer.
Retour
L'équipe Chrome aimerait connaître vos impressions et vos expériences avec l'API Serial.
Parlez-nous de la conception de l'API
Y a-t-il quelque chose dans l'API qui ne fonctionne pas comme prévu? Ou vous manquez-vous des méthodes ou des propriétés dont vous avez besoin pour mettre en œuvre votre idée?
Déposer un problème de spécification sur le Dépôt GitHub de l'API série ou ajoutez vos réflexions à un problème existant.
Signaler un problème avec le déploiement
Vous avez trouvé un bogue avec la mise en œuvre de Chrome? Ou la mise en œuvre est-elle différente de la spécification?
Signaler un bogue dans https://new.crbug.com. Assurez-vous d'inclure autant de détails que possible, de fournir des instructions simples pour reproduire le bogue, et
Composants (modifier) ajusté à Clignoter> Série
. Échec fonctionne très bien pour un partage rapide et facile des répétitions.
Montrez votre soutien
Envisagez-vous d'utiliser l'API série? Votre assistance publique aide l'équipe Chrome à hiérarchiser les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est important de les prendre en charge.
Envoyez un tweet à @Cromodev avec le hashtag
#SerialAPI
et faites-nous savoir où et comment vous l'utilisez.
Liens utiles
Ville:
Merci
Grâce à Bourse Reilly y Joe medley pour leurs critiques de cet article. Photo d'usine d'aéronefs par Fiducie des musées de Birmingham au Unsplash.