Comment débuter avec JavaScript et des modules Yoctopuce

Comment débuter avec JavaScript et des modules Yoctopuce

Cette semaine, nous poursuivons notre série d'articles "pour les débutants" et nous allons parler de JavaScript, et plus particulièrement de comment utiliser notre librairie JavaScript/EcmaScript 2017 dans un browser Web. Nous allons voir comment il est possible de remplir automatiquement un formulaire HTML avec les données d'un capteur Yoctopuce.



Avant de commencer, nous partons du principe que vous connaissez un minimum les langages HTML et JavaScript, car le but n'est pas d'écrire un énième tutoriel sur le sujet mais de comprendre comment utiliser ces langages pour interagir avec nos modules. De la même manière, si vous n'êtes pas familier avec les modules Yoctopuce, nous vous recommandons de commencer par la lecture des précédents articles de cette série, en particulier celui sur la structure logique des modules Yoctopuce.

Remarque concernant Node.js


Notre librairie JavaScript/EcmaScript 2017 est aussi utilisable dans Node.js, mais l'installation est légèrement différente. Pour plus de détails, vous pouvez consulter notre article "Comment débuter en Node.js avec des modules Yoctopuce".


Les particularités de JavaScript


Il est impossible d'accéder directement aux périphériques USB depuis du code JavaScript. Le script peut communiquer uniquement avec des modules Yoctopuce qui sont branchés à un YoctoHub ou à un ordinateur qui exécute un VirtualHub. Les communications entre le script JS et les modules Yoctopuce passent par une connexion WebSocket entre le YoctoHub et le browser et les YoctoHubs transmettent ensuite les requêtes aux modules concernés.

Par conséquent pour utiliser des modules branchés par USB sur la machine qui exécute le browser, il faut que le VirtualHub soit installé.

La communication entre le script JavaScript et le module Yoctopuce passe obligatoirement par TCP
La communication entre le script JavaScript et le module Yoctopuce passe obligatoirement par TCP



Un petit exemple


Pour illustrer l'utilisation de notre librairie JavaScript, nous allons
partir d'une page web minimaliste qui contient uniquement un formulaire HTML. Nous allons voir comment ajouter un bouton pour remplir automatiquement ce formulaire avec la température mesurée par un Yocto-Temperature.


La page de départ:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript and Yoctopuce</title>
</head>
<style>
    body {
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>
<body>
<h1>JavaScript and Yoctopuce</h1>

<form method="GET" action="/dummy.html">
    <table>
        <tr>
            <td><label for="hwid">Hardware ID:</label></td>
            <td><input id='hwid'></td>
        </tr>
        <tr>
            <td><label for="curVal">Current Value:</label></td>
            <td><input id="curVal"></td>
        </tr>
        <tr>
            <td><label for="unit">Unit:</label></td>

            <td><input id='unit'></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit" value="Submit">Ok</button>
                <button type="reset" value="Reset">Cancel</button>
            </td>
        </tr>
    </table>
</form>
</body>
</html>




Le VirtualHub


Comme nous l'avons dit, pour que le code JavaScript puisse accéder au port USB, il faut installer et lancer le VirtualHub sur la machine qui affiche la page web. La procédure pour installer le VirtualHub est expliquée dans cet article.


Chargement de la librairie


La première chose à faire est de charger les fichiers JavaScript de notre librairie. Il existe deux solutions.

Hébergement privé


La première consiste à télécharger et héberger la librairie sur son propre serveur. Vous pouvez la télécharger depuis le site de Yoctopuce, depuis npm ou encore depuis GitHub.

L'archive contient quatre répertoires: Le répertoire Documentation contient la documentation, le répertoire lib les fichiers sources de la librairie, les deux autres répertoires contiennent des exemples d'utilisation de la librairie. Le répertoire example_html regroupe les exemples qui sont utilisables directement dans un browser web alors que le répertoire example_node contient des exemples qui fonctionnent uniquement sous Node.js.

Seuls les fichiers yocto_xxx.js du répertoire lib ont besoin d'être hébergés sur votre serveur. Le plus simple est de créer un sous-répertoire ylib et d'y copier tous les fichiers yocto_xxx.js.

Il faut ensuite modifier la page web pour importer les fichiers que nous allons utiliser dans notre script. Nous avons besoin d'inclure l'indispensable "yocto_api.js" qui permet d'utiliser la librairie, mais aussi "yocto_temperature.js" qui permet d'utiliser le capteur de température. Si vous ne savez pas quel fichier inclure, vous pouvez relire notre article sur
la structure logique des modules Yoctopuce.


...
<script src="ylib/yocto_api.js"></script>
<script src="ylib/yocto_temperature.js"></script>
...



Utilisation d'un Content Delivery Network


L'autre solution est de passer par un CDN (Content Delivery Network). L'avantage est que vous n'avez pas besoin d'héberger les fichiers de la librairie, cependant vous êtes dépendant d'un service externe.

Il existe plusieurs CDN mais celui que nous trouvons le plus pratique est jsdelivr.net qui permet de référencer directement notre librairie depuis notre package npm. Il permet aussi de "minifier" les fichiers à la volée.

Le lien à utiliser est composé de 4 parties:

  1. l'url de base : "https://cdn.jsdelivr.net/npm/"
  2. Le nom du package npm: yoctolib-es2017
  3. la version de la librairie précédée du caractère '@' : @1.10.30813
  4. le nom du fichier: yocto_api.js


Notez qu'en remplaçant l'extension '.js' par '.min.js', jsdelivr va minifier à la volée les fichiers JavaScript référencés. Cela permet de réduire les temps de chargement de la page.

Concrètement, pour inclure les versions minifiées des fichiers yocto_api.js et yocto_temperature.js de la version 1.10.30813 de notre librairie JavaScript/EcmaScript 2017, il faut utiliser les liens suivants:

...
<script src="https://cdn.jsdelivr.net/npm/yoctolib-es2017@1.10.30813/yocto_api.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/yoctolib-es2017@1.10.30813/yocto_temperature.min.js"></script>
...




async / await


Notre librairie JavaScript/EcmaScript 2017 utilise les nouveaux opérateurs async et await qui permettent de gérer beaucoup plus facilement les opérations asynchrones. Ces opérateurs utilisent en interne les promesses (en anglais: Promise) pour gérer correctement les appels asynchrones qui pourraient autrement fausser le flux d'exécution du code. Ce qu'il faut retenir, c'est que les fonctions ou méthodes async doivent impérativement être appelées avec l'opérateur await.

Pour rappel, toutes les méthodes de notre librairies sont de type async sauf:

  • la méthode YAPI.GetTickCount()
  • les méthodes FindXXX(hwid), FirstXXX() et nextXXX()
  • toutes les méthodes des classes YMeasure, WlanRecord et CellRecord


Pour plus de détails sur le sujet, vous pouvez consulter le chapitre dédié dans la documentation de nos modules.


Le bouton pour remplir le formulaire


Maintenant que nous avons chargé les fichiers de la librairie, il reste à ajouter le bouton qui réalise les étapes suivantes:

Établir la connexion avec le VirtualHub


Pour pouvoir accéder aux modules, il faut indiquer à la librairie l’adresse du YoctoHub ou du VirtualHub à l'aide de la méthode YAPI.RegisterHub. Dans cet exemple, le Yocto-Temperature est branché sur la même machine, on peut donc utiliser l’adresse "localhost".

await YAPI.RegisterHub("localhost");


Vous trouverez plus de détails sur les divers usages de YAPI.RegisterHub dans cet autre article.

Récupérer l'objet YTemperature


Comme vous avez lu l'article sur la structure logique des modules Yoctopuce, vous savez que le Yocto-Temperature offre différentes fonctionnalités parmi lesquelles on trouve temperature.

Pour récupérer l'objet qui permet d’interagir avec cette fonctionnalité, il y a plusieurs manières.

FirstXXX


Si vous êtes sûr de n'avoir qu'une seule fonctionnalité temperature disponible, vous pouvez faire au plus simple et utiliser la méthode FirstTemperature de la classe YTemperature.

let ytemp = YTemperature.FirstTemperature();
if (ytemp == null) {
    alert("No temperature sensor found");
    return;
}
...


Les méthodes FirstXXXX renvoient la première occurrence de la fonctionnalité cherchée, ou null si rien ne correspond.

FindXXX et numéro de série


Vous pouvez aussi utiliser la méthode FindTemperature de la classe YTemperature avec le numéro de série du module. Supposons que le numéro de série du Yocto-Temperature soit TMPSENS1-019CB, vous pouvez utiliser:

let ytemp = YTemperature.FindTemperature("TMPSENS1-019CB.temperature");
if (!await ytemp.isOnline()) {
  alert("No temperature sensor found");
  return;
}


A la différence de FirstXXX, FindXXX renvoie toujours un objet valide, c'est pourquoi il faut tester si le module est connecté avec la méthode isOnline().

FindXXX et nom logique


A la place du numéro de série, vous pouvez utiliser un nom logique que vous aurez par exemple affecté à l'aide du VirtualHub.

Affectation d'un nom logique au capteur du Yocto-Temperature
Affectation d'un nom logique au capteur du Yocto-Temperature


Mettons que vous ayez appelé le capteur de température "myTemp". Il vous suffira alors d'écrire:

let ytemp = YTemperature.FindTemperature("myTemp");
if (! await ytemp.isOnline()) {
  alert('Temperature sensor "myTemp" not found');
  return;
}


L'intérêt des noms logiques est double: d'une part ils permettent de s'y retrouver plus facilement dans les systèmes complexes composés de nombreux modules Yoctopuce et d'autre part ils permettent de fabriquer des systèmes en plusieurs exemplaires sans avoir à adapter le code aux numéros de séries des modules de chaque exemplaire.

Utiliser l'objet YTemperature


Maintenant que l'on a récupéré l'objet YTemperature, il reste à obtenir la température et l'unité de mesure à l'aide des méthodes get_currentValue() et get_unit().

let value = await ytemp.get_currentValue();
let unit = await ytemp.get_unit();
console.log(hwid + " => " + value.toString() + unit);
document.getElementById("curVal").value = value;
document.getElementById("unit").value = unit;




Stopper la librairie


Avant de terminer le script, il faut appeler la méthode YAPI.FreeAPI qui va libérer toutes les ressources utilisées par la librairie mais surtout s'assurer que toutes les communications soient terminées correctement.

await YAPI.FreeAPI();



Une fois tout mis bout à bout, notre page web ressemble à ceci:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript and Yoctopuce</title>
</head>
<style>
    body {
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>
<script src="https://cdn.jsdelivr.net/npm/yoctolib-es2017@1.10.30813/yocto_api.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/yoctolib-es2017@1.10.30813/yocto_temperature.min.js"></script>
<body>

<h1>JavaScript and Yoctopuce</h1>
<script>

    async function loadValueFromSensor()
    {
        await YAPI.RegisterHub("localhost");
        let ytemp = YTemperature.FirstTemperature();
        if (ytemp == null) {
            alert("No temperature sensor found");
            return;
        }
        let hwid = await ytemp.get_hardwareId();
        let value = await ytemp.get_currentValue();
        let unit = await ytemp.get_unit();
        console.log(hwid + " => " + value.toString() + unit);
        document.getElementById("hwid").value = hwid;
        document.getElementById("curVal").value = value;
        document.getElementById("unit").value = unit;

        await YAPI.FreeAPI();
    }

</script>
<button type="button" onclick="loadValueFromSensor()">Load Value from sensor</button><br>
<form method="GET" action="/dummy.html">
    <table>
        <tr>
            <td><label for="hwid">Hardware ID:</label></td>
            <td><input id='hwid'></td>
        </tr>
        <tr>
            <td><label for="curVal">Current Value:</label></td>
            <td><input id="curVal"></td>
        </tr>
        <tr>
            <td><label for="unit">Unit:</label></td>

            <td><input id='unit'></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit" value="Submit">Ok</button>
                <button type="reset" value="Reset">Cancel</button>

            </td>
        </tr>
    </table>
</form>
</body>
</html>



Le formulaire est rempli avec les données du Yocto-Temperature
Le formulaire est rempli avec les données du Yocto-Temperature




YSensor


Notre exemple ne gère que les capteurs de température, mais il est possible de le faire fonctionner avec n'importe quel senseur Yoctopuce en modifiant quelques lignes. Il suffit d'utiliser la classe YSensor à la place de la classe YTemperature:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript and Yoctopuce</title>
</head>
<style>
    body {
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>
<script src="https://cdn.jsdelivr.net/npm/yoctolib-es2017@1.10.30813/yocto_api.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/yoctolib-es2017@1.10.30813/yocto_temperature.min.js"></script>
<body>

<h1>JavaScript and Yoctopuce</h1>
<script>

    async function loadValueFromSensor()
    {
        await YAPI.RegisterHub("localhost");
        let sensor = YSensor.FirstSensor();
        if (sensor == null) {
            alert("No temperature sensor found");
            return;
        }
        let hwid = await sensor.get_hardwareId();
        let value = await sensor.get_currentValue();
        let unit = await sensor.get_unit();
        console.log(hwid + " => " + value.toString() + unit);
        document.getElementById("hwid").value = hwid;
        document.getElementById("curVal").value = value;
        document.getElementById("unit").value = unit;

        await YAPI.FreeAPI();
    }

</script>
<button type="button" onclick="loadValueFromSensor()">Load Value from sensor</button><br>
<form method="GET" action="/dummy.html">
    <table>
        <tr>
            <td><label for="hwid">Hardware ID:</label></td>
            <td><input id='hwid'></td>
        </tr>
        <tr>
            <td><label for="curVal">Current Value:</label></td>
            <td><input id="curVal"></td>
        </tr>
        <tr>
            <td><label for="unit">Unit:</label></td>

            <td><input id='unit'></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit" value="Submit">Ok</button>
                <button type="reset" value="Reset">Cancel</button>

            </td>
        </tr>
    </table>
</form>
</body>
</html>



Avec cette version du code, la page fonctionnera avec n'importe quel senseur Yoctopuce. C'est possible car toutes les classes Yoctopuce correspondant à des fonctionnalités de type senseur héritent de la classe YSensor. Les méthodes get_currentValue() et get_unit() sont implémentées dans cette classe et fonctionnent sur n'importe quel senseur.

Le formulaire est rempli avec les données d'un Yocto-Light-V3
Le formulaire est rempli avec les données d'un Yocto-Light-V3



La gestions des erreurs


Par défaut, si une erreur se produit, les fonctions de la librairie lancent une exception. Pour gérer les erreurs et afficher un message correctement formaté, il existe deux solutions.

On peut attraper les exceptions à l'aide de blocs try {} catch().
Par exemple comme ceci:

try {
    YAPI.RegisterHub("localhost");
} catch (err) {
    alert("Erreur:" . err.message;
    return;
}



Mais il est aussi possible de désactiver la génération des exceptions par la librairie à l'aide de la méthode "YAPI.DisableExceptions". Dans ce cas, il faut tester la valeur de retour de chaque appel à la librairie.

YAPI.DisableExceptions();
let errmsg = new YErrorMsg();
let res = await YAPI.RegisterHub('localhost', errmsg);
if (res != YAPI_SUCCESS) {
    alert(errmsg.msg);
    return;
}



Ces deux solutions permettent de traiter correctement les erreurs et d'afficher un message clair. L'utilisation de l'une ou l'autre est surtout une question d'habitudes de programmation.

La suite...


Voilà, on a vous a expliqué les bases, maintenant avec l'aide de la doc de référence, vous devriez être capables de réaliser des projets un peu plus ambitieux :-)

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.