Il y a quelques semaines mois nous avions annoncé l'API Java, Elle est finalement disponible, mieux nous avons deux versions de l'API Java. Une version Java standard et une version pour Android. Vous pouvez les télécharger sur l'endroit habituel. Comme nous avons déjà parlé de la librairie Java standard, nous allons nous attarder sur les spécificités de la librairie Android.
Contrairement aux autres plates-formes Java (qui ne proposent pas d'accès à USB) avec Android il est possible d'accéder aux périphériques USB nativement depuis une classe Java. En effet depuis Android 3.1 Google offre une API pour envoyer et recevoir des paquets USB. Cela permet en théorie d'utiliser n'importe quel appareil Android récent pour interagir avec nos modules USB sans avoir à rooter ou bidouiller sa tablette.
Il faut cependant que la tablette ou le téléphone supporte le mode USB Host et que le firmware du constructeur implémente correctement cette fonctionnalité. Si vous vous savez pas ce qu'est le Host mode voici une petite explication:
Dans une liaison USB il y a toujours un Host (un PC par exemple) et un Device (un clavier par exemple). Le Host est responsable de l'alimentation des périphériques (c'est votre PC qui alimente votre clavier et non l'inverse), il est aussi responsable du bon fonctionnement de la communication. Dans le cas d'un PC et d'un clavier tout semble évident et clair, mais dans le cas d'une tablette Android c'est un petit peu plus compliqué, car elle peut être Host et/ou Device. Prenons l'exemple d'une tablette Acer Iconia Tab A200, nous avons :
- 1 port micro USB pour le cas où la tablette va fonctionner comme un Device (pour brancher la tablette à un PC)
- 1 port USB type A (le port qui est sur tous les PC) qui va fonctionner comme un Host (pour brancher un clavier sur la tablette).
Les deux ports USB de l'Iconia Tab A200
Pour revenir à notre utilisation, nous avons donc besoin d’une tablette qui va fonctionner comme un Host sur laquelle on branchera nos modules USB. Nous avons utilisé avec succès les deux tablettes suivantes:
- Acer Iconia Tab A200
- Asus Transformer Pad TF300T (avec le dernier firmware)
Les machines suivantes devraient fonctionner correctement mais n’on pas été testées dans notre lab:
- Galaxy Nexus
- Lenovo ThinkPad Tablet
- Asus Transformer TF101
- Motorola Xoom
- Toshiba Thrive AT100
- Samsung Galaxy Tab 7.0 Plus (Wifi)
Depuis quelques temps, on commence à voir apparaitre des petites "box" Android très bon marché qui se branchent directement sur la TV (par exemple le MK 802 et le MK805).
Notre expérience nous a montré que ces systèmes n’implémente pas correctement cette fonctionnalité sous Android. Concrètement claviers et clefs USB sont supportés mais les autres périphériques serons ignorés par le firmware.
Pour des raisons de sécurité, Android va toujours vous prévenir avant d'autoriser une application à accéder aux périphériques USB.
Android vous demandera confirmation la première fois que vous brancher un périphérique USB
Premier exemple
Maintenant que nous avons une tablette qui supporte le "Host mode", une librairie Java prévue pour Android, regardons comment interagir avec un Yocto-Meteo. Nous allons créer une app très basique qui affichera les trois valeurs des trois sondes du Yocto-Meteo connecté ou un message "Not connected" si le module n'est pas branché.
L'API Yoctopuce fonctionne comme sur toutes les autres plates-formes, il y a cependant deux étapes supplémentaires dans la version Android.
La première consiste à ajouter dans son fichier AndroidManifest.xml le fait qu'on va utiliser la fonctionnalité USB Host:
<manifest ...> ... <uses-feature android:name="android.hardware.usb.host" /> ... </manifest>
La seconde est d'activer le Host mode dans notre API. Pour accéder au port USB, il faut fournir un pointeur sur un objet ou un sous-objet android.content.Context en utilisant la méthode YAPI.EnableUSBHost. Comme la classe android.app.Activity hérite de android.content.Context, le plus simple est d'appeler YAPI.EnableUSBHost(this) au démarrage de l'application.
...
try {
// Pass the application Context to the Yoctopuce Library
YAPI.EnableUSBHost(this);
// Register all usb device
YAPI.RegisterHub("usb");
} catch (YAPI_Exception e) {
//report the error
...
}
...
}
Une fois ces deux étapes réglées, il n'y a plus besoin de se préoccuper de la partie communication. La librairie Yoctopuce se chargera elle-même de demander l'accès au port USB et de maintenir la communication. Il ne reste plus qu'à récupérer les valeurs quand cela nous arrange.
Dans notre app nous voulons mettre à jour 2 fois par seconde les trois champs textes avec la valeur du capteur correspondant. La seule difficulté est de s'assurer que notre code sera exécuté par le thread principal car nous allons modifier les champs texte.
Le plus simple est de rajouter un Handler dans la boucle d’évènements qui va
-1 mettre à jour la liste des modules connectés
-2 afficher la température
-3 afficher l'humidité
-4 afficher la pression
-5 enregistrer à nouveau le handler dans la boucle d'évènements.
Voici le code du handler:
public void run()
{
try {
YAPI.UpdateDeviceList();
} catch (YAPI_Exception e1) {
temp_msg.setText("update device list failed with "+e1.getLocalizedMessage());
return;
}
YTemperature temp_sensor=YTemperature.FirstTemperature();
if(temp_sensor!=null && temp_sensor.isOnline()) {
try {
temp_msg.setText(
String.format("%.1f %s",temp_sensor.getCurrentValue(),temp_sensor.getUnit()));
} catch (YAPI_Exception e) {
temp_msg.setText(String.format("%s",e.getLocalizedMessage()));
}
}else {
temp_msg.setText("No temperature sensor connected");
}
YPressure pres_sensor = YPressure.FirstPressure();
if(pres_sensor!=null && pres_sensor.isOnline()) {
try {
pres_msg.setText(
String.format("%.0f %s",pres_sensor.getCurrentValue(),pres_sensor.getUnit()));
} catch (YAPI_Exception e) {
pres_msg.setText(String.format("%s",e.getLocalizedMessage()));
}
} else{
pres_msg.setText("No pressure sensor connected");
}
YHumidity hum_sensor = YHumidity.FirstHumidity();
if(hum_sensor!=null && hum_sensor.isOnline()) {
try {
hum_msg.setText(
String.format("%.0f %s",hum_sensor.getCurrentValue(),hum_sensor.getUnit()));
} catch (YAPI_Exception e) {
hum_msg.setText(String.format("%s",e.getLocalizedMessage()));
}
}else {
hum_msg.setText("No humidity sensor connected");
}
handler.postDelayed(this, 500);
}
...
Et voilà le résultat
Les fichiers sources de cet exemple sont disponibles dans la librairie Java Android.Vous pouvez aussi télécharger directement l'application ici si vous voulez tester si votre tablette est compatible. Il y a actuellement très peu d'exemples Android fournis avec la librairie mais nous allons bien évidement rajouter des exemples pour chaque module. Nous allons aussi proposer quelques exemples directement sur Google Play.