Commander un Arduino avec une tablette Android

- Etude de cas -


précédentsommairesuivant

XII. Le client web mobile du projet Domotique

Nous abordons maintenant l'écriture du client web mobile.

A lire

  • [ref1] : " Introduction aux frameworks JSF2, Primefaces et Primefaces Mobile " disponible à l'URL [http://tahe.developpez.com/java/primefaces/] ;
  • [ref3] : " Introduction à Java EE avec Netbeans 6.8 " disponible à l'URL [http://tahe.developpez.com/java/javaee].

XII-A. Les du client web mobile

Le client web mobile permet de gérer les Arduinos à distance avec le navigateur d'un smartphone ou d'une tablette. Il présente à l'utilisateur les écrans suivants :

Image non disponible

La vue d'accueil [1] propose les opérations possibles. La vue [pinWrite] [2] permet d'écrire une valeur sur une pin d'un Arduino.

Image non disponible

La vue [pinRead] [1] permet de lire la valeur d'une pin d'un Arduino. La vue [blink] [2] permet de faire clignoter une led d'un Arduino :

Image non disponible

La vue [commands] [1] permet d'envoyer une commande JSON à un Arduino. De chaque vue, on peut revenir à la vue d'accueil avec l'icône [2].

XII-B. L'architecture du client web mobile

L'architecture du client web mobile est la suivante :

Image non disponible
  • la couche [DAO] communique avec le serveur REST. C'est un client REST implémenté par Spring-Android ;
  • la couche [web] est une couche JSF2 (Java Server Faces) avec la bibliothèque Ajax PFM (Primefaces Mobile).

La couche [DAO] dialogue avec le serveur REST des Arduinos :

Image non disponible

Le serveur REST des Arduinos est exécuté sur un serveur Tomcat. Pour l'application web mobile, nous utiliserons le serveur Glassfish. En mode développement on est amené à redéployer souvent les applications sur les serveurs. Or redéployer une application sur le serveur Tomcat relance Tomcat lui-même donc l'application REST des Arduinos. En mettant le client web mobile sur Glassfish on évite de relancer le serveur REST.

Pour que les serveurs Glassfish et Tomcat puissent fonctionner ensemble, il faut qu'ils travaillent sur des ports différents. Or par défaut, ils travaillent tous les deux sur le port 8080. On pourra changer le port du serveur Tomcat de la façon suivante :

Image non disponible
  • en [1], dans la fenêtre Servers double-cliquer sur le serveur Tomcat ;
  • en [2], modifier son port HTTP.

XII-C. Les projets Eclipse du client web mobile

Image non disponible

Les projets Eclipse suivent l'architecture ci-dessus :

Image non disponible

En [1] les deux projets Eclipse du client web mobile :

  • [webmobile-restClient] : projet de la couche [DAO] ;
  • [webmobile-pfm] : le projet web Primefaces Mobile

XII-D. La couche [DAO] du client web mobile

Dans l'architecture du client web mobile

Image non disponible

La couche [DAO] dialogue avec le serveur REST des Arduinos :

Image non disponible

La couche [DAO] est un client REST comme l'étaient les couches [métier] et [DAO] du projet Android (paragraphe , page et paragraphe , page ). On y trouve du code analogue.

XII-D-1. Le projet Eclipse

Le projet Eclipse de la couche [DAO] est le suivant :

Image non disponible
  • en [1], le projet [webmobile-restClient] est un projet Maven ;
  • en [2], les dépendances Maven ;
  • en [3], l'implémentation du client REST ;

XII-D-2. Les dépendances Maven

Le fichier [pom.xml] du projet est le suivant :

 
CacherSélectionnez
  • lignes 5-7 : l'identité Maven du projet ;
  • lignes 29-33 : Pour le client REST, on a besoin du framework SpringMVC ;
  • lignes 34-38 : la dépendance sur la bibliothèque JSON Jackson ;
  • lignes 39-43 : le client et le serveur REST échangent des entités définies dans le projet Maven [domotique-entities].

XII-D-3. L'implémentation du client REST

Image non disponible
Image non disponible

Le client REST offre à la couche [web], l'interface [IMetier] suivante :

 
CacherSélectionnez

C'est l'interface de la couche [métier] du serveur. C'est normal. Lorsqu'on met bout à bout le client et le serveur, on voit que la couche [web] du client dialogue avec la couche [métier] du serveur.

L'implémentation [Metier] de cette interface pourrait être la suivante :

 
CacherSélectionnez

Vous connaissez cette implémentation. C'est celle que vous avez écrite pour le client Android. Revoyez les couches [métier] au paragraphe , page et [DAO] au paragraphe , page du projet Android. Il y a une différence : la bibliothèque JSON utilisée est Jackson et non Gson.

 : écrire la classe [RestMetier].

XII-D-4. Les tests du client REST

Image non disponible
  • dans le dossier [support] du TP, vous trouverez un projet Eclipse [webmobile-console] [1] ;
  • importez-le dans Eclipse. C'est un projet Maven [2] ;
  • en [3], les dépendances Maven du projet. Celui-ci dépend du client REST [webmobile-restClient]. Les autres dépendances en découlent ;Image non disponible
  • en [4], vous trouverez quatre applications Java testant certaines fonctionnalités du client REST ;
  • les quatre applications utilisent Spring pour instancier le client REST [5].

Examinons le code de la classe [ListArduinos] qui affiche la liste des Arduinos connectés :

 
CacherSélectionnez
  • ligne 7 : le client REST est instancié ;
  • ligne 9 : on lui demande la liste des Arduinos connectés ;

Le fichier de configuration de Spring [] est le suivant :

 
CacherSélectionnez
  • ligne 12 : définition du client REST ;
  • ligne 13 : injection de l'URL du service REST distant. Vous serez peut-être amenés à modifier cette valeur ;
  • ligne 14 : injection du client REST de Spring ;
  • ligne 17 : le client REST de Spring. La classe appartient au paquetage [org.springframework] ;
  • ligne 18 : on injecte dans cette classe une liste de convertisseurs de messages. Cette notion a été expliquée au paragraphe , page .
  • ligne 25 : le convertisseur des messages JSON. On utilise ici la bibliothèque Jackson ;

Travail à faire : Passer les quatre tests du client REST.

XII-E. La couche [web] de l'application web mobile

A lire :

  • le cours JSF (Java Server Faces) de [ref1] ;
Image non disponible

XII-E-1. Le projet Eclipse

Le projet Eclipse de la couche [web] est le suivant :

Image non disponible
  • en [1], le projet est un projet Maven ;
  • en [2], les dépendances Maven du projet. Celui-ci dépend uniquement du client REST [webmobile-restClient]. Les autres dépendances en découlent ;
  • en [3], les classes du projet :
  • le paquetage [arduino.jsf.beans] contient les trois beans JSF de l'application de portées respectives Application, Session et Request,
  • le paquetage [com.corejsf.util] est un paquetage utilitaire pour gérer l'internationalisation des messages. Nous ne l'expliciterons pas ici. C'est fait dans le cours JSF de [ref1] ;

XII-E-2. Le projet Maven

Le fichier [pom.xml] est le suivant :

 
CacherSélectionnez
  • lignes 5-7 : l'identité Maven du projet ;
  • lignes 18-27 : les dépendances vis à vis des bibliothèques JSF ;
  • lignes 28-33 : les dépendances vis à vis de la bibliothèque Primefaces Mobile ;
  • lignes 34-38 : la dépendance sur le client REST ;
  • lignes 46-51 : le dépôt MAven où peut être trouvée la bibliothèque Primefaces Mobile.

XII-E-3. La configuration de la couche [web]

Image non disponible
  • la configuration et les pages XHTML de la couche [web] sont dans le dossier [webapp] [1] ;
  • le projet est configuré par les fichiers [web.xml] et [faces-config.xml] [2].

XII-E-4. Le fichier [web.xml]

Le fichier [web.xml] est le suivant :

 
CacherSélectionnez

C'est le fichier standard de configuration d'une application web JSF. Il n'y a rien ici de spécifique à Primefaces Mobile.

XII-E-5. Le fichier de configuration [faces-config.xml]

Le fichier [faces-config.xml] configure les différents éléments d'une application JSF. Il est ici le suivant :

 
CacherSélectionnez
  • lignes 12-18 : définissent le fichier des messages internationalisés. Il s'appelle [messages.properties] et se trouve dans le Classpath du projet [1] :Image non disponible
  • ligne 19 : un kit de rendu des pages XHTML. Ici, c'est le kit de Primefaces Mobile qui est utilisé ;
  • lignes 23-27 : le bean de portée [Application][2] ;
  • lignes 29-33 : le bean de portée [Session] [2] ;
  • lignes 35-43 : le bean de portée [Request] [2]. On notera qu'on y injecte la référence du bean de portée [Application] (lignes 39-42).

XII-E-6. Le bean de portée [Application]

Le bean de portée [Application] est instancié au démarrage de l'application JSF. Il reste en mémoire pendant la durée de vie de l'application d'où son nom. Il est accessible à toutes les requêtes de tous les utilisateurs. A cause de cette concurrence d'accès, il est généralement utilisé uniquement en lecture.

Le code de la classe [ApplicationData] est le suivant :

 
CacherSélectionnez
  • ligne 5 : la classe [ApplicationData] implémente l'interface [IMetier] du client REST ;
  • ligne 9 : une référence sur le client REST ;
  • lignes 13-16 : la référence sur le client REST est obtenue avec Spring ;
  • lignes 18-46 : implémentation de l'interface [IMetier]. Tout est délégué au client REST. Nous allons ainsi pouvoir cacher le client REST aux autres beans de l'application JSF. Ceux-ci s'adresseront au bean [ApplicationData] plutôt qu'au client REST.

XII-E-7. Le fichier de configuration de Spring

Image non disponible

Le fichier [spring-restClient.xml] est le même que celui décrit au paragraphe , page .

XII-E-8. Le bean de portée Session

Le bean de portée [Session] est la mémoire d'un utilisateur. Toutes les requêtes de celui-ci peuvent écrire et lire de l'information dans cette mémoire. Ici, nous ne mémorisons qu'une information :

 
CacherSélectionnez
  • ligne 6 : l'unique information de la session : la langue utilisée pour les pages affichées par l'application web mobile, ici le français.

XII-E-9. La page principale du projet PFM (PrimeFaces Mobile)

Image non disponible

La page [index.html] ci-dessus est l'unique page du projet PFM. Son code est le suivant :

 
CacherSélectionnez
  • la page [index.html] est l'unique page affichée par l'application. Elle définit cinq vues. A un moment donné, une seule de ces cinq vues est visible. Au démarrage c'est la première qui est visible. On passe ensuite aux suivantes par navigation ;
  • lignes 11-13 : la vue [home]. Elle présente quatre liens pour passer à l'une des quatre autres vues. Ces dernières ont toutes une icône permettant de revenir à la vue [home] ;
  • lignes 14-16 : la vue [commands] permet d'envoyer une commande JSON aux Arduinos connectés ;
  • lignes 17-19 : la vue [blink] permet de faire clignoter une led sur les Arduinos connectés ;
  • lignes 20-22 : la vue [pinWrite] permet d'écrire une valeur binaire ou analogique sur l'une des pins des Arduinos connectés ;
  • lignes 23-25 : la vue [pinRead] permet de lire la valeur binaire ou analogique de l'une des pins des Arduinos connectés.

XII-E-10. La vue [home]

Image non disponible

Le code [home.xhtml] de cette vue est le suivant :

 
CacherSélectionnez
  • lignes 11-15 : définissent l'entête de la vue ;
  • ligne 11 : le libellé [1] de l'entête ;
  • ligne 13 : le bouton [2]. Un clic sur ce bouton fait apparaître la vue [config.xhtml] (attribut href). Ici, elle n'a pas été définie. Donc le bouton sera inactif. Vous pourrez le rendre actif en créant une vue [config.xhtml] permettant de choisir une autre langue que le français ;
  • ligne 16 : le contenu de la vue. La balise est obligatoire ;
  • ligne 17 : le formulaire. Il y en normalement un dans chaque vue ;
  • ligne 18 : l'unique composant de ce formulaire, un [DataList] ;
  • ligne 19 : le libellé [3] du DataList ;
  • ligne 20 : un lien vers la vue [pinRead] (attribut value) ;
  • ligne 21 : un lien vers la vue [pinWrite] (attribut value) ;
  • ligne 22 : un lien vers la vue [blink] (attribut value) ;
  • ligne 23 : un lien vers la vue [commands] (attribut value) ;
  • ligne 29 : le bas de page de la vue affichée. Mettez votre nom par exemple.

XII-E-11. Le fichier des messages

Image non disponible

La vue [home.xhtml] détaillée précédemment utilise des messages provenant du fichier [messages_fr.properties] :

 
CacherSélectionnez

Si vous internationalisez l'application en y ajoutant l'anglais, vous aurez à remplir le fichier [messages_en.properties] avec les mêmes clés que dans [messages_fr.properties] et des textes en anglais.

XII-E-12. La vue [blink.xhtml]

Nous allons examiner l'une des vues comme exemple à suivre. La vue [blink.xhtml] est la suivante :

Image non disponible

Le code XHTML est le suivant :

 
CacherSélectionnez
  • lignes 10-14 : l'entête [1] de la vue ;
  • ligne 12 : l'icône [A] qui permet de revenir sur la vue [home] (attribut href) ;
  • ligne 15 : le contenu de la vue ;
  • ligne 16 : le formulaire de la vue ;
  • ligne 18 : le libellé [2] ;
  • ligne 19-21 : la liste de cases à cocher [3] ;
  • ligne 19 : la liste des éléments cochés sera mémorisée dans le champ [selectedArduinosIds] du bean de portée [request] RequestData :
 
CacherSélectionnez
  • ligne 20 : la liste est alimentée par la liste des Arduinos connectés. Celle-ci est trouvée dans le bean [ApplicationData] :
 
CacherSélectionnez

Le libellé de chaque case à cocher sera l'adresse IP de l'Arduino (attribut itemLabel). La valeur postée sera l'identifiant de l'Arduino (attribut itemValue) ;

  • ligne 24 : le bouton [4] qui demande au client REST, la liste des Arduinos connectés. Elle le fait avec un appel Ajax, donc sans rechargement de page. L'attribut immediate=true permet de s'affranchir des tests de validité du formulaire. Ils ne seront pas exécutés. La liste des Arduinos de la ligne 19 sera régénérée (attribut update) ;
  • ligne 25 : le libellé [5] ;
  • ligne 27 : un champ PFM ;
  • ligne 28 : le libellé [6]. Notez l'attribut for qui référence le composant d'id pin. PFM utilise cette information pour sa mise en page ;
  • lignes 29-31 : la liste déroulante [7]. La valeur postée sera affectée (attribut value) au champ suivant de [RequestData] :
 
CacherSélectionnez
  • ligne 30 : la liste déroulante est alimentée (attribut value) par le champ suivant de [RequestData] :
 
CacherSélectionnez

Le libellé affiché (itemLabel) ainsi que la valeur postée (itemValue) seront le n° de pin.

  • ligne 33 : un message d'erreur non représenté sur la copie d'écran. Ce message apparaît si le n° de pin posté est invalide ;
  • lignes 35-42 : le champ PFM des composants 8 et 9 ;
  • ligne 36 : le libellé [8] ;
  • ligne 37 : le champ de saisie [9]. La valeur postée sera mémorisée (attribut value) dans le champ suivant de [RequestData] :
    On peut se demander si un type int n'aurait pas été préférable. A l'affichage, la valeur initiale de [dureeClignotement] est affichée dans le champ de saisie. Si le type est int, la valeur 0 est affichée. Avec le type String, rien n'est affiché. D'où le choix de ce dernier ;

     
    CacherSélectionnez
  • ligne 38 : le champ est obligatoire (attribut required) ;

  • ligne 40 : la durée du clignotement doit être entre 100 ms et 10 s ;

  • ligne 43 : affiche un message d'erreur si la saisie est incorrecte ;

  • lignes 45-53 : on a un code analogue pour la saisie du nombre de clignotements ;

  • lignes 54 : le bouton qui va faire clignoter les leds des Arduinos sélectionnés ;

La méthode [RequestData].clignoter va être exécutée (attribut action) par un appel Ajax. Les zones identifiées par msgErreur1 (ligne 33), msgErreur2 (ligne 43), msgErreur3 (ligne 53), reponses (ligne 56), exceptions (ligne 69) seront mises à jour avec le résultat de l'appel Ajax (attribut update) ;

  • lignes 56-67 : un bloc de la vue qui contient le fragment de la ligne 57. Celui-ci n'est affiché que si après l'appel Ajax, la liste des réponses des Arduinos est non vide ;Image non disponible
  • ligne 60 : le libellé [1] ;
  • lignes 62-64 : ce code produit la liste [2] alimentée par le champ suivant de [RequestData] :

     
    CacherSélectionnez
  • ligne 63 : la réponse d'un Arduino est affichée sous la forme [2] ;

  • lignes 69-80 : un bloc de la vue qui contient le fragment de la ligne 70. Celui-ci n'est affiché que si après l'appel Ajax, la liste des exceptions produite par l'appel Ajax est non vide ;Image non disponible

  • ligne 73 : le libellé [1] ;

  • lignes 74-78 : ce code produit la liste [2] alimentée par le champ suivant de [RequestData] :

     
    CacherSélectionnez
  • ligne 76 : chaque exception est affichée sous la forme [2]. Ici le câble réseau des Arduinos avait été déconnecté de l'ordinateur hôte ;

La vue [blink.xhtml] utilise les messages suivants du fichier [messages_fr.properties] :

 
CacherSélectionnez

Pour terminer cet exemple, il ne nous reste plus qu'à décrire la méthode [RequestData].clignoter qui fait clignoter les leds.

XII-E-13. La méthode [RequestData].clignoter

Le code de la méthode est le suivant :

 
CacherSélectionnez
  • pour comprendre ce code, il faut se souvenir que les champs [selectedArduinosIds, dureeClignotement, nbClignotements] ont reçu les valeurs saisies par l'utilisateur ;
  • ligne 7 : on parcourt la liste des Arduinos sélectionnés par l'utilisateur ;
  • ligne 10 : pour chacun d'eux, on demande au bean [ApplicationData] de faire clignoter la led. Les réponses JSON des Arduinos sont cumulés dans la liste de la ligne 4 ;
  • ligne 14 : les exceptions sont cumulées dans la liste de la ligne 5 par la méthode privée [recordException] suivante :
 
CacherSélectionnez

XII-F. Travail à faire

 : en suivant le modèle qui vient d'être décrit pour la vue [blink], réalisez les vues [pinWrite], [pinRead] et [commands].


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Serge Tahé. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.