Contrôler les modules Yoctopuce depuis l'iPad

Contrôler les modules Yoctopuce depuis l'iPad

Comme vous le savez, nous fournissons déjà une API en Objective-C qui permet d'accéder à nos modules depuis un Mac. Il y a d'autres machines qui utilisent l'Objective-C, ce sont les iPhone, iPad et iPod. Si, actuellement, il n'est pas possible de brancher directement un module Yoctopuce sur un device IOS, il est tout à fait possible d'interagir avec nos modules par le réseau (Wifi ou filaire). Que diriez-vous de monitorer tous vos modules Yoctopuce confortablement depuis votre canapé avec un iPad ?

Tous les systèmes que nous avons mis en place pour des clients ou dans nos posts de blog et qui interagissaient avec des smartphones étaient implémentés soit en Javascript, soit en PHP. L'avantage évident de ces solutions est la portabilité: que vous ayez un téléphone sous IOS, Android, Windows ou même WebOS, votre application fonctionnera. Cependant, malgré le support de plus en plus répandu de HTML5, l'interface est forcément plus simpliste et moins dynamique qu'une application native. D'un point de vue commercial, il peut être aussi intéressant de ne pas publier les sources de son application. Avec l'arrivée dans quelques temps du YoctoHub-Wireless, de nombreux iPad, et iPhone vont se transformer en centre de contrôle de Yocto-Relay ou Yocto-Meteo. Nous aurions pu décider de développer cette application en secret, mais nous avons pensé que cela pourrait intéresser du monde. Le but de ce post est de prouver qu'il est facile de créer une interface basique qui va interagir avec nos modules.

Voilà l'objectif de la semaine
Voilà l'objectif de la semaine


L'initialisation

Nous partons du template Master/detail de Xcode et insérons les quelques appels nécessaires pour afficher les informations des modules dans l'interface. Il faut tout d'abord appeler InitAPI pour que l'API initialise ses structures internes. Comme il n'y a pas de détection USB à faire, il faut appeler InitAPI avec le paramètre Y_DETECT_NONE. Pour simplifier le traitement des erreurs, les exceptions sont désactivées. Dans cette configuration, si une erreur se produit lors d'un appel à l'API, la fonction retourne une valeur invalide au lieu de générer une exception qu'il faudrait traper.

        [YAPI DisableExceptions];
        [YAPI InitAPI:Y_DETECT_NONE,nil];


Récupérer la liste des modules Yoctopuce

C'est le gros du travail! L'objectif ici n'est pas de faire du pooling et de mettre à jour l'interface, mais d'utiliser un mécanisme de callback qui est appelé chaque fois qu'une connexion/déconnexion se produit. Dans un langage comme le C++, nous utiliserions la fonction RegisterDeviceArrivalCallback, mais en Objective-C la tradition est plus d'utiliser un objet délégué qui implémente un protocole. Concrètement, notre objet YVMasterViewControler devra se conformer au protocole YDeviceArrival ainsi qu'à YDeviceRemoval et s'enregistrer comme "delegate" avec SetDelegate. Le protocole YDeviceArrival ne définit qu'une seule méthode - (void)yDeviceArrival:(YModule *)module; (pour YDeviceRemoval c'est - (void)yDeviceRemoval:(YModule *)module;). Ces deux méthodes ne peuvent être appelées par l'API que durant l'exécution de la méthode de classe UpdateDeviceList: , il faut donc que l'on appelle périodiquement la méthode UpdateDeviceList de la classe YAPI pour que l'API appelle la méthode YDeviceRemoval de notre objet délégué. La solution est d'utiliser un NSTimer qui va périodiquement appeler UpdateDeviceList:

Voilà la déclaration de notre YVMasterViewController

...
@interface YVMasterViewController: UITableViewController<YDeviceArrival,YDeviceRemoval>
...
- (void)yDeviceArrival:(YModule *)module;
- (void)yDeviceRemoval:(YModule *)module;
...
@end


Et son implémentation

@implementation YVMasterViewController
..
- (void)viewDidLoad
{
        ...
    [YAPI SetDelegate:self];
    NSError *err;
    if(YISERR([YAPI RegisterHub:@"172.17.17.59" :&err])){
        NSLog(@"Register Hub failed with : %@",[err localizedDescription]);
    }

    hotplug_timer = [NSTimer scheduledTimerWithTimeInterval:1
                                                     target:self
                                                   selector:@selector(timerFired:)
                                                   userInfo:nil
                                                    repeats:YES];
    ...
}

-(void)timerFired:(NSTimer *) theTimer
{
    [YAPI UpdateDeviceList:nil];
}


- (void)yDeviceArrival:(YModule *)module
{
    NSLog(@"yDeviceArrival %@",module);
    ...
}

- (void)yDeviceRemoval:(YModule *)module
{
    NSLog(@"yDeviceRemoval %@",module);
    ...
}

@end


Le reste du code est peu ou prou le code du template Master-Detail de Xcode, au lieu d'ajouter des objets NSDate, nous allons ajouter nos objets YModule.

La vue détaillée

Pour la vue détaillée, c'est encore plus simple, le template s'occupe de mettre à jour notre pointeur sur notre objet YModule. Il suffit de disposer nos widgets avec Interface Builder, et de définir une méthode qui mette à jour l'interface avec les valeurs de l'objet YModule. Là aussi, on utilise un NSTimer pour périodiquement rafraîchir l'interface avec les valeurs qui peuvent changer (nom logique, consommation, etc..).

...
- (void)updateView
{
    // Update the user interface for the detail item for attributes that can change.

    if (self.detailItem) {
        self.detailDescriptionLabel.text = [self.detailItem description];
        [logicalNameView setText:[self.detailItem logicalName]];
        [consumptionView setText:[NSString stringWithFormat:@"%0d mA",[self.detailItem usbCurrent]]];
        Y_BEACON_enum swVal = [beaconView isOn]?Y_BEACON_ON:Y_BEACON_OFF;
        if(swVal != [self.detailItem beacon])
            [beaconView setOn:([self.detailItem beacon]==Y_BEACON_ON? YES:NO)];
        [luminosityView setValue:[self.detailItem luminosity]];
    }
}

- (void)configureView
{
    // Update the user interface for the newly selected the detail item.

    if (self.detailItem) {
        NSLog(@"configureView for %@",self.detailItem);
        NSData *data = [self.detailItem loadURL:@"/icon2d.png"];
        UIImage *img = [UIImage imageWithData:data];
        [_icon2dView setImage:img];
        [serialView setText:[self.detailItem serialNumber]];
        [prodNameView setText:[self.detailItem productName]];
        [prodReleaseView setText:[NSString stringWithFormat:@"%d",[self.detailItem productRelease]]];
        [firmwareView setText:[NSString stringWithFormat:@"%d",[self.detailItem firmwareRelease]]];
        [self updateView];
        NSLog(@"configureView done for %@",self.detailItem);
    }
}

-(void)timerFired:(NSTimer *) theTimer
{
    [self updateView];
}
...



  



Voilà, comme vous avez pu le remarquer cet exemple est très basique, mais permet de comprendre les principales étapes pour interagir avec nos modules. Vous trouverez les sources complètes de ce projet dans la prochaine version de la Librairie Objective-C. D'ici quelques semaines mois vous devriez trouver une application similaire mais beaucoup plus complète directement dans votre app store. Pour les possesseurs de smartphones et tablettes sous Android, l'API Java devrait bientôt être rendue public en beta test.

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.