Le produit que nous examinons aujourd’hui est le kit de surveillance de la qualité de l’air « AirGradient ONE », qui est une version mise à jour du précédent moniteur de qualité de l’air AirGradient. L’appareil est équipé de capteurs Sensirion et Plantower, lui permettant de mesurer de nombreux paramètres de qualité de l’air tels que le CO2, les PM2,5, les COVT, les NOx, la température et l’humidité. Il s’agit d’un moniteur de qualité de l’air intérieur qui est à la fois un logiciel open source et un matériel ouvert. Cela signifie que le code source Arduino, les diagrammes schématiques, le PCB et les modèles 3D du boîtier sont disponibles pour les développeurs.
Déballage du kit de bricolage AirGradient ONE


L’appareil était emballé dans une boîte en carton, avec une carte de vœux du fabricant. La carte comporte un code QR renvoyant vers une page Web contenant le guide d’installation.


Depuis que j’ai demandé la version Kit (il existe aussi un modèle entièrement assemblé), certains capteurs n’étaient pas pré-assemblés et étaient bien emballés dans des joints séparés. Le PCB principal se trouvait déjà à l’intérieur du boîtier et les vis n’étaient pas encore fixées. Les composants supplémentaires dans la boîte comprenaient un tournevis, des vis, un câble USB Type-C et un adaptateur 5 V 2 A.






Caractéristiques
Ce kit est l’AirGradient ONE utilisant PCB V9 avec l’ESP32-C3 Mini comme microcontrôleur principal. De plus, il comprend un écran OLED de 1,3 pouces avec une résolution de 128 × 64 pixels. La carte mère est également équipée de 11 LED NeoPixel RGB programmables qui sont utilisées pour visualiser le niveau de qualité de l’air. Les détails des autres composants contenus dans les packages sont répertoriés ci-dessous.
- 1x capteur PM Plantower PMS5003
- 1x capteur de CO2 Senseair S8
- 1x module de capteur de température et d’humidité SHT4x
- 1x module de capteur SGP41 TVOC/NOx
- 1x adaptateur 5V 2000mA
- 1x câble USB Type-C à 90 degrés
- 4x vis Torx T6 M1,8 × 10
- 1x tournevis Torx T6
Assemblage du kit AirGradient ONE
Le fabricant fournit les instructions de construction via cette page Web. Les instructions de montage sont bien écrites et faciles à suivre. En gros, je n’avais que trois composants à installer, comme indiqué ci-dessous.


Pour le module Senseair S8, il existe deux jeux de connecteurs mâles : l’un est un connecteur mâle 1×4 et l’autre est un connecteur mâle 1×5 broches. J’ai dû placer le capteur dans la prise du PCB étiquetée « CO2 Sensor », en m’assurant que l’orientation du capteur était correcte.
Le module SGP41 et le module SHT4x sont très similaires, avec le même nombre de broches. J’ai donc soigneusement vérifié l’étiquette sur les modules et inséré le module SGP41 dans le socket étiqueté « I2C3 » et le SHT1X dans le socket étiqueté « SHT4x ». Notez que la couleur de la sérigraphie de ces deux modules peut différer de celle affichée sur la page Web d’instructions : dans mon cas, le SGP41 avait une sérigraphie bleue et le SHT4X avait une sérigraphie magenta. De plus, lors de l’installation des modules dans le socket, j’ai dû m’assurer que les modules étaient orientés vers l’extérieur, comme le montrent les figures suivantes.
Le capteur PMS utilise un connecteur JST, et dans mon cas, il était déjà connecté au PCB. Je viens donc de vérifier que les deux extrémités du câble sont bien branchées.
Après avoir installé les modules, nous pouvons alimenter l’appareil en branchant l’USB Type-C dans la prise située à l’arrière du boîtier. Il y a une fente pour câble à l’arrière du boîtier pour maintenir le câble en place et l’empêcher de pendre ou de s’emmêler.






Après avoir mis l’appareil sous tension, il s’initialise avec le micrologiciel par défaut et l’écran OLED s’allume, ce qui signifie que tout fonctionne correctement. Ensuite, je ferme les couvercles supérieur et inférieur du boîtier et je les vis solidement. Maintenant, il est prêt pour la prochaine étape.
Utilisation du moniteur de qualité de l’air AirGradient ONE
Lorsque l’appareil est allumé, un message nous demandera de configurer l’unité de mesure. Nous pouvons accéder à l’écran de configuration en appuyant longuement sur le petit bouton situé à l’arrière du boîtier. En appuyant brièvement sur le bouton, nous pouvons parcourir l’unité de mesure des PM2,5 et l’unité de température comme indiqué ci-dessous.
- Température : °C, PM : ug/m3
- Température : °C, PM : AQI américain
- Température : °F, PM : ug/m3
- Température : °F, PM : AQI américain
Après avoir choisi les unités préférées, j’ai à nouveau appuyé longuement sur le bouton pour enregistrer la configuration et redémarrer l’appareil.


Lors de la première mise sous tension, l’appareil demandera à se connecter au WiFi. Pour ce faire, j’ai dû enregistrer le numéro de série de l’appareil, qui sera affiché sur l’écran OLED lors du processus de démarrage. J’ai ensuite utilisé mon téléphone portable pour rechercher le point d’accès WiFi de l’appareil nommé «AG-xxxxxx« , où « xxxxxx » était le numéro de série de l’appareil.
Une fois connecté au hotspot de l’appareil, j’ai défini le SSID et le mot de passe de mon hotspot WiFi cible puis j’ai enregistré les paramètres pour terminer la configuration WiFi.


Après l’écran de configuration, les LED RVB de l’appareil afficheront les couleurs correspondant à la qualité de l’air, tandis que l’écran OLED affichera les données des capteurs en utilisant les unités choisies. Le kit AirGradient ONE fonctionnera même s’il n’y a pas de connexion WiFi.




Connectez-vous au tableau de bord AirGradient
Comme il y a un port de connexion USB à l’arrière du boîtier, j’ai connecté l’appareil à mon ordinateur portable à l’aide du câble USB Type-C fourni. J’ai ouvert l’IDE Arduino et observé les messages affichés dans le moniteur série pour vérifier si des messages étaient en cours d’impression. Après observation, j’ai découvert que l’appareil collectait des données de mesure, y compris le RSSI du point d’accès WiFi connecté, et envoyait ces données au serveur AirGradient Dashboard au format JSON. L’URL par défaut est http://hw.airgradient.com/sensors/airgradient:xxxxx/measuresoù xxxxx est le numéro de série de l’appareil. Cependant, le serveur a rejeté la demande et a renvoyé le message d’erreur «sensor 'airgradient:xxxxxx' unknown« .
Pour résoudre ce problème, j’ai dû créer un compte AirGradient Dashboard et ajouter des informations sur mon appareil telles que l’emplacement et le numéro de série. Après avoir créé et ajouté avec succès mon appareil au tableau de bord, j’ai redémarré l’appareil et j’ai attendu quelques secondes qu’il se connecte à Internet et commence à envoyer des données. Si la connexion réussit, nous verrons quelque chose comme les chiffres suivants.




Flasher le micrologiciel AirGradient
Au moment de cet examen, il existe deux méthodes pour flasher l’appareil : le flashage direct à l’aide du navigateur Web et le flashage manuel avec l’IDE Arduino. Ici, j’ai décidé d’utiliser l’IDE Arduino pour flasher ma carte. Pour cette test, j’ai utilisé l’IDE Arduino 1.8.13, déjà installé sur mon ordinateur. J’ai téléchargé le code source depuis le dépôt GitHub du fabricant et ouvert le fichier ONE_V9.ino. Comme suggéré sur la page Web, j’ai choisi la plateforme ESP32 et sélectionné la Lolin C3 Mini comme carte cible.


La liste des bibliothèques requises est écrite dans l’en-tête du fichier ONE_V9.ino. Dans mon cas, les six bibliothèques suivantes étaient nécessaires. Vous pouvez soit utiliser Library Manager pour installer ces bibliothèques, soit les télécharger et les copier manuellement dans les bibliothèques Arduino.
- WifiManager par tzapu, tablatronix testé avec la version 2.0.11-beta
- U8g2 par Oliver testé avec la version 2.32.15
- Sensirion I2C SGP41 par Sensation Version 0.1.0
- Algorithme d’indice de gaz Sensirion par Sensation version 3.2.1
- Arduino-SHT de Johannes Winkelmann version 1.2.2
- Adafruit NeoPixel par Adafruit Version 1.11.0
Ma première compilation a échoué à cause de certaines bibliothèques manquantes. Dans mon cas, je devais installer ces bibliothèques supplémentaires.
- Bibliothèque PMS de Markusz Kakl version 1.1.0
- S8 UART par Josep Comas Version 1.0.0
- Sensirion Core par Sensirion version 0.6.0
Après l’installation de ces bibliothèques, la compilation échouait toujours, mais les problèmes résidaient dans les fichiers PMS.h et PMS.cpp. Après avoir cherché sur Internet, j’ai trouvé une solution dans cet article, qui mentionnait que le fabricant utilisait une version modifiée de la bibliothèque PMS. J’avais donc besoin de mettre à jour ces deux fichiers avec le code suivant :
#ifndef PMS_H #define PMS_H #include « Stream.h » class PMS { public: static const uint16_t SINGLE_RESPONSE_TIME = 1000; const uint16_t statique TOTAL_RESPONSE_TIME = 1000 * 10 ; const uint16_t statique STEADY_RESPONSE_TIME = 1000 * 30 ; const uint16_t statique BAUD_RATE = 9600 ; struct DATA { // Particules standards, CF=1 uint16_t PM_SP_UG_1_0; uint16_t PM_SP_UG_2_5 ; uint16_t PM_SP_UG_10_0 ; // Environnement atmosphérique uint16_t PM_AE_UG_1_0; uint16_t PM_AE_UG_2_5 ; uint16_t PM_AE_UG_10_0; // Nombre de particules brutes (nombre de particules dans 0,1 l d’air uint16_t PM_RAW_0_3; uint16_t PM_RAW_0_5; uint16_t PM_RAW_1_0; uint16_t PM_RAW_2_5; uint16_t PM_RAW_5_0; uint16_t PM_RAW_10_0; // Formaldéhyde (HCHO) concentration en mg/m^3 – unités PMSxxxxST uniquement uint16_t AMB_HCHO; // Température et humidité – unités PMSxxxxST uniquement int16_t AMB_TMP; uint16_t AMB_HUM; }; PMS(Stream&); void sleep(); void wakeUp(); void activeMode(); void passiveMode(); void requestRead(); bool read(DATA& data); bool readUntil(DATA& data, uint16_t timeout = SINGLE_RESPONSE_TIME); privé : enum STATUS { STATUS_WAITING, STATUS_OK }; enum MODE { MODE_ACTIVE, MODE_PASSIVE }; uint8_t _payload[50]; Flux* _stream ; DONNÉES* _données ; STATUT _statut ; MODE_mode = MODE_ACTIVE ; uint8_t _index = 0 ; uint16_t _frameLen; uint16_t _checksum ; uint16_t _calculatedChecksum ; boucle vide (); char Char_PM2[10]; } ; #fin si
|
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
#ifndef PMS_H #définir PMS_H #include « Stream.h » classe PMS { publique: const uint16_t statique SINGLE_RESPONSE_TIME = 1000 ; const uint16_t statique TOTAL_RESPONSE_TIME = 1000 * 10 ; const uint16_t statique STEADY_RESPONSE_TIME = 1000 * 30 ; const uint16_t statique BAUD_RATE = 9600 ; structure DONNÉES { // Particules standards, CF=1 uint16_t PM_SP_UG_1_0 ; uint16_t PM_SP_UG_2_5 ; uint16_t PM_SP_UG_10_0 ; // Environnement atmosphérique uint16_t PM_AE_UG_1_0; uint16_t PM_AE_UG_2_5 ; uint16_t PM_AE_UG_10_0; // Nombre de particules brutes (nombre de particules dans 0,1l d’air uint16_t PM_RAW_0_3; uint16_t PM_RAW_0_5; uint16_t PM_RAW_1_0; uint16_t PM_RAW_2_5; uint16_t PM_RAW_5_0; uint16_t PM_RAW_10_0; // Concentration de formaldéhyde (HCHO) en mg/m^3 – unités PMSxxxxST uniquement uint16_t AMB_HCHO ; // Température et humidité – unités PMSxxxxST uniquement int16_t AMB_TMP ; uint16_t AMB_HUM ; } ; PMS (flux&); annuler le sommeil (); void wakeUp(); void activeMode(); void modepassif(); void requestRead(); bool read (DONNÉES et données); bool readUntil(DATA& data, uint16_t timeout = SINGLE_RESPONSE_TIME); privé: enum STATUS { STATUS_WAITING, STATUS_OK } ; énumération MODE { MODE_ACTIVE, MODE_PASSIVE } ; uint8_t _charge utile[50]; Flux* _stream ; DONNÉES* _données ; STATUT _statut ; MODE_mode = MODE_ACTIVE ; uint8_t _index = 0 ; uint16_t _frameLen; uint16_t _checksum ; uint16_t _calculatedChecksum ; boucle vide (); char Char_PM2[10]; } ; #fin si |
#include « PMS.h » PMS::PMS(Stream& stream) { this->_stream = &stream; } // Mode veille. Pour une faible consommation d’énergie et prolonger la durée de vie du capteur. void PMS::sleep() { commande uint8_t[] = { 0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73 } ; _stream->write(commande, sizeof(commande)); } // Mode de fonctionnement. Des données stables doivent être obtenues au moins 30 secondes après le réveil du capteur du mode veille en raison des performances du ventilateur. void PMS::wakeUp() { commande uint8_t[] = { 0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74 } ; _stream->write(commande, sizeof(commande)); } // Mode actif. Mode par défaut après la mise sous tension. Dans ce mode, le capteur enverrait automatiquement les données série à l’hôte. void PMS::activeMode() { commande uint8_t[] = { 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71 } ; _stream->write(commande, sizeof(commande)); _mode = MODE_ACTIVE ; } // Mode passif. Dans ce mode, le capteur enverrait des données série à l’hôte uniquement sur demande. void PMS::passiveMode() { commande uint8_t[] = { 0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70 } ; _stream->write(commande, sizeof(commande)); _mode = MODE_PASSIVE ; } // Demande de lecture en mode passif. void PMS::requestRead() { if (_mode == MODE_PASSIVE) { commande uint8_t[] = { 0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71 } ; _stream->write(commande, sizeof(commande)); } } // Fonction non bloquante pour analyser la réponse. bool PMS::read(DONNÉES& données) { _data = &data; boucle(); return _status == STATUS_OK ; } // Fonction de blocage pour analyser la réponse. Le délai d’attente par défaut est de 1 s. bool PMS::readUntil(DATA& data, uint16_t timeout) { _data = &data; uint32_t start = millis(); faire { boucle(); si (_status == STATUS_OK) pause ; } while (millis() – start < timeout); return _status == STATUS_OK ; } void PMS::loop() { _status = STATUS_WAITING; if (_stream->available()) { uint8_t ch = _stream->read(); switch (_index) { cas 0 : if (ch != 0x42) { return ; } _calculatedChecksum = ch; casser; cas 1 : if (ch != 0x4D) { _index = 0; retour; } _calculatedChecksum += ch; casser; cas 2 : _calculatedChecksum += ch ; _frameLen = ch << 8; casser; cas 3 : _frameLen |= ch; // Capteur non pris en charge, longueur de trame différente, erreur de transmission, etc. if (_frameLen != 2 * 9 + 2 && _frameLen != 2 * 13 + 2) { _index = 0; retour; } _calculatedChecksum += ch; casser; par défaut : if (_index == _frameLen + 2) { _checksum = ch << 8 ; } sinon if (_index == _frameLen + 2 + 1) { _checksum |= ch; if (_calculatedChecksum == _checksum) { _status = STATUS_OK ; // Particules standards, CF=1. _data->PM_SP_UG_1_0 = makeWord(_payload[0]_charge utile[1]); _data->PM_SP_UG_2_5 = makeWord(_payload[2]_charge utile[3]); _data->PM_SP_UG_10_0 = makeWord(_payload[4]_charge utile[5]); // Environnement atmosphérique. _data->PM_AE_UG_1_0 = makeWord(_payload[6]_charge utile[7]); _data->PM_AE_UG_2_5 = makeWord(_payload[8]_charge utile[9]); _data->PM_AE_UG_10_0 = makeWord(_payload[10]_charge utile[11]); // Nombre total de particules pour 100 ml d’air _data->PM_RAW_0_3 = makeWord(_payload[12]_charge utile[13]); _data->PM_RAW_0_5 = makeWord(_payload[14]_charge utile[15]); _data->PM_RAW_1_0 = makeWord(_payload[16]_charge utile[17]); _data->PM_RAW_2_5 = makeWord(_payload[18]_charge utile[19]); _data->PM_RAW_5_0 = makeWord(_payload[20]_charge utile[21]); _data->PM_RAW_10_0 = makeWord(_payload[22]_charge utile[23]); // Concentration de formaldéhyde (unités PMSxxxxST uniquement) _data->AMB_HCHO = makeWord(_payload[24]_charge utile[25]) / 1000 ; // Température et humidité (unités PMSxxxxST uniquement) _data->AMB_TMP = makeWord(_payload[20]_charge utile[21]); _data->AMB_HUM = makeWord(_payload[22]_charge utile[23]); } _index = 0; retour; } else { _calculatedChecksum += ch; uint8_t payloadIndex = _index – 4; // La charge utile est commune à tous les capteurs (2×6 premiers octets). if (payloadIndex < sizeof(_payload)) { _payload[payloadIndex] = ch; } } casser; } _index++; } }
|
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
#include « PMS.h » PMS : PMS (flux et flux) { ceci->_stream = &stream; } // Mode veille. Pour une faible consommation d’énergie et prolonger la durée de vie du capteur. void PMS::sleep() { commande uint8_t[] = { 0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73 } ; _stream->write(commande, sizeof(commande)); } // Mode de fonctionnement. Des données stables doivent être obtenues au moins 30 secondes après le réveil du capteur du mode veille en raison des performances du ventilateur. annuler PMS :: wakeUp () { commande uint8_t[] = { 0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74 } ; _stream->write(commande, sizeof(commande)); } // Mode actif. Mode par défaut après la mise sous tension. Dans ce mode, le capteur enverrait automatiquement les données série à l’hôte. annuler PMS :: activeMode () { commande uint8_t[] = { 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71 } ; _stream->write(commande, sizeof(commande)); _mode = MODE_ACTIVE ; } // Mode passif. Dans ce mode, le capteur enverrait des données série à l’hôte uniquement sur demande. void PMS::passiveMode() { commande uint8_t[] = { 0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70 } ; _stream->write(commande, sizeof(commande)); _mode = MODE_PASSIVE ; } // Requête de lecture en mode passif. annuler PMS :: requestRead () { si (_mode == MODE_PASSIVE) { commande uint8_t[] = { 0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71 } ; _stream->write(commande, sizeof(commande)); } } // Fonction non bloquante pour analyser la réponse. bool PMS :: read (DONNÉES et données) { _données = &données; boucle(); return _status == STATUS_OK ; } // Fonction de blocage pour analyser la réponse. Le délai d’attente par défaut est de 1 s. bool PMS::readUntil(DATA& data, uint16_t timeout) { _données = &données; uint32_t start = millis(); faire { boucle(); si (_status == STATUS_OK) pause ; } while (millis() – start < timeout); return _status == STATUS_OK ; } annuler PMS :: boucle () { _status = STATUS_WAITING ; si (_stream->disponible()) { uint8_t ch = _stream->read(); commutateur (_index) { cas 0 : si (ch != 0x42) { retour; } _calculatedChecksum = ch; casser; cas 1: si (ch != 0x4D) { _index = 0 ; retour; } _calculatedChecksum += ch; casser; cas 2 : _calculatedChecksum += ch; _frameLen = ch << 8; casser; cas 3 : _frameLen |= ch; // Capteur non pris en charge, longueur de trame différente, erreur de transmission, etc. si (_frameLen != 2 * 9 + 2 && _frameLen != 2 * 13 + 2) { _index = 0 ; retour; } _calculatedChecksum += ch; casser; défaut: si (_index == _frameLen + 2) { _checksum = ch << 8 ; } sinon si (_index == _frameLen + 2 + 1) { _checksum |= ch; si (_calculatedChecksum == _checksum) { _statut = STATUS_OK ; // Particules standards, CF=1. _data->PM_SP_UG_1_0 = makeWord(_payload[0]_charge utile[1]); _data->PM_SP_UG_2_5 = makeWord(_payload[2]_charge utile[3]); _data->PM_SP_UG_10_0 = makeWord(_payload[4]_charge utile[5]); // Environnement atmosphérique. _data->PM_AE_UG_1_0 = makeWord(_payload[6]_charge utile[7]); _data->PM_AE_UG_2_5 = makeWord(_payload[8]_charge utile[9]); _data->PM_AE_UG_10_0 = makeWord(_payload[10]_charge utile[11]); // Nombre total de particules pour 100 ml d’air _data->PM_RAW_0_3 = makeWord(_payload[12]_charge utile[13]); _data->PM_RAW_0_5 = makeWord(_payload[14]_charge utile[15]); _data->PM_RAW_1_0 = makeWord(_payload[16]_charge utile[17]); _data->PM_RAW_2_5 = makeWord(_payload[18]_charge utile[19]); _data->PM_RAW_5_0 = makeWord(_payload[20]_charge utile[21]); _data->PM_RAW_10_0 = makeWord(_payload[22]_charge utile[23]); // Concentration de formaldéhyde (unités PMSxxxxST uniquement) _data->AMB_HCHO = makeWord(_payload[24]_charge utile[25]) / 1000 ; // Température et humidité (unités PMSxxxxST uniquement) _data->AMB_TMP = makeWord(_payload[20]_charge utile[21]); _data->AMB_HUM = makeWord(_payload[22]_charge utile[23]); } _index = 0 ; retour; } autre { _calculatedChecksum += ch; uint8_t payloadIndex = _index – 4; // La charge utile est commune à tous les capteurs (2×6 premiers octets). si (payloadIndex < sizeof(_payload)) { _charge utile[payloadIndex] = ch; } } casser; } _index++; } } |
La compilation et le téléchargement ont été effectués avec succès. Cependant, j’ai compris que l’appareil ne parvenait pas à se connecter au WiFi. J’ai donc décidé de résoudre ce problème en codant manuellement le SSID et le mot de passe. Après cela, l’appareil a fonctionné normalement.


Open source
Personnalisation du code source Arduino
Comme mentionné ci-dessus, nous pouvons accéder au code source sur GitHub, et non seulement au firmware de ce kit, mais aussi au firmware d’autres versions, et quelques exemples y sont disponibles.
J’ai ensuite modifié le code source (ONE_V9.ino) pour envoyer les données à mon propre serveur en modifiant la valeur du APIROOT variable en haut du code source à l’URL de mon propre serveur. Ensuite, j’ai modifié le sendToServer() fonction en ajoutant le numéro de série de l’appareil à la requête HTTP. Après avoir mis à jour la valeur du POSTURL chaîne pour correspondre à mes besoins, j’ai compilé et téléchargé le nouveau firmware sur l’appareil. Après quelques secondes, l’appareil a commencé à envoyer les données à mon propre serveur avec succès.





Les 11 LED RVB étant programmables, j’ai continué à modifier le code source pour changer le comportement des LED. Avec la configuration par défaut, ces voyants sont éteints lors du démarrage et seront allumés une fois que l’appareil accédera à l’écran principal.
Étant donné que l’appareil utilise la bibliothèque NeoPixel d’Adafruit, je peux contrôler la couleur de chaque LED en appelant simplement le setPixelColor fonctionner avec l’indice LED souhaité et les valeurs des composants RVB. Par conséquent, j’ai ajouté le code suivant à la fin de la fonction de configuration pour que les LED s’allument de manière aléatoire pendant quelques secondes avant de revenir à l’état normal.
void setup() { … int i; int j; int r; entier g; int b; for(i = 0; i < 11; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); retard(1); } pixels.show(); for(i = 0; i < 32; i++) { for(j = 0; j < 11; j++) { r = aléatoire(0, 256); g = aléatoire (0, 256); b = aléatoire (0, 256) ; pixels.setPixelColor( j, pixels.Color(r, g, b)); } délai (50); pixels.show(); } for(i = 0; i < 11; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); } pixels.show(); }
|
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
void setup() { … int je; int j; int r; entier g; int b; pour(je = 0; je < 11; je++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); retard(1); } pixels.show(); pour(je = 0; je < 32; je++) { pour(j = 0; j < 11; j++) { r = aléatoire (0, 256); g = aléatoire (0, 256); b = aléatoire (0, 256) ; pixels.setPixelColor( j, pixels.Color(r, g, b)); } retard (50); pixels.show(); } pour(je = 0; je < 11; je++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); } pixels.show(); } |


Fichiers de conception matérielle
Non seulement les codes sources sont disponibles, mais les diagrammes schématiques et les fichiers PCB sont également accessibles aux développeurs via cette page Web. Ces fichiers sont au format KiCad et j’ai pu les ouvrir avec KiCad 7.0 sans aucun problème.





Imprimez en 3D votre propre boîtier
Le constructeur met également à disposition des développeurs des modèles 3D du boîtier. Ces modèles sont au format STL et peuvent être téléchargés via cette page web où deux fichiers ZIP sont disponibles en téléchargement : un pour le coffret et l’autre pour le support clipsable.
Le modèle de boîtier 3D est composé de trois modèles : le boîtier inférieur, le boîtier supérieur et les modèles de zone de câbles. J’ai visualisé ces modèles 3D en ouvrant les fichiers STL dans le logiciel MeshLab, comme le montrent les figures suivantes. J’ai également testé l’impression du modèle de zone de câble en découpant le fichier STL avec PrusaSlicer 2.6.0 et en l’imprimant à l’aide de Printrun 2.1. Ce modèle était facile à imprimer et le modèle imprimé est présenté dans la figure suivante.




Conclusion
Le moniteur de qualité de l’air intérieur AirGradient ONE fonctionne très bien, même si en observant les messages via le port série, j’ai remarqué que les valeurs de mesure sont parfois instables après le redémarrage de l’appareil. Heureusement, ils se stabilisent en quelques secondes. Le caractère open source de l’appareil permet également de personnaliser le micrologiciel, l’électronique et le boîtier.
Je tiens à remercier AirGradient d’avoir fourni le moniteur de qualité de l’air One Kit pour cet examen. Vous pouvez commander la version entièrement assemblée et testée de cet AirGradient ONE pour 195 $, ou la version en kit examinée ici pour 138 $, sur le site Web du fabricant.
Retrouvez l’histoire de Raspberry Pi dans cette vidéo :

-
Moniteur de qualité de l'air intérieur, Moniteur De Qualité De L'air Compteur De Particules De Poussière D'air À 3 Canaux Analyseur De Gaz Compteur D'air Détecteur PM10 Pm1.0 Pm2.5 pour la maison et l
-
Professionnel Moniteur Qualité de l'Air 5-en-1 avec Capteur CO₂ – Mesure en Temps Réel : CO2, HCHO (Formaldéhyde), TVOC, Température et Humidité – Analyseur pour Intérieur Maison, Bureau, École
