Passer au contenu principal

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.

igraal_fr-fr

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

  1. Demander un jeton par votre origine.
  2. 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

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:

if ( "serial" dans le 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é.


port const = attendre le navigateur . série . requestPort ( ) ;


ports const = attendre le navigateur . série . 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).


filtres const = [
{ usbVendorId : 0x2341 , usbProductId : 0x0043 } ,
{ usbVendorId : 0x2341 , usbProductId : 0x0001 }
] ;


port const = attendre le navigateur . série . requestPort ( { filtres } ) ;

const { usbProductId , usbVendorId } = port . getInfo ( ) ;

invite-port-série-1927133
Invite de l'utilisateur à sélectionner un micro: bit BBC

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.


port const = attendre le navigateur . série . requestPort ( ) ;


attendre le port . ouvert ( { 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é.

lecteur const = port . lisible . getReader ( ) ;


while ( vrai ) {
const { value , done } = attendre le lecteur . lire ( ) ;
si ( fait ) {
lecteur . releaseLock ( ) ;
pause ;
}
console . log ( 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.

while ( port . lisible ) {
lecteur const = port . lisible . getReader ( ) ;

essayez {
while ( vrai ) {
const { value , done } = attendre le lecteur . lire ( ) ;
si ( fait ) {

lecteur . releaseLock ( ) ;
pause ;
}
if ( valeur ) {
console . log ( 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 ) ;
lecteur const = textDecoder . lisible . getReader ( ) ;


while ( vrai ) {
const { value , done } = attendre le lecteur . lire ( ) ;
si ( fait ) {

lecteur . releaseLock ( ) ;
pause ;
}

console . log ( 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.

écrivain const = port . inscriptible . getWriter ( ) ;

const data = new Uint8Array ( [ 104 , 101 , 108 , 108 , 111 ] ) ;
attendez l' écrivain . écrire ( données ) ;


écrivain . 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 ) ;

écrivain const = textEncoder . inscriptible . getWriter ( ) ;

attendez l' écrivain . write ( "bonjour" ) ;

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 le port . fermer ( ) ;

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 ().



lecteur const = port . lisible . getReader ( ) ;


while ( vrai ) {
const { value , done } = attendre le lecteur . lire ( ) ;
si ( fait ) {
lecteur . releaseLock ( ) ;
pause ;
}

console . log ( valeur ) ;
}



attendez le lecteur . annuler ( ) ;
attendre le port . fermer ( ) ;

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 ) ;
lecteur const = textDecoder . lisible . getReader ( ) ;


while ( vrai ) {
const { value , done } = attendre le lecteur . lire ( ) ;
si ( fait ) {
lecteur . releaseLock ( ) ;
pause ;
}

console . log ( valeur ) ;
}

const textEncoder = new TextEncoderStream ( ) ;
const writableStreamClosed = textEncoder. lisible . pipeTo ( port . inscriptible ) ;

lecteur . annuler ( ) ;
attendre readableStreamClosed . catch ( ( ) => { } ) ;

écrivain . fermer ( ) ;
attendre writableStreamClosed ;

attendre le port . fermer ( ) ;

É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 . série . addEventListener ( "se connecter" , ( événement ) => {
} ) ;

navigateur . série . addEventListener ( "déconnecter" , ( é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 le port . setSignals ( { break : false } ) ;


attendre le port . setSignals ( { dataTerminalReady : true } ) ;


attendre le port . setSignals ( { requestToSend : false } ) ;

signaux const = port d' attente . getSignals ( ) ;
console . log ( ` Effacer pour envoyer: $ { signaux . clearToSend } ` ) ;
console . log ( ` Data Carrier Detect: $ { signaux . dataCarrierDetect } ` ) ;
console . log ( ` Ensemble de données prêt: $ { signaux . dataSetReady } ` ) ;
console . log ( ` Indicateur de sonnerie: $ { signaux . 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.

avion-usine-2628261
Usine d'avions de la Seconde Guerre mondiale à Castle Bromwich

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 TextDecoderStreamalors nous devons appeler pipeThrough () pour le canaliser à travers notre nouveau LineBreakTransformer.

class LineBreakTransformer {
constructeur ( ) {
ceci . morceaux = "" ;
}

transform ( morceau , contrôleur ) {
ceci . morceaux + = morceau ;
const lines = ceci . morceaux . split ( "rn" ) ;
ceci . morceaux = lignes . pop ( ) ;
lignes . forEach ( ( line ) => controller . enqueue ( line ) ) ;
}

flush ( contrôleur ) {
contrôleur . mettre en file d'attente ( ce . morceaux ) ;
}
}

const textDecoder = new TextDecoderStream ( ) ;
const readableStreamClosed = port . lisible . pipeTo ( textDecoder . inscriptible ) ;
lecteur const = textDecoder . lisible
. pipeThrough ( nouveau TransformStream ( nouveau 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.


Erreur: Attention: Contenu protégé.