Depuis quelques années, les interfaces Web remplacent progressivement les applications natives dans de nombreux domaines, en particulier pour toutes les applications d'accès à des bases de données. Les interfaces Web n'ont plus rien à envier aux interfaces natives en terme de convivialité, mais en terme de fonctionalité le navigateur Web impose certaines contraintes, en particulier pour accéder aux périphériques sur la machine de l'utilisateur. Néanmoins, on peut permettre à une interface web d'accéder aussi à des périphériques USB si ils ont été conçus pour cet usage, comme c'est le cas des modules Yoctopuce.
L'exemple que nous allons vous donner cette semaine part d'un besoin que nous avons rencontré récemment dans la mise en place de notre nouveau système d'inventaire des composants électroniques, dont nous vous avions déjà présenté l'un des éléments dans un précédent article.
Une bobine de composants avec une étiquette DataMatrix
Le problème
Pour permettre une vérification des étiquettes sans déplacer les composants de leur lieu de stockage, nous voulons pouvoir utiliser un lecteur de codes-barre 2D sans fil traditionnel, et scanner simplement les bobines ou boîtes de composants pour les saisir les codes 2D dans l'interface Web de notre système. Nous avions à disposition un lecteur Datalogic QM-4200, dont la base est raccordée au PC par un câble USB. Le comportement standard du lecteur est d'envoyer les codes lus à l'hôte comme s'il s'agissait d'un clavier. C'est pratique parce que cela peut être utilisé avec n'importe quelle application de saisie, mais ça a plusieurs inconvénients:
- Un premier inconvénient est que si le curseur n'est pas sur le bon champs de saisie, l'information ira au mauvais endroit. Ce problème peut facilement être détecté par l'ajout d'une quittance auditive sur chaque saisie réussie.
- Plus problématique, certains codes-barre 2D contiennent des séparateurs sous forme de caractères spéciaux, qui sont soit filtrés, soit interprétés par le navigateur de manière imprévisible. C'est le cas en particulier des codes DataMatrix encodés selon le standard ANSI MH10.8.2, qui est utilisé pour la description des composants électroniques. Sans ces caractères spéciaux, il n'est pas possible de séparer les différents contenus de l'étiquette. Mais si on configure le lecteur pour envoyer ces codes via une saisie de clavier, le navigateur déplace le curseur dans un autre champ au moment où le séparateur est transmis et perd le reste du code.
- Plus inquiétant, si le lecteur est configuré pour envoyer des codes de contrôle sous forme de saisie du clavier, cela permet en réalité à une personne mal intentionnée de déclencher à l'insu de l'utilisateur n'importe quelle commande sur l'ordinateur. Il suffit de placer une étiquette DataMatrix forgée avec les codes de contrôle désirés, et la prochaine fois que le code sera scanné, un programme pourra être lancé par l'opérateur à son insu.
La solution
La meilleure solution consiste donc à raccorder le lecteur via une liaison RS-232, entièrement séparée du clavier. Sans surprise, c'est la solution préconisée dans la plupart des cas pour les lecteurs industriels. Pour notre petit lecteur bon marché, il faut chercher un peu, mais Datalogic vend un câble alternatif pour raccorder la base du lecteur via un lien RS-232 plutôt que directement par USB. Ce qui nous ramène à la question de base de cet article: comment accéder à un périphérique RS-232 depuis une interface Web ?
Raccordement d'un lecteur DataLogic QM-4200 par un Yocto-RS232
La solution proposée par Yoctopuce est la passerelle VirtualHub. Ce service se lance sur la même machine où tourne le navigateur, et offre une interface HTTP/WebSocket permettant d'accéder à tous les modules d'interface Yoctopuce connectés à la machine cliente depuis un navigateur internet. Mais attention, si la page Web qui a besoin d'accéder aux modules Yoctopuce vient d'une application web tierce (comme un serveur Intranet), quelques règles doivent être respectées:
- les règles CORS (cross-origin ressource sharing): lorsqu'une page web sur un serveur veut accéder à un service web sur un autre serveur (en l'occurrence le VirtualHub), ce dernier doit inclure des entêtes particulières dans ses réponses pour indiquer au navigateur qu'il est normal qu'il soit utilisé en prevenance d'un autre serveur. Le VirtualHub se charge de ceci de manière transparente.
- les règles HTTPS (HTTP sécurisé): lorsqu'une application Web est sécurisée par une URL https://, elle ne peut pas accéder à un service web non sécurisé. Pour respecter cette règle, il faut impérativement que le code JavaScript accède au VirtualHub via une URL https ou wss. Pour cela vous devrez utiliser le VirtualHub 2.0, car la version originale n'inclut pas de cryptographie.
Implémentation
En pratique, il n'est pas très compliqué de rajouter une possibilité de saisie automatique à un formulaire existant sur un site intranet. La manière la plus élégante consiste à le faire via un module EcmaScript, qui sont maintenant supportés par tous les navigateur depuis quelques années. Pour cela, il suffit d'ajouter une ligne de code HTML de la page existante qui ressemble à ceci:
Le code source de ce module de gestion des codes-barre peut être codé soit directement en JavaScript, soit en TypeScript si on préfère profiter d'un minimum de typage lors du codage. Nous vous donnerons les exemples ci-dessous en TypeScript, mais vous trouverez le code source équivalent en JavaScript sur GitHub.
Pour importer la librairie Yoctopuce pour EcmaScript dans une page HTML depuis un module ES2016, y compris l'interface port série, on utilise les ligne ci-dessous. Nous avons simplement copié ces deux fichiers js, qui proviennent du répertoire dist/esm de la librairie TypeScript, sur le serveur web.
import { YSerialPort } from './yocto-api-esm/yocto_serialport.js'
Pour commencer, il faut initialiser la librairie pour se connecter en mode sécurisé au VirtualHub sur la machine du navigateur (addresse localhost qui est toujours 127.0.0.1). Tous les appels à la librairie étant asynchrones, on les appelle depuis une fonction async en les préfixant du mot-clé await:
{
let errmsg = new YErrorMsg();
if(await YAPI.RegisterHub('wss://127.0.0.1:4443', errmsg) != YAPI.SUCCESS) {
console.error('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
return;
}
}
enableDeviceHandlers();
Pour se connecter au lecteur codes-barre lui-même, on ajoute quelques lignes à la fonction enableDeviceHandlers pour chercher si une interface série (le Yocto-RS232) nommée DataMatrixReader est disponible sur la machine. Si oui, on la configure avec le bon protocole série, et on configure une fonction callback qui sera appelée à chaque nouveau message reçu sur l'interface.
let port = <YSerialPort> YSerialPort.FindSerialPort("DataMatrixReader");
if(!await port.isOnline()) {
console.error('No Yocto-RS232 named DataMatrixReader found');
await YAPI.FreeAPI();
return;
}
await port.set_serialMode("9600,8N1");
await port.set_protocol("Frame:15ms");
await port.reset();
await port.registerValueCallback(barcodeHandler);
console.log('Ready to receive DataMatrix codes');
Notez au passage que l'utilisation d'un nom logique sur l'interface série nous permettrait d'utiliser plusieurs périphériques série si nécessaire, sans risque de les confondre.
La fonction de callback va lire le dernier message mémorisé par l'interface série, en décoder les différents champs et remplir les champs du formulaire correspondant en se basant sur leur nom:
{
let messages: string[] = await port.readMessages('',1);
await port.reset();
if(messages.length == 0 || !messages[0]) return;
let form: HTMLFormElement =
document.getElementsByName('panelform').item(0) as HTMLFormElement;
var formData = new FormData(form);
for(let msg of messages) {
let mh10: MH10Dict = decodeMH10code(msg);
let fieldname: string;
for(fieldname in mh10) {
if(formData.has(fieldname)) {
let input: HTMLInputElement = document.getElementsByName(fieldname).item(0) as HTMLInputElement
input.value = mh10[fieldname];
}
}
}
}
Si vous voulez réutiliser ce code pour votre propre usage, prenez soin de remplacer la chaîne 'panelform' par la valeur de l'attribut name de votre propre formulaire. Vous trouverez l'intégralité du code source, y compris la fonction decodeMH10code, dans le projet d'exemple sur GitHub.
Conclusion
Les modules d'interface Yoctopuce permettent facilement d'élargir les modes de saisie d'un formulaire web par l'utilisation de périphériques locaux. Nous l'avons démontré pour l'utilisation d'une interface série, mais il est tout aussi simple d'utiliser de la même manière une sonde de température/humidité/pression par exemple pour une application de métrologie, un lecteur de pont de wheatstone pour mesurer une cellule de poids, ou encore une entrée 4-20mA pour lire la valeur d'un capteur industriel.