Projet DIY IoT : Construire une jardinière intelligente à faible coût
Il y a quelques semaines, j'ai décidé d'acheter une plante grasse pour mon bureau, uniquement pour ses bienfaits sur l'environnement. Si vous ne le savez pas, cultiver des plantes grasses ou des cactus présente de nombreux avantages : elles contribuent à purifier l'air, à améliorer l'humidité des espaces et à enrichir l'air en oxygène
Après quelques jours passés avec Lana (oui, je l'ai appelée Lana 💕) sur mon bureau, j'ai commencé à ressentir un manque. Passionnée de création et IoT chez Ubidots , j'ai décidé de créer un « pot de fleurs intelligent » pour Lana à l'aide de nos outils. Après quelques jours de travail acharné et de nombreux problèmes d'impression, j'ai finalement obtenu ce super résultat et j'avais hâte de partager mon processus avec vous 🙆♀️💚 :
Ce projet s'inspire d'un précédent, créé par Paul a Maker 👨💻 (Impression 3D, Électronique, Logiciels), que je suis depuis quelques mois. J'ai appris de nombreuses astuces et techniques grâce à lui. Si vous cherchez l'inspiration pour vos projets électroniques, suivez -le , croyez-moi !
Personnellement, j'aime beaucoup trouver l'inspiration en suivant les projets d'autres personnes. Quoi qu'il en soit, je trouve toujours le moyen d'y ajouter ma touche personnelle, de citer mes sources et, bien sûr, de partager le résultat final pour que d'autres puissent s'en inspirer également. 🤓 🤓
Cet article contient les étapes de mon projet, ainsi que toutes les ressources nécessaires pour reproduire le « Smart Planter ».
Exigences
- Une plante grasse ou un cactus
- NodeMCU ESP8266
- Capteur de température/humidité DHT11
- Capteur d'humidité du sol
- Anneau RGB
- (5) LED blanches
- Résistance de 220 Ω
- Fils
- Plaque d'essai PCB
- Connecteurs mâles à angle droit
- Imprimante 3D
- fers à souder
- fil à souder
Étape par étape
- Impression 3D
- Câblage
- Enveloppe
- Programmation du NodeMCU ESP8266
- Dashboard - Contrôle et surveillance
- Résumé
1. Impression 3D
Mes compétences en modélisation 3D sont assez limitées (j'y travaille pour créer davantage de projets avec l'imprimante 3D), mais il existe une communauté ouverte appelée Thingiverse qui nous facilite grandement la tâche. C'est une communauté de conception dynamique pour découvrir, créer et partager des objets imprimables en 3D. Après avoir examiné de nombreux modèles de jardinières, j'ai décidé d'imprimer celui-ci :
Cliquez ici pour télécharger le fichier - thing:2857938
J'ai beaucoup aimé ce modèle car il s'agissait déjà d'un pot de fleurs IoT , et la lampe était un accessoire à la fois esthétique et pratique. En fait, ce modèle correspondait parfaitement à ce que j'avais en tête depuis le début
- Lampe pour télécommande.
- Espace prévu pour placer des composants électroniques afin d'ajouter quelques capteurs.
Cependant, je savais que l'espace disponible pour l'électronique était insuffisant pour toutes les fonctionnalités que je souhaitais intégrer. Pour résoudre ce problème, j'ai imprimé deux fois la pièce inférieure :
- Pièce blanche : Pour placer le NodeMCU ESP8266, les capteurs et les fils.
- Pièce transparente : Pour placer l'anneau NeoPixel.
Ce qui a donné naissance au chef-d'œuvre ci-dessous :
REMARQUE : L’anneau NeoPixel n’est pas obligatoire pour ce projet ; il s’agit simplement d’un accessoire esthétique. Vous pouvez également n’en utiliser qu’un seul.
2. Câblage
Conformément au micrologiciel fourni dans ce guide, reportez-vous au schéma et au tableau ci-dessous pour établir une connexion correcte entre les composants utilisés.
3. Boîtier
Une fois les connexions électriques correctement effectuées, placez tous les composants à l'intérieur du pot de fleurs comme indiqué ci-dessous :
Comme vous pouvez le constater, j'ai placé le NodeMCU sur une plaque d'essai PCB avec 10 connecteurs à angle droit. L'idée était d'établir la connexion avec les capteurs et de gagner de la place pour l'électronique. Honnêtement, j'aurais pu mieux organiser les câbles. Cependant, le but était de créer un circuit imprimé personnalisé pour le pot de fleurs, dans lequel tout serait intégré. J'ai également percé la pièce blanche pour y faire passer les câbles de l'anneau NeoPixel. Pour finir, j'ai collé l'anneau NeoPixel, pointe vers le bas, sur la partie inférieure, puis j'ai collé la pièce transparente sur la pièce blanche afin de diffuser la lumière. Au final, j'ai obtenu ce superbe résultat :
4. Programmation du NodeMCU ESP8266
1. Pour utiliser la ESP8266 dans l'IDE Arduino, vous devez l' installer gestionnaire de cartes Arduino préconfiguré . Si vous ne savez pas comment ajouter une carte avec l'IDE Arduino, consultez cet article pour plus d'informations .
2. Une fois la plateforme ESP8266 installée, sélectionnez le périphérique ESP8266 que vous utilisez. Dans notre exemple, il s'agit d'un « NodeMCU 1.0 ». Pour sélectionner votre carte dans l'IDE Arduino, choisissez Outils > Carte > Module ESP8266 générique .
3. Téléchargez et installez la Ubidots MQTTESP8266 . Pour des explications détaillées sur l'installation des bibliothèques avec l'IDE Arduino, consultez ce guide .
4. Collez le code ci-dessous dans l'IDE Arduino. Ensuite, indiquez votre jeton Ubidots unique , le SSID (nom du réseau Wi-Fi ) et le mot de passe du réseau disponible.
REMARQUE : N'oubliez pas d'attribuer les broches appropriées aux composants utilisés si vous utilisez une connexion différente de celle indiquée ci-dessus.
/* Jardinière intelligente RGB intégrée à Ubidots pour la surveillance et le contrôle. Ce code permet : 1) de lire deux capteurs : DHT11 et humidité du sol ; 2) de publier les relevés des capteurs sur Ubidots; 3) de s'abonner à plusieurs variables pour le contrôle à distance. Bibliothèques requises : - Ubidots ESP8266 MQTT - (ubidots) -ubidotsNeoPixel - (https://github.com/adafruit/Adafruit_NeoPixel) - DHT - (https://github.com/adafruit/DHT-sensor-library) Réalisé par : Maria Hernández - Développeuse IoT chez Ubidots Révision : José García - Responsable du développement et du support chez Ubidots /******************************************* * Inclure les bibliothèques ****************************************/ #include<Adafruit_NeoPixel.h> #inclure<stdio.h> #inclure<map> #include "DHT.h" #include "UbidotsESPMQTT.h" /**************************************** * Définition des broches ****************************************/ #define LIGHTPIN D1 // Broche numérique pour la lampe LED. #define DHTPIN D5 // Broche numérique pour le capteur DHT. #define NEOPIXELSPIN D6 // Broche numérique pour l'anneau NeoPixel. #define MOISTUREPIN A0 // Broche analogique pour le capteur d'humidité. /**************************************** * Définition des constantes ****************************************/ #define TOKEN "BBFF-xxxxxxxxxx" // Attribuez votre jeton Ubidots . #define WIFINAME "xxxxxxxxxx" // Attribuez votre SSID. #define WIFIPASS "xxxxxxxxxx" // Attribuez votre mot de passe WiFi. #define DEVICE "planter" // Étiquette de l'appareil Ubidots . #define VAR_PUB_1 "temperature" // Étiquette des variables Ubidots pour la publication des données. #define VAR_PUB_2 "humidity" #define VAR_PUB_3 "soil-moisture" #define VAR_PUB_4 "heat-index" #define VAR_SUB_1 "light-1" // Étiquette des variables Ubidots pour l'abonnement aux données ; // Ces variables doivent être créées sur Ubidots. #define VAR_SUB_2 "light-2" #define NUMPIXELS 12 // Anneau NeoPixel 12 bits // Décommentez le type que vous utilisez #define DHTTYPE DHT11 // DHT 11 //#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 //#define DHTTYPE DHT21 // DHT 21 (AM2301) typedef enum { red, green, blue, yellow, white, black } NeoPixelColor; // R, G, B uint8_t myColors[][6] = {{250, 0, 0}, // Rouge. {0, 255, 0}, // Vert. {0, 0, 255}, // Bleu. {255, 255, 0}, // Jaune. {255, 255, 255}, // Blanc. {0, 0, 0}}; // Noir. const uint8_t nombreDeVariables = 2; // Nombre de variables pour l'abonnement. char *variableLabels[nombreDeVariables] = {VAR_SUB_1, VAR_SUB_2}; // Étiquette des variables pour l'abonnement. float valeur; // Stockage de la valeur entrante. int dernièreValeur; bool lumièreBas; // Indicateur pour contrôler les conditions de la lumière du bas. unsigned long tempsInitialisation; // Stockage de l'heure d'initialisation. const long SECONDES_POUR_RECONNECTER = 180000; // Période de reconnexion à la connexion MQTT. // Foncteur de comparaison pour mapper les fonctions. struct cmp_str { bool operator()(char const *a, char const *b) const { return strcmp(a, b) < 0; } }; // Déclaration de la fonction map. typedef std::function<void()> FunctionType; typedef std::map<const char *, FunctionType, cmp_str> mapTopicSubscription; /**************************************** * Définition des instances ****************************************/ Ubidots client(TOKEN); Adafruit_NeoPixel pixels(NUMPIXELS, NEOPIXELSPIN, NEO_GRB + NEO_KHZ800); DHT dht(DHTPIN, DHTTYPE); mapTopicSubscription ubiSubTopic; /**************************************** * Fonctions principales ****************************************/ void setup() { initTime = millis(); // Enregistrement de l'heure d'initialisation Serial.begin(115200); pinMode(LIGHTPIN, OUTPUT); // Déclaration du mode de la broche // Définition des fonctions mappées pour gérer l'événement d'abonnement. ubiSubTopic[VAR_SUB_1] = &subscriptionHandler1; ubiSubTopic[VAR_SUB_2] = &subscriptionHandler2;ubidotsSetBroker("ubidots"); // Configure correctement le broker pour le // compte professionnel. client.setDebug(true); // Passe une valeur booléenne (true ou false) pour activer les messages de débogage. client.wifiConnection(WIFINAME, WIFIPASS); // Établit la connexion WiFi. client.begin(callback); dht.begin(); // Initialise le capteur DHT. pixels.begin(); // Initialise l'anneau NeoPixel. pixels.clear(); // Désactive toutes les couleurs des pixels. // Établit l'abonnement avec les variables définies.ubidotsSubscribe(DEVICE, VAR_SUB_1);ubidotsSubscribe(DEVICE, VAR_SUB_2); } void loop() { // Rétablit l'abonnement avec les variables définies en cas de perte de connexion ou toutes les 3 minutes. if (!client.connected() || abs(millis() - initTime) > SECONDS_TO_RECONNECT) { initTime = millis(); client.reconnect();ubidotsSubscribe(DEVICE, VAR_SUB_1);ubidotsSubscribe(DEVICE, VAR_SUB_2); } client.reconnect(); // Lecture des valeurs de température, d'humidité et d'humidité du sol. float humidity = dht.readHumidity(); float temperature = dht.readTemperature(); int soilMoisture = analogRead(MOISTUREPIN); // Calcul de l'indice de chaleur en degrés Celsius (isFahreheit = false). float heatIndexC = dht.computeHeatIndex(temperature, humidity, false); // Vérification des échecs de lecture et sortie anticipée (pour réessayer). if (isnan(humidity) || isnan(temperature)) { Serial.println(F("Échec de la lecture du capteur DHT !")); } // Contrôle les couleurs des NeoPixels en fonction des valeurs de température. if (bottomLight) { if (inRange(temperature, 0, 16)) colorWipe(blue, 50); if (inRange(temperature, 16, 21)) colorWipe(green, 50); if (inRange(temperature, 21, 26)) colorWipe(yellow, 50); if (inRange(temperature, 26, 40)) colorWipe(red, 50); } // Ajoute les variables à publier sur Ubidots. client.add(VAR_PUB_1, temperature); client.add(VAR_PUB_2, humidity); client.add(VAR_PUB_3, soilMoisture); client.addubidotsVAR_PUB_4, heatIndexC); // Publie toutes les variables ajoutées au périphérique défini. client.ubidotsPublish(DEVICE); client.loop(); delay(1000); } /**************************************** * Fonctions d'abonnement ****************************************/ // Fonction exécutée lorsque var_sub_1 change d'état. void subscriptionHandler1() { if (value == 1) { Serial.println("Lampe du pot allumée."); digitalWrite(LIGHTPIN, HIGH); } else { Serial.println("Lampe du pot éteinte."); digitalWrite(LIGHTPIN, LOW); } }; // Fonction exécutée lorsque var_sub_2 change d'état. void subscriptionHandler2() { if (value != lastValue) { if (value == 1) { Serial.println("Lumière du bas du pot allumée."); for (int i = 0; i < 3; i++) { colorWipe(red, 50); colorWipe(green, 50); colorWipe(blue, 50); }; colorWipe(white, 200); bottomLight = true; } else { Serial.println("La lumière du bas du pot de fleurs est éteinte."); colorWipe(white, 50); colorWipe(black, 200); bottomLight = false; } } lastValue = value; }; /**************************************** * Fonctions auxiliaires ****************************************/ // Retourne un entier avec la longueur d'un char int strLen(char *s) { int l = 0; while (*s != '\0') { s++; l++; } return (l); } // Fonction de rappel pour gérer l'abonnement void callback(char *topic, byte *payload, unsigned int length) { char *variableLabel = (char *)malloc(sizeof(char) * 30); getVariableLabelTopic(topic, variableLabel); // Enregistre l'étiquette de la variable. valeur = btof(payload, longueur); // Enregistre la valeur de la variable abonnée. executeCases(variableLabel); // Exécute le gestionnaire de fonction pour la // variable abonnée. free(variableLabel); // Libère la mémoire. } // Analyse le sujet reçu pour extraire l'étiquette de la variable. void getVariableLabelTopic(char *topic, char *variableLabel) { sprintf(variableLabel, ""); for (int i = 0; i < numberOfVariables; i++) { char *resultLv = strstr(topic, variableLabels[i]); if (resultLv != NULL) { uint8_t len = strlen(resultLv); char result[100]; uint8_t i = 0; for (i = 0; i < len - 3; i++) { result[i] = resultLv[i]; } result[i] = '\0'; snprintf(variableLabel, strLen(result) + 1, "%s", result); break; } } } // Conversion d'un tableau de caractères en valeur flottante. float btof(byte *payload, unsigned int length) { char *demo_ = (char *)malloc(sizeof(char) * 10); for (int i = 0; i < length; i++) { demo_[i] = payload[i]; } return atof(demo_); } // Exécute la fonction d'abonnement correspondante en fonction de la valeur reçue. void executeCases(char *variableLabel) { if (ubiSubTopic.find(variableLabel) != ubiSubTopic.end()) { mapTopicSubscription::iterator i = ubiSubTopic.find(variableLabel); (i->second)(); } } // Remplit les pixels de l'anneau NeoPixel un par un avec de la couleur. void colorWipe(NeoPixelColor color, int wait) { int r, g, b; r = myColors[color][0]; g = myColors[color][1]; b = myColors[color][2]; for (int i = 0; i < pixels.numPixels(); i++) { pixels.setPixelColor(i, r, g, b); pixels.show(); delay(wait); } } // Vérifie si la valeur reçue est dans la plage attendue bool inRange(float x, int low, int high) { return ((x - low) > 0 && (high - x) >= 0); }
5. Vérifiez cliquez sur l'icône Coche en haut à gauche de l'IDE Arduino
6. Téléversez le code dans votre « NodeMCU 1.0 » . Pour ce faire, choisissez l' icône flèche vers la droite » coche ».
7. Pour vérifier la connectivité de l'appareil et les données envoyées, ouvrez le moniteur série en sélectionnant l'icône « loupe » dans le coin supérieur droit de l'IDE Arduino pour voir les logs ainsi que les réponses du Ubidots .
8. Après quelques secondes d'initialisation, le code fourni créera automatiquement un nouvel appareil dans votre Ubidots . Rendez-vous dans la section « Appareils » de votre compte Ubidots ; vous devriez y voir les nouveaux appareils créés.
Saisissez le périphérique « Planter » et consultez les variables configurées pour transmettre les données :
9. Créez ensuite deux nouvelles variables brutes pour établir l'abonnement et contrôler les lumières à distance. Pour ce faire, cliquez sur « Ajouter une variable > Variable brute » et attribuez-leur l'étiquette définie dans le code. Dans l'exemple de code fourni, les étiquettes des variables à créer sont « light-1 » et « light-2 » .
Une fois les variables créées avec succès, vous devriez obtenir le résultat suivant :
5. Dashboard - Contrôle et surveillance
L'intégration étant désormais terminée, il est temps de présenter les données des appareils sur un Dashboard . dashboard permettra également de contrôler l'état des deux lampes.
1. Pour créer votre premier dashboard , accédez à la Dashboard Onglet (Données → Dashboards ) . Ensuite, sélectionnez l'icône plus (+) en haut à droite, puis choisissez le type de widget souhaité. Vous devriez pouvoir créer dashboards comme celui ci-dessous :
En savoir plus sur Dashboards Ubidots : Personnalisation de l’application : Styles personnalisés pour vos dashboards et widgets
Ubidots est très intuitif et permet à tous les utilisateurs de gérer leurs données et de le personnaliser à leur guise. Pour en savoir plus, je vous recommande de consulter les guides suivants :
- Principes de base Ubidots : appareils, variables, Dashboardset alertes
- Principes de base Ubidots : Applications, organisations et utilisateurs expliqués
2. Ubidots prend en charge les événements déjà intégrés pour vous permettre d'envoyer des événements, des alertes et des notifications basés sur les données de vos capteurs et actionneurs.
Découvrez les types d'événements pris en charge et apprenez à les configurer:
- notifications par e-mail
- notifications SMS
- Événements Webhook - En savoir plus
- notifications Telegram
- Notifications Slack - En savoir plus
- Notifications d'appels vocaux - En savoir plus
- Notification de retour à la normale - En savoir plus
- Notifications de géorepérage - En savoir plus
6. Résumé
Après quelques heures de conception et de programmation (et beaucoup de cafés), j'ai donné vie à ce pot de fleurs intelligent :
Comme je l'ai mentionné au début, j'ai créé cet objet car je ne voulais pas seulement une nouvelle décoration de bureau, mais aussi parce que je sentais qu'il manquait quelque chose à Lana. Je souhaitais inventer ma propre façon de communiquer avec elle grâce à IoT et aux données. Si vous souhaitez interagir avec vos plantes autrement, vous pouvez les écouter grâce au MIDI Sprout . C'est génial, non ? 🤩
Il s'agit ici de la version V0 du Smart Planter et je souhaite encore améliorer certains points, comme le design, l'organisation électronique avec un circuit imprimé personnalisé et l'intégration avec d'autres services tels que Google Assistant, Alexa et Twitter.
J'espère que vous avez apprécié autant que moi. Si vous avez des commentaires ou des questions concernant le projet, n'hésitez pas à me contacter ! Je suis tout à fait ouverte aux suggestions constructives pour améliorer ce type de projets et les partager avec vous. 😁💚
Projets IoT plus utiles :