Cette semaine, nous continuons notre série d'articles "pour les débutants" et on va parler de Java. Comme pour les précédentes introductions aux différents langages de programmation, nous allons réaliser une petite application en Java FX qui va afficher la valeur d'un capteur de température Yoctopuce.
Cet article suppose que vous avez déjà quelques connaissances de Java et plus particulièrement de Java FX car le but de cet article n'est pas de faire un tutoriel sur Java FX mais d'apprendre à utiliser nos modules dans une application écrite en Java. 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.
Création du projet Java FX avec IntelliJ IDEA
Note: Pour illustrer cet article, nous avons utilisé IntelliJ IDEA car a notre avis c'est l'IDE le plus pratique et rapide. Mais Netbeans et Eclipse proposent les même fonctionnalités.
Après avoir lancé IntelliJ, créez un nouveau projet Java FX.
Créez un nouveau projet Java FX
Creation de l'interface graphique
On commence par modifier le fichier .fxml pour ajouter deux Label qui devrons afficher l'identifiant du capteur et la valeur courante du capteur de température.
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.ColumnConstraints?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<columnConstraints>
<ColumnConstraints/>
</columnConstraints>
<rowConstraints>
<RowConstraints/>
<RowConstraints/>
</rowConstraints>
<children>
<Label text="Label" fx:id="lab_hwid"/>
<Label text="Label" fx:id="lab_value" GridPane.rowIndex="1">
<font>
<Font size="36.0"/>
</font>
</Label>
</children>
</GridPane>
Il faut aussi mettre à jour le code Java du contrôleur pour qu'il puisse retrouver ces deux labels. Il faut déclarer deux attributs lab_hwid et lab_value correspondant aux deux labels que l'on a défini dans le fichier .fxml.
import javafx.scene.control.Label;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable{
public Label lab_hwid;
public Label lab_value;
@Override
public void initialize(URL location, ResourceBundle resources) {
lab_hwid.setText("No sensor detected");
lab_value.setText("N/A");
}
}
Si vous exécuter le projet vous devriez avoir une fenêtre comme ceci:
Installation de la librairie Yoctopuce
Java vs Android
Nous avons deux librairies distinctes qui sont écrites en Java: la librairie Java et la librairie Android. Si 90% du code est identique et implémente la même API public, elles ne sont pas interchangeables. Comme son nom l'indique la libraire Android fonctionne uniquement sous Android et ne peut pas être utilisé sur un PC. De la même manière la librairie Java ne fonctionnera pas correctement sur sous Android. Pour un utilisation sur un PC, il faut donc utiliser la librairie Yoctopuce Java, mais pas la version Android.
Afin de pouvoir utiliser la librairie Yoctopuce dans ce projet, il faut tout d'abord la télécharger et l'installer quelque part sur votre disque. La librairie peut être téléchargée sur notre site depuis cette page. C'est un fichier zip qui contient les sources de la librairie, quelques exemples d'utilisation, la documentation et des binaire qui sont utilisable directement. Une fois téléchargé il suffit de décompressé la librairie à quelque part sur votre disque. Notez qu'il est aussi possible d’obtenir la librairie depuis GitHub ou sur Maven.
Il faut ensuite dire à IntelliJ d'ajouter la librairie au projet. Il faut ouvrir le panneau "Project Structure" qui est accessible depuis le menu "File", accéder à l'onglet "Libraries". Il faut ensuite cliquer sur l’icône en forme de plus vert pour ajouter une librairie de type "Java". Dans la boîte de dialogue, sélectionnez le répertoire Binaries de la librairie Yoctopuce, de cette manière tous les fichiers .jar et les librairies dynamiques nécessaires seront inclus. A la fin, IntelliJ va vous proposer d'ajouter automatiquement cette librairie au projet, évidement il faut cliquer sur "Ok".
il faut ajouter une librairie de type Java
Il ne reste plus qu'a ajouter le code qui va utiliser cette librairie.
Initialisation de l'API
La première chose à faire consiste initialiser l'API à l'aide de YAPI.RegisterHub, un bon endroit pour faire ça est dans la méthode initialize, ainsi, si l'initialisation de l'API Yoctopuce se passe mal, on pourra afficher un message d'erreur et arrêter l'application.
public void initialize(URL location, ResourceBundle resources) {
lab_hwid.setText("No sensor detected");
lab_value.setText("N/A");
try {
YAPI.RegisterHub("usb");
} catch (YAPI_Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText("Init error");
alert.setContentText(e.getLocalizedMessage());
alert.showAndWait();
Platform.exit();
}
}
Mettre à jour l'interface avec la température
Contrairement à une application console, on ne peut pas se permette de créer une boucle sans fin pour lire le capteur en permanence. C'est pourquoi on va utiliser la class Timeline qui permet d'appeler périodiquement une méthode periodicTimer.
Ce qui nous donne le code suivant:
...
private Timeline timeline;
@Override
public void initialize(URL location, ResourceBundle resources) {
...
timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.setAutoReverse(false);
timeline.getKeyFrames().add(
new KeyFrame(Duration.millis(100),
new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
periodicTimer();
}
}));
timeline.play();
}
}
La méthode periodicTimer va se charger de:
- Appeler YAPI.HandleEvents assez régulièrement. En fait ce n'est pas 100% nécessaire dans notre cas, mais c'est une bonne pratique de donner le contrôle à l'API Yoctopuce de temps en temps.
- Appeler YAPI.UpdateDeviceList une fois toutes les deux secondes, ce qui forcera l'API à re-détecter le branchement de nouveaux modules. C'est un processus assez lourd, il faut éviter de le faire trop souvent d'où les deux secondes entre chaque appel.
- Détecter la première fonctionnalité YTemperature disponible à l'aide de YTemperature.FirstTemperature()
- Si cette fonctionnalité est disponible, lire la température et mettre à jour l'interface.
private YTemperature sensor;
private void periodicTimer() {
try {
if (hardwaredetect == 0) {
YAPI.UpdateDeviceList();
}
hardwaredetect = (hardwaredetect + 1) % 20;
YAPI.HandleEvents();
if (sensor == null) sensor = YTemperature.FirstTemperature();
if (sensor != null) {
lab_hwid.setText(sensor.get_friendlyName());
lab_value.setText(sensor.get_currentValue() + sensor.get_unit());
}
} catch (YAPI_Exception e) {
lab_hwid.setText("Sensor is offline");
lab_value.setText("OFFLINE");
sensor = null;
}
}
Et une fois qu'on compile tout ça, on obtient le résultat attendu, une fenêtre Windows qui affiche la température dès qu'un capteur de température Yoctopuce est branché:
Ça marche!
Note: le code complet de l'application est disponible sur GitHub:https://github.com/yoctopuce-examples/java_beginners
Une petite amélioration
Cet exemple ne gère que les capteurs de température, mais en changeant juste deux lignes, on peut le faire marcher avec n'importe quel senseur Yoctopuce: il suffit d'utiliser la classe YSensor à la place de la classe YTemperature:
public Label lab_hwid;
public Label lab_value;
private int hardwaredetect;
private Timeline timeline;
private YSensor sensor;
@Override
public void initialize(URL location, ResourceBundle resources) {
lab_hwid.setText("No sensor detected");
lab_value.setText("N/A");
try {
YAPI.RegisterHub("usb");
} catch (YAPI_Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setHeaderText("Init error");
alert.setContentText(e.getLocalizedMessage());
alert.showAndWait();
Platform.exit();
}
timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.setAutoReverse(false);
timeline.getKeyFrames().add(
new KeyFrame(Duration.millis(100),
new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
periodicTimer();
}
}));
timeline.play();
}
private void periodicTimer() {
try {
if (hardwaredetect == 0) {
YAPI.UpdateDeviceList();
}
hardwaredetect = (hardwaredetect + 1) % 20;
YAPI.HandleEvents();
if (sensor == null) sensor = YSensor.FirstSensor();
if (sensor != null) {
lab_hwid.setText(sensor.get_friendlyName());
lab_value.setText(sensor.get_currentValue() + sensor.get_unit());
}
} catch (YAPI_Exception e) {
lab_hwid.setText("Sensor is offline");
lab_value.setText("OFFLINE");
sensor = null;
}
}
}
Maintenant, l'application marche aussi avec un capteur de lumière, un voltmètre ou n'importe quel capteur Yoctopuce.
Ça marche aussi avec les autres capteurs
Ce "tour de magie" fonctionne car toutes les classes Yoctopuce correspondant à des fonctionnalités de type senseur héritent de la classe YSensor. Vous pouvez donc utiliser la classe YSensor pour accéder aux fonctions de base d'un senseur comme obtenir la valeur courante ou l'unité de mesure.
Exécuter l'application en dehors d'InteliJ
InteliJ permet de packager l'application Java FX sous la forme d'un exécutable qui contient la machine virtuel Java et l'application. La procédure est expliquée sur le site de JetBrains. Malheureusement, InteliJ n'est pas suffisamment malin pour inclure automatiquement les fichiers de la librairie Yoctopuce dans cet exécutable.
Pour contourner ce problème il faut ouvrir la fenêtre "Project Structure" et accéder au panneau "artefact"et ajouter la librairie Yoctopuce dans le répertoire de sortie en double cliquant sur la libraire que nous avons inclus plus tôt. De cette manière InteliJ va inclure les fichiers .jar de notre librairie dans l’application.
il faut ajouter la librairie à l'artefact
Malheureusement les librairies dynamiques qui sont nécessaires pour accéder directement au port USB, ne seront pas copiées. La solution est de copier manuellement les fichiers .dll, .so et .dylib dans le répertoire où InteliJ copie l’exécutable.
Conclusion
Nous avons volontairement gardé ce code très simple, par exemple, il ne gère qu'un seul capteur branché par USB. Bien évidement, la librairie permet de gérer plusieurs capteurs, qu'ils soient connectés en USB ou connectés sur un YoctoHub distant.
La librairie Java est l'une des plus versatiles de nos librairies, car en plus de l'utilisation "traditionnelle" que nous venons d'illustrer il est aussi possible en mode "HTTP callback" ou "WebSocket callback" qui permettent aux modules Yoctopuce qui sont branchés sur un YoctoHub de se connecter directement à un WEB service écrit en Java:
Maintenant que nous avons vu les bases, il ne vous reste plus qu'a écrire vos propres applications en vous aidant de la documentation de référence. Vous pouvez aussi parcourir notre blog, qui est plein d'exemples d'utilisation de nos modules. Et si avec tout ça vous n'arrivez toujours pas à vous en sortir, vous pouvez toujours envoyer un email à support@yoctopuce.com.