Publié le 24 novembre 2014 - par

RpiDroid, un web service pour le Raspberry Pi

RpiDroid_250pxComment utiliser les entrées et sorties du GPIO d’un Raspberry Pi à l’aide de Web-Service ?

C’est la question que s’est posée Dominique, lecteur du blog et administrateur du forum framboise314…

Parti d’une idée trouvé sur le blog idleman.fr, il souhaitait obtenir le même résultat, mais en utilisant un Web-Service. Le but étant de ne pas ouvrir le port SSH (22 par défaut) sur l’Internet.

Je laisse la parole à Dominique :

Avantage du web-service

L’avantage du Web-Service pour la gestion des ports GPIO est que le Raspberry Pi n’a que cela à gérer. La partie cliente, peut-être développée dans n’importe quel langage de développement, le Raspberry Pi ne reçoit que des informations d’écriture ou de lecture à effectuer.
Dans un souci de sécurité, l’avantage du Web-Service est qu’il ne peut faire que ce pour quoi est prévu…

Mon projet de départ est la gestion de l’éclairage extérieur d’ambiance de la terrasse et du jardin. Le tout automatisé en fonction des horaires, des saisons, et de la tombée de la nuit.
Je souhaite en dehors de l’automatisme, pouvoir allumer ou éteindre un éclairage à partir d’une page Web, mais principalement depuis une application Android. Un peu à la manière de l’application « Raspberry control », mais en version Web-Service.

Description du Web-Service

Le Web-service est écrit en PHP, il est de type SOAP. Pour créer ce Web-Service, j’utilise la bibliothèque NuSoap, disponible sur le site Sourceforge (http://sourceforge.net/projects/nusoap/). Celle-ci permet le développement d’un serveur SOAP en PHP. L’utilisation du PHP est un atout majeur, il est en effet très facile de stocker ce type de Web-Service sur tout Raspberry Pi, dont les prérequis sont un serveur Web, PHP et la bibliothèque WiringPi (http://wiringpi.com).

Le logiciel client peut être développé avec tout type de logiciel, sachant invoquer un Web-Service de type SOAP. Il est donc facile de le porter sur tout type de plate-forme cliente. Suivant l’utilisation, et principalement suivant le client, le Raspberry Pi a besoin d’être visible depuis Internet, ou pas.

Exemples :

  • Le client est en interne au réseau local, donc pas besoin d’accès via Internet, aucun accès au Web-Service depuis l’extérieur.
  • Le client est une page Web, accessible depuis Internet, 2 possibilités :
    • Le client est hébergé sur une machine Web faisant partie du même réseau local que le Raspberry Pi. La machine cliente est stockée dans le réseau local, et est accessible depuis Internet. Dans ce cas, le Raspberry Pi n’a pas besoin d’être accessible depuis Internet.
    • Le client est hébergé chez un hébergeur Internet (payant ou gratuit). Dans ce cas le Web-Service du Raspberry doit être accessible depuis Internet pour que le client y accède. Connaissant la machine cliente, il est possible de sécuriser l’accès au Raspberry depuis Internet, en limitant l’accès web du Raspberry Pi qu’uniquement à la machine cliente. Cela peut se faire simplement via le fichier « .htaccess ».
  • Le client est un programme pour iPhone, Android, Windows Phone ou autre. Je parle bien de programme et non d’une page web. Dans ce cas le Raspberry Pi doit être accessible en web depuis Internet.

Par mesure de sécurité, l’utilisation des commandes du Web-Service est accessible à l’aide d’un Token (clé de sécurité), que le client doit connaitre pour envoyer des ordres au Raspberry Pi via ce Web-Service.

Fonctionnalités du Web-Service

Constitution du Web-service

  • La bibliothèque NuSoap.
  • Le fichier principal du Web-service : « wspi.php »
  • Un fichier « config.inc.php » qui contient différentes informations spécifiques à l’utilisateur:
    • La variable « $token », que l’on qualifie de clé de sécurité. Ce Token est libre, il doit être renseigné lors de l’appel du Web-service. Si le Token est différent entre le client et le serveur, le Web-Service retourne au client une erreur de clé de sécurité non valide, et donc ne fait aucune action. La valeur retournée est 9999, il faudra l’interpréter dans le logiciel client comme étant « Clé de sécurité non valide ».
    • Un tableau « $commandes », qui contient le nom que l’on souhaite donner à chacun des ports GPIO (éclairage escalier, éclairage chambre, …), ainsi que le numéro du port auquel il est attaché. Ces informations sont déclarées sur le Web-Service, de cette façon elles sont récupérées par le ou les logiciels clients. Le numéro de port déclaré peut-être le numéro du GPIO ou le numéro WiringPi, au choix de l’utilisateur, dès l’instant que ce choix est le même pour tous les ports.
    • La variable « $typePin » permet de préciser si le numéro du port spécifié dans le tableau « $commande » (ci-dessus), est un numéro de port physique « P » ou le numéro de port WiringPi « W ». Le Web-service fera lui-même la conversion si besoin.

 Les méthodes du Web-service

  • setPin() : Permet « d’allumer » ou « éteindre » un port GPIO.
    – Trois valeurs d’entrée : le numéro du pin à écrire, la valeur de l’état (1 ou 0), et le Token de sécurité.
    – Une valeur en retour : l’état du pin (1 ou 0). Valeur lu sur le port GPIO après que l’action demandée soit effectuée.
  • getPin() : Permet de lire un port GPIO.
    – Deux valeurs d’entrée : le numéro du pin à lire, et le Token de sécurité.
    – Une valeur en retour : l’état du pin lu (1 ou 0).
  • getMaterielTab() : Permet de lire les ports GPIO déclarés dans le Web-Service, ainsi que les informations de chacun des ports.
    – Deux valeurs en entrée : Le token de sécurité, et un deuxième paramètre qui permet de demander si l’on souhaite ou pas un retour de l’état (0 ou 1) de chacun des ports GPIO.
    – Une valeur sous forme de tableau en retour : Chacun des enregistrements du tableau contient le nom du port défini dans le Web-Service par l’utilisateur (éclairage escalier, éclairage chambre, …), le numéro du pin associé, et si demandé, l’état du pin (1 ou 0).
  • getMaterielXml() : Idem getMaterielTab(), mais au lieu de retourner un tableau, le résultat est retourné dans une chaîne sous un format XML.

Interrogation du Web-Service

Pour interroger le Web-Service, nous avons besoin d’un client. Ci-dessous nous allons détailler le minimum nécessaire en PHP pour interroger le Web-Service.

Le client a besoin de la bibliothèque NuSoap. Voici ci-dessous les possibilités d’un client en PHP. L’exemple ci-dessus n’est pas un script fonctionnel en l’état, il permet simplement de démontrer comment utiliser les différentes fonctions du web-service.

/* Déclaration du webService */

include('lib/nusoap.php');

ini_set("soap.wsdl_cache_enabled", "0");

$client = new nusoap_client('$WS_adresse.''http://adresse_webservice/wspi/wspi.php?wsdl');

 

/* Exemples d’interrogation */

/* ************************ */

/* Pour mettre le GPIO 1 au niveau 1 */

/* ********************************* */

/* Déclaration des paramètres d'entrée du Web-service */

$parametres = array('pin'=>1, 'valeur'=>1, 'cle' =>"Token");

/* Execution du web-service et affichage de l'état du pin */

echo $client->call('setPin', $parametres);

 

/* Pour lire l'état du GPIO 1 */

/* ************************** */

$parametres = array('pin'=>$pin, 'cle' =>"Token");

echo $client->call('getPin', $parametres);

 

/* Pour lire les déclarations GPIO faite dans le web-service */

/* ********************************************************* */

$parametres = array('cle' =>"Token", 'litEtat' =>1);

$valTableau = $client->call('getMaterielTab', $parametres);

/* $valTableau est un tableau retourné par le Web-Service contenant toutes les déclarations GPIO effectuées sur la partie serveur */

Les lignes 1 à 5 sont la déclaration du web-service.

  • Les lignes 9 à 14 décrivent comment écrire sur un port GPIO via le web-service.
  • Les lignes 16 à 19 montrent comment lire l’état d’un port GPIO.
  • Les lignes 21 à 24 permettent de retourner la liste des ports déclarés sur le web-service.

Information : les commandes GPIO sont effectuées avec l’utilisateur « www-data » (utilisateur web), si cela ne fonctionne pas, vérifier que les droits sur « /usr/local/bin/gpio » sont bien « rwxr-xr-x ».

Téléchargement

Le fichier ZIP contient 2 dossiers :

  • Le dossier « wspi » : Dossier complet du Web-Service à installer sur le Raspberry.
  • Le dossier « client » : Dossier qui contient un exemple de client PHP, à installer sur une machine autre que le Raspberry. Dans ce dossier, ne pas oublier d’ajouter le dossier « lib » contenant la librairie « NuSoap », c’est le même dossier de librairie pour le serveur et le client.

Un client Android
Un Client Android en cours de développement, cette application permet d’interroger et d’interagir avec les ports GPIO du Raspberry Pi.

rpidroid_01

L’interface de lecture et d’action

rpidroid_02

Le menu de l’application

rpidroid_03

La page de configuration du Web-Service

Le prototype du client Android est téléchargeable au format APK

Note de framboise314 : Pour ceux qui auraient des soucis pour installer l’appli APK, voyez http://www.frandroid.com/applications/184151_comment-installer-un-fichier-apk-sur-son-terminal-android

Vidéo

Résumé

Ce projet à l’origine pour interagir entre un logiciel sous Android et un Raspberry Pi gestionnaire de l’éclairage extérieur, porte le nom de « PiDroid »

A la suite d’un surf sur Internet j’ai découvert que ce nom existait déjà pour un autre Projet. Je recherche donc un autre nom pour ce projet, toute suggestion est la bienvenue. Actuellement je pense à « RPiDroid », et c’est donc le nom que l’on utilisera pour le moment.

J’ai quelques idées en cours de développement pour étoffer ce projet. Actuellement j’ai ajouté une possibilité de rebooter le Raspberry Pi depuis l’application Android, ainsi que d’arrêter le système pour intervention sur l’installation. Le but étant d’arrêter les Raspberry Pi depuis l’application Android, évitant ainsi de prendre la main sur le Raspberry Pi depuis une autre machine via SSH.

RpiDroid_FBToute idée d’amélioration est la bienvenue, dès lors que cela reste une fonctionnalité ouverte, et non une fonctionnalité spécifique à un utilisateur.

Le fichier APK pour appareil Android est fourni (Android v3.0 minimum). L’application est actuellement prévue graphiquement pour Smartphone (mode portrait), mais peut être installée sur tablette.
Aujourd’hui je fournis l’APK de cette façon, car j’attends que le projet soit un peu plus avancé pour le mettre en ligne sur le Play Store.
Ceux qui n’ont pas d’appareil Android peuvent utiliser ce Web-Service depuis une page PHP en s’appuyant sur la partie « Client PHP » fournie dans le même fichier compressé que le Web-Service. Ne pas oublier d’ajouter le dossier « lib » dans le dossier de votre client PHP.

N’hésitez pas à poster vos réactions et vos idées dans le forum, un sujet est ouvert pour cette occasion dans la section :
« La domotique avec le Raspberry Pi -> Des interfaces pour le Raspberry Pi » :

http://forums.framboise314.fr/viewtopic.php?f=71&t=285

 

Share Button

À propos François MOCQ

Électronicien d'origine, devenu informaticien, et passionné de nouvelles technologies, formateur en maintenance informatique puis en Réseau et Télécommunications. Dès son arrivée sur le marché, le potentiel offert par Raspberry Pi m’a enthousiasmé j'ai rapidement créé un blog dédié à ce nano-ordinateur (www.framboise314.fr) pour partager cette passion. .

3 réflexions au sujet de « RpiDroid, un web service pour le Raspberry Pi »

  1. jeanluitbrille

    Bonjour et merci pour ce Forum.
    Un peu de C, merci gert et dom un peu de php merci Stéphane un peu de Python et un peu ce C du Raspbian et Mysql merci la communauté.
    Une une petite page web qui fait clignoter et commence a ressembler a quelque chose et pour développé mieux j’achète PY deux: OH désespoir oh malheur… le bcm2835.h avec mon AM2302 capteur de température et humidité ne lit plus rien et pas de vrai Solution en vue si de l’aide pouvait surgir de ce forum Hum quelle délice une vision du problème.
    dans tous les cas par avance merci.
    le code qui fonctionne sous PY 512 B mais pas avec PY 2:
    // How to access GPIO registers from C-code on the Raspberry-Pi et AM2302
    // Exemple programme
    // Avril -2015
    // Dom and Gert and Jean-Luc
    //
    // processeur ARM avec Linux

    #define BCM2708_PERI_BASE 0x20000000
    #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #define MAXTIMINGS 100

    //variables globales

    float data_meteo[2] ;
    char nom_tablejm[20] ;
    int heure ;
    int dhtpin = 11;
    int main()
    {

    if (!bcm2835_init())
    return 1;

    readDHT(dhtpin);

    coherence();

    connection();
    // affich_table();

    creat_tableJM_id() ;
    ecrit_table();
    deconnection() ;
    return 0;
    }

    int bits[250], data[100];
    int bitidx = 0;

    int readDHT(int pin) {

    int counter = 0;
    int laststate = HIGH;
    int j=0;
    float h,f ;
    // Mettre le port en sortie !

    bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);

    bcm2835_gpio_write(pin, HIGH);
    usleep(500000); // 500 ms
    bcm2835_gpio_write(pin, LOW);
    usleep(20000);

    // met le port en entree

    bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);

    data[0] = data[1] = data[2] = data[3] = data[4] = 0;

    // wait for pin to drop?
    while (bcm2835_gpio_lev(pin) == 1) {
    usleep(1);
    }

    // read data!
    for (int i=0; i3) && (i%2 == 0)) {
    // shove each bit into the storage bytes
    data[j/8] < 200)
    data[j/8] |= 1;
    j++;
    }
    }

    if ((j >= 39) &&
    (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {

    h = data[0] * 256 + data[1];
    h /= 10;

    f = (data[2] & 0x7F)* 256 + data[3];
    f /= 10.0;
    if (data[2] & 0x80) f *= -1;
    printf(« Temp = %.1f *C, Hum = %.1f \%\n », f, h);
    data_meteo[0] = f ;
    data_meteo[1] = h ;

    }

    return 1;
    }

    MYSQL *conn;
    MYSQL_RES *res;
    MYSQL_ROW row;

    int connection()
    {
    char *server = « localhost »;
    char *user = « root »;
    char *password = « mdpmysql »;
    char *database = « Domo »;

    conn = mysql_init(NULL);

    /* Connection à la database */
    if (!mysql_real_connect(conn, server,
    user, password, database, 0, NULL, 0)) {
    fprintf(stderr, « %s\n », mysql_error(conn));
    return 1;
    }
    }
    //debug
    int affich_table() {
    if (mysql_query(conn, « show tables »)) {
    fprintf(stderr, « %s\n », mysql_error(conn));
    return 1;
    }
    res = mysql_use_result(conn);
    printf(« MySQL Les Tables de la Database sont:\n »);
    while ((row = mysql_fetch_row(res)) != NULL)
    printf(« %s \n », row[0]);
    }

    int ecrit_table() {

    char heurechar[20] ;
    char humchar[20] ;
    char tempchar[20] ;
    char reqd[150] = « INSERT INTO `Journee »;

    strcat(reqd,(« %s »,nom_tablejm));

    char reqm[50] = « `(`heure`,`temperature`, `humidite`) VALUES (« ;

    strcat(reqd,reqm);

    char reqf[5] = « ) » ;

    sprintf(heurechar, »%d, »,heure);
    strcat(reqd,(« %s »,heurechar));
    sprintf(tempchar, »%.1f, »,data_meteo[0]);
    strcat(reqd ,(« %s », tempchar));
    sprintf(humchar, »%.1f »,data_meteo[1]);
    strcat(reqd ,(« %s », humchar)) ;
    strcat(reqd, reqf);

    //pour debug
    // printf(« la ligne: %s \n »,reqd);

    if (mysql_query(conn, reqd)) {
    fprintf(stderr, « %s\n », mysql_error(conn));
    return 1;
    }
    }

    int creat_tableJM_id()
    {

    time_t secondes;
    struct tm instant;
    time(&secondes);
    instant=*localtime(&secondes);
    sprintf(nom_tablejm, »%d_%d »,instant.tm_mday ,instant.tm_mon+1 );
    heure = instant.tm_hour ;
    char reqd[150] = « CREATE TABLE IF NOT EXISTS Journee »;
    char reqf [150] =  » (id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, heure INT, temperature FLOAT, humidite FLOAT, PRIMARY KEY (id))ENGINE=INNODB; »;

    strcat(reqd , (« %s »,nom_tablejm));
    strcat(reqd, reqf);
    // printf(« %s \n », reqd);

    if (mysql_query(conn, (« %s »,reqd)))
    {
    fprintf(stderr, « %s\n », mysql_error(conn));
    return 1 ;
    }
    return heure ;
    }
    int deconnection(){
    mysql_free_result(res);
    mysql_close(conn);
    }

    int coherence()
    {
    int e = 0;
    while ((« %.1f »,data_meteo[1]) > 100 ||(« %.1f »,data_meteo[1]) == 0 || ((« %.1f »,data_meteo[0]) > 45 ) || ((« %.1f »,data_meteo[0]) = 40){
    printf(« Appareil Hors Service ou déconnecter !!! \n »);
    system(« Attention | mail -r util@infos.fr -s DHT-HS votre@gmail.com« );
    // system(« . /sbin/shutdown -t1 -a -r now »);
    // system(‘echo Attention ‘.$nomportbtn.’ OFF | mail -r « util@infos.fr » -s « alarme » votre@gmail.com‘);
    // . /sbin/shutdown -t1 -a -r now a tester after mail
    break ;
    }
    readDHT(dhtpin);
    }
    return 3 ;
    }

    Répondre

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Complétez ce captcha SVP * Time limit is exhausted. Please reload CAPTCHA.