Avec un Atmega, créer un capteur de température sans fil
Pour continuer le projet de domotique avec le Raspberry, la première étape importante pour moi est d’avoir un capteur capable d’envoyer sans fil des données. Ici je vous présente un exemple de sonde mesurant température et humidité.
Dans cet article (très très long), je préviens que vous n’allez peut être pas créer la meilleure sonde du monde. De nombreux sites proposent des méthodes poussées pour arriver à une solution optimale. Ici je vous présente le résultat de mes tests et vous propose de le réaliser chez vous. Je compte sur les experts pour proposer des améliorations via les commentaires 🙂
Pour rappel ma sonde fonctionne sur deux piles AA, avec un Atmega328, une LED pour indiquer le fonctionnement et un émetteur 433Mhz. La LED est optionnelle car source de consommation d’énergie mais pratique pour confirmer que tout fonctionne.
Après 16 17 18 19 20 jours de fonctionnement (la rédaction de l’article a pris du temps), ma sonde émet toujours les données avec une distance de 5m entre la sonde et la Gateway (un arduino connecté à un Raspberry Pi), sans murs mais avec un meuble en bois. Voici l’évolution du niveau des piles sur deux semaines :
La sonde a le fonctionnement suivant : toutes les 5 secondes (oui c’est pour les tests), la sonde DHT11 est activée, la température et l’humidité sont lues ainsi que le niveau des piles. Ces données constituent le message à envoyer. Le message est envoyé 4 fois à 160ms d’interval. Chaque envoi fait s’allumer puis éteindre la LED.
Vous pouvez donc imaginer qu’en diminuant le nombre d’envois, en supprimant la LED et en augmentant le temps entre chaque mesure, vos piles pourront durer facilement un an (je ferais bientôt un article sur le sujet).
Pré requis
Avant de pouvoir vous lancer dans l’aventure, il faut avoir un peu de matériel et un environnement de travail prêt à l’emploi.
Matériel
Vous aurez besoin :
- D’un atmega328 (juste la puce) avec ou sans bootloader, peu importe car nous allons y installer le notre. Vous en trouverez facilement sur ebay ou des sites chinois dans les 1.5€/pièce ou encore Amazon. En en commandant plusieurs vous pouvez encore diminuer un peu le prix.
- D’un Arduino UNO où vous pouvez enlever l’atmega. Il sera utilisé pour envoyer le bootloader et le programme de gestion de la sonde. Vous pourrez utiliser cet Arduino (ou un autre) comme récepteur. Comptez dans les 10€ (version non officielle mais légale), un peu plus sur Amazon (plus rapide). La carte pourra servir pour fabriquer d’autres sondes.
- Une sonde de température. J’ai utilisé une DHT11 que j’avais à la maison. Ce n’est vraiment pas ce qu’il y a de mieux, la DHT22 étant bien meilleure, mais je n’avais que ça sous la main à l’époque. Comptez 1.40€ la DHT11 ou 4.5€ la DHT22 (mais ca vaut le cout)
- Une résistance 4.7KΩ nécessaire pour la sonde DHT11
- Un émetteur et un récepteur 433Mhz. L’émetteur sera pour la sonde, le récepteur pour l’Arduino connecté au Raspberry. Un peu moins de 1€ la paire. Mais attention tous n’ont pas la même qualité … Par la suite je testerai d’autres modules de communication.
- Des piles AA. J’en utilise 2 que j’ai mis dans un boitier récupéré sur une guirlande LED de Noël. Les boitiers coutent environ 3.5€ les dix pièces (ou ici pour une livraison plus rapide).
- Des fils
- Une breadboard. Par le suite vous pourrez utiliser des plaques de prototypage, moins encombrantes et réutiliser la breadboard pour d’autres montages.
- (Optionnel mais très conseillé !) Des condensateurs de 22µF. Il en faudra 2 si vos Atmega328 sont configurés par défaut pour utiliser un oscillateur externe (et je ne crois pas que vous puissiez le savoir à l’avance)
- (Optionnel mais très conseillé !) Un résonateur 8Mhz ou 16Mhz si vos Atmega328 sont configurés par défaut pour utiliser un oscillateur externe
Vous voilà maintenant équipés et prêt à assembler votre sonde.
Environnement de travail
Quand je parle d’environnement de travail c’est essentiellement l’outil Arduino IDE. Prenez bien la version 1.5.8+, même si c’est une beta, pour pouvoir travailler !
Il s’agit maintenant de pouvoir configurer votre Atmega pour fonctionner avec son oscillateur interne (8Mhz) pour diminuer sa consommation générale. Pour cela je vous conseille de charger le fichier ZIP ici. L’archive doit être décompressée dans le sous répertoire hardware situé avec les différents programmes de votre Arduino. Voici ce que vous devez avoir :
Au démarrage de l’IDE Arduino vous devriez voir les nouvelles cartes installées :
Installation d’un bootloader optimisé
Voici le câblage pour charger le bootloader :
Une fois réalisé :
- Connecter l’arduino UNO à votre ordinateur via son câble USB
- Démarrer Arduino IDE puis confirmer la configuration
- Upload du programme pour que le UNO puisse envoyer le bootloader. Le programme est disponible dans le menu « Fichier > Exemples > ArduinoISP ». Puis cliquer sur « Téléverser »
L‘Arduino UNO est maintenant prêt à envoyer un bootloader à votre montage !
- Sélectionner le type de carte pour votre sonde. Nous choisissons donc un atmega328 sur un arduino en 3.3V et à la fréquence de 8Mhz
- Maintenant sélectionner la carte qui va programmer le bootloader. Il s’agit de notre Arduino
- Reste à graver le bootloader avec la commande « Graver le bootloader »
Vous avez maintenant configuré votre node pour fonctionner en 3.3V en utilisant l’oscillateur interne qui fonctionne à 8Mhz. C’est la première étape pour optimiser l’utilisation de l’énergie !
Vous pouvez maintenant ajouter votre sonde et l’émetteur. Si vous avez mis un résonateur, vous pouvez l’enlever (ainsi que les condensateurs) :
La carte Arduino UNO vous sera utile pour envoyer le programme dans votre nouvel Atmega. Vous pouvez la connecter comme sur le dessin ci dessus où bien prendre l’Atmega du node, le mettre sur la carte UNO, charger le programme grâce à l’IDE puis replacer l’Atmega du node sur la breadboard. A vous de voir, personnellement je déplace l’atmega 😉
La photo du montage final :
Installation du programme du capteur
Dans l’Arduino IDE vous devrez installer les librairies suivantes :
- La librairie DHT pour récupérer les données de votre sonde. Disponible ici.
- La librairie Narcoleptic pour mettre en sommeil « profond » votre node et ainsi économiser les piles. Disponible ici.
- La librairie Manchester pour envoyer les données via votre émetteur 433Mhz. Disponible ici.
L’installation des librairies se fait de la manière suivante :
- Récupérer le .zip de la librairie
- L’importer grâce à l’outil d’importation dans Arduino IDE (Sketches > Import librairies)
Voici le programme à envoyer vers votre node grâce à l’Arduino IDE :
#include <Narcoleptic.h> #include <dht.h> #include <Manchester.h> #define BLINK_MODE true #define NODE_ID 1 // On 8bits so 0..255 #define MESSAGE_SIZE 6 // Number of bytes to send #define SEND_MESSAGE_DELAY 5000 // Delay in ms between each value's extraction #define SEND_433_COUNT 4 // How many times the message has to be send #define SEND_433_PAUSE 160 // 16 multiple // Define connectors used for the node #define TX_PIN 7 #define LED_PIN 13 #define DHT11_PIN 2 dht DHT; // Array of bytes to will make the message // In this node : 2 bytes for voltage, 2 bytes for uint8_t msgData[MESSAGE_SIZE] = {0, 0, 0, 0, 0, 0}; //-------------------------------------------------------------------------------------------------- // Read current supply voltage //-------------------------------------------------------------------------------------------------- long readVcc() { bitClear(PRR, PRADC); ADCSRA |= bit(ADEN); // Enable the ADC long result; // Read 1.1V reference against Vcc #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); // For ATtiny84 #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega328 #endif delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA,ADSC)); result = ADCL; result |= ADCH<<8; result = 1126400L / result; // Back-calculate Vcc in mV ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC); // Disable the ADC to save power return result; // Vcc in millivolts } void setup() { pinMode(LED_PIN, OUTPUT); if (BLINK_MODE) digitalWrite(LED_PIN, LOW); man.setupTransmit(TX_PIN, MAN_1200); msgData[0] = NODE_ID; // Wait 1s to allow DHT11 to initialize Narcoleptic.delay(1000); } void loop() { // Read Vcc value long currentVcc = readVcc(); uint16_t uint16_currentVcc = (uint16_t)currentVcc; // Save millivolts in two bytes to keep high precision. Will be decoded by the gateway uint8_t byteData[2] = {uint16_currentVcc >> 8, uint16_currentVcc & 0xFF}; msgData[2] = byteData[0]; msgData[3] = byteData[1]; // Read data from DHT11 sensor int chk = DHT.read11(DHT11_PIN); // DHT11 values can be put in a byte value due to the low precision msgData[4] = (uint8_t)DHT.humidity; msgData[5] = (uint8_t)DHT.temperature; // Send message SEND_433_COUNT times with a delay of SEND_433_PAUSE ms for each for (int i=0; i<SEND_433_COUNT; i++) { msgData[1] = i; if (BLINK_MODE) digitalWrite(LED_PIN, HIGH); man.transmitArray(MESSAGE_SIZE, msgData); if (BLINK_MODE) digitalWrite(LED_PIN, LOW); // Wait between each send Narcoleptic.delay(SEND_433_PAUSE); } // Wait before getting new sensor value Narcoleptic.delay(SEND_MESSAGE_DELAY); }
Et après ?
Le prochain article montrera comment recevoir les données et les envoyer vers le Raspberry Pi qui saura (en principe) quoi en faire !
Il reste quand même à améliorer l’ensemble ! Comme par exemple :
- Optimisation du code. L’idée est de faire une bibliothèque générale, disponible sous GitHub, qui regroupera toutes les fonctions de récupération, conversion, etc. en fonction des capteurs connectés : DHT11, DHT22, LM36, etc.
- D’autres modules d’émission : NRF24L01+, ESP8266, etc.
Les modules 433Mz sont capricieux, pas toujours de bonne qualité, j’ai pas l’impression que ce soit le meilleur choix. Je vais donc continuer l’investigation
La suite du projet Pi Home Connect bientôt !
Pingback: Avec un Atmega, créer un capteur de température sans fil | RoboTechno()