Ceci est une ancienne révision du document !
Chaque jour, l’air que nous respirons est plus ou moins pollué, chaud et humide. Il varie selon l’heure, selon la météo et les sources d’émission de polluants, selon vos activités (à l’intérieur ou à l’extérieur, à proximité du trafic, dans un parc, …). Quel est l’air que vous respirez ? Il nous entoure, on le respire… mais il est invisible, sauf en cas de forte pollution. L’évaluation de la qualité de l’air (confort thermique et pollution) est possible par la mesure de paramètres météorologiques et de polluants atmosphériques.
Au quotidien, nous sommes informé(e)s sur la qualité de l’air et la météo, via les médias, sites internet et panneaux d’affichage municipaux. Pour l’Île-de-France, cette information est principalement issue des mesures de l’air par MétéoFrance et AirParif, mesures réalisées ponctuellement dans des stations et complétée par des modèles. Elles ne sont pas forcément représentatives de notre propre exposition à la pollution de l'air selon nos activités et des changements de température et d'humidité selon les espaces fréquentés.
Les fablab, « laboratoire de fabrication numérique », mettent à disposition des outils permettant à tous de créer des objets, électroniques ou non, tels que des drones, des figurines ou encore des capteurs environnementaux. Ils font partie d’un mouvement de démocratisation de la science où chaque citoyen peut créer des capteurs et collecter des données grâce à des tutoriaux ouverts à tous, disponibles généralement sur internet, et à de l’électronique à bas prix. La collecte de données citoyennes permet à chacun de créer sa propre information sur ses expositions environnementales par exemple, voire d’enrichir une base de données scientifiques (sciences citoyennes).
Nous avons développé une première version du capteur en Septembre 2015. Cette version se présente sous la forme d'un kit et comprend deux capteurs: un capteur de température et d'humidité relative (DHT22) et un capteur de particules fines (SHARP GP2Y1010AU0F).
La communication vers le smartphone (Android ou iOS) se fait via Bluetooth Low Energy (4.0) grâce à un RFDuino.
Le schéma sous Eagle
Et le PCB
La station connectée que vous allez assembler et utiliser contient essentiellement deux capteurs : un capteur de température & humidité, le DHT22, qui va convertir ces grandeurs physiques en signal électrique ; un capteur de particules fines basé sur le principe de diffusion de la lumière qui va convertir la lumière déviée par les particules entrant dans le capteur en signal électrique. Pour fonctionner, ces capteurs utiliseront l’énergie fournie par une batterie rechargeable via le port USB d’un ordinateur par exemple. Les signaux électriques qu’il vont générer seront transmis par l’intermédiaire de la puce RFDUINO en bluetooth vers une application installable sur un smartphone (ANDROID ou IOS). Cette application permettra au “citoyen participatif” d’envoyer la donnée et ses coordonnées temporelles et GPS vers un serveur sur internet permettant une cartographie des mesures enregistrées au sein d’une base de données.
Le montage de la station se déroule en plusieurs étapes :
- 5 blocs à souder : (1) le chargeur de batterie, (2) les résistances, (3) les diodes électroluminescentes (LEDs), (4) le gros condensateur, (5) le capteur de température-humidité (DHT22)
- puis 2 blocs à brancher : (6) le capteur de particules fines (Sharp) et (7) la batterie. Après il ne reste plus qu’à insérer le tout dans le boîtier fabriqué avec une imprimante 3D et un couvercle avec une découpeuse laser.
Insérer les pattes des résistances par le dessus :
Les tordre pour faciliter la soudure. Les souder et les couper.
Les petites à gauche, les grandes à droite. La première vers l’arrière, la seconde vers l’avant, etc.
Insérer le condensateur par le dessus, à l’emplacement A, avec la masse (petite patte ou le signe -) vers le bas du PCB. Le plier pour qu’il soit plus bas que les LEDs. Souder, couper.
Voilà, on a fini de souder les différents composants au circuit imprimé, alias le PCB ! Il reste deux blocs à brancher pour finaliser la station environnementale.
Brancher le capteur à l’emplacement C. On peut repérer le sens : avec les 2 encoches vers l’extérieur.
Brancher la batterie à l’emplacement D, ATTENTION par le dessous du circuit imprimé. Si tout va bien, ça s’allume !
Et on rentre le montage dans un des 2 boîtiers.
La température et l’humidité de l’air :
La température est, en physique, le degré d’agitation moléculaire des particules d’un corps. Ici elle est donnée en °Celsius (où 0°C correspond à la température de l’eau qui gèle et 100°C). La station OpenAir mesure la température de l’air.
L’humidité relative est le rapport entre la quantité de vapeur d’eau contenue dans l’air et la quantité maximale de vapeur d’eau que pourrait contenir l’air (variable selon la température). Elle est donnée en %. Une valeur de 100% indique la saturation de l’air et donc une condensation de la vapeur d’eau. L’indice de confort thermique Humidex intègre les données d’humidité et de température de l’air. Il permet d’estimer un degré d’inconfort : de aucun à un coup de chaleur.
Les concentrations de particules
Les particules sont « les poussières respirables par l’homme ». Leur diamètre est tellement fin qu’elles pénètrent facilement dans les voies respiratoires. Elles ont des conséquences sur la santé (maladies respiratoires, cardio-vasculaires, cancers, perturbateurs endocriniens…). Les capteurs montés mesurent plus particulièrement les particules les plus fines (d’un diamètre inférieur à 2,5 µm). La principale source d’émission est le trafic routier, mais il existe d’autres sources tels que la fumée des feux de cheminée, les rejets des usines, l’épandage dans les zones agricoles…
Le temps d’autonomie est fonction de l’utilisation de la station. En conditions normales, la batterie est prévue pour une autonomie d’environ 7h. Pour recharger la station, ATTENTION, il faut la brancher sur l’adaptateur secteur (présent dans le kit). Environ 1h.
Pour Android:
Pour iOS AppStore
Quand on lance l’application :
Lien utiles :
Code Source :
//Bibliothèques utilisées #include "DHT.h" #include <RFduinoBLE.h> //A commenter pour désactiver les messages de debug sur le port série #define DEBUG //Déclaration du pinout #define BATT_SENS_PIN 2 #define DUST_SENSOR_PIN 3 #define LED_POWER_PIN 4 #define DHT_PIN 5 #define LEDS_PIN 6 // Indicateurs à leds #define LED_AIR 0 #define LED_HUMIDEX 1 #define LED_BLUETOOTH 2 #define NB_PIXELS 3 //RGB pour traversants, GRB pour CMS //#define LED_MODE_GRB const int nb_leds = NB_PIXELS*3; uint8_t leds[nb_leds]; //Initialisation de la bibliothèque DHT DHT dht(DHT_PIN, DHT22); // Variables globales int i; float ppm; long last_time; int sample_rate = 1000; // en millisecondes boolean ble_connected = false; union _floatToChar { // Utilitaire de conversion float f; char c[4]; } floatToChar; void setup() { #ifdef DEBUG Serial.begin(9600); // Initialisation du port série de debug Serial.println("OpenAir !"); #endif pinMode(LEDS_PIN, OUTPUT); setRGB(LED_BLUETOOTH, 0, 55, 200); setRGB(LED_AIR, 0, 55, 200); setRGB(LED_HUMIDEX, 0, 55, 200); showLeds(); analogReference(VBG); // Référence de 1.2V interne dht.begin(); // Initialisation du DHT22 pinMode(BATT_SENS_PIN, INPUT); // Initialisation du moniteur de batterie pinMode(LED_POWER_PIN, OUTPUT); // Initialisation du capteur de particules fines pinMode(DUST_SENSOR_PIN, INPUT); i = 0; ppm = 0; last_time = millis(); // Initialisation de la base de temps RFduinoBLE.deviceName = "OpenAir"; // Initialisation de la connexion bluetooth RFduinoBLE.advertisementData = "FDS06"; // Numéro de série RFduinoBLE.begin(); setRGB(LED_BLUETOOTH, 0, 0, 0); setRGB(LED_AIR, 0, 0, 0); setRGB(LED_HUMIDEX, 0, 0, 0); showLeds(); } void loop() { // On vérifie que la radio n'utilise pas les ressources while (!RFduinoBLE.radioActive); while (RFduinoBLE.radioActive); // Lecture du capteur de particules fines i++; digitalWrite(LED_POWER_PIN, LOW); delayMicroseconds(280); ppm += analogRead(DUST_SENSOR_PIN)*3.6 / 1023.0; delayMicroseconds(40); digitalWrite(LED_POWER_PIN, HIGH); delayMicroseconds(9680); if (millis() - last_time> sample_rate) { float voltage = ppm / i; float ppmpcf = (voltage - 0.0356) * 120000 / 100; float humidity = dht.readHumidity(); float temperature = dht.readTemperature(); float batterie = (float) analogRead(BATT_SENS_PIN) * 3.6 * 2.0 / 1023.0 ; #ifdef DEBUG if (isnan(temperature) || isnan(humidity)) { Serial.println("Erreur lors de la lecture du DHT22"); } #endif sendData(ppmpcf, humidity, temperature, batterie); setLedAirQuality(ppmpcf); setLedHumidex(humidity, temperature); setRGB(LED_BLUETOOTH, 0, 0, (ble_connected) ? 255 : 0); showLeds(); i = 0; ppm = 0; last_time = millis(); } } void RFduinoBLE_onConnect() { ble_connected = true; // Selection d'un interval de connection plus lent, pour économiser la batterie et // laisser le temps aux zones de code critiques de s'executer sans que la radio reprenne // la main. RFduinoBLE_update_conn_interval(900, 1000); } void RFduinoBLE_onDisconnect() { ble_connected = false; } void RFduinoBLE_onReceive(char *data, int len) { if (len> 0) { Serial.println(data); } } void sendData(float ppmpcf, float humidity, float temperature, float batterie) { #ifdef DEBUG Serial.print("ppmpcf: "); Serial.print(ppmpcf); Serial.print("\tHumidity: "); Serial.print(humidity); Serial.print(" %\tTemperature: "); Serial.print(temperature); Serial.print(" *C\t Batterie :"); Serial.print(batterie); Serial.println(" V"); #endif char data[16]; floatToChar.f = ppmpcf; data[0] = floatToChar.c[0];data[1] = floatToChar.c[1]; data[2] = floatToChar.c[2];data[3] = floatToChar.c[3]; floatToChar.f = humidity; data[4] = floatToChar.c[0];data[5] = floatToChar.c[1]; data[6] = floatToChar.c[2];data[7] = floatToChar.c[3]; floatToChar.f = temperature; data[8] = floatToChar.c[0];data[9] = floatToChar.c[1]; data[10] = floatToChar.c[2];data[11] = floatToChar.c[3]; floatToChar.f = batterie; data[12] = floatToChar.c[0];data[13] = floatToChar.c[1]; data[14] = floatToChar.c[2];data[15] = floatToChar.c[3]; RFduinoBLE.send(data, 16); } void setLedAirQuality(float ppmpcf) { if (ppmpcf <75) { // Excellent setRGB(LED_AIR, 0, 255, 0); } else if (ppmpcf <150) { // Very good setRGB(LED_AIR, 55, 200, 0); } else if (ppmpcf <300) { // Good setRGB(LED_AIR, 110, 145, 0); } else if (ppmpcf <1050) { // Fair setRGB(LED_AIR, 145, 110, 0); } else if (ppmpcf <3000) { // Poor setRGB(LED_AIR, 200, 55, 0); } else { // Very poor setRGB(LED_AIR, 255, 0, 0); } } // https://fr.wikipedia.org/wiki/Indice_humidex // http://www.physlink.com/Education/AskExperts/ae287.cfm void setLedHumidex(float H, float T) { float e = 6.112 * pow(10, 7.5*T / (237.7+T)) * H/100.0; float humidex = T + 5.0/0.9 * (e - 10.0); #ifdef DEBUG Serial.print("Humidex : "); Serial.println(humidex); #endif if (humidex <29) { // Aucun inconfort setRGB(LED_HUMIDEX, 0, 255, 0); } else if (humidex <150) { // Un certain inconfort setRGB(LED_HUMIDEX, 55, 200, 0); } else if (humidex <300) { // Beaucoup d'inconfort : évitez les efforts setRGB(LED_HUMIDEX, 110, 145, 0); } else if (humidex <1050) { // Danger setRGB(LED_HUMIDEX, 145, 110, 0); } else { // Coup de chaleur imminent setRGB(LED_HUMIDEX, 255, 0, 0); } } void setRGB(int led, uint8_t r, uint8_t g, uint8_t b) { #ifdef LED_MODE_GRB leds[led*3] = g*0.3; leds[led*3+1] = r*0.3; #else leds[led*3] = r*0.3; leds[led*3+1] = g*0.3; #endif leds[led*3+2] = b*0.3; } void showLeds() { noInterrupts(); for (int wsOut = 0; wsOut <nb_leds; wsOut++) { for (int x=7; x>=0; x--) { NRF_GPIO->OUTSET = (1UL <<LEDS_PIN); if (leds[wsOut] & (0x01 <<x)) { __ASM ( \ " NOP\n\t" \ " NOP\n\t" \ " NOP\n\t" \ " NOP\n\t" \ " NOP\n\t" \ ); NRF_GPIO->OUTCLR = (1UL <<LEDS_PIN); } else { NRF_GPIO->OUTCLR = (1UL <<LEDS_PIN); __ASM ( \ " NOP\n\t" \ " NOP\n\t" \ " NOP\n\t" \ ); } } } delayMicroseconds(50); // latch and reset WS2812. interrupts(); }
Nous sommes en train de travailler sur la version 2 de la station qui intégrera des capteurs de gaz (Ozone et NO2).