Archives par étiquette : statut

10 – Le serveur de monitoring

Au départ je souhaitais pouvoir prendre la main à distance sur le Pi pour m’assurer que tout fonctionne bien durant la semaine. Cependant, les contraintes d’autonomie du Pi sur batterie me forçant à ne temporiser sont fonctionnement 2 minutes toutes les 10 minutes, la fenêtre de tir pour choper le Pi lorsqu’il est up est franchement serrée.

Sans compter sur l’autonomie, je ne pourrai pas surveiller le Pi à longueur de journée pour voir si tout fonctionne bien, que rien ne gêne les prises de vue, etc,… Il faut donc que le Pi se manifeste tout seul, régulièrement : c’est le principe du « battement de coeur ». Le Pi envoi de lui même des battements de coeur réguliers, et si les battements de coeur s’arrêtent, c’est que quelque chose à mal tourné.

L’idée est donc d’utiliser un serveur distant, qui accusera réception de ces battements de coeur, et m’enverra un mail pour me dire que tout va bien. Chaque battement de coeur sera accompagné d’une miniature de la dernière photo prise. Tout est enregistré dans une base de données, et j’ai prévu une page qui récapitule toutes les battements de coeur enregistrés avec leur photo miniature. Ce qui me permettra également d’avoir un aperçu des travaux en direct.

Inutile d’envoyer un battement de coeur à chaque prise de vue. Un mail toutes les 10 minutes, c’est trop. Deux mails par heure, c’est mieux 🙂

Serveur web – Apache

Très concrètement, le serveur de monitoring est un simple serveur web Apache, accompagné d’une base de données MySQL et de quelques scripts PHP.

Je ne détail pas ici l’installation et la configuration de ces composants. C’est un sujet bien à part qui mériterait un chapitre complet. Si vous voulez faire pareil, vous pouvez utiliser un hébergement mutualisé chez Free ou OVH (les ftp Free mis à disposition des Freenautes font également parfaitement l’affaire).

Base de données

Je n’ai besoin que d’une seule table pour enregistrer chaque battement de coeur ainsi que la photo associée. Voici le schéma de la table heartbeat que j’utilise :

CREATE TABLE `heartbeat` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `date` int(11) NOT NULL,
  `log` text COLLATE utf8_bin NOT NULL,
  `img` text COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;

Description des champs :

  • id : un simple indexe auto incrémenté
  • date : champ entier pour stocker la date du battement de coeur sous la forme d’un timestamp
  • log : champt text permettant d’enregistrer des infos diverses
  • img : champ text contenant le nom de la miniature de la photo associée au battement de coeur

Fonctions et fichier de configuration

J’ai rassembler les fonctions génériques que j’utilise dans le fichier func.php que vous pouvez télécharger ici : func.php.tar.gz

L’ensemble des paramètres de configuration des scripts PHP sont rassemblés dans le fichier conf.php que vous pouvez télécharger ici : conf.php.tar.gz

Script PHP heartbeat.php

C’est ce script qui va être appelé par la commande curl comme expliqué dans le chapitre précédent. Sont rôle est de réceptionner la photo miniature, d’enregistrer la date de réception, et d’envoyer un mail.

Je vais à l’essentiel, le code de ce script est donc très minimaliste :

<?php

header('Content-type: text/html; charset=utf-8');

// inclusion des fichiers requis
require_once('conf.php');
require_once('func.php');

// initialisation de la session
$session_id = sessionStart();
// connexion à la base de données
$db_connect = dbConnect();
// nettoie la variable $_REQUEST
$_REQUEST   = clearRequest ($_REQUEST);

// enregistre la tentative de connexion dans un fichier de log
logIt('access', 'heartbeat connection ...');

// vérifie que le token donné correspond à celui attendu ;)
if(!empty($_REQUEST['token']) && $_REQUEST['token'] == $conf['token']['heartbeat']) {

  // si le fichier est bien réceptionné
  if (is_uploaded_file($_FILES['img']['tmp_name'])) {
    if (move_uploaded_file($_FILES['img']['tmp_name'], $conf['upload_dir'].'/'.$_FILES['img']['name'])) {

      $field_data = array (
                              'date'  => time(),
                              'img'   => $_FILES['img']['name'],
                              'log'   => ''
                          );
      // enregistre le battement de coeur en base de données dans la table heartbeat
      $add        = addData ('heartbeat', $field_data);

      // titre du mail à envoyer
      $mail_title = 'Pi TimeLapse - HeartBeat '.date("d.m.y H:i:s");

      // corps du mail à envoyer, contenant la date et la minature
      $mail_core  = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
                      <html>
                        <head>
                          <title>'.$conf['site_name'].'</title>
                          <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
                          <meta http-equiv="Content-Language" content="Fr" />
                          <META name="Author" lang="fr" content="MagdiWeb" />
                          <META name="Copyright" content="© MagdiWeb" />
                        </head>
                        <body>
                          '.$mail_title.'<br>
                          '.$field_data['log'].'<br>
                          <img src="http://pi_timelapse/'.$conf['upload_dir'].'/'.$_FILES['img']['name'].'">

                        </body>
                      </html>';

      // envoie le mail
      $mail       = mailIt ('mon_adresse_mail@mail.fr', $mail_title, $mail_core);
      logIt('access', $mail_title);
    }
    else {
      logIt('access', 'unable to mv uploaded file '.$_FILES['img']['name']);
    }
  }
  else{
    logIt('access', 'error during file upload ...');
  }

}
else{
  logIt('access', 'wrong heartbeat token ...');
}

// écrit l'ensemble des messages/logs dans un fichier
writeLog ();

?>

Voici une screenshot du mail que je reçois sur mon smartphone lors de la réception d’un battement de coeur de la part du Pi (sur la photo on voit un bout de mon bureau,… c’est pour les tests 😉 :

photo

Dashboard

J’ai également prévu une page type dashboard qui affiche toutes les miniatures reçues avec les dates. Pour le moment, je ne publie pas cette page, mais lorsque le chantier commencera, je la synchroniserai avec ce blog afin que vous puissiez suivre en directe l’évolution des travaux, et constater que le dispositif fonctionne bien 🙂

Toujours aussi minimaliste, le but est simplement d’afficher l’ensemble des miniatures sous forme d’une mosaïque d’images.

<?php

header('Content-type: text/html; charset=utf-8');

require_once('conf.php');
require_once('func.php');

$session_id = sessionStart();
$db_connect = dbConnect();
$_REQUEST   = clearRequest ($_REQUEST);

if(!empty($_REQUEST['token']) && $_REQUEST['token'] == $conf['token']['index']) {

$heartbeats = selectAll ('heartbeat');

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <title><?php echo $conf['site_name']; ?></title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <meta http-equiv="Content-Language" content="Fr" />
    <META name="Author" lang="fr" content="MagdiWeb" />
    <META name="Copyright" content="© MagdiWeb" />  
    <link rel="stylesheet" type="text/css" href="style.css" />
  </head>
  <body>
    <?php
      $nb_heartbeat = sizeof($heartbeats);
      echo '('.$nb_heartbeat.' beats)';
    ?>
    <table>
    <?php
      $c = 0;
      foreach($heartbeats as $heartbeat) {
        if($c == 0){echo '<tr>';}
        echo '<td>'.humanDate ($heartbeat['date'], 'full').'<br><img src="'.$conf['upload_dir'].'/'.$heartbeat['img'].'"></td>';
        $c++;
        if($c == 4){$c=0; echo '</tr>';}
      }
    ?>
    </table>

  </body>
</html>

<?php

}else{
  logIt('access', 'wrong index token ...');
}

writeLog ();

?>

Voici une screenshot de ce que cela donne pour l’instant (toujours avec des photos de test 😉 :

Screenshot-1