Archives par étiquette : javascript

10 – Module 7 – VPN

J’utilise un petit serveur VPN PPTP pour que mes amis et moi puissions facilement échanger des fichiers ou jouer ensemble en réseau 🙂 C’est très facile à mettre en place aussi bien coté serveur en installant le paquet pptpd, que coté client car c’est nativement supporté par Windows.

Ce module me permet d’afficher la liste des personnes qui sont connectées à mon serveur VPN PPTP.

jarvis_screenshot_VPNJe ne détail pas dans cet article comment installer et configurer PPTPD. Voici un tutoriel qui vous aidera à mettre en place ce type de VPN : https://help.ubuntu.com/community/PPTPServer

Le serveur pptpd étant installé sur ma gateway, il faut procéder de la même manière que pour le module graphique de la bande passante pour transférer les données sur le Pi en utilisant netcat. La seule chose de nouveau ici est la commande last qui permet de récuppérer les informations de connexion des clients du VPN.

Transférer les données vers le Pi

Côté Pi (serveur netcat) :

#!/bin/bash

### BEGIN INIT INFO
# Provides:          nc_vpn_srv
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: vpn for Jarvis
# Description:       Enable service provided by daemon.
### END INIT INFO

dst_port=12346
dst_dir=/home/jarvis/vpn
dst_file=vpn_oberon.log

nc_vpn()
{
  while [ "true" ]
  do
    nc -q 1 -u -l 12346 > $dst_dir/$dst_file < /dev/null
    sleep 5
  done
}

case "$1" in
        stop)
                echo " Stoping vpn for Jarvis..."
                killall vpn
                killall nc
                ;;
        start)
                echo " Starting vpn for Jarvis..."
                nc_vpn&
                exit 0
                ;;
        *)
                exit 1
                ;;
esac

exit 0

Côté gateway (client netcat) :

#! /bin/bash

### BEGIN INIT INFO
# Provides:          nc_vpn_clt
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: vpn for Jarvis
# Description:       Enable service provided by daemon.
### END INIT INFO

src_port=8889
dst_port=12346
dst_host=10.0.0.1

nc_vpn()
{
        while [ "true" ]
        do
                last | grep ppp | grep "logged in" | nc -q 1 -p $src_port -u $dst_host $dst_port
                sleep 5
        done
}

case "$1" in
        stop)
                echo " Stoping vpn for Jarvis..."
                killall vpn
                killall nc
                ;;
        start)
                echo " Starting vpn for Jarvis..."
                nc_vpn&
                exit 0
                ;;
        *)
                exit 1
                ;;
esac

exit 0

Excécutez ces scripts au démarrage du système en les placants dans le répertoire /etc/init.d puis exécutant la commande suivante :

update-rc.d nom_du_script.sh defaults

index.php

Une simple <div> suffit car nous voulons simplement afficher une liste d’utilisateurs :

<div id="vpn"></div>

style.css

Un petit peu de mise en forme pour faire joli 🙂

/* vpn */

div#vpn
{
  left              : 550px;
  bottom            : 10px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
  color : #FFF;
}

td.vpn
{
  text-align        : left;
  font-size         : 30px;
  padding           : 5px;
}

img.vpn
{
  width : 20px;
  height : 20px;
}

javascript.js

Une simple requête AJAX permet de récupérer les données à afficher.

/* VPN */

var vpn_timeout;

function vpn ()
{
  $.ajax({
    async : false,
    type: "GET",
    url: "./ajax.php",
    data: "block=vpn",
    success: function(html){
      $("#vpn").html(html);
    }
  });

  vpn_timeout = setTimeout("vpn()", 5000);
}

ajax.php

Rien de particulier pour ce module :

  /////////////////////////////////////////////////
  //  VPN PPTPD
  /////////////////////////////////////////////////

  if($block == 'vpn'){
    echo vpn();
  }

inc.php

Deux fonctions sont nécessaires pour ce module :

  • vpn_parseData() : parse le fichier envoyé à travers netcat
  • vpn() : créé un tableau HTML avec les noms des utilisateurs connectés
  /////////////////////////////////////////////////
  //  VPN PPTPD
  /////////////////////////////////////////////////

  function vpn () {

    $datas = vpn_parseData ("/home/jarvis/vpn/vpn_oberon.log");

    $html  = '';

    if(sizeof($datas) > 0){
      $html .= '<table cellspacing="0px">';
      foreach($datas as $data){
        $html .= '<tr>';
        $html .= '<td valign="middle"><img class="vpn" src="pict/vpn.png"></td><td class="vpn">'.$data[0].'</td>';
        $html .= '</tr>';
      }
      $html .= '</table>';
    }

    return $html;
  }

  function vpn_parseData ($stat_file) {
    $datas = array();
    if(filemtime($stat_file) < time()-10){return $datas;}
    $stats = fopen($stat_file, 'r');
    while (($line = fgets($stats)) !== false) {
      $explode_line = str_word_count($line, 1, "0123456789.");
      $datas[]  = $explode_line;
    }
    fclose($stats);
    return $datas;
  }

Et voilà pour ce dernier module qui s’avère très simple 🙂

7 – Module 4 – Ping de serveur

Si vous avez des serveurs, des NAS, ou n’importe quel autre type de machine dont vous souhaitez connaitre l’état (allumé/éteint, ou disponible/indisponible), ce type de module, encore une fois très simple, vous sera d’une grande utilité 🙂

jarvis_screenshot_pingL’idée est d’afficher en vert les serveurs qui répondent correctement aux solicitations du module, et en rouge ceux qui ne répondent pas. Pour accentuer le caractère alarmant d’une machine qui ne répond pas, nous ajouterons une animation pour optenir ce résultat :

ping

index.php

Comme pour les autres modules, une seule <div> suffit.

 <div id="ping"></div>

La balise reste vide, et sera « remplie » par la fonction JavaScript.

style.css

Pour ce module, la feuille de style est à peine plus longue :

/* ping */

div#ping
{
  left              : 0px;
  bottom            : 0px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
}

td.ping
{
  font-size         : 30px;
  text-align        : left;
  border-radius     : 10px;
  padding           : 5px 10px;
  font-weight       : bold;
}

td.ping_up
{
  color             : #00DD00;
}

td.ping_down
{
  background-image  : url('pict/warning.gif');
  color             : #DD0000;;
}

Les noms des machines sont affichés dans un tableau <table> dont chaque case <td> peut soit utiliser le style « ping_up« , si la machine répond, soit « ping_down«  si la machine ne répond pas. Dans ce dernier cas, nous utiliserons une image, un gif animé, pour faire « clignoter » la case en rouge, du mois, en donner l’impression 🙂

javascript.js

La fonction javascript de ce module ne fait qu’une requête AJAX, et affiche le résultat dans la div de la page index.php :

/* PING */

var ping_timeout;

function ping ()
{
  $.ajax({
    async : false,
    type: "GET",
    url: "./ajax.php",
    data: "block=ping",
    success: function(html){
      $("#ping").html(html);
    }
  });

  ping_timeout = setTimeout("ping()", 30000);
}

Il est important d’avoir une vision temps réel de l’état de ses machines, nous fixons donc le délai de rafraichissement à 30 secondes. Vous pouvez réduire ce délai selon vos besoins, mais veillez à ce qu’il reste supérieur au temps que met la fonction PHP pour tester toutes vos machines. Dans mon cas, je surveille six machines dont trois à travers internet. En moyenne, il faut 4 à 5 secondes pour tester toutes les machines. Toutefois, il n’est pas rare que cela prenne 20 secondes ! J’ai donc fixer à 30 secondes le temps à attendre entre chaque rafraichissement du module.

ajax.php

Il suffit de rajouter ces quelques lignes au fichier ajax.php pour que la bonne fonction soit appelée :

/////////////////////////////////////////////////
  //  PING
  /////////////////////////////////////////////////

  if($block == 'ping'){
    echo ping();
  }

inc.php

Dans ce fichier nous allons déclarer la fonction ping() qui est chargée de lancer les requêtes sur les différents serveurs, puis de construire le tableau HTML qui sera affiché.

En général, pour surveiller l’état d’un serveur, on utilise la commande ping qui permet simplement de savoir si la machine ciblée répond aux requêtes ICMP. Cela pose plusieurs problèmes. En effet, il est fort probable que le trafic ICMP soit bloqué par un firewall en amont du serveur visé ce qui faussera le résultat. De plus, si vous souhaiter surveiller un serveur web par exemple, il se peut très bien que la machine réponde bien aux pings, mais que le service web soit indisponible. Les pings n’ont donc que peu d’intéret…

L’idée, est plutôt de verier si les services qui tournent sur nos machines sont bien disponibles. Pour cela, nous allons simplement ouvrir une socket grâce à la fonction PHP fsockopen(). Si l’ouverture de la socket échoue c’est que le service n’est pas disponible 🙂

/////////////////////////////////////////////////
  //  PING
  /////////////////////////////////////////////////

  function ping () {
    $hosts    = array();
    // Définition des machines à tester
    $hosts_ip = array(
                    'Oberon'    => array('10.0.0.1',  '22'),    // SSH
                    'Triton'    => array('10.0.0.2',  '15915'), // TeamSpeak
                    'Ananke'    => array('10.0.0.3',  '2049'),  // NFS
                    'ds110j'    => array('10.0.0.4',  '2049'),  // NFS
                    'ds210j'    => array('10.0.0.5',  '2049'),  // NFS
                    'ds212j'    => array('10.0.0.6',  '2048')   // NFS
                );

    // pour chaque machine on test l'ouverture d'une socket sur le port spécifié
    // on stock le résultat 'up' ou 'down' dans la variable $hosts
    foreach($hosts_ip as $hostname => $host_data){
      $host_ip    = $host_data[0];
      $host_port  = $host_data[1];
      $socket     = 0;
      $socket     = @fsockopen($host_ip, $host_port, $errno, $errstr, 3);
      if($socket && !$errno){$hosts[$hostname] = 'up';}
      else{$hosts[$hostname] = 'down';}
    }

    // construction du tableau HTML
    // pour chaque machine testée, on affiche son nom et on fixe le style 'ping_up' ou 'ping_down' à la balise td
    $html  = '';
    $html .= '<table cellspacing="10px">';
    $c=0;
    foreach($hosts as $hostname => $host_status){
      if($c == 0){$html .= '<tr>';}
      $html .= '<td class="ping ping_'.$host_status.'">'.$hostname.'</td>';
      $c++;
      if($c == 2){$c = 0; $html .= '</tr>';}
    }
    if($c != 0){$html .= '</tr>';}
    $html .= '</table>';

    return $html;
  }

La variable $hosts_ip contient la liste des machines à tester et afficher. Le nom à affiché, l’adresse IP, et le port TCP du service à tester y sont stocké. Vous devez adapter les noms, adresses IP et numéro de port à vos besoins.

Comme vous pouvez le voir dans les commentaires du code, selon la machine à tester, j’ouvre une socket sur des services tels que SSH, TeamSpeak et NFS.  Cela fonctionne également très bien sur des serveurs FTP, HTTP, POP3, etc,… Tant que le service à tester écoute sur un port TCP, cela fonctionnera 🙂

Note : Il est possible d’optimiser cette fonction PHP en parallèlisant l’ouverture des sockets sur chaque machine. En effet, cette fonction teste les machines une par une ce qui peut être long… En « forkant » cette tâche grâce à la fonction PHP pcntl_fork(), il est possible de lancer toutes les requêtes d’un seul coup et ainsi diminuer le temps total que met la fonction pour renvoyer le tableau HTML à afficher. N’hésitez pas à laisser un commentaire si vous souhaitez plus de détails sur cette manière de procéder 🙂

Optimisation en utilisant le fork

Suite à la demande de lepopeye en commentaire de cet article, je vais expliquer comment paralléliser l’ouverture des sockets et ainsi gagner un temps précieux à chaque exécution de la fonction.

Le principe est simple : Pour chaque machine à tester, nous allons créer un processus fils grâce à la fonction PHP fork_pcntl() qui lancera la fonction fsockopen(). Comme les processus fils et le processus père ne peuvent pas partager de variables (à moins de faire appel à des techniques de mémoire partagée…), il convient de stocker les résultats dans une petite base de données SQlite 🙂 Le processus père attend que tous les processus fils soient terminés pour aller lire le contenu de la base de données SQlite (qui contient l’état de chaque machine). Le reste est inchangé, nous construisons le tableau HTML à afficher comme dans la fonction ping() initiale 🙂 A savoir que le fork n’est possible qu’en ligne de commande, il faudra donc adapter le fichier ajax.php de cette manière :

  /////////////////////////////////////////////////
  //  PING
  /////////////////////////////////////////////////

  if($block == 'ping'){
    echo shell_exec('php5 fork.php'); // fork.php étant le fichier dans lequel se trouve la fonction ping_fork();
  }

Voici la version « forkée » de la fonction ping(), que vous pouvez utiliser directement en la copiant dans un fichier fork.php :

function ping_fork() {

  $hosts_ip = array(
                    'Oberon'    => array('10.0.0.1',  '22'),    // SSH
                    'Triton'    => array('10.0.0.2',  '15915'), // TeamSpeak
                    'Ananke'    => array('10.0.0.3',  '2049'),  // NFS
                    'ds110j'    => array('10.0.0.4',  '2049'),  // NFS
                    'ds210j'    => array('10.0.0.5',  '2049'),  // NFS
                    'ds212j'    => array('10.0.0.6',  '2048')   // NFS
                );

  $pids  = array();

  // Connexion à la base de données sqlite et création de la table hosts_status si elle n'existe pas encore
  $db = new SQLite3('ifstat/hosts.sqlite');
  $db->exec('CREATE TABLE IF NOT EXISTS hosts_status (host_name VARCHAR(10), host_status VARCHAR(5));');

  // pour chaque machine, on créé un processus fils
  foreach($hosts_ip as $host_name => $host){
    $pids[$host_name] = pcntl_fork();
    if(!$pids[$host_name]) {
      $socket = @fsockopen($host[0], $host[1], $errno, $errstr, 3);
      if($socket && !$errno){$status = 'up';}else{$status = 'down';}
      // on attend que la table hosts_status ne soit plus verrouillée par un éventuel accès concurrent
      if($db->busyTimeout(5000)){
        $db->exec("INSERT INTO hosts_status VALUES ('$host_name', '$status');");
      }
      exit();
    }
  }

  // le processus père doit attendre que tous les processus fils soient terminés
  foreach($pids as $host_name => $pid){
    pcntl_waitpid($pid, $status, WUNTRACED);
  }

  $results = $db->query('select * from hosts_status;');

  $html  = '';
  $html .= '<table cellspacing="10px">';
  $c=0;
  while($host = $results->fetchArray(SQLITE3_ASSOC)){
    if($c == 0){$html .= '<tr>';}
    $html .= '<td class="ping ping_'.$host['host_status'].'">'.$host['host_name'].'</td>';
    $c++;
    if($c == 2){$c = 0; $html .= '</tr>';}
  }
  if($c != 0){$html .= '</tr>';}
  $html .= '</table>';

  $db->exec("DELETE FROM hosts_status;");

  return $html;
}

echo ping_fork();

Le timeout de la fonction fsockopen() est ici fixé à 3 secondes, ce qui veut dire que l’on doit attendre au moins 3 secondes avant de déclarer la machine cible comme « down » (non disponible). Dans la version non forkée de la fonction ping() si une machine ne répondait pas, il fallait attendre 3 secondes avant de tester la machine suivante, et ainsi de suite. Avec mes 6 machines, si aucune ne répond, il aurait fallu attendre 6×3 = 18 secondes avant d’avoir le résultat final. Avec la version forkée, les 6 requêtes sont envoyées en même temps. Quelque soit le nombre de machines à tester, nous aurons donc une réponse au bout de 3 secondes maximum 🙂

J’utilise à présent cette version forkée sur mon dashscreen 🙂 Merci à lepopeye de m’avoir forcé un peu la main 😉

8 – Module 5 – TeamSpeak

Si vous ne connaissez pas TeamSpeak, il s’agit d’un logiciel d’audioconférence qui permet à plusieurs personnes de discuter via Internet (pour plus d’informations http://fr.wikipedia.org/wiki/TeamSpeak). Ce module sert à afficher l’état du serveur TeamSpeak (allumé/éteint) ainsi que la liste des personnes qui y sont connectées.

jarvis_screenshot_TS3Pour obtenir ces informations j’utilise TeamSpeak 3 PHP Framework qui est téléchargeable gratuitement. Cette grosse lib PHP permet d’accéder à toutes les fonctionnalités du serveur TeamSpeak3. Que demande le peuple ? 🙂

Il suffit de télécharger et décompresser TeamSpeak 3 PHP Framework à la racine de votre répertoire web.

index.php

Comme pour les autres modules, une seule <div> suffit. Vous commencez à avoir l’habitude 😉

 <div id="ts3"></div>

La balise reste vide, et sera « remplie » par la fonction JavaScript…

style.css

Feuille de style minimaliste pour ce module :

/* ts3 */

div#ts3
{
  left              : 340px;
  bottom            : 10px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
  color             : #FFF;
  font-weight       : bold;
  text-align        : center;
}

td.ts3_user
{
  text-align        : left;
  font-size         : 30px;
  padding-left      : 10px;
}

javascript.js

Encore une fois, une simple requête AJAX permet de récupérer les informations à afficher.

/* TS3 */

var ts3_timeout;

function ts3 ()
{
  $.ajax({
    async : false,
    type: "GET",
    url: "./ajax.php",
    data: "block=ts3",
    success: function(html){
      $("#ts3").html(html);
    }
  });

  ts3_timeout = setTimeout("ts3()", 10000);
}

Le délai de rafraichissement est fixé à 10 secondes pour voir rapidement qui se connecte/déconnecte du serveur.

ajax.php

Cela se passe d’explications…

  /////////////////////////////////////////////////
  //  TS3
  /////////////////////////////////////////////////

  if($block == 'ts3'){
    echo ts3();
  }

inc.php

C’est ici que nous utilisons TeamSpeak 3 PHP Framework.

Dans un premier temps j’ouvre une socket sur le port 30033 (comme pour le Module 4 – Ping de serveur) pour vérifier que le serveur TeamSpeak tourne bien. Si oui, alors j’affiche la bannière du serveur (l’image triton_ts3.png), puis j’utilise  TeamSpeak 3 PHP Framework pour récupérer la liste et l’état des utilisateurs connectés 🙂

  /////////////////////////////////////////////////
  //  TS3
  /////////////////////////////////////////////////

  function ts3 () {

    $host_ip    = '10.0.0.1';
    $host_port  = '30033';
    $socket     = 0;
    $socket     = @fsockopen($host_ip, $host_port, $errno, $errstr, 3);
    $html       = '';

    if($socket && !$errno){
      require_once("./TS3_PHP_Framework-1.1.12/libraries/TeamSpeak3/TeamSpeak3.php");
      $ts3_ServerInstance = TeamSpeak3::factory("serverquery://login:password@10.0.0.1:10011/");
      $ts3_VirtualServer  = $ts3_ServerInstance->serverGetById(1);

      $html .= '<img width="200px" src="pict/triton_ts3.png" style="margin-bottom : 10px;">';
      $html .= '<table cellspacing="0px" cellpadding="0px">';
      foreach($ts3_VirtualServer->clientList() as $client){
        if($client["client_unique_identifier"] == 'serveradmin'){continue;}
        $html .= '  <tr>';
        $html .= '    <td valign="middle">';
        $html .= '      <img style="width : 20px;" src="./TS3_PHP_Framework-1.1.12/images/viewer/'.$client->getIcon().'.png" alt="">';
        $html .= '    </td>';
        $html .= '    <td valign="middle">';
        $html .= '      '.htmlspecialchars($client);
        $html .= '    </td>';
        $html .= '  </tr>';
      }
      $html .= '</table>';
    }

    return $html;
  }

Ce module est très simple à réaliser grâce à la lib  TeamSpeak 3 PHP Framework 🙂

6 – Module 3 – Météo

Intéressons nous maintenant au module météo qui affiche la météo du jour et les prévisions pour 3 à 5 jours.

jarvis_screenshot_meteoCe module est particulièrement délicat car il est très difficile à personnaliser. En effet, il s’agit d’utiliser des « widgets » mis à disposition par des sites spécialisés et qui proposent des options de configuration limitées. Pour le moment, je n’ai pas encore trouvé de design qui me plaise totalement, je change régulièrement le type d’affichage jusqu’à en trouvé un qui me plaise et qui soit suffisamment lisible de loin.

J’aime beaucoup le design de la météo Google, qui apparait automatiquement quand vous taper « météo » dans la barre de recherche :

meteo_googleCependant, je n’ai pas, pour le moment, trouver le moyen de l’insérer dans une page web…

Widgets

J’ai repéré 3 sites qui proposent des widgets météo plus ou moins complets et plus ou moins jolis : my-meteo.fr, tameteo.com et meteocity.com

Tous propose de personnaliser les informations à afficher, le nombre de jours de prévision, les couleurs des éléments ainsi que différents styles d’icônes.Une fois vos options choisies, le site génère du code HTML à copier/coller dans votre page.

Voici des aperçu des otpions de base de chaque site :

my-meteo.fr

my-meteo

tameteo.com

tameteo

meteocity.com

meteocityEn rédigeant cet article je me suis replongé dans les options du widget proposé par meteocity. Je suis finalement parvenu à trouver quelque chose qui me convient à peu près, même si je ne suis toujours pas emballé à 100% :

meteocity_okC’est déjà un peu plus sympa 🙂 Hormis les informations sur l’humidité et le vent, le reste est parfaitement lisible de loin. Il va falloir ruser pour masquer ces informations inutiles 😉

index.php

Nous ajoutons à notre fichier index.php une simple balise <div> qui reste vide pour le moment.

 <div id="meteo"></div>

Comment pour l’ensemble des modules de ce dashscreen, c’est une fonction JavaScript qui sera charger d’insérer le contenu à afficher dans la div du module concerné.

style.css

Cas particulier de ce module, nous n’avons pas la possibilité d’agir directement sur les styles CSS du code fourni par le site météo. Nous avons devons donc simplement positionner la div qui contiendra les informations météo.

/* meteo */

div#meteo
{
  right             : 0px;
  top               : 300px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
  color             : #FFF;
  font-weight       : bold;
  text-align        : center;
}

javascript.js

La fonction JavaScript de ce module se content d’envoyer une requête AJAX et d’insérer le résultat de la requête dans la div idoine.

/* meteo */

var meteo_timeout;

function meteo ()
{
  $.ajax({
    async : false,
    type: "GET",
    url: "./ajax.php",
    data: "block=meteo",
    success: function(html){
      $("#meteo").html(html);
    }
  });

  meteo_timeout = setTimeout("meteo()", 3600000);
}

Rafraichir les informations météo une fois par heure (toutes les 3600000 ms) est largement suffisant.

inc.php

Pour ce module nous avons besoin d’une fonction PHP qui renvoie le code généré par le widget. Ce qui nous donne une fonction très simple, dans laquelle il vous suffit de copier/coller le code HTML qui vous a généré le site météo :

/////////////////////////////////////////////////
//  Meteo
/////////////////////////////////////////////////

function meteo () {
  $meteo = 'coller ici le code HTML généré par le site météo';
  return $meteo;
}

Masquer les informations inutiles

Si vous souhaitez masquer certaines informations fournis par le widget, il suffit d’ajouter une <div> de couleur noir au dessus des éléments que vous voulez voir disparaitre.

Ajoutez une <div> dans le fichier index.php juste en dessous de la div meteo :

<div id="meteo"></div>
<div id="meteo_black"></div>

Puis modifier le fichier style.css en ajoutant le code suivant dans la section meteo :

div#meteo_black
{
  right             : 0px;
  top               : 420px;
  width             : 600px;
  height            : 100px;
  position          : absolute;
  z-index           : 9999;
  background-color  : rgba(0, 0, 0, 1);
}

Bien entendu, vous devrez adapter la position et la taille de la div en fonction de vos besoins 🙂

Voici le rendu final avec ce nouveau widget météo :

dashscreen_new_meteoJe suis plutôt satisfait du résultat car c’est très lisible et que le design est très épuré 🙂

Avec ces trois premiers modules horloge, xplanet et météo, il est déjà possible de réaliser un beau dashscreen dans votre séjour. Ces informations peuvent être intéressantes pour tout le monde et son utiles au quotidien 🙂

Les prochains modules qui vont suivres sont plus des modules de « monitoring » qui ont pour rôle la surveillance de serveurs et de réseaux.

A suivre…

5 – Module 2 – Xplanet

Voilà mon module préféré 🙂 Celui que je trouve le plus joli et qui mériterait un écran pour lui tout seul. L’affichage de la terre avec la phase d’ensoleillement et la carte des nuages en temps réel ainsi que la phase de la lune 🙂

jarvis_screenshot_xplanetCe module s’appuie sur le logiciel Xplanet qui permet de générer des images de toutes les planètes et satellites natuels du système solaire. Vous pouvez représenter, en temps réel toujours, le système solaire en entier avec la position des astres et planètes, zoomer sur une ou plusieurs planètes etc,…

Concernant la terre, vous pouvez afficher la position des villes et tout un tas d’informations météos notamment. Il est également possible de représenter nos satellites artificiels, avec leur position réelle, leur orbite, etc… Je vous laisse parcourir la galerie de screenshot de Xplanet qui donne une idée des possibilités et du rendu. Perso, je trouve cela magnifique 🙂 Un jour, j’achèterai un grand écran juste pour afficher le système solaire 😀

Xplanet

Installation

Xplanet est un soft qui existe depuis… très longtemps ! Il est dispo dans les dépôts Debian, donc pour l’installer, rien de plus simple :

apt-get install xplanet

Les maps

Xplanet contient de base une « map » pour chaque planète (une image qui représente la surface). Vous pouvez, et je vous le conseille, télécharger des maps de meilleure qualité en haute définition. Il est également intéressant de télécharger une map dédiée à la partie de la surface de la terre non exposée au soleil (nuit), sinon, Xplanet se contentera d’asombrir la map du jour.

Vous trouverez ici de nombreuses maps pour la terre et tous les autres astres du système solaire :

Exemple de map pour la terre – jour :

earth-livingExemple de map pour la terre – nuit :

night-electricXplanet se chargera de créer une combinaison des deux images pour repésenter la partie ensoleillée de la terre et la partie plongée dans l’obscurité.

Génération des images

Xplanet n’est au final qu’un générateur d’image qui représente les astres dans leur état à un instant T et depuis un certain point de vue. Tout se passe en ligne de commande, et comme vous avez pu le constater en parcourant le site web de Xplanet, il y des centaines d’options ! Je vais ici me limiter aux paramètres que j’utilise pour mon affichage.

Je génère en fait deux images distinctes, une pour la terre et une pour la lune. Voici mon fichier de configuration xplanet.conf :

[default]                       # Values in this section apply to all bodies unless overridden below.

arc_color=white
arc_thickness=1
bump_scale=3
cloud_gamma=1
cloud_ssec=false
cloud_threshold=90
color={255,255,255}             # fallback color in case an image map isn't found
draw_orbit=false
grid=false
grid1=6
grid2=15
magnify=1
marker_color=red
max_radius_for_label=3
min_radius_for_label=.01
min_radius_for_markers=40
orbit={-.5,.5,2}
orbit_color={255,255,255}       # color for the orbit
random_origin=true
random_target=true
shade=30                        # 0 = black, 100 = same as dayside
text_color={255,0,0}            # color for text (markers & body label)
twilight=6                      # blend the day and night images for
                                # pixels within this many degrees of
                                # the terminator

[sun]
"Sun"
color={255,255,166}
map=/home/jarvis/xplanet/img/sunmap.jpg
max_radius_for_label=0
shade=100

[earth]
"Earth"
color={28, 82, 110}
map=/home/jarvis/xplanet/img/land_ocean_ice_2048.jpg
night_map=/home/jarvis/xplanet/img/night-dark.jpg
cloud_map=/home/jarvis/xplanet/img/clouds_2048.jpg
min_radius_for_label=0

[moon]
"Moon"
color={100, 100, 100}
map=/home/jarvis/xplanet/img/moonmap2k.jpg

Dans les sections [earth] pour la terre et [moon] pour la lune, vous voyez les chemins vers les maps pour le mode jour « map » et le mode nuit « night_map« .

Les nuages

Vous avez également repéré la map « cloud_map » pour la terre. En effet, Xplanet permet de calquer une image ou carte des nuages sur la terre pour obtenir un résultat très réalise avec la couverture nuageuse modiale presque en temps réel.

cloud_combined_2048Vous pouvez obtenir cette carte des nuages ou « cloud_map » sur différents sites. Selon les sources, elles sont mises à jour entre 1 et 10 fois par jour : http://xplanet.sourceforge.net/clouds.php

Il convient de faire un petit script qui va télécharger la dernière carte des nuages publiée. Une tâche CRON se chargera d’exécuter le script à intervalle régulier. Voici mon script xplanet_cloud.sh :

#!/bin/sh

pat=/home/jarvis/xplanet/img/ # destination de l'image téléchargée
tmp=$pat"tmp_clouds_2048.jpg" # nom du fichier temporaire
img=$pat"clouds_2048.jpg"     # nom du fichier final

rm $tmp # supprimer l'ancien fichier temporaire

wget -O $tmp http://xplanet.sourceforge.net/clouds/clouds_2048.jpg # télécharge l'image

if [ -f $tmp ] ; then # si le fichier a bien été téléchargée...
  mogrify -resize 2000x1000 $tmp # redimenssionne l'image téléchargée pour qu'elle est la même résolution que la map "jour"
  mv $tmp $img # remplace l'ancienne image par la nouvelle
  chown -R jarvis:www-data $pat && chmod -R 775 $pat # change les droits sur le fichier
fi

N’oubliez pas de rendre le script exécutable avec un chmod 755 xplanet_cloud.sh 😉

Et voilà la tâche CRON associée qui peut être configurée en utilisant la commande crontab -e :

0 */4 * * *     /home/jarvis/xplanet/xplanet_cloud.sh

Toutes les 4 heures, le script est exécuté et une nouvelle carte des nuages est téléchargée 🙂

Générer les images

Dernière étape, lancer xplanet au démarrage du système pour qu’il génère les images de la terre et de la lune toutes les N minutes. Pour un petit script qui contient deux commandes (une pour l’image de la terre et une pour l’image de la lune). Voici mon script xplanet.sh :

#!/bin/sh

# TERRE
xplanet -conf /home/jarvis/xplanet/xplanet.conf -output /home/jarvis/xplanet/img/xplanet_earth.png -wait 120 -body earth -latitude 40 -longitude 10 -geometry 500x500 &

# LUNE
xplanet -conf /home/jarvis/xplanet/xplanet.conf -output /home/jarvis/xplanet/img/xplanet_moon.png -wait 600 -body moon -geometry 250x250 &

On passe à la commande xplanet les paramètres suivants :

  • -conf : le fichier de configuration xplanet.conf
  • -output : le fichier de sortie
  • -wait : l’intervalle de temps, en seconde, à attendre entre chaque génération d’image (120 secondes soit 2 minutes pour la terre, pour pouvoir bien observer l’ensoleillement tout au long de la journée. 600 secondes soit 10 minutes sont suffisantes pour la lune, dont la phase varie très lentement).
  • -body : nom du corps céleste à afficher, définie dans le fichier de configuration
  • -geometry : taille, en pixel, de l’image générée
  • -latitude & -longitude : permet de fixer le point centrale de l’image pour la terre. En choisissant la latitude 40 et la longitude 10, l’image sera centrée à peu près sur l’Italie. N’y voyez aucune affinité particulière avec ce pays, simplement c’est un angle de vue qui laisse apparaitre la France et toute l’Europe, l’Afrique en entière, une bonne partie de la Russie, les Amériques, et le pôle nord 🙂 C’est joli ! Vous pouvez également choisir le point de vue du soleil par exemple, pour toujours voir la face ensoleillée de la terre, ce qui permettra de voyager un peu et de ne pas voir toujours la même partie du globe 🙂

Il suffit ensuite de place ce script dans le répertoire /etc/init.d et de lancer la commande suivante pour qu’il soit exécuté à chaque démarrage du système :

update-rc.d xplanet.sh defaults

Nous avons fait la moitié du travail 🙂 Toutes les 2 minutes, une nouvelle image (de 500×500 pixels) de la terre est générée avec une carte des nuages mise à jour toutes les 4 heures. Toutes les 10 minutes, l’image de la phase de la lune ( de 250×250 pixels) est mise à jour.

xplanet_earthxplanet_moon

Il ne nous reste plus qu’à créer le module qui affiche ces images sur notre écran 🙂

index.php

Dans la page d’index, nous ajoutons deux balises <div>, contenant chacune une balise <img>, une pour la terre et une pour la lune.

  <div id="earth"><img id="img_earth" src="pict/blank.png"></div>
  <div id="moon"><img id="img_moon" src="pict/blank.png"></div>

Pour éviter l’affichage d’une erreur au chargement de la page il convient d’initialiser les sources des balises <img> avec une image vide blank.png.

style.css

La feuille de style pour ce module est très simple car il suffit de définir la position et la taille des div qui contiennent les images à afficher.

/* earth */

div#earth
{
  width             : 500px;
  height            : 500px;
  left              : 0px;
  top               : 0px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
}

/* moon */

div#moon
{
  width             : 250px;
  height            : 250px;
  left              : 500px;
  top               : 0px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
}

javascript.js

Il s’agit simplement de remplacer l’image affichée par la nouvelle image générée. Le problème c’est que le nom du fichier ne changeant pas, le navigateur aura tendance à afficher l’image qui est déjà stockée dans son cache. Pour palier ce problème nous ajouterons un timestamp (date et heure exprimées en nombre de secondes écoulée de le 1er janver 1970) dans le chemin de l’image. De cette manière le navigateur pensera qu’il s’agit d’une nouvelle image à chaque fois.

Par souci de fluidité, il convient également de précharger les images avant de les substituer à l’écran. On évite ainsi que l’image se charge au fur et à mesure de son affichage.

/* xplanet */

var xplanet_timeout;

function xplanet () {

  var now = new Date().getTime();

  /* préchargement des images */
  var img_earth = $("<img />").attr("src", "xplanet/img/xplanet_earth.png?"+now);
  var img_moon  = $("<img />").attr("src", "xplanet/img/xplanet_moon.png?"+now);

  /* affichage des nouvelles images à l'écran */
  $("#img_earth").attr("src", "xplanet/img/xplanet_earth.png?"+now);
  $("#img_moon").attr("src", "xplanet/img/xplanet_moon.png?"+now);

  xplanet_timeout = setTimeout("xplanet()", 120000);
}

La fonction est exécutée toutes les 120000ms (soit toutes les 2 minutes) ce qui, au final, fait défiler l’ensoleillement de la terre et de la lune au fil de la journée 🙂

C’est vraiment plaisant d’observer le défilement de l’ensoleillement au cours de la journée, et de pouvoir prévoir la météo des prochains jours en constant l’approche d’une grosse perturbation au nord ouest de la France 🙂

4 – Module 1 – Date et Heure

Rentrons dans le vif du sujet avec ce premier module qui affiche la date et l’heure.

jarvis_screenshot_heureCe module est très simple, entièrement réalisé en JavaScript. Le module est baptisé : horloge

index.php

Dans la page d’index, c’est donc la balise <div> avec l’id horloge qui nous intéresse.

 <div id="horloge"></div>

La balise reste vide, et sera « remplie » par la fonction JavaScript.

style.css

Comme pour tous les modules, il convient de créer un div dont l’id correspond au nom du module (ici horloge) qui contiendra les informations à afficher, puis de définir sa taille et sa position sur l’écran.

/* horloge */

div#horloge
{
  right             : 0px;
  top               : 0px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
  color             : #FFF;
  font-weight       : bold;
  text-align        : center;
}

div.horloge_heure
{
  font-size         : 180px;
  background-color  : rgba(0, 0, 0, 1);
}

div.horloge_date
{
  font-size         : 50px;
  background-color  : rgba(0, 0, 0, 1);
}

span.horloge_grey
{
  color             : #888;
  font-size         : inherit;
}

javascript.js

Cette fonction très simple se base sur l’heure du système, et affiche les heures sur 24h et les minutes en gros, puis juste en dessous, le jour de la semaine, je jour dans le mois, le nom du mois et l’année.

var horloge_timeout;

function horloge()
{
  dows  = ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"];
  mois  = ["janv", "f&eacute;v", "mars", "avril", "mai", "juin", "juillet", "ao&ucirc;t", "sept", "oct", "nov", "d&eacute;c"];

  now          = new Date;
  heure        = now.getHours();
  min          = now.getMinutes();
  sec          = now.getSeconds();
  jour_semaine = dows[now.getDay()];
  jour         = now.getDate();
  mois         = mois[now.getMonth()];
  annee        = now.getFullYear();

  if (sec < 10){sec0 = "0";}else{sec0 = "";}
  if (min < 10){min0 = "0";}else{min0 = "";}
  if (heure < 10){heure0 = "0";}else{heure0 = "";}

  horloge_heure   = heure + ":" + min0 + min;
  horloge_date    = "<span class='horloge_grey'>" + jour_semaine + "</span> " + jour + " " + mois + " <span class='horloge_grey'>" + annee + "</span>";
  horloge_content = "<div class='horloge_heure'>" + horloge_heure + "</div><div class='horloge_date'>" + horloge_date + "</div>";

  $("#horloge").html(horloge_content);

  horloge_timeout = setTimeout("horloge()", 1000);
}

Toutes les 1000 ms, soit chaque secondes, le contenu de la div horloge est mis à jour avec le contenu de la variable horloge_content. Vous pouvez d’ailleurs afficher les secondes sur l’écran si vous le souhaitez 🙂

Et voilà pour ce premier module très très simple mais parmis les plus utiles, pour se mettre en jambe 🙂