IMA4 2017/2018 P49
Sommaire
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)
- 1 * Raspberry Pi 3
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 | 2h | |||||||||||
Envoi des données de capteurs | 4h30 | 4h | 7h30 | 1h30 | ||||||||||||||
Rédaction du wiki | 1h30 | 1h |
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 :
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
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, est 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.
Semaine 8
Semaine 9
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 :