Le 31 mai 2015

Contrôler son Raspberry pi avec une appli sur Android sur son téléphone

Thermostat réglable à distance.

Le but est d'agir sur les GPIO du PI depuis une appli sur son téléphone.
Dans mon cas, j'ai acheté une petite carte à relais (4 euros pour le modèle à 2 relais isolés par optos) et je commande un relais depuis mon téléphone qui commande une chaudière (le pi est branché à la place du thermostat d'ambiance qui, pour moi était inexistant).

  

Dans cet article, je vais (essayer de) vous expliquer comment faire l' interface graphique pour piloter votre pi.

Pré requis : Le pi doit avoir une adresse ip connue de l'extérieur si on veut s'en servir ailleurs qu'à la maison.
On a donc :
- une adresse IP du pi en interne (locale comme 192.168.0.12)
- une adresse IP du pi en externe (WAN comme 90.105.40.22 - c'est juste un exemple - je ne vous donne pas la mienne ;-). dans ce cas il faut aussi s'occuper de la box (NAT etc.).

Principe :
Sur le pi : Apache + PHP
Sur le téléphone : une appli graphique faite sous App-inventor (gratuit - il faut quand même un compte Google)

Réalisation :
Sur le pi on créé une page appi.php.
Sur le téléphone, il suffit que l'application cherche à se connecter à http://adrpi/appi.php?action=toto (adrpi représente l'adresse du pi)
Dans la page appi.php on récupère l'action et on titille les GPIO en fonction de cette action.
On peut même faire plus avec http://adrpi/appi.php?action=toto&value=machin voire http://adrpi/appi.php?action=toto&value=machin&value2=truc
(Notez que j'utilise action, value et value2 mais vous êtes entièrement libre).

Comme j'ai un capteur de température sur mon pi, j'ai aussi besoin d'en avoir l'information sur mon téléphone. Aussi quand je lance une action sur la page php, celle-ci me retourne systématiquement  une page vide avec, comme titre les informations voulues. En effet, dans sa version actuelle (2.0) apache ne peut utiliser d'autres méthodes que http et seule l'information titre, dans ce cas peut être exploitée par le composant WebViewer de App-inventor.

Page php (appi.php) :

D'abord récupérer toutes les commandes passées à appi.php. Contenu de appi.php :

<?php
foreach ($_GET as $k=>$v) {
   $$k=$v;
   echo "<!-- $i $k=${$k} -->\n";
   $i++;
}
Ceci créera les variables action, value et value2 avec leurs valeurs remplies (par exemple $action=toto)
La deuxième ligne (echo) sert juste à mettre dans un commentaires les valeurs reçues (pour debug).
Une fois ceci fait, un vulgaire switch sur action, par exemple vous permet de faire ce que vous voulez :
$act=strtolower(substr($action,0,5));

echo "<!-- act=$act -->$n";

switch($act) {
case "allum":
   $type = "Start";
   system("$site/startchau.py",$cr);
   if($cr==0) {
   respond();
}
break;
case "etein":
  $type = "Stop";
...

Le retour des infos :
J'avais besoin de connaître l'état de la chaudière (allumée ou éteinte, la température de consigne de jour, celle de nuit, la température mesurée, etc.
J'ai choisi un format dont les valeurs sont séparées par <deux points> et décidé de communiquer les températures en centièmes de degrés pour ne pas avoir de virgules. Ainsi 19,5 °C était représenté par 1950. L'ordre des informations était aussi fixe :
État de la chaudière (0 ou 1), température de consigne de jour, température de consigne de nuit, température mesurée... Et ça donne :
1:2100:1600:1947
grâce à une petite fonction qui s'en occupe
(je ne vous donne pas le détail de toutes mes variables, mais vous en reconnaîtrez sûrement quelques unes)

function respond() {
   global $mode, $state, $consj, $consn, $nuitd, $nuitf, $temp, $noty;
   print "<html><head>\n";
   print "<title>$mode:$state:$consj:$consn:$nuitd:$nuitf:$temp:$noty</title>\n";
   print "</head><body>\n";
   print "$mode:$state:$consj:$consn:$nuitd:$nuitf:$temp:$noty\n";
   print "</body></html>\n";
}

Les "\n" sont là pour faire plus joli si on doit examiner le code source de la page
... qui produit donc ceci (exemple partiel) :

<html><head>
<title>1:2100:1600:1947</title>
</head><body>
1:2100:1600:1947
</body></html>

Le téléphone n'avait plus qu'à se débrouiller avec ça :-)
Notez que la ligne encadrée par les balises body n'est pas indispensable.

L'appli graphique :

Justement parlons-en. Sous App-inventor, dans la liste des User interface, on trouve le composant WebViewer.
On le glisse dans son projet et on le rend invisible. On coche également la case IgnoreSslerrors (pour éviter "page Web non trouvée").

Quand je veux allumer la chaudière, j'envoie http://adrpi/appi.php?action=allume et ma page php reçoit donc la variable $action="allume".
Pour le faire depuis l'interface graphique, on passe en mode Blocks (on quitte le mode Designer), on clique une fois sur WebViever (que j'ai renommé en Appi) et on choisit
call <Appi> .GoToUrl que j'ai intégré dans une SendA (comme Send Action) qu'on appelle avec le paramètre allume (par exemple) qui arrive alors à travers la variable Action de la procédure SendA. La variable globale url contient http://90.105.40.22/appi.php (encore une fois l'IP n'est qu'un exemple)

Il faut aussi un composant Clock que l'on trouve à gauche (dans le mode Designer) dans la rubrique Sensors sur lequel on décoche TimerEnabled. J'ai réglé TimerInterval à 500 pour avoir 1/2 seconde. Comme on le voit ici, après avoir envoyé la commande, on autorise le timer à se mettre en route.

Lorsqu'il se déclenche (1/2 seconde plus tard, donc) il initialise la variable globale res pour refléter le contenu du titre de la page web (peut-être) reçue. Si res est vide, on décrémente une variable retry (fixée à 10 au début) et on quitte. Si res est remplie, on arrête le timer et on passe à l'analyse des valeurs reçues.

Voila la fonction (à peu près) complète :

LabRefresh est un label qui affiche une sorte de compte-rendu de ce qui se passe et getmots est la fonction qui analyse les données séparées par les <deux-points> pour afficher les diverses infos aux bons endroits.
On voit, dans cette fonction ce qui se passe si jamais retry arrive à 0 : on affiche le compte-rendu, on arrête le timer et ont quitte.
Je n'ai pas montré qu'à chaque passage dans la décrémentation on ajoute un point à la fin du label LabRefresh pour faire une petite animation :

Après de nombreux essais à tâtons, l'ensemble marche parfaitement (je peux aussi parler à l'interface et le résultat est bluffant :-)

NB je ne suis pas très content de la structure de mon article, si quelqu'un a de meilleures idées, je suis ouvert ;-)