IMA4 2017/2018 P49 : Différence entre versions

De Wiki de Projets IMA
(Semaine 7)
(Semaine 14)
 
(26 révisions intermédiaires par 2 utilisateurs non affichées)
Ligne 144 : Ligne 144 :
 
| 1h30
 
| 1h30
 
|
 
|
| 2h (video)
+
| 3h
 +
| 3h
  
 
|}
 
|}
Ligne 308 : Ligne 309 :
 
On réalise alors une requête POST à l'aide de la commande cURL sur l'URL renseignée au début et sur le port de réception de l'application, en n'oubliant pas d'indiquer la base de données sur laquelle ces données doivent se retrouver.  
 
On réalise alors une requête POST à l'aide de la commande cURL sur l'URL renseignée au début et sur le port de réception de l'application, en n'oubliant pas d'indiquer la base de données sur laquelle ces données doivent se retrouver.  
  
#curl -X POST '$URL:$send_port/write?db=$database' --data-binary '$data,hostname=$nodename value=$value'
+
"<i>#curl -X POST '$URL:$send_port/write?db=$database' --data-binary '$data,hostname=$nodename value=$value'</i>"
  
 
Les données, que nous pouvons retrouver derrière --data-binary, sont composées de $data qui est le nom de la table (par exemple co2, humidity, pressure, ...), $hostname correspondant à l'identifiant du noeud, et $value qui est la valeur mesurée par les capteurs.
 
Les données, que nous pouvons retrouver derrière --data-binary, sont composées de $data qui est le nom de la table (par exemple co2, humidity, pressure, ...), $hostname correspondant à l'identifiant du noeud, et $value qui est la valeur mesurée par les capteurs.
Ligne 332 : Ligne 333 :
 
==Semaine 8==
 
==Semaine 8==
  
Durant cette semaine, nous avons pu terminer la partie initialisation du script, qui prend en compte les variables  
+
<p align="justify">Durant cette semaine, nous avons pu terminer la partie initialisation du script, qui prend en compte les variables et qui récupère les données de la base de données à exploiter.</p>
 +
<BR \>
 +
 
 
[[Fichier:script_old_init.png|thumb|1200px|center|Partie du script Bash permettant l'initialisation des variables nécessaires tels que les chemins de fichiers ou encore les noms des bases de données et l'URL de l'application, mais aussi la partie où nous faisons un dump de la base de données éudiée pour l'exploiter par la suite]]
 
[[Fichier:script_old_init.png|thumb|1200px|center|Partie du script Bash permettant l'initialisation des variables nécessaires tels que les chemins de fichiers ou encore les noms des bases de données et l'URL de l'application, mais aussi la partie où nous faisons un dump de la base de données éudiée pour l'exploiter par la suite]]
  
 
+
<BR \>
 +
<p align="justify">Tout d'abord, nous avons placer une variable 'SILENT_MODE' qui, lorsqu'elle est différente de 0, permet d'obtenir un script plus verbeux qui va nous signaler dans quelle partie il se trouve actuellement (lecture de la base de données, envoie des données sur influxDB), ce qui permet un déverminage plus aisé.
 +
Vient ensuite les variables nécessaires au script, comme stipulé la semaine passée, mais avec des noms finalement différents : en effet, nous avons appris entre temps à émettre des requêtes avec SQLite directement à partir d'un script Bash et non en passant par un script dédié à SQLite, simplifiant ainsi l'arborescence de fichiers.
 +
Nous retrouvons <i>db</i> qui est la base de données elle-même dont nous récupérons les données, et dont on effectuera un 'dump' à la ligne 47 (dump auquel nous reviendrons un peu plus bas lorsque nous reparlerons des dernières variables). Ce dump sera identifié par la variable <i>db_request</i>.
 +
Des lignes 22 à 26, il s'agit de variables propres à l'utilisation de influxDB :
 +
* <i>nodename</i> permet de récupérer le nom du noeud envoyant les données pour afficher la provenance des données sur l'application.
 +
* <i>URL</i> est l'adresse URL par laquelle l'application est accessible.
 +
* <i>send_port</i> et <i>app_port</i> sont les ports respectifs de réception de données et de l'application comme vu la semaine passée
 +
* <i>influxDB_database</i> la base de données d'influxDB sur laquelle nous envoyons les données.
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
Ces 5 dernières variables permettent d'avoir un script plus dynamique et plus adaptable en cas de changement d'application (changement des ports de référence d'influxDB, données pour du suivi médical et non du suivi de qualité d'air, nouvelle adresse du serveur).
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
Nous trouvons enfin les 5 nouvelles variables dont nous parlions au début, que nous n'étions pas obligé de (ne devrions pas d'ailleurs) placer ici, nécessaires au bon déroulement de ce programme dans notre cas :
 +
* <i>table</i> : il s'agit du nom de la table que parcourt le script lors de la lecture du dump de la base. En effet, le dump est constitué des lignes permettant de créer la base Sensors.db, soit la création des tables ('CREATE TABLE') puis le remplissage de celles-ci ('INSERT INTO ... VALUES').<BR \>
 +
</p>
 +
<BR \>
 
[[Fichier:script_old_dump.png|thumb|1200px|center|Document obtenu (volontairement tronqué) suite au dump de la base de données Sensors.db ]]
 
[[Fichier:script_old_dump.png|thumb|1200px|center|Document obtenu (volontairement tronqué) suite au dump de la base de données Sensors.db ]]
 +
<BR \>
 +
<p align="justify">
 +
La technique que nous utiliserons dans ce script  va consister à récupérer les données de la table <i>data</i>, et il nous faut donc savoir dans quelle table nous nous trouvons. C'est l'intérêt de cette variable. En effet, les 3 variables suivantes sont contenues dans la table <i>data</i> :
 +
* <i>timestamp</i> : ou horodatage en anglais, sera la date et l'heure d'émission des données envoyée à influxDB
 +
* <i>timestamp_old</i> : l'ancien <i>timestamp</i>, permettant de comparer les variables et de savoir si nous avons fait le tour des valeurs mesurées à un même moment. Nous pouvons alors ajouter ou enlever des capteurs de la station sans aucun problème.
 +
* <i>value</i> : tout simplement la valeur mesurée par les capteurs que nous envoyons à l'application en ligne.
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
La dernière variable, <i>sent</i> est le 'flag' permettant de savoir si les valeurs correspondant à telle date ont déjà été envoyées sur l'application ou non. Elle est cependant contenue dans la table <i>polls</i>.
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
Une fois les variables créées, le script peut commencer, et la première étape est donc le dump de la base de données <i>Sensors.db</i> (ou <i>$db</i>). Nous demandons donc à SQLite (SQLite3 étant installé sur le système en question) de faire un dump grâce à la commande <BR \>
 +
"<i><b>sqlite3</b> base_de_données <b>.dump</b></i>".
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
Ce dump est envoyé vers <i>$db_dump</i> afin d'être lu plus tard par le programme pour récupérer les données au travers des variables vues ci-dessus avant de les envoyer sur influxDB.
 +
</p>
  
 
==Semaine 9==
 
==Semaine 9==
  
  
<b>
+
 
 
[[Fichier:script_old_read.png|thumb|1200px|center|Partie du script Bash traitant le fichier de la base de données pour en extraire les variables à envoyer à l'application sur le serveur, via une requête POST ]]
 
[[Fichier:script_old_read.png|thumb|1200px|center|Partie du script Bash traitant le fichier de la base de données pour en extraire les variables à envoyer à l'application sur le serveur, via une requête POST ]]
  
<p align='justify'>Nous avons terminé la lecture du dump de Sensors.db et arrivons à extraire les données que nous souhaitons envoyer. Les données sont stockées dans trois variables <i>sensor</i>, <i>value</i> et <i>timestamp</i> permettant donc de savoir sur quelle table envoyer les données, grâce à <i>sensor</i>, que sont la valeur <i>value</i> récupérée par le capteur au temps <i>timestamp</i>.
+
<p align='justify'>
La requête POST, commentée dans la capture ci-dessus, fonctionne correctement pour une seule donnée en console et ne devrait donc pas poser de problèmes lors de l'envoi de toutes les données.</p>
+
Nous avons terminé la lecture du dump de Sensors.db et arrivons à extraire les données que nous souhaitons envoyer grâce à la commande <i>cut</i> appliquée sur chaque ligne du dump de la base de données.  
<p align='justify'>L'envoi des données se fera donc en N requêtes CURL où N est le nombre de données à envoyer. Cette solution n'étant pas optimale, nous aurons probablement à l'avenir à créer un fichier contenant les données à envoyer sous un certain format, facilement exploitable par CURL pour l'envoi de données sur InfluxDB. Suite à l'envoi des données concernant une certaine date de mesure, le <i>timestamp</i> change, et nous pouvons donc informer la base de données que les données ont bien été envoyées sur l'application influxDB en mettant le flag <i>sent</i> à 1.</p>
+
En effet, chaque ligne contenant des données suivant le format suivant :<BR \>
  
 +
<i><b>INSERT INTO</b> "data" <b>VALUES</b>(sensors_identifier,data,poll_time);</i> ,<BR \>
  
<p align='justify'>Nous sommes retournés à l'INRIA pour récupérer des données et effectuer ainsi des tests du script lorsqu'il sera complètement terminé. Nous avons donc fait des dump des bases de données config.db et sensors.db qui stockent, réciproquement, les configurations des capteurs (offset, sensibilité, unités de mesure) et les valeurs récupérées par les capteurs avec leur timestamp et autres informations (donnée envoyée par exemple). Les bases de données ont chacune deux tables, que voici représentées : </p>
+
il nous faut récupérer la partie après la première parenthèse contenant les valeurs, soit le champ 2 en prenant comme symbole de découpage '('. Les données sont ensuite séparées par des virgules, nous récupérons les champs 1, 2 et 3 respectivement dans nos variables <i>$sensor</i>, <i>$value</i> et <i>timestamp</i> permettant donc de savoir sur quelle table envoyer les données, grâce à <i>sensor</i>, que sont la valeur <i>value</i> récupérée par le capteur au temps <i>timestamp</i>.
 +
La requête POST, commentée dans la capture ci-dessus, fonctionne correctement pour une seule donnée en console et ne devrait donc pas poser de problèmes lors de l'envoi de toutes les données.<BR \>
 +
<i>(spoiler du futur : tout ne se passe jamais comme prévu)</i>
 +
</p>
 +
<BR \>
 +
<p align='justify'>
 +
L'envoi des données se fera donc en N requêtes CURL où N est le nombre de données à envoyer. Cette solution n'étant pas optimale, nous aurons probablement à l'avenir à créer un fichier contenant les données à envoyer sous un certain format, facilement exploitable par CURL pour l'envoi de données sur InfluxDB. Suite à l'envoi des données concernant une certaine date de mesure, le <i>timestamp</i> change, et nous pouvons donc informer la base de données que les données ont bien été envoyées sur l'application influxDB en mettant le flag <i>sent</i> à 1.
 +
</p>
 +
 
 +
 
 +
<p align='justify'>
 +
Nous sommes retournés à l'INRIA pour récupérer des données et effectuer ainsi des tests du script lorsqu'il sera complètement terminé. Nous avons donc fait des dump des bases de données config.db et sensors.db qui stockent, réciproquement, les configurations des capteurs (offset, sensibilité, unités de mesure) et les valeurs récupérées par les capteurs avec leur timestamp et autres informations (donnée envoyée par exemple). Les bases de données ont chacune deux tables, que voici représentées :  
 +
</p>
  
 
<BR \>
 
<BR \>
Ligne 358 : Ligne 413 :
  
  
<p align='justify'>Nous avons donc modifié le script Bash afin de le rendre plus propre. Nous reconstruisons les bases de données présentes sur la Raspberry de l'INRIA à l'aide des dumps récupérés. Nous reprenons l'idée d'un script de requêtes SQL permettant d'effectuer une requête SQL pour obtenir les données à envoyer, avec leur timestamp et les données des capteurs et de rediriger le résultat de cette requête vers un document que lira le script Bash pour en extraire les informations à l'aide de commandes cut.</p>
+
<p align='justify'>
<p align='justify'>L'architecture du script Bash ne change donc pas, et conserve les phases suivantes :
+
Nous avons donc modifié le script Bash afin de le rendre plus propre. Nous reconstruisons les bases de données présentes sur la Raspberry de l'INRIA à l'aide des dumps récupérés. Nous reprenons l'idée d'un script de requêtes SQL permettant d'effectuer une requête SQL pour obtenir les données à envoyer, avec leur timestamp et les données des capteurs et de rediriger le résultat de cette requête vers un document que lira le script Bash pour en extraire les informations à l'aide de commandes cut.
<ul><li>Affectation des variables</li>
+
</p>
<li>Ouverture de la base de données et récupération des données à envoyer</li>
+
<p align='justify'>
<li>Envoi des données sur InfluxDB</li>
+
L'architecture du script Bash ne change donc pas, et conserve les phases suivantes :
<li>Vérification de l'envoi des données et mise à jour de la base</li>
+
<ul><li>Affectation des variables</li>
</ul>
+
  <li>Ouverture de la base de données et récupération des données à envoyer</li>
 +
  <li>Envoi des données sur InfluxDB</li>
 +
  <li>Vérification de l'envoi des données et mise à jour de la base</li>
 +
</ul>
 +
</p>
  
De plus, nous avons pu commencer le tutoriel sur docker qui devrait nous permettre de faciliter le déploiement de nos différents nœuds et de réduire l'encombrements à l'aide des compartiments docker.
+
 
 +
<b>
 +
De plus, nous avons pu commencer le tutoriel sur docker qui devrait nous permettre de faciliter le déploiement de nos différents nœuds et de réduire l'encombrement à l'aide des compartiments docker.
 
</b>
 
</b>
 
  
 
==Semaine 10==
 
==Semaine 10==
  
 
+
<p align="justify">
[[Fichier:script_new_init.png|thumb|1200px|center|Initialisation du script Bash après changement de technique pour la lecture de la base de données Sensors.db ]]
+
La semaine précédente, nous avions changé de technique d'approche concernant la lecture de la base de données. Bien que nous étions restés sur le fait de passer par un dump de la base de données nous intéressant, nous ne passions plus par un script SQL, mais nous avions rentré ces commandes directement dans le script Bash.
 
+
</p>
 +
<BR \>
  
 
[[Fichier:script_new_sql.png|thumb|1200px|center|Partie du script permettant de lire la base de données Sensors.db ]]
 
[[Fichier:script_new_sql.png|thumb|1200px|center|Partie du script permettant de lire la base de données Sensors.db ]]
  
 +
<p align="justify">
 +
Cette semaine, nous avons profité jusqu'au bout de la possibilité d'entrer des commandes directement depuis le script Bash pour changer l'approche de lecture de la base de données : plutôt que de passer par un dump de la base de Sensors.db, nous effectuons directement notre requête SQL dans le script, à savoir récupérer les identifiants des capteurs <i>sensor_identifier</i>, la valeur  mesurée <i>data</i> et l'heure d'émission de la valeur, le timestamp, <i>poll_time</i> de la table <i>data</i>. Nous effectuons une jointure entre les tables <i>data</i> et <i>polls</i> sur le timestamp présent dans les deux tables. <BR \>
 +
Cette jointure nous permettra donc de filtrer les données déjà envoyées sur l'application en ligne grâce au flag <i>sent</i> de la table <i>polls</i>. Nous ordonnons ensuite les valeurs par horodatage croissant pour respecter l'ordre chronologique.
 +
<BR \>
 +
Le résultat de cette requête sera envoyé vers <i>$db_request</i>, variable pointant vers le document grâce auquel nous allons récupérer les valeurs à envoyer.
 +
</p>
 +
<BR \>
 +
[[Fichier:script_new_init.png|thumb|1200px|center|Initialisation du script Bash après changement de technique pour la lecture de la base de données Sensors.db ]]
 +
<BR \>
 +
<p align="justify">
 +
Ce changement nous a donc permis de simplifier notre technique pour récupérer les valeurs : plutôt que de faire des <i>cut</i> en fonction du début de la ligne lue (<i>CREATE TABLE</i> ou encore <i>INSERT INTO</i>), nous savons que nous disposons directement des bonnes valeurs et il nous reste alors à faire le découpage des valeurs. Nous gagnons donc en complexité et donc en temps de réponse étant donné que nous n'avons alors plus besoin de lire toutes les lignes pour créer les tables et surtout les lignes permettant de remplir les tables ne nous intéressant pas. De plus, le filtre du à la sélection des données n'ayant pas encore été envoyées diminue le nombre de résultats suite à notre requête.
 +
</p>
  
 
==Semaine 11==
 
==Semaine 11==
  
<b>
+
<p align="justify">
Bash :
+
Concernant le script, nous avons donc continué et passé à la partie envoi de données. Connaissant la commande permettant d'envoyer les données et ayant déjà récupérer les valeurs à envoyer, nous pensions que cela se ferait assez facilement.
Continuation lecture base de donnée et envoie des données + test sur l'application (problèmes)
+
En effet, influxDB accepte de recevoir les données grâce à la commande <i>cURL</i>, écrite de la manière suivante :<BR \>
</b>
+
"<i><b>curl -XPOST</b> "adresse_influxDB<b>:</b>port_envoi<b>/write?db=</b>base_données_influxDB" <b>--data-binary "</b>table_influxDB,<b>hostname=</b>ID_noeud <b>value=</b>valeur_envoyée heure_de_la_valeur"</i> <BR \>
 
+
le XPOST signifiant que nous effectuons une requête HTTP avec une méthode POST pour envoyer les données à l'application.
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
Cependant, afin de pouvoir envoyer les données de manière dynamique et en passant donc par des variables, il a fallu effectuer plusieurs tests pour que la commande reconnaisse l'adresse sur laquelle envoyer les données et les données en elle-même.<BR \>
 +
La solution que nous avons trouvé a été de créer une nouvelle variable qui, à partir des variables générales en début de script, reconstitue l'adresse de l'application en une seule chaine de caractères. Les données, elles, sont traitées de la même manière et nous reconstituons donc la requête à partir des variables obtenues suite au découpage de la requête SQL. Nous obtenons ainsi les deux variables suivantes :<BR \>
 +
* <i>site="$URL:$send_port/write?db=$influxDB_database"</i><BR \>
 +
* <i>data="$sensor, hostname=$nodename value=$value $timestamp"</i><BR \>
  
 +
et la commande devient alors : <BR \>
 +
<i>curl -XPOST $site --data-binary $data</i><BR \>
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
Cependant, cette solution n'est pas tout a fait ce que nous espérions. En effet, lors d'une requête HTTP, différents codes peuvent être renvoyés suite à l'envoi de données sur un serveur. Un code de 2XX (comprendre entre 200 et 299) signifiera un succès de la requête, 3XX une redirection de la requête, 4XX une erreur du client web et 5XX une erreur du serveur (les codes 1XX étant des informations).
 +
Nous souhaitons donc être sûrs que notre requête a bien fonctionné, autrement dit que influxDB a bien reçu les valeurs que nous avons envoyé. Pour cela, il nous faut recevoir un code 2XX, souvent 204 pour influxDB. Nous n'avons pas encore trouvé la solution de ce problème, mais nous songeons à rediriger le code reçu sur un document texte qui, après découpage grâce à <i>cut</i>, nous permettra d'obtenir le code. Cependant ce procédé est lourd et nous cherchons d'autres solutions.
 +
</p>
  
 
==Semaine 12==
 
==Semaine 12==
Ligne 401 : Ligne 489 :
 
*passez par le docker swarm afin de créer un cluster de raspy workers avec le serveur qui ferait office de manager.
 
*passez par le docker swarm afin de créer un cluster de raspy workers avec le serveur qui ferait office de manager.
 
*Le fichier de config doit renommer le noeuds (en fonction de ceux déjà existants?)lancer le téléchargement. A long terme il devra aussi demander les capteurs présents et leur emplacement afin de connaitre l'architecture de la maquette
 
*Le fichier de config doit renommer le noeuds (en fonction de ceux déjà existants?)lancer le téléchargement. A long terme il devra aussi demander les capteurs présents et leur emplacement afin de connaitre l'architecture de la maquette
******************
 
* Envoie des données sur le serveur (correction du problème)<\BR>
 
* Barre de progression lors du déroulement du script<\BR>
 
* Recupération du code renvoyé par la requête HTTP ( /!\ MODIFIER LES 'REQUETES POST' PAR 'METHODRE POST')<\BR>
 
* boucle en cas de problème d'envoi<\BR>
 
* INSTALLATION DE BC SUR LES NOEUDS
 
 
</b>
 
</b>
  
 +
<p align="justify">
 +
Concernant l'avancé du script, nous avons réussi à envoyer les données sur l'application et à récupérer le statut HTTP après la lecture du manuel concernant cURL. Il se trouve que nous pouvons récupérer le statut HTTP grâce à "<i>--write-out</i>". Et pour retirer tout affichage nuisible au bon déroulement du script, nous appliquons aussi l'argument "<i>--silent</i>" permettant de passer la commande cURL de manière moins verbeuse. Après avoir fait un test, le programme fonctionne correctement et nous recevons bien des statuts 204. Prouvant le bon déroulement du programme, nous recevons bien les données sur influxDB et pouvons ainsi les voir sur internet.
 +
</p>
 +
<BR \>
 +
<p align="justify">
 +
Afin de montrer la progression du script lors de son exécution, nous avons réalisé un affichage s'actualisant au fur et à mesure de la progression du script en mettant en avant le nombre de valeurs déjà traitées, le total de valeurs à traiter, et le pourcentage de progression.<BR \>
 +
Cet affichage ayant nécessité une division entre deux nombres, il nous a fallu installer le paquet <i>bc</i> permettant de réaliser des calculs et de gérer les flottants dans un script Bash.
 +
Par conséquent, il sera très important de ne pas oublier d'installer <i>bc</i> lors de l'installation de noeuds pour lancer le script de manière manuelle. En effet, il sera intéressant pour l'opérateur de voir que le programme s’exécute correctement, et que le système n'a pas planté.<BR \>
 +
Cependant, les noeuds devant lancer le script de manière automatique n'ont pas d'opérateur derrière visualisant la console, et cette partie sera donc inutile la plupart du temps.
 +
</p>
  
 
==Semaine 13==
 
==Semaine 13==
  
<b>
+
 
* Programme quasi fini jusqu'à la perte des données => la prochaine fois, faudra utiliser Git (retour 2 semaines avant)
+
<p align="justify">
</b>
+
Le programme arrivait à son terme, seul rester la mise à jour de la table de données avec un <i>sqlite3 UPDATE</i>. Les données étaient correctement récupérées, bien envoyées sur influxDB où nous pouvions les visualiser en direct, avec la progression du script en cours possible en console. Cependant une erreur de manipulation de fichiers nous a fait perdre les deux dernières semaines. Bien que nous sachions comment faire, il va nous falloir un peu de temps pour remettre au point le programme en l'état.
 +
<BR \>
 +
Ce problème aura au moins soulever le point que nous aurions du utiliser un système de versionnage comme Git plutôt que de se satisfaire de copier-coller de temps à autre.
 +
<BR \>
 +
Du coup, voici le lien du nouveau Git :
 +
https://github.com/Nicolas-Havard/Apolline
 +
</p>
  
 
==Semaine 14==
 
==Semaine 14==
  
<b>
+
 
* rattrapage du temps perdu
+
 
* finition du programme bash => temps long (environ 325 secondes pour envoyer 1000 valeurs)
+
<p align="justify" >
 +
Cette semaine nous avons récupéré le programme tel qu'il était avant la suppression des fichiers et avons donc retrouvé un script permettant d'envoyer les données sur influxdb avec la progression du déroulement du script en direct. <BR \>
 +
</p>
 +
<BR \>
  
 
[[Fichier:script_data sending.png|thumb|1200px|center|Partie du script permettant d'envoyer les données sur la base influxDB et de mettre à jour la base de données pour indiquer que les valeurs ont été envoyées ]]
 
[[Fichier:script_data sending.png|thumb|1200px|center|Partie du script permettant d'envoyer les données sur la base influxDB et de mettre à jour la base de données pour indiquer que les valeurs ont été envoyées ]]
  
 +
<BR \>
 +
<p align="justify">
 +
Nous avons aussi mis au point la mise à jour de la base de données concernant le flag <i>sent</i> et son passage à 1 lorsque toutes les valeurs ayant été envoyées pour ce timestamp ont été récupérées pas l'application. Après quelques problèmes de syntaxe, nous sommes parvenus à résoudre notre problème en construisant la requête SQL dans une variable à part avant de la donnée en paramètre de la commande <i>sqlite3</i>.
 +
Comme nous pouvons le voir ci-dessous, la mise à jour de la base de données est bien prise en compte :
 +
</p>
 +
<BR \>
 +
[[Fichier:data_sent.png|thumb|720px|center|Dump de la base de données Sensors.db après l'exécution du script ]]
 +
<BR \>
 +
<p align="justify">
 +
Nous avons de plus ajouter un document permettant de visualiser les données ayant été envoyées par le programme, à la manière d'un historique, lors de la récupération des valeurs. Ce fichier est donc composé des éléments envoyés sous la forme <i>ID_sensor | value | timestamp</i> :
 +
</p>
 
[[Fichier:data_example.png|thumb|480px|center|Exemple de valeurs récupérées lors de l'envoi des données grâce aux 'cut' du résultat de la requête ]]
 
[[Fichier:data_example.png|thumb|480px|center|Exemple de valeurs récupérées lors de l'envoi des données grâce aux 'cut' du résultat de la requête ]]
 +
<BR \>
 +
<p align="justify">
 +
Cependant, à l'issu de ce programme, nous pouvons constaté que le temps d'envoi des données vers l'application web est long : environ 325 secondes, soit presque 5 min 30 pour envoyer 1000 valeurs. En partant de cette mesure, et en supposant que le temps d'exécution soit linéaire ou autrement dit en O(n) où n est le nombre de valeurs envoyées, étant donné que nous ne disposons que d'une boucle, il nous faudrait donc 3.5 secondes pour envoyer 10 valeurs soit 7 secondes pour en envoyer 20. Le noeud sur lequel nous avons pu faire des essais disposant de 18 capteurs, et prenant des mesures toutes les 30 secondes, il nous faudrait donc "perdre" 7 secondes toutes les 30 secondes pour envoyer les valeurs sur le serveur.<BR \>
 +
Il est toutefois possible d'améliorer ce programme en complexité. En effet, <i>cURL</i> peut prendre en argument un fichier de valeurs à envoyer. Ce fichier pouvant contenir jusque 5 000 valeurs, il nous faudrait faire des fichiers de 5000 lignes construits à partir du résultat de la requête SQL, en récupérant tout les timestamps envoyés pour ensuite les mettre à jour dans la base. Cette façon de procéder rajoute des contraintes tels que la gestion d'un timestamp dont certaines valeurs mesurées associées à ce timestamp seraient envoyées, mais pas toutes (valeur 4990 à 5000 par exemple et 8 valeurs qui seraient disposés dans le fichier suivant).<BR \>
 +
Cette solution nous permettrait donc  de passer de n requêtes cURL à ceil(n/5000). Mais il nous faudrait en contrepartie prendre le temps de découper le fichier en fichiers de 5000 lignes, ce qui dans le cas d'une coupure internet pour le noeud, ne serait pas forcément négligeable non plus. Il nous faudrait donc tester cette possibilité.
 +
</p>
 +
 +
<p align="justify">
 +
Afin de se rendre compte du fonctionnement du programme, nous avons réalisé la vidéo suivante :
 +
[[Fichier:video_script.avi|thumb|480px|center|Vidéo permettant de voir l'exécution du programme réalisé durant ce projet et envoyant les données sur une application influxDB]]
 +
 +
<BR \>
 +
Nous avons ensuite voulu créer notre Dockerfile permettant la création d'une image prête à être utilisé pour mettre en place nos conteneurs. Ce Dockerfile s'appuie sur l'image d'origine ubuntu afin de pouvoir tester notre script ainsi que le reste du programme, mais pour notre tuteur, il aurait été plus logique d'utiliser une image permettant de lire le nodejs car il préfère avoir un rendu final sous forme d'application nodejs.
  
[[Fichier:data_sent.png|thumb|720px|center|Dump de la base de données Sensors.db après l'exécution du script ]]
 
  
=> fichier de config ?
+
[[Fichier:docker.png|thumb|480px|center|Dockerfile associé au projet ]]
</b>
+
Nous tenons à préciser que ce dockerfile n'est qu'une ébauche de ce qui pourrait être réellement fait si nous poussions les capacités de Docker à fond.
 +
<BR \>
  
 
=Documents Rendus=
 
=Documents Rendus=
 +
Rapport : [[Media:Projet_IMA_4.pdf|Rapport de projet]]
 +
Lien vers git du script : https://github.com/Nicolas-Havard/Apolline

Version actuelle datée du 21 mai 2018 à 00:06


Présentation générale

  • Nom du projet : Station Modul'Air
  • Résumé : Développer l'aspect modulaire de la station de suivi de la qualité de l'air conçue par des laboratoires de recherche tout en améliorant le système initial et en permettant une installation rapide des prochains nœuds de contrôle.
  • Membres du projet : DELBROUCQ Hugo et HAVARD Nicolas
  • Superviseurs du projet : KASSI Redha (IRCICA) et ROUVOY Romain (INRIA)

Description

Lors de précédents projets, une station de contrôle de la qualité de l'air a été conçue afin d'étudier l'air au sein du campus de l'Université de Lille. La station initiale comporte de multiples capteurs : CO, CO2, microparticules, composé organique volatil par exemple pour étudier l'air, mais aussi des capteurs de bruit, de présence, de température ou de pression pour enregistrer les conditions des prises de mesures.

Cependant, réaliser un contrôle de la qualité de l'air en un seul point peut avoir un intérêt limité. Notre projet consiste donc à faciliter la mise en place des futurs systèmes et à permettre à ceux existant d'être mis à jour à distance. Le réseau de nœuds de capteurs devra communiquer avec une application web centralisée à l'INRIA permettant de visionner les différentes données au cours du temps et ce pour chaque nœud. De plus, les capteurs des stations doivent pouvoir être permutés facilement, au gré de l'opérateur, pour modifier la nature des données mesurées sans passer plusieurs heures à reconfigurer le système.

Objectifs

  • Faciliter l'installation de nœuds pour que les opérateurs n'aient que quelques lignes de commandes à taper pour rendre le système opérationnel
  • Permettre la mise à jour à distances de tous les nœuds simultanément
  • Permettre un aspect modulaire de la station, en rendant les capteurs 'plug and play' avec le minimum possible d'activité humaine pour changer les configurations

Analyse du projet

Positionnement par rapport à l'existant

Il existe déjà une version de ce projet existant réalisé par d'autres étudiants. Néanmoins, celui ci n'est pas satisfaisant car il ne fonctionne que sur un seul nœud. De plus les données sont stockées en local et non en ligne ce qui rend difficile la visualisation de ces données par un tiers. C'est pourquoi il va falloir remanier le code afin de permettre cela. De plus, les différents capteurs doivent être modulables. C'est à dire que si l'on modifie leur place sur la maquette, il faut un système permettant la reconnaissance du capteur placé au préalable.

Analyse du premier concurrent

Atmo Hauts-de-France est une association de surveillance de l'air qui mesure le taux de dioxyde de soufre (SO2), dioxyde d'azote (NO2), ozone (O3), les poussières (PM10 et PM25) ou encore la radioactivité de l'air dans le nord de la France et partage les données sur leur site internet en donnant un indice compris entre 1 et 10 pour aider les néophytes à comprendre le niveau de l'air actuel.

Analyse du second concurrent

Notre second courant est Foobot, une entreprise ciblant avec ses produits les ménages. Cette société propose une station de contrôle de la qualité de l'air dont les données sont accessibles depuis une application sur téléphone. Cet outil a pour but de renseigner l'utilisateur sur les problèmes qui apparaissent en cas de mauvaise qualité de l'air, les causes possibles et les démarches à réaliser afin de prévenir d'autres problèmes pouvant apparaître. Pour y parvenir, il mesure différents taux dans l'air tels que les COV (composés organiques volatils), les particules fines, la température et l'humidité et déduit de ces données des comportement à établir grâce à des modèles mathématiques.

Scénario d'usage du produit ou du concept envisagé

Donald veut importer des bananes depuis l'Afrique afin de les vendre plus cher pour devenir millionnaire (et peut être même président ensuite !). Son seul et unique but est donc de se faire le plus de marge possible. Néanmoins, il souhaite que ses clients continuent d'acheter ses bananes, et se soucie donc de la qualité de celles-ci à leur arrivée. Il s'intéresse en particulier à la qualité du transport de ces bananes.

Lorsqu'il demande à ses partenaires de lui fournir des informations en temps réel de la qualité de ses bananes lors de leur transport, ces derniers ne savent pas quoi lui répondre. Malheureusement pour ses partenaires, Abdel et Kader, cette contrainte est très problématique car ils ne connaissent aucun moyen de contrôler la qualité des bananes en temps réel dans le réseau de transport. C'est pourquoi ils demandent à des étudiants de Polytech Lille de résoudre leur problème. Heureusement pour eux, l'INRIA et l'IRCICA possèdent déjà un prototype d'une station de suivi de la qualité de l'air. Ils se mirent donc à travailler dans le but de satisfaire leur demande pour que Donald devienne très riche pour construire un joli mur autour de sa maison.

Réponse à la question difficile

Préparation du projet

Cahier des charges

Choix techniques : matériel et logiciel

  • Choix Technique :
    • Remplacement des programmes en C++ par du NodeJS : le NodeJS est en effet plus adapté pour notre utilisation avec les échanges entre les noeuds et le serveur puisqu'il fonctionne de manière asynchrone, ainsi que pour afficher en temps réel les données sur l'application web dédiée à la visualisation des données récoltées par les différents noeuds.



  • Choix Matériel :
    (ce matériel nous a été fourni par l'IRCICA/INRIA soudé à une maquette déjà conçue par de précédents projets)
    • 1 * Raspberry Pi 3
    • 1 * Arduino Mega
    • 1 * Capteur de mouvement PIR
    • 1 * Capteur de température, pression et humidité
    • 1 * Capteur de bruit
    • 1 * Set de capteurs chimiques Alphasense (CO, CO2, microparticules)

Liste des tâches à effectuer

Dans un premier temps, nous allons nous concentrer sur la partie informatique du projet en récupérant le code existant sur le prototype et en le transférant sur un dépôt Git. Nous aurons ainsi à disposition un dépot Git pour le code et la configuration du Raspberry Pi et un autre pour le programme Arduino.

Ensuite, il est prévu de permettre l'envoi de donnée via différents protocoles comme le WiFi, l'Ethernet, le Bluetooth, le LoRa ou encore le Zigbee afin de permettre plus de libertés à la station et pousser l'idée de la modularité sur l'envoi des données.

Enfin, si nous y arrivons, il serait envisageable de pousser la modularité sur les composants du systèmes en ajoutant la possibilité de retirer la Raspberry Pi ou l'Arduino et de les remplacer par d'autres cartes.

Calendrier prévisionnel

Pour les vacances de Février, nous pensons que nous aurons fini de trier le code existant et que nous aurons ajouté ce code sur les dépôts Git dédiés. Nous projetons de plus avoir bien avancé dans la traduction du code C++ et avoir implanté les quelques fonctionnalités demandées pour le Raspberry comme la possibilité d'éteindre proprement la machine à l'aide d'un bouton entre autre.

Réalisation du Projet

Feuille d'heures

Tâche Prélude Heures S1 Heures S2 Heures S3 Heures S4 Heures S5 Heures S6 Vacances Février Heures S7 Heures S8 Heures S9 Heures S10 Heures S11 Heures S12 Heures S13 Heures S14 Heures S15 Total
Analyse du projet 3h30 8h30 6h 6h 3h30 6h 6h
Envoi des données de capteurs 4h30 4h 7h30 3h 4h20 6h 7h 3h
Rédaction du wiki 1h30 1h 1h30 3h 3h

Prologue

Nous nous sommes rendus à deux reprises dans les laboratoires de l'IRCICA puis de l'INRIA afin d'en apprendre plus sur notre projet et de comprendre ce que nos clients attendaient de nous. Nous avons aussi profité de ces visites pour voir la maquette déjà conçue sur laquelle nous allons travailler, et récupérer les codes de l'Arduino et du Raspberry. De plus, il semblerait que les parties électroniques comprenant l'Arduino et la programmation des capteurs en Python (nécessaires à l'acquisition des données de certains capteurs) aient déjà été réalisées avant notre arrivée. Nous devons donc réaliser l'architecture logicielle du projet afin de comprendre ce que la personne nous précédant a réalisé ainsi que l'architecture adaptée à plusieurs nœuds que nous avons donc à faire.

Semaine 1

Durant la première semaine, nous avons tout d'abord rattrapé notre retard sur la rédaction du Wiki. Nous avons aussi pu analyser le code du premier nœud de notre système qu'il nous faut encore ajouter au git du projet afin de clarifier son fonctionnement :

De plus, nous avons aussi établi le fonctionnement du mode de communication entre les différents nœuds et notre interface. En effet, l'utilisation de telegraf permet de traiter les données de chaque nœud facilement pour ensuite les centraliser sur influxdb qui les stocke dans une base de données pour ensuite envoyer ces données à grafana qui est un logiciel permettant des simulations graphiques et la possibilité d'utiliser un interface agréable.

Collecte :
On peut voir sur la partie Telegraf que l'outil fonctionne par scrutation. Il demande d'abord au nœud à un intervalle de 30s les données qu'il renvoie une donnée correspondant à la moyenne des données prélevées par le nœud lors de ces 30s. Cela permet d'éviter des écarts trop important ne reflétant pas la réalité.



Base de données :

Fonct reseau.png
Fonctionement du réseau nœud/interface

Semaine 2

  • Nous avons profité de ce début de semaine pour préparer l'installation de Telegraf que nous espérions terminer mercredi. Nous avons donc repéré les fichiers de configuration et ce qu'il nous fallait y mettre dedans, ainsi que la procédure d'installation du paquet sur la Raspberry.


  • Le mercredi après-midi, nous avons pu installer Telegraf sur la Raspberry basée à l'INRIA et avons commencé à configurer ce dernier pour qu'il fonctionne avec la base de données en temps réel située sur le serveur de l'INRIA et avons du effectuer différents paramétrages de la Raspberry pour que le système fonctionne correctement.

Semaine 3

Le lundi nous avons poursuivi notre documentation sur le sujet pour ensuite aller le mercredi à l'INRIA faire fonctionner Télégraf. Nous avons alors eu un problème qui s'est posé, en effet Télégraf n'est pas adapté à une base SQLite comme celle utilisée dans la Rasp Pi. Nous avons donc essayé de faire deux choses :


  • Changer la base SQLite mais nous ne connaissions pas les conséquences sur le reste du programme se servant d'une librairie propre à SQLite et de plus, nous avons eu du mal à trouver un convertisseur valable. L'exportation était simple à réaliser mais il aurait fallu modifier les fichiers en interaction avec la base car ils se servaient de bibliothèques sqlite3.h, cela aurait pu entrer en conflit avec le reste du programme que nous ne maîtrisons malheureusement pas complètement.

   Manipulation pour changer la base SQLite en MySQL : 
         exporter la base en fichier .dump puis utiliser le script python qui remplace les marqueurs SQLite par des marqueurs MySQL pour enfin réimporter la base au format MySQL.


  • Créer un fichier .conf prenant en charge la base SQLite en input. Mais la aussi nous ne disposions pas des connaissances nécessaires à sa réalisation. En effet, d'après ce que nous avons pu observer, les fichiers d'input disponibles sur le git de telegraf sont uniques et ont peu de points commun entre eux.

Nous avons donc continué de perdre bêtement du temps sur cette idée qui de plus est lourde à supporter pour une Rasp Pi.


Semaine 4

  • Nous avons pu récupérer une Raspberry Pi afin d'effectuer des tests en dehors du laboratoire et obtenir ainsi plus d'indépendance. La Raspberry n'ayant aucun rapport avec les projets existant à l'INRIA, et ne connaissant pas les mots de passe de la machine, nous avons du réinstaller le système d'exploitation Raspbian sur la carte avant d'installer les mises à jours pour partir sur une bonne base.

  • Recherches de compatibilités entre Telegraf et SQLite
  • Abandon de la solution Telegraf car inadaptée à notre architecture


Semaine 5

Nous avons choisi d'abandonner la solution que proposait Telegraf, soit une application qui permettait l'envoi de données vers la base de données en temps réel influxDB. En effet, malgré une grande variété de bases de données lisibles par Telegraf, les bases SQLite n'étaient pas pré configurées pour être adaptées à cette application. De plus, le rejet de Telegraf permet de simplifier l'installation et d'économiser des ressources.


Nous avons choisi de partir sur une solution constituée d'un script C lancé par un Cron de la Raspberry pour lancer de manière asynchrone les données non envoyées par le noeud sur le serveur de l'INRIA. L'envoi des données sur le serveur se fera via une requête REST (à détailler) à l'aide de cURL.

Dans le but de conserver le choix de nodeJS, le script C sera remplacé par un script Javascript, avec le framework NodeJS.

Pour cela, nous nous inspirerons du paquet Node-influx (git du paquet ici)


Semaine 6

Nous nous sommes intéressés à deux solutions pour envoyer les données sur influxDB :


  • la requête cURL en Bash permettant d'envoyer jusque 5 000 données comprises dans un fichier, par exemple un fichier texte nommé sensors_data.txt sur le port d'écoute de l'application influxDB, à savoir le port 8086 de apolline.lille.inria.fr dans notre cas. Nous aurons donc une commande du type suivant :

curl -i -XPOST 'http://apolline.lille.inria.fr:8086/write?db=airquality' --data-binary @sensors_data.txt


L'intérêt de cette méthode serait d'envoyer les données de la base de données SQLite sur un fichier sql au travers des commandes suivantes :

.output airquality.sql
.dump airquality.sql

avant de passer ce fichier sql à la commande curl pour envoyer les différentes données sur l'application.


  • via un script Javascript permettant d'envoyer les données des différentes séries sur l'application.


Dans le but de tester l'efficacité de la commande bash qui semble être la plus simple et la plus efficace, nous avons installé les différentes applications utilisées que sont influxDB et Grafana dans le but de reproduire le système étudié et de pouvoir le manipuler sans aucun risque. De cette manière, nous devrions pouvoir tester l'envoi et la réception de données sur influxDB, et la visualisation de celles-ci sur Grafana.

Semaine 7

Nous avons commencé la conception d'un script Bash permettant d'envoyer les données sur le serveur afin de les regrouper sur influxDB et de pouvoir les traiter par la suite. Il sera placé dans le répertoire /etc/cron.hourly dans le cas où nous pourrions envoyer les données toutes les heures : les données seraient ainsi cumulées durant une heure en local dans une base de donnée SQLite, afin d'être envoyées toutes les heures sur le serveur. Ce script se décompose en plusieurs parties :

  • les variables utilisées dans le script correspondant aux fichiers que le programme va lire ou écrire
  • les variables qui vont être appelées par le script comme les noms des bases de données, les adresses URL sur lesquelles nous envoyons les données où les variables systèmes comme le nom de la machine
  • le script permettant de récupérer les données de la base SQLite
  • les commandes récupérant les données à envoyer et effectuant les requêtes sur l'adresse du serveur


  • Les différentes variables sont :

    • db_sql : un dump de la base de donnée sur laquelle se trouve les données. Nous récupérons alors toutes les tables et leurs contenu dans ce fichier.
    • script_database : script externe pour SQLite3 permettant le dump automatique des données (possibilité de se séparer de ce fichier à l'avenir en récupérant le contenu de la base de données via une commande Bash unique)


    • URL : l'adresse URL du serveur sur lequel nous souhaitons envoyer les données, et sur lequel se trouve l'application influxDB
    • port_envoi : par défaut 8086. C'est le port d'écoute d'influxDB et sur lequel il nous faut envoyer les données pour que l'application les ajoute aux bases désirées
    • port_application : par défaut 8083. C'est le port sur lequel il faut se rendre pour visualiser l'application influxDB et donc les données stockées sur la base en ligne
    • database : la base de données stockant les données en ligne et sur laquelle nous envoyons les données mesurées par les capteurs du noeud
    • nodename : le nom du noeud, soit l'identifiant permettant de distinguer l'émetteur des données sur la base


  • Le script SQLite, lui, interagit avec la base de données database renseignée dans les variables de début. Actuellement, il crée un fichier d'écriture sur lequel sera écrit les résultats des requêtes du script. Les requêtes affichent la liste des données à envoyer provenant des différentes tables de la base de données database :

.output bdd.txt
SELECT * FROM co2 WHERE SEND_FLAG=0;
SELECT * FROM humidity WHERE SEND_FLAG=0;
SELECT * FROM pressure WHERE SEND_FLAG=0;
[...]
.exit

Actuellement, les noms des tables sont rédigées à la main, nous allons voir s'il est possible d'effectuer ces requêtes sur les différentes tables de manières automatique en récupérant le nom de toutes les tables et en rédigeant les requêtes SQL via une boucle. Cependant, nous pensons aussi partir sur un dump de la base de données, ce qui nous permettrait de récupérer les données comme elles sont écrites :

CREATE TABLE test1(one varchar(10), two smallint);
INSERT INTO "test1" VALUES('hello!',10);
INSERT INTO "test1" VALUES('hel',42);
CREATE TABLE test2 (id integer, titre VARCHAR(15));
INSERT INTO "test2" VALUES(1,'premiere valeur');
INSERT INTO "test2" VALUES(2,'seconde valeur');

(il s'agit de tables et de données tests, comme leur noms l'indiquent, et non des véritables tables. Mais le principe reste le même)

Si la récupération des données avec le dump est la même qu'avec la première méthode et nécessite donc un découpage du fichier pour récupérer les informations intéressantes, il nous permettrait de modifier facilement les flags d'envoi et de reconstruire la base de données en modifiant donc le flag lorsque la donnée a pu être envoyée sur influxDB.

  • Une fois la base lue, et les données à envoyer isolées, il nous faut alors envoyer les données sur l'application.

On réalise alors une requête POST à l'aide de la commande cURL sur l'URL renseignée au début et sur le port de réception de l'application, en n'oubliant pas d'indiquer la base de données sur laquelle ces données doivent se retrouver.

"#curl -X POST '$URL:$send_port/write?db=$database' --data-binary '$data,hostname=$nodename value=$value'"

Les données, que nous pouvons retrouver derrière --data-binary, sont composées de $data qui est le nom de la table (par exemple co2, humidity, pressure, ...), $hostname correspondant à l'identifiant du noeud, et $value qui est la valeur mesurée par les capteurs.


Devrait alors se distinguer deux cas, qui ne sont pas encore terminés : le cas où la requête HTTP renvoie un code 204 signifiant que l'envoi de données à été réalisé, et le cas où nous recevons un code 400 pour une erreur de syntaxe.

    • En cas de succès, il faut alors modifier le flag d'envoi de la données à 0 pour signaler que la donnée n'est plus à envoyer au serveur.
    • Le second cas, à l'avenir, devra être signalé dans un fichiers de logs pour que l'administrateur puisse remarquer l'erreur et traiter le problème. Aucune modification ne sera apportée à la donnée, qui conservera donc un flag d'envoi de 1 (nécessitant donc d'être envoyée).


Nous avons placé à la fin la commande xdg-open $URL:$app_port permettant, après l'envoi des données, d'ouvrir l'adresse du serveur sur le port de l'application pour constater la réception de nouvelles données. Évidemment, le script tournant sur un Raspberry Pi sans interface homme-machine, il sera inutile d'ouvrir un onglet internet à chaque fois que des données seront envoyées sur le serveur, soit une nouvelle page toutes les heures voire beaucoup plus. Cette commande est présente pour la conception du script.


De plus, nous avons aussi pu établir l'architecture de notre système pour un nœud. Le système à plusieurs nœuds sera semblable à celui avec un nœud unique mais aura plus de fonctionnalités. Cette organisation peut de plus changer au fil du temps.

Noeud unique.png
Fonctionnement du système avec un nœud unique

Semaine 8

Durant cette semaine, nous avons pu terminer la partie initialisation du script, qui prend en compte les variables et qui récupère les données de la base de données à exploiter.


Partie du script Bash permettant l'initialisation des variables nécessaires tels que les chemins de fichiers ou encore les noms des bases de données et l'URL de l'application, mais aussi la partie où nous faisons un dump de la base de données éudiée pour l'exploiter par la suite


Tout d'abord, nous avons placer une variable 'SILENT_MODE' qui, lorsqu'elle est différente de 0, permet d'obtenir un script plus verbeux qui va nous signaler dans quelle partie il se trouve actuellement (lecture de la base de données, envoie des données sur influxDB), ce qui permet un déverminage plus aisé. Vient ensuite les variables nécessaires au script, comme stipulé la semaine passée, mais avec des noms finalement différents : en effet, nous avons appris entre temps à émettre des requêtes avec SQLite directement à partir d'un script Bash et non en passant par un script dédié à SQLite, simplifiant ainsi l'arborescence de fichiers. Nous retrouvons db qui est la base de données elle-même dont nous récupérons les données, et dont on effectuera un 'dump' à la ligne 47 (dump auquel nous reviendrons un peu plus bas lorsque nous reparlerons des dernières variables). Ce dump sera identifié par la variable db_request. Des lignes 22 à 26, il s'agit de variables propres à l'utilisation de influxDB :

  • nodename permet de récupérer le nom du noeud envoyant les données pour afficher la provenance des données sur l'application.
  • URL est l'adresse URL par laquelle l'application est accessible.
  • send_port et app_port sont les ports respectifs de réception de données et de l'application comme vu la semaine passée
  • influxDB_database la base de données d'influxDB sur laquelle nous envoyons les données.


Ces 5 dernières variables permettent d'avoir un script plus dynamique et plus adaptable en cas de changement d'application (changement des ports de référence d'influxDB, données pour du suivi médical et non du suivi de qualité d'air, nouvelle adresse du serveur).


Nous trouvons enfin les 5 nouvelles variables dont nous parlions au début, que nous n'étions pas obligé de (ne devrions pas d'ailleurs) placer ici, nécessaires au bon déroulement de ce programme dans notre cas :

  • table : il s'agit du nom de la table que parcourt le script lors de la lecture du dump de la base. En effet, le dump est constitué des lignes permettant de créer la base Sensors.db, soit la création des tables ('CREATE TABLE') puis le remplissage de celles-ci ('INSERT INTO ... VALUES').


Document obtenu (volontairement tronqué) suite au dump de la base de données Sensors.db


La technique que nous utiliserons dans ce script va consister à récupérer les données de la table data, et il nous faut donc savoir dans quelle table nous nous trouvons. C'est l'intérêt de cette variable. En effet, les 3 variables suivantes sont contenues dans la table data :

  • timestamp : ou horodatage en anglais, sera la date et l'heure d'émission des données envoyée à influxDB
  • timestamp_old : l'ancien timestamp, permettant de comparer les variables et de savoir si nous avons fait le tour des valeurs mesurées à un même moment. Nous pouvons alors ajouter ou enlever des capteurs de la station sans aucun problème.
  • value : tout simplement la valeur mesurée par les capteurs que nous envoyons à l'application en ligne.


La dernière variable, sent est le 'flag' permettant de savoir si les valeurs correspondant à telle date ont déjà été envoyées sur l'application ou non. Elle est cependant contenue dans la table polls.


Une fois les variables créées, le script peut commencer, et la première étape est donc le dump de la base de données Sensors.db (ou $db). Nous demandons donc à SQLite (SQLite3 étant installé sur le système en question) de faire un dump grâce à la commande
"sqlite3 base_de_données .dump".


Ce dump est envoyé vers $db_dump afin d'être lu plus tard par le programme pour récupérer les données au travers des variables vues ci-dessus avant de les envoyer sur influxDB.

Semaine 9

Partie du script Bash traitant le fichier de la base de données pour en extraire les variables à envoyer à l'application sur le serveur, via une requête POST

Nous avons terminé la lecture du dump de Sensors.db et arrivons à extraire les données que nous souhaitons envoyer grâce à la commande cut appliquée sur chaque ligne du dump de la base de données. En effet, chaque ligne contenant des données suivant le format suivant :
INSERT INTO "data" VALUES(sensors_identifier,data,poll_time); ,
il nous faut récupérer la partie après la première parenthèse contenant les valeurs, soit le champ 2 en prenant comme symbole de découpage '('. Les données sont ensuite séparées par des virgules, nous récupérons les champs 1, 2 et 3 respectivement dans nos variables $sensor, $value et timestamp permettant donc de savoir sur quelle table envoyer les données, grâce à sensor, que sont la valeur value récupérée par le capteur au temps timestamp. La requête POST, commentée dans la capture ci-dessus, fonctionne correctement pour une seule donnée en console et ne devrait donc pas poser de problèmes lors de l'envoi de toutes les données.
(spoiler du futur : tout ne se passe jamais comme prévu)


L'envoi des données se fera donc en N requêtes CURL où N est le nombre de données à envoyer. Cette solution n'étant pas optimale, nous aurons probablement à l'avenir à créer un fichier contenant les données à envoyer sous un certain format, facilement exploitable par CURL pour l'envoi de données sur InfluxDB. Suite à l'envoi des données concernant une certaine date de mesure, le timestamp change, et nous pouvons donc informer la base de données que les données ont bien été envoyées sur l'application influxDB en mettant le flag sent à 1.


Nous sommes retournés à l'INRIA pour récupérer des données et effectuer ainsi des tests du script lorsqu'il sera complètement terminé. Nous avons donc fait des dump des bases de données config.db et sensors.db qui stockent, réciproquement, les configurations des capteurs (offset, sensibilité, unités de mesure) et les valeurs récupérées par les capteurs avec leur timestamp et autres informations (donnée envoyée par exemple). Les bases de données ont chacune deux tables, que voici représentées :


Schéma de la base de donnée Sensors.db et de ces deux tables 'data' et 'polls', permettant de faire le lien entre les capteurs, les données récupérées et la date à laquelle ont été récupéré les données
Schéma de la base de donnée config.db et de ces deux tables 'sensors' et 'settings', permettant de garder en mémoire les paramètres de configuration de la Raspberry et des capteurs, mais aussi les métadonnées telles que l'unité de mesure des données


Nous avons donc modifié le script Bash afin de le rendre plus propre. Nous reconstruisons les bases de données présentes sur la Raspberry de l'INRIA à l'aide des dumps récupérés. Nous reprenons l'idée d'un script de requêtes SQL permettant d'effectuer une requête SQL pour obtenir les données à envoyer, avec leur timestamp et les données des capteurs et de rediriger le résultat de cette requête vers un document que lira le script Bash pour en extraire les informations à l'aide de commandes cut.

L'architecture du script Bash ne change donc pas, et conserve les phases suivantes :

  • Affectation des variables
  • Ouverture de la base de données et récupération des données à envoyer
  • Envoi des données sur InfluxDB
  • Vérification de l'envoi des données et mise à jour de la base


De plus, nous avons pu commencer le tutoriel sur docker qui devrait nous permettre de faciliter le déploiement de nos différents nœuds et de réduire l'encombrement à l'aide des compartiments docker.

Semaine 10

La semaine précédente, nous avions changé de technique d'approche concernant la lecture de la base de données. Bien que nous étions restés sur le fait de passer par un dump de la base de données nous intéressant, nous ne passions plus par un script SQL, mais nous avions rentré ces commandes directement dans le script Bash.


Partie du script permettant de lire la base de données Sensors.db

Cette semaine, nous avons profité jusqu'au bout de la possibilité d'entrer des commandes directement depuis le script Bash pour changer l'approche de lecture de la base de données : plutôt que de passer par un dump de la base de Sensors.db, nous effectuons directement notre requête SQL dans le script, à savoir récupérer les identifiants des capteurs sensor_identifier, la valeur mesurée data et l'heure d'émission de la valeur, le timestamp, poll_time de la table data. Nous effectuons une jointure entre les tables data et polls sur le timestamp présent dans les deux tables.
Cette jointure nous permettra donc de filtrer les données déjà envoyées sur l'application en ligne grâce au flag sent de la table polls. Nous ordonnons ensuite les valeurs par horodatage croissant pour respecter l'ordre chronologique.
Le résultat de cette requête sera envoyé vers $db_request, variable pointant vers le document grâce auquel nous allons récupérer les valeurs à envoyer.


Initialisation du script Bash après changement de technique pour la lecture de la base de données Sensors.db


Ce changement nous a donc permis de simplifier notre technique pour récupérer les valeurs : plutôt que de faire des cut en fonction du début de la ligne lue (CREATE TABLE ou encore INSERT INTO), nous savons que nous disposons directement des bonnes valeurs et il nous reste alors à faire le découpage des valeurs. Nous gagnons donc en complexité et donc en temps de réponse étant donné que nous n'avons alors plus besoin de lire toutes les lignes pour créer les tables et surtout les lignes permettant de remplir les tables ne nous intéressant pas. De plus, le filtre du à la sélection des données n'ayant pas encore été envoyées diminue le nombre de résultats suite à notre requête.

Semaine 11

Concernant le script, nous avons donc continué et passé à la partie envoi de données. Connaissant la commande permettant d'envoyer les données et ayant déjà récupérer les valeurs à envoyer, nous pensions que cela se ferait assez facilement. En effet, influxDB accepte de recevoir les données grâce à la commande cURL, écrite de la manière suivante :
"curl -XPOST "adresse_influxDB:port_envoi/write?db=base_données_influxDB" --data-binary "table_influxDB,hostname=ID_noeud value=valeur_envoyée heure_de_la_valeur"
le XPOST signifiant que nous effectuons une requête HTTP avec une méthode POST pour envoyer les données à l'application.


Cependant, afin de pouvoir envoyer les données de manière dynamique et en passant donc par des variables, il a fallu effectuer plusieurs tests pour que la commande reconnaisse l'adresse sur laquelle envoyer les données et les données en elle-même.
La solution que nous avons trouvé a été de créer une nouvelle variable qui, à partir des variables générales en début de script, reconstitue l'adresse de l'application en une seule chaine de caractères. Les données, elles, sont traitées de la même manière et nous reconstituons donc la requête à partir des variables obtenues suite au découpage de la requête SQL. Nous obtenons ainsi les deux variables suivantes :

  • site="$URL:$send_port/write?db=$influxDB_database"
  • data="$sensor, hostname=$nodename value=$value $timestamp"
et la commande devient alors :
curl -XPOST $site --data-binary $data


Cependant, cette solution n'est pas tout a fait ce que nous espérions. En effet, lors d'une requête HTTP, différents codes peuvent être renvoyés suite à l'envoi de données sur un serveur. Un code de 2XX (comprendre entre 200 et 299) signifiera un succès de la requête, 3XX une redirection de la requête, 4XX une erreur du client web et 5XX une erreur du serveur (les codes 1XX étant des informations). Nous souhaitons donc être sûrs que notre requête a bien fonctionné, autrement dit que influxDB a bien reçu les valeurs que nous avons envoyé. Pour cela, il nous faut recevoir un code 2XX, souvent 204 pour influxDB. Nous n'avons pas encore trouvé la solution de ce problème, mais nous songeons à rediriger le code reçu sur un document texte qui, après découpage grâce à cut, nous permettra d'obtenir le code. Cependant ce procédé est lourd et nous cherchons d'autres solutions.

Semaine 12

Nous avons pu finir le tuto docker proposé par le site éponyme | docker.com La partie docker va consister à créer un cluster via docker swarm qui va regrouper et gérer tout nos nœuds. Pour l'heure nous utiliserons une raspberry en mode manager et une autre en mode worker (même système que maitre/esclave ).

Fonctionnement de notre partie docker :

  • Après avoir fini le tutoriel, nous allons maintenant faire en sorte d'importer cette technologie à notre projet.

Le principal travail sera de stocker toutes les parties de code utiles à tous les nodes dans un unique compartiment afin de l'importer à l'installation de chaque node. De plus, le compartiment sera stocké sur le compte eeikon (plus tard voir inria/qarpediem/ sur hub docker à l'adresse [1]et pourra par la suite être stocké sur le compte de l'INRIA.

  • Fichiers à importer : on prévoit d'importer tous les fichiers présents sur la raspy et laisser un script d'installation/configuration qui lancerait le téléchargement depuis le hub docker
  • importer le système d'exploitation raspbian? permettrait d'alléger encore l'application mais pas si nécessaire car les raspy peuvent supporter l'OS. (solution à réaliser si le temps le permet)
  • passez par le docker swarm afin de créer un cluster de raspy workers avec le serveur qui ferait office de manager.
  • Le fichier de config doit renommer le noeuds (en fonction de ceux déjà existants?)lancer le téléchargement. A long terme il devra aussi demander les capteurs présents et leur emplacement afin de connaitre l'architecture de la maquette

Concernant l'avancé du script, nous avons réussi à envoyer les données sur l'application et à récupérer le statut HTTP après la lecture du manuel concernant cURL. Il se trouve que nous pouvons récupérer le statut HTTP grâce à "--write-out". Et pour retirer tout affichage nuisible au bon déroulement du script, nous appliquons aussi l'argument "--silent" permettant de passer la commande cURL de manière moins verbeuse. Après avoir fait un test, le programme fonctionne correctement et nous recevons bien des statuts 204. Prouvant le bon déroulement du programme, nous recevons bien les données sur influxDB et pouvons ainsi les voir sur internet.


Afin de montrer la progression du script lors de son exécution, nous avons réalisé un affichage s'actualisant au fur et à mesure de la progression du script en mettant en avant le nombre de valeurs déjà traitées, le total de valeurs à traiter, et le pourcentage de progression.
Cet affichage ayant nécessité une division entre deux nombres, il nous a fallu installer le paquet bc permettant de réaliser des calculs et de gérer les flottants dans un script Bash. Par conséquent, il sera très important de ne pas oublier d'installer bc lors de l'installation de noeuds pour lancer le script de manière manuelle. En effet, il sera intéressant pour l'opérateur de voir que le programme s’exécute correctement, et que le système n'a pas planté.
Cependant, les noeuds devant lancer le script de manière automatique n'ont pas d'opérateur derrière visualisant la console, et cette partie sera donc inutile la plupart du temps.

Semaine 13

Le programme arrivait à son terme, seul rester la mise à jour de la table de données avec un sqlite3 UPDATE. Les données étaient correctement récupérées, bien envoyées sur influxDB où nous pouvions les visualiser en direct, avec la progression du script en cours possible en console. Cependant une erreur de manipulation de fichiers nous a fait perdre les deux dernières semaines. Bien que nous sachions comment faire, il va nous falloir un peu de temps pour remettre au point le programme en l'état.
Ce problème aura au moins soulever le point que nous aurions du utiliser un système de versionnage comme Git plutôt que de se satisfaire de copier-coller de temps à autre.
Du coup, voici le lien du nouveau Git : https://github.com/Nicolas-Havard/Apolline

Semaine 14

Cette semaine nous avons récupéré le programme tel qu'il était avant la suppression des fichiers et avons donc retrouvé un script permettant d'envoyer les données sur influxdb avec la progression du déroulement du script en direct.


Partie du script permettant d'envoyer les données sur la base influxDB et de mettre à jour la base de données pour indiquer que les valeurs ont été envoyées


Nous avons aussi mis au point la mise à jour de la base de données concernant le flag sent et son passage à 1 lorsque toutes les valeurs ayant été envoyées pour ce timestamp ont été récupérées pas l'application. Après quelques problèmes de syntaxe, nous sommes parvenus à résoudre notre problème en construisant la requête SQL dans une variable à part avant de la donnée en paramètre de la commande sqlite3. Comme nous pouvons le voir ci-dessous, la mise à jour de la base de données est bien prise en compte :


Dump de la base de données Sensors.db après l'exécution du script


Nous avons de plus ajouter un document permettant de visualiser les données ayant été envoyées par le programme, à la manière d'un historique, lors de la récupération des valeurs. Ce fichier est donc composé des éléments envoyés sous la forme ID_sensor | value | timestamp :

Exemple de valeurs récupérées lors de l'envoi des données grâce aux 'cut' du résultat de la requête


Cependant, à l'issu de ce programme, nous pouvons constaté que le temps d'envoi des données vers l'application web est long : environ 325 secondes, soit presque 5 min 30 pour envoyer 1000 valeurs. En partant de cette mesure, et en supposant que le temps d'exécution soit linéaire ou autrement dit en O(n) où n est le nombre de valeurs envoyées, étant donné que nous ne disposons que d'une boucle, il nous faudrait donc 3.5 secondes pour envoyer 10 valeurs soit 7 secondes pour en envoyer 20. Le noeud sur lequel nous avons pu faire des essais disposant de 18 capteurs, et prenant des mesures toutes les 30 secondes, il nous faudrait donc "perdre" 7 secondes toutes les 30 secondes pour envoyer les valeurs sur le serveur.
Il est toutefois possible d'améliorer ce programme en complexité. En effet, cURL peut prendre en argument un fichier de valeurs à envoyer. Ce fichier pouvant contenir jusque 5 000 valeurs, il nous faudrait faire des fichiers de 5000 lignes construits à partir du résultat de la requête SQL, en récupérant tout les timestamps envoyés pour ensuite les mettre à jour dans la base. Cette façon de procéder rajoute des contraintes tels que la gestion d'un timestamp dont certaines valeurs mesurées associées à ce timestamp seraient envoyées, mais pas toutes (valeur 4990 à 5000 par exemple et 8 valeurs qui seraient disposés dans le fichier suivant).
Cette solution nous permettrait donc de passer de n requêtes cURL à ceil(n/5000). Mais il nous faudrait en contrepartie prendre le temps de découper le fichier en fichiers de 5000 lignes, ce qui dans le cas d'une coupure internet pour le noeud, ne serait pas forcément négligeable non plus. Il nous faudrait donc tester cette possibilité.

Afin de se rendre compte du fonctionnement du programme, nous avons réalisé la vidéo suivante :

Fichier:Video script.avi
Vidéo permettant de voir l'exécution du programme réalisé durant ce projet et envoyant les données sur une application influxDB


Nous avons ensuite voulu créer notre Dockerfile permettant la création d'une image prête à être utilisé pour mettre en place nos conteneurs. Ce Dockerfile s'appuie sur l'image d'origine ubuntu afin de pouvoir tester notre script ainsi que le reste du programme, mais pour notre tuteur, il aurait été plus logique d'utiliser une image permettant de lire le nodejs car il préfère avoir un rendu final sous forme d'application nodejs.


Dockerfile associé au projet

Nous tenons à préciser que ce dockerfile n'est qu'une ébauche de ce qui pourrait être réellement fait si nous poussions les capacités de Docker à fond.

Documents Rendus

Rapport : Rapport de projet
Lien vers git du script : https://github.com/Nicolas-Havard/Apolline